From 246b3f2a5fdbf2e3f48510378d246a6b28a770f2 Mon Sep 17 00:00:00 2001 From: "Laszlo Boszormenyi (GCS)" Date: Thu, 20 Sep 2018 19:16:39 +0100 Subject: [PATCH] Import thrift_0.11.0.orig.tar.gz [dgit import orig thrift_0.11.0.orig.tar.gz] --- .clang-format | 56 + .dockerignore | 1 + .editorconfig | 112 + .rustfmt.toml | 7 + .travis.yml | 196 + CHANGES | 2656 ++ CMakeLists.txt | 124 + CONTRIBUTING.md | 99 + LANGUAGES.md | 305 + LICENSE | 239 + Makefile.am | 135 + Makefile.in | 1114 + NOTICE | 5 + README.md | 178 + Thrift.podspec | 18 + aclocal.m4 | 1719 + aclocal/ac_prog_bison.m4 | 54 + aclocal/ax_boost_base.m4 | 301 + aclocal/ax_check_openssl.m4 | 124 + aclocal/ax_compare_version.m4 | 177 + aclocal/ax_cxx_compile_stdcxx.m4 | 982 + aclocal/ax_cxx_compile_stdcxx_11.m4 | 39 + aclocal/ax_dmd.m4 | 107 + aclocal/ax_javac_and_java.m4 | 129 + aclocal/ax_lib_event.m4 | 194 + aclocal/ax_lib_zlib.m4 | 173 + aclocal/ax_lua.m4 | 664 + aclocal/ax_prog_dotnetcore_version.m4 | 61 + aclocal/ax_prog_haxe_version.m4 | 60 + aclocal/ax_prog_perl_modules.m4 | 77 + aclocal/ax_signed_right_shift.m4 | 127 + aclocal/ax_thrift_internal.m4 | 28 + aclocal/libtool.m4 | 8388 +++++ aclocal/ltoptions.m4 | 437 + aclocal/ltsugar.m4 | 124 + aclocal/ltversion.m4 | 23 + aclocal/lt~obsolete.m4 | 99 + appveyor.yml | 101 + bootstrap.sh | 57 + bower.json | 15 + build/appveyor/MING-appveyor-build.bat | 36 + build/appveyor/MING-appveyor-install.bat | 21 + build/appveyor/MING-appveyor-test.bat | 16 + build/appveyor/MSVC-appveyor-build.bat | 47 + build/appveyor/MSVC-appveyor-install.bat | 72 + build/appveyor/MSVC-appveyor-test.bat | 25 + build/appveyor/MSYS-appveyor-build.bat | 47 + build/appveyor/MSYS-appveyor-install.bat | 41 + build/appveyor/MSYS-appveyor-test.bat | 26 + build/appveyor/README.md | 34 + build/appveyor/build-libevent.bat | 30 + build/appveyor/build-zlib.bat | 49 + build/appveyor/cl_banner_apache_thrift.bat | 24 + build/appveyor/cl_banner_build.bat | 23 + build/appveyor/cl_banner_install.bat | 23 + build/appveyor/cl_banner_test.bat | 23 + build/appveyor/cl_setcompiler.bat | 63 + build/appveyor/cl_setenv.bat | 92 + build/appveyor/cl_setgenerator.bat | 74 + build/appveyor/cl_showenv.bat | 67 + build/appveyor/simulate-appveyor.bat | 35 + build/cmake/CPackConfig.cmake | 68 + build/cmake/ConfigureChecks.cmake | 76 + build/cmake/DefineCMakeDefaults.cmake | 93 + build/cmake/DefineInstallationPaths.cmake | 26 + build/cmake/DefineOptions.cmake | 219 + build/cmake/DefinePlatformSpecifc.cmake | 131 + build/cmake/FindAnt.cmake | 30 + build/cmake/FindCabal.cmake | 30 + build/cmake/FindGHC.cmake | 36 + build/cmake/FindGLIB.cmake | 122 + build/cmake/FindGradle.cmake | 30 + build/cmake/FindInttypes.cmake | 41 + build/cmake/FindLibevent.cmake | 45 + build/cmake/NewPlatformDebug.cmake | 44 + build/cmake/README-MSYS2.md | 63 + build/cmake/README.md | 60 + build/cmake/ThriftMacros.cmake | 105 + build/cmake/android-toolchain.cmake | 26 + build/cmake/config.h.in | 154 + build/cmake/mingw32-toolchain.cmake | 24 + build/docker/README.md | 168 + build/docker/Vagrantfile | 59 + build/docker/centos-7.3/Dockerfile | 199 + build/docker/debian-jessie/Dockerfile | 204 + build/docker/debian-stretch/Dockerfile | 231 + build/docker/refresh.sh | 82 + build/docker/run.sh | 30 + build/docker/scripts/autotools.sh | 6 + build/docker/scripts/cmake.sh | 23 + build/docker/scripts/cross-test.sh | 16 + build/docker/scripts/dpkg.sh | 5 + build/docker/scripts/make-dist.sh | 9 + build/docker/scripts/sca.sh | 62 + build/docker/scripts/ubsan.sh | 30 + build/docker/ubuntu-artful/Dockerfile | 254 + build/docker/ubuntu-trusty/Dockerfile | 223 + build/docker/ubuntu-trusty/Dockerfile.orig | 231 + build/docker/ubuntu-xenial/Dockerfile | 249 + build/travis/installCXXDependencies.sh | 29 + build/travis/installDependencies.sh | 66 + build/wincpp/README.md | 219 + build/wincpp/build-thrift-compiler.bat | 79 + build/wincpp/build-thrift.bat | 164 + build/wincpp/scripts/cl_setarch.bat | 47 + build/wincpp/scripts/cl_setcompiler.bat | 58 + build/wincpp/scripts/cl_setgenerator.bat | 69 + build/wincpp/scripts/tpversions.bat | 24 + .../wincpp/thirdparty/src/build-libevent.bat | 86 + build/wincpp/thirdparty/src/build-openssl.bat | 106 + build/wincpp/thirdparty/src/build-zlib.bat | 75 + cleanup.sh | 89 + compile | 347 + compiler/cpp/CMakeLists.txt | 217 + compiler/cpp/Makefile.am | 205 + compiler/cpp/Makefile.in | 2314 ++ compiler/cpp/README.md | 101 + compiler/cpp/coding_standards.md | 4 + compiler/cpp/compiler.sln | 20 + compiler/cpp/compiler.vcxproj | 251 + compiler/cpp/compiler.vcxproj.filters | 199 + compiler/cpp/src/Makefile.am | 87 + compiler/cpp/src/Makefile.in | 1157 + compiler/cpp/src/thrift/audit/t_audit.cpp | 464 + compiler/cpp/src/thrift/audit/t_audit.h | 14 + compiler/cpp/src/thrift/common.cc | 69 + compiler/cpp/src/thrift/common.h | 43 + .../src/thrift/generate/t_as3_generator.cc | 2594 ++ .../src/thrift/generate/t_c_glib_generator.cc | 4562 +++ .../src/thrift/generate/t_cocoa_generator.cc | 3301 ++ .../src/thrift/generate/t_cpp_generator.cc | 4486 +++ .../src/thrift/generate/t_csharp_generator.cc | 3224 ++ .../cpp/src/thrift/generate/t_d_generator.cc | 742 + .../src/thrift/generate/t_dart_generator.cc | 2516 ++ .../src/thrift/generate/t_delphi_generator.cc | 3920 ++ .../src/thrift/generate/t_erl_generator.cc | 1251 + .../cpp/src/thrift/generate/t_generator.cc | 190 + .../cpp/src/thrift/generate/t_generator.h | 322 + .../thrift/generate/t_generator_registry.h | 106 + .../cpp/src/thrift/generate/t_go_generator.cc | 3639 ++ .../cpp/src/thrift/generate/t_gv_generator.cc | 345 + .../src/thrift/generate/t_haxe_generator.cc | 2983 ++ .../cpp/src/thrift/generate/t_hs_generator.cc | 1732 + .../src/thrift/generate/t_html_generator.cc | 1088 + .../src/thrift/generate/t_html_generator.h | 240 + .../src/thrift/generate/t_java_generator.cc | 5381 +++ .../src/thrift/generate/t_javame_generator.cc | 3296 ++ .../cpp/src/thrift/generate/t_js_generator.cc | 2285 ++ .../src/thrift/generate/t_json_generator.cc | 793 + .../src/thrift/generate/t_lua_generator.cc | 1138 + .../thrift/generate/t_netcore_generator.cc | 3187 ++ .../src/thrift/generate/t_ocaml_generator.cc | 1762 + .../cpp/src/thrift/generate/t_oop_generator.h | 112 + .../src/thrift/generate/t_perl_generator.cc | 1683 + .../src/thrift/generate/t_php_generator.cc | 2679 ++ .../cpp/src/thrift/generate/t_py_generator.cc | 2743 ++ .../cpp/src/thrift/generate/t_rb_generator.cc | 1263 + .../cpp/src/thrift/generate/t_rs_generator.cc | 3280 ++ .../cpp/src/thrift/generate/t_st_generator.cc | 1056 + .../src/thrift/generate/t_swift_generator.cc | 2209 ++ .../src/thrift/generate/t_xml_generator.cc | 692 + .../src/thrift/generate/t_xsd_generator.cc | 376 + compiler/cpp/src/thrift/globals.h | 141 + compiler/cpp/src/thrift/logging.cc | 77 + compiler/cpp/src/thrift/logging.h | 47 + compiler/cpp/src/thrift/main.cc | 1307 + compiler/cpp/src/thrift/main.h | 119 + compiler/cpp/src/thrift/parse/parse.cc | 39 + compiler/cpp/src/thrift/parse/t_base_type.h | 117 + compiler/cpp/src/thrift/parse/t_const.h | 50 + compiler/cpp/src/thrift/parse/t_const_value.h | 155 + compiler/cpp/src/thrift/parse/t_container.h | 47 + compiler/cpp/src/thrift/parse/t_doc.h | 55 + compiler/cpp/src/thrift/parse/t_enum.h | 110 + compiler/cpp/src/thrift/parse/t_enum_value.h | 50 + compiler/cpp/src/thrift/parse/t_field.h | 134 + compiler/cpp/src/thrift/parse/t_function.h | 93 + compiler/cpp/src/thrift/parse/t_list.h | 41 + compiler/cpp/src/thrift/parse/t_map.h | 45 + compiler/cpp/src/thrift/parse/t_program.h | 395 + compiler/cpp/src/thrift/parse/t_scope.h | 188 + compiler/cpp/src/thrift/parse/t_service.h | 61 + compiler/cpp/src/thrift/parse/t_set.h | 41 + compiler/cpp/src/thrift/parse/t_struct.h | 171 + compiler/cpp/src/thrift/parse/t_type.h | 109 + compiler/cpp/src/thrift/parse/t_typedef.cc | 34 + compiler/cpp/src/thrift/parse/t_typedef.h | 66 + compiler/cpp/src/thrift/platform.h | 50 + compiler/cpp/src/thrift/plugin/Makefile.am | 47 + compiler/cpp/src/thrift/plugin/Makefile.in | 652 + compiler/cpp/src/thrift/plugin/plugin.cc | 501 + compiler/cpp/src/thrift/plugin/plugin.h | 44 + compiler/cpp/src/thrift/plugin/plugin.thrift | 202 + .../cpp/src/thrift/plugin/plugin_output.cc | 412 + .../cpp/src/thrift/plugin/plugin_output.h | 38 + compiler/cpp/src/thrift/plugin/type_util.h | 94 + compiler/cpp/src/thrift/thriftl.cc | 3496 ++ compiler/cpp/src/thrift/thriftl.ll | 473 + compiler/cpp/src/thrift/thrifty.cc | 3057 ++ compiler/cpp/src/thrift/thrifty.hh | 179 + compiler/cpp/src/thrift/thrifty.yy | 1200 + compiler/cpp/src/thrift/version.h | 29 + compiler/cpp/src/thrift/version.h.in | 29 + compiler/cpp/src/thrift/windows/config.h | 70 + compiler/cpp/test/CMakeLists.txt | 77 + compiler/cpp/test/Makefile | 984 + compiler/cpp/test/Makefile.am | 51 + compiler/cpp/test/Makefile.in | 984 + compiler/cpp/test/cpp_plugin_test.cmake | 45 + compiler/cpp/test/cpp_plugin_test.sh | 27 + compiler/cpp/test/plugin/conversion_test.cc | 496 + compiler/cpp/test/plugin/cpp_plugin.cc | 43 + compiler/cpp/test/plugin/t_cpp_generator.cc | 4486 +++ composer.json | 30 + config.guess | 1441 + config.h | 461 + config.hin | 460 + config.sub | 1813 + configure | 30103 ++++++++++++++++ configure.ac | 1055 + contrib/Rebus/App.config | 33 + contrib/Rebus/Program.cs | 81 + contrib/Rebus/Properties/AssemblyInfo.cs | 38 + contrib/Rebus/README.md | 21 + contrib/Rebus/RebusSample.csproj | 102 + contrib/Rebus/RebusSample.sln | 28 + contrib/Rebus/ServiceImpl/Both.cs | 35 + contrib/Rebus/ServiceImpl/Client.cs | 157 + contrib/Rebus/ServiceImpl/Server.cs | 143 + contrib/Rebus/sample.thrift | 30 + contrib/Stomp/README.md | 18 + contrib/Stomp/Thrift.Transport.STOMP.pas | 200 + contrib/Vagrantfile | 133 + contrib/async-test/Makefile | 33 + contrib/async-test/aggr.thrift | 8 + contrib/async-test/test-leaf.py | 24 + contrib/async-test/test-server.cpp | 97 + contrib/fb303/LICENSE | 16 + contrib/fb303/Makefile.am | 46 + contrib/fb303/README.md | 37 + contrib/fb303/TClientInfo.cpp | 178 + contrib/fb303/TClientInfo.h | 320 + contrib/fb303/acinclude.m4 | 258 + contrib/fb303/aclocal/ax_boost_base.m4 | 198 + .../fb303/aclocal/ax_cxx_compile_stdcxx_11.m4 | 134 + contrib/fb303/aclocal/ax_javac_and_java.m4 | 121 + contrib/fb303/aclocal/ax_thrift_internal.m4 | 28 + contrib/fb303/bootstrap.sh | 26 + contrib/fb303/configure.ac | 164 + contrib/fb303/cpp/FacebookBase.cpp | 124 + contrib/fb303/cpp/FacebookBase.h | 103 + contrib/fb303/cpp/Makefile.am | 84 + contrib/fb303/cpp/ServiceTracker.cpp | 481 + contrib/fb303/cpp/ServiceTracker.h | 215 + contrib/fb303/global_footer.mk | 21 + contrib/fb303/global_header.mk | 38 + contrib/fb303/if/fb303.thrift | 113 + contrib/fb303/java/build.xml | 195 + contrib/fb303/java/src/FacebookBase.java | 114 + contrib/fb303/php/FacebookBase.php | 89 + contrib/fb303/py/Makefile.am | 44 + contrib/fb303/py/fb303/FacebookBase.py | 83 + contrib/fb303/py/fb303_scripts/__init__.py | 20 + .../py/fb303_scripts/fb303_simple_mgmt.py | 191 + contrib/fb303/py/setup.py | 48 + contrib/mingw-cross-compile.sh | 19 + contrib/parse_profiling.py | 312 + contrib/thrift-maven-plugin/pom.xml | 92 + .../thrift/maven/AbstractThriftMojo.java | 380 + .../java/org/apache/thrift/maven/Thrift.java | 262 + .../thrift/maven/ThriftCompileMojo.java | 78 + .../thrift/maven/ThriftTestCompileMojo.java | 93 + .../thrift/maven/TestAbstractThriftMojo.java | 102 + .../org/apache/thrift/maven/TestThrift.java | 163 + .../src/test/resources/idl/shared.thrift | 36 + .../src/test/resources/idl/tutorial.thrift | 152 + contrib/thrift.el | 140 + contrib/thrift.spec | 238 + contrib/thrift.vim | 91 + contrib/thrift_dump.cpp | 91 + contrib/transport-sample/Makefile | 25 + contrib/transport-sample/README.md | 61 + contrib/transport-sample/Sample.thrift | 39 + contrib/transport-sample/ThriftCommon.cpp | 37 + contrib/transport-sample/ThriftCommon.h | 207 + contrib/transport-sample/client/ReadMe.txt | 40 + contrib/transport-sample/client/client.cpp | 195 + .../transport-sample/client/client.vcxproj | 105 + .../client/client.vcxproj.filters | 66 + contrib/transport-sample/client/stdafx.cpp | 8 + contrib/transport-sample/client/stdafx.h | 15 + contrib/transport-sample/client/targetver.h | 8 + contrib/transport-sample/config.h | 24 + contrib/transport-sample/server/ReadMe.txt | 40 + contrib/transport-sample/server/server.cpp | 168 + .../transport-sample/server/server.vcxproj | 106 + .../server/server.vcxproj.filters | 66 + contrib/transport-sample/server/stdafx.cpp | 8 + contrib/transport-sample/server/stdafx.h | 15 + contrib/transport-sample/server/targetver.h | 8 + contrib/transport-sample/thriftme.bat | 1 + contrib/transport-sample/thriftme.sh | 24 + contrib/transport-sample/transport-sample.sln | 26 + contrib/vagrant/centos-6.5/README.md | 61 + contrib/vagrant/centos-6.5/Vagrantfile | 274 + contrib/zeromq/Makefile | 39 + contrib/zeromq/README.md | 30 + contrib/zeromq/TZmqClient.cpp | 48 + contrib/zeromq/TZmqClient.h | 65 + contrib/zeromq/TZmqClient.py | 64 + contrib/zeromq/TZmqServer.cpp | 96 + contrib/zeromq/TZmqServer.h | 83 + contrib/zeromq/TZmqServer.py | 79 + contrib/zeromq/csharp/AssemblyInfo.cs | 46 + contrib/zeromq/csharp/Main.cs | 60 + contrib/zeromq/csharp/TZmqClient.cs | 78 + contrib/zeromq/csharp/TZmqServer.cs | 56 + contrib/zeromq/csharp/ThriftZMQ.csproj | 109 + contrib/zeromq/csharp/ThriftZMQ.sln | 42 + contrib/zeromq/storage.thrift | 4 + contrib/zeromq/test-client.cpp | 40 + contrib/zeromq/test-client.py | 36 + contrib/zeromq/test-receiver.cpp | 40 + contrib/zeromq/test-sender.cpp | 32 + contrib/zeromq/test-server.cpp | 43 + contrib/zeromq/test-server.py | 33 + debian/README.md | 41 + debian/changelog | 66 + debian/compat | 1 + debian/control | 202 + debian/copyright | 129 + debian/dirs | 2 + debian/docs | 1 + debian/libthrift-dev.install | 4 + debian/libthrift0.install | 5 + debian/php5-thrift.dirs | 1 + debian/rules | 228 + debian/substvars | 1 + debian/thrift-doc.docs | 2 + debian/thrift-doc.install | 2 + depcomp | 791 + doap.rdf | 145 + doc/coding_standards.md | 48 + doc/committers.md | 54 + doc/images/cgrn.png | Bin 0 -> 1125 bytes doc/images/cred.png | Bin 0 -> 1169 bytes doc/images/credfull.png | Bin 0 -> 1057 bytes doc/images/cyel.png | Bin 0 -> 946 bytes doc/images/thrift-layers.png | Bin 0 -> 27211 bytes doc/install/README.md | 43 + doc/install/centos.md | 75 + doc/install/debian.md | 46 + doc/install/os_x.md | 27 + doc/install/windows.md | 186 + doc/licenses/lgpl-2.1.txt | 504 + doc/licenses/otp-base-license.txt | 20 + doc/specs/HeaderFormat.md | 82 + doc/specs/idl.md | 272 + doc/specs/thrift-binary-protocol.md | 254 + doc/specs/thrift-compact-protocol.md | 294 + doc/specs/thrift-protocol-spec.md | 101 + doc/specs/thrift-rpc.md | 178 + doc/specs/thrift-sasl-spec.txt | 108 + doc/specs/thrift.tex | 1057 + install-sh | 508 + lib/Makefile.am | 117 + lib/Makefile.in | 855 + lib/as3/build.xml | 180 + lib/as3/coding_standards.md | 1 + .../org/apache/thrift/AbstractMethodError.as | 31 + lib/as3/src/org/apache/thrift/Set.as | 82 + .../org/apache/thrift/TApplicationError.as | 106 + lib/as3/src/org/apache/thrift/TBase.as | 67 + lib/as3/src/org/apache/thrift/TError.as | 29 + .../apache/thrift/TFieldRequirementType.as | 32 + lib/as3/src/org/apache/thrift/TProcessor.as | 32 + .../apache/thrift/meta_data/FieldMetaData.as | 57 + .../thrift/meta_data/FieldValueMetaData.as | 44 + .../apache/thrift/meta_data/ListMetaData.as | 31 + .../apache/thrift/meta_data/MapMetaData.as | 33 + .../apache/thrift/meta_data/SetMetaData.as | 31 + .../apache/thrift/meta_data/StructMetaData.as | 31 + .../apache/thrift/protocol/TBinaryProtocol.as | 316 + .../src/org/apache/thrift/protocol/TField.as | 43 + .../src/org/apache/thrift/protocol/TList.as | 33 + .../src/org/apache/thrift/protocol/TMap.as | 33 + .../org/apache/thrift/protocol/TMessage.as | 42 + .../apache/thrift/protocol/TMessageType.as | 28 + .../org/apache/thrift/protocol/TProtocol.as | 124 + .../apache/thrift/protocol/TProtocolError.as | 39 + .../thrift/protocol/TProtocolFactory.as | 27 + .../apache/thrift/protocol/TProtocolUtil.as | 148 + .../src/org/apache/thrift/protocol/TSet.as | 33 + .../src/org/apache/thrift/protocol/TStruct.as | 31 + .../src/org/apache/thrift/protocol/TType.as | 39 + .../thrift/transport/TFullDuplexHttpClient.as | 251 + .../apache/thrift/transport/THttpClient.as | 134 + .../org/apache/thrift/transport/TSocket.as | 194 + .../org/apache/thrift/transport/TTransport.as | 127 + .../thrift/transport/TTransportError.as | 37 + lib/c_glib/CMakeLists.txt | 86 + lib/c_glib/Makefile.am | 118 + lib/c_glib/Makefile.in | 1604 + lib/c_glib/README.md | 34 + lib/c_glib/coding_standards.md | 5 + .../processor/thrift_dispatch_processor.c | 143 + .../processor/thrift_dispatch_processor.h | 95 + .../processor/thrift_multiplexed_processor.c | 346 + .../processor/thrift_multiplexed_processor.h | 114 + .../c_glib/processor/thrift_processor.c | 45 + .../c_glib/processor/thrift_processor.h | 76 + .../c_glib/protocol/thrift_binary_protocol.c | 911 + .../c_glib/protocol/thrift_binary_protocol.h | 72 + .../protocol/thrift_binary_protocol_factory.c | 50 + .../protocol/thrift_binary_protocol_factory.h | 56 + .../c_glib/protocol/thrift_compact_protocol.c | 1609 + .../c_glib/protocol/thrift_compact_protocol.h | 107 + .../thrift_compact_protocol_factory.c | 140 + .../thrift_compact_protocol_factory.h | 70 + .../protocol/thrift_multiplexed_protocol.c | 158 + .../protocol/thrift_multiplexed_protocol.h | 76 + .../thrift/c_glib/protocol/thrift_protocol.c | 620 + .../thrift/c_glib/protocol/thrift_protocol.h | 341 + .../protocol/thrift_protocol_decorator.c | 623 + .../protocol/thrift_protocol_decorator.h | 72 + .../c_glib/protocol/thrift_protocol_factory.c | 43 + .../c_glib/protocol/thrift_protocol_factory.h | 73 + .../protocol/thrift_stored_message_protocol.c | 192 + .../protocol/thrift_stored_message_protocol.h | 78 + .../src/thrift/c_glib/server/thrift_server.c | 195 + .../src/thrift/c_glib/server/thrift_server.h | 93 + .../c_glib/server/thrift_simple_server.c | 138 + .../c_glib/server/thrift_simple_server.h | 70 + lib/c_glib/src/thrift/c_glib/thrift.c | 101 + lib/c_glib/src/thrift/c_glib/thrift.h | 49 + .../c_glib/thrift_application_exception.c | 277 + .../c_glib/thrift_application_exception.h | 86 + lib/c_glib/src/thrift/c_glib/thrift_struct.c | 52 + lib/c_glib/src/thrift/c_glib/thrift_struct.h | 68 + .../transport/thrift_buffered_transport.c | 390 + .../transport/thrift_buffered_transport.h | 77 + .../thrift_buffered_transport_factory.c | 55 + .../thrift_buffered_transport_factory.h | 86 + .../c_glib/transport/thrift_fd_transport.c | 265 + .../c_glib/transport/thrift_fd_transport.h | 74 + .../transport/thrift_framed_transport.c | 383 + .../transport/thrift_framed_transport.h | 77 + .../thrift_framed_transport_factory.c | 55 + .../thrift_framed_transport_factory.h | 86 + .../c_glib/transport/thrift_memory_buffer.c | 285 + .../c_glib/transport/thrift_memory_buffer.h | 72 + .../c_glib/transport/thrift_platform_socket.h | 120 + .../c_glib/transport/thrift_server_socket.c | 253 + .../c_glib/transport/thrift_server_socket.h | 90 + .../transport/thrift_server_transport.c | 62 + .../transport/thrift_server_transport.h | 89 + .../thrift/c_glib/transport/thrift_socket.c | 374 + .../thrift/c_glib/transport/thrift_socket.h | 72 + .../c_glib/transport/thrift_ssl_socket.c | 806 + .../c_glib/transport/thrift_ssl_socket.h | 218 + .../c_glib/transport/thrift_transport.c | 162 + .../c_glib/transport/thrift_transport.h | 176 + .../transport/thrift_transport_factory.c | 44 + .../transport/thrift_transport_factory.h | 71 + lib/c_glib/test/CMakeLists.txt | 202 + lib/c_glib/test/ContainerTest.thrift | 35 + lib/c_glib/test/Makefile.am | 324 + lib/c_glib/test/Makefile.in | 1822 + lib/c_glib/test/glib.suppress | 64 + lib/c_glib/test/testapplicationexception.c | 180 + lib/c_glib/test/testbinaryprotocol.c | 859 + lib/c_glib/test/testbufferedtransport.c | 328 + lib/c_glib/test/testcompactprotocol.c | 1293 + lib/c_glib/test/testcontainertest.c | 529 + lib/c_glib/test/testdebugproto.c | 941 + lib/c_glib/test/testfdtransport.c | 184 + lib/c_glib/test/testframedtransport.c | 326 + lib/c_glib/test/testmemorybuffer.c | 223 + lib/c_glib/test/testoptionalrequired.c | 227 + lib/c_glib/test/testserialization.c | 95 + lib/c_glib/test/testsimpleserver.c | 122 + lib/c_glib/test/teststruct.c | 111 + lib/c_glib/test/testthrifttest.c | 112 + lib/c_glib/test/testthrifttestclient.cpp | 639 + lib/c_glib/test/testtransportsocket.c | 364 + lib/c_glib/test/testtransportsslsocket.c | 542 + lib/c_glib/thrift_c_glib.pc.in | 30 + lib/cocoa/README.md | 21 + lib/cocoa/coding_standards.md | 1 + lib/cocoa/src/TApplicationError.h | 55 + lib/cocoa/src/TApplicationError.m | 231 + lib/cocoa/src/TBaseClient.h | 27 + lib/cocoa/src/TBaseClient.m | 51 + lib/cocoa/src/TBinary.swift | 122 + lib/cocoa/src/TEnum.swift | 31 + lib/cocoa/src/TError.h | 23 + lib/cocoa/src/TError.m | 23 + lib/cocoa/src/TList.swift | 148 + lib/cocoa/src/TMap.swift | 158 + lib/cocoa/src/TProcessor.h | 35 + lib/cocoa/src/TProcessorFactory.h | 33 + lib/cocoa/src/TProtocol.swift | 190 + lib/cocoa/src/TSerializable.swift | 178 + lib/cocoa/src/TSet.swift | 161 + lib/cocoa/src/TSharedProcessorFactory.h | 28 + lib/cocoa/src/TSharedProcessorFactory.m | 49 + lib/cocoa/src/TStruct.swift | 31 + lib/cocoa/src/Thrift.h | 20 + lib/cocoa/src/protocol/TBase.h | 46 + lib/cocoa/src/protocol/TBinaryProtocol.h | 49 + lib/cocoa/src/protocol/TBinaryProtocol.m | 740 + lib/cocoa/src/protocol/TCompactProtocol.h | 42 + lib/cocoa/src/protocol/TCompactProtocol.m | 983 + lib/cocoa/src/protocol/TMultiplexedProtocol.h | 38 + lib/cocoa/src/protocol/TMultiplexedProtocol.m | 66 + lib/cocoa/src/protocol/TProtocol.h | 164 + lib/cocoa/src/protocol/TProtocolDecorator.h | 34 + lib/cocoa/src/protocol/TProtocolDecorator.m | 295 + lib/cocoa/src/protocol/TProtocolError.h | 76 + lib/cocoa/src/protocol/TProtocolError.m | 33 + lib/cocoa/src/protocol/TProtocolFactory.h | 36 + lib/cocoa/src/protocol/TProtocolUtil.h | 33 + lib/cocoa/src/protocol/TProtocolUtil.m | 171 + lib/cocoa/src/server/TSocketServer.h | 51 + lib/cocoa/src/server/TSocketServer.m | 239 + lib/cocoa/src/transport/TAsyncTransport.h | 46 + lib/cocoa/src/transport/TFramedTransport.h | 33 + lib/cocoa/src/transport/TFramedTransport.m | 180 + .../src/transport/THTTPSessionTransport.h | 47 + .../src/transport/THTTPSessionTransport.m | 268 + lib/cocoa/src/transport/THTTPTransport.h | 39 + lib/cocoa/src/transport/THTTPTransport.m | 182 + lib/cocoa/src/transport/TMemoryBuffer.h | 37 + lib/cocoa/src/transport/TMemoryBuffer.m | 121 + .../src/transport/TNSFileHandleTransport.h | 38 + .../src/transport/TNSFileHandleTransport.m | 118 + lib/cocoa/src/transport/TNSStreamTransport.h | 43 + lib/cocoa/src/transport/TNSStreamTransport.m | 153 + lib/cocoa/src/transport/TSSLSocketTransport.h | 37 + lib/cocoa/src/transport/TSSLSocketTransport.m | 304 + .../src/transport/TSSLSocketTransportError.h | 30 + .../src/transport/TSSLSocketTransportError.m | 23 + lib/cocoa/src/transport/TSocketTransport.h | 36 + lib/cocoa/src/transport/TSocketTransport.m | 131 + lib/cocoa/src/transport/TTransport.h | 48 + lib/cocoa/src/transport/TTransportError.h | 43 + lib/cocoa/src/transport/TTransportError.m | 27 + lib/cpp/3rdparty.props | 25 + lib/cpp/CMakeLists.txt | 219 + lib/cpp/Makefile.am | 290 + lib/cpp/Makefile.in | 1992 + lib/cpp/README.md | 296 + lib/cpp/coding_standards.md | 4 + lib/cpp/libthrift.vcxproj | 369 + lib/cpp/libthrift.vcxproj.filters | 283 + lib/cpp/libthriftnb.vcxproj | 298 + lib/cpp/libthriftnb.vcxproj.filters | 75 + lib/cpp/src/thrift/TApplicationException.cpp | 81 + lib/cpp/src/thrift/TApplicationException.h | 115 + lib/cpp/src/thrift/TBase.h | 38 + lib/cpp/src/thrift/TDispatchProcessor.h | 141 + lib/cpp/src/thrift/TLogging.h | 195 + lib/cpp/src/thrift/TOutput.cpp | 126 + lib/cpp/src/thrift/TOutput.h | 58 + lib/cpp/src/thrift/TProcessor.h | 230 + lib/cpp/src/thrift/TToString.h | 114 + lib/cpp/src/thrift/Thrift.h | 136 + lib/cpp/src/thrift/VirtualProfiling.cpp | 425 + .../src/thrift/async/TAsyncBufferProcessor.h | 46 + lib/cpp/src/thrift/async/TAsyncChannel.cpp | 37 + lib/cpp/src/thrift/async/TAsyncChannel.h | 73 + .../thrift/async/TAsyncDispatchProcessor.h | 151 + lib/cpp/src/thrift/async/TAsyncProcessor.h | 84 + .../thrift/async/TAsyncProtocolProcessor.cpp | 53 + .../thrift/async/TAsyncProtocolProcessor.h | 55 + .../async/TConcurrentClientSyncInfo.cpp | 242 + .../thrift/async/TConcurrentClientSyncInfo.h | 126 + .../src/thrift/async/TEvhttpClientChannel.cpp | 155 + .../src/thrift/async/TEvhttpClientChannel.h | 86 + lib/cpp/src/thrift/async/TEvhttpServer.cpp | 161 + lib/cpp/src/thrift/async/TEvhttpServer.h | 74 + .../src/thrift/concurrency/BoostMonitor.cpp | 214 + lib/cpp/src/thrift/concurrency/BoostMutex.cpp | 73 + .../thrift/concurrency/BoostThreadFactory.cpp | 162 + .../thrift/concurrency/BoostThreadFactory.h | 63 + lib/cpp/src/thrift/concurrency/Exception.h | 64 + .../src/thrift/concurrency/FunctionRunner.h | 118 + lib/cpp/src/thrift/concurrency/Monitor.cpp | 225 + lib/cpp/src/thrift/concurrency/Monitor.h | 133 + lib/cpp/src/thrift/concurrency/Mutex.cpp | 380 + lib/cpp/src/thrift/concurrency/Mutex.h | 189 + .../concurrency/PlatformThreadFactory.h | 52 + .../thrift/concurrency/PosixThreadFactory.cpp | 335 + .../thrift/concurrency/PosixThreadFactory.h | 129 + lib/cpp/src/thrift/concurrency/StdMonitor.cpp | 213 + lib/cpp/src/thrift/concurrency/StdMutex.cpp | 71 + .../thrift/concurrency/StdThreadFactory.cpp | 153 + .../src/thrift/concurrency/StdThreadFactory.h | 61 + lib/cpp/src/thrift/concurrency/Thread.h | 177 + .../src/thrift/concurrency/ThreadManager.cpp | 584 + .../src/thrift/concurrency/ThreadManager.h | 213 + .../src/thrift/concurrency/TimerManager.cpp | 347 + lib/cpp/src/thrift/concurrency/TimerManager.h | 147 + lib/cpp/src/thrift/concurrency/Util.cpp | 44 + lib/cpp/src/thrift/concurrency/Util.h | 151 + .../src/thrift/processor/PeekProcessor.cpp | 132 + lib/cpp/src/thrift/processor/PeekProcessor.h | 83 + lib/cpp/src/thrift/processor/StatsProcessor.h | 242 + .../thrift/processor/TMultiplexedProcessor.h | 224 + lib/cpp/src/thrift/protocol/TBase64Utils.cpp | 317 + lib/cpp/src/thrift/protocol/TBase64Utils.h | 45 + lib/cpp/src/thrift/protocol/TBinaryProtocol.h | 250 + .../src/thrift/protocol/TBinaryProtocol.tcc | 454 + .../src/thrift/protocol/TCompactProtocol.h | 266 + .../src/thrift/protocol/TCompactProtocol.tcc | 826 + .../src/thrift/protocol/TDebugProtocol.cpp | 394 + lib/cpp/src/thrift/protocol/TDebugProtocol.h | 204 + .../src/thrift/protocol/THeaderProtocol.cpp | 254 + lib/cpp/src/thrift/protocol/THeaderProtocol.h | 210 + lib/cpp/src/thrift/protocol/TJSONProtocol.cpp | 1101 + lib/cpp/src/thrift/protocol/TJSONProtocol.h | 325 + .../thrift/protocol/TMultiplexedProtocol.cpp | 40 + .../thrift/protocol/TMultiplexedProtocol.h | 95 + lib/cpp/src/thrift/protocol/TProtocol.cpp | 33 + lib/cpp/src/thrift/protocol/TProtocol.h | 764 + .../src/thrift/protocol/TProtocolDecorator.h | 151 + .../src/thrift/protocol/TProtocolException.h | 105 + lib/cpp/src/thrift/protocol/TProtocolTap.h | 177 + lib/cpp/src/thrift/protocol/TProtocolTypes.h | 36 + .../src/thrift/protocol/TVirtualProtocol.h | 513 + lib/cpp/src/thrift/qt/CMakeLists.txt | 28 + lib/cpp/src/thrift/qt/TQIODeviceTransport.cpp | 169 + lib/cpp/src/thrift/qt/TQIODeviceTransport.h | 68 + lib/cpp/src/thrift/qt/TQTcpServer.cpp | 151 + lib/cpp/src/thrift/qt/TQTcpServer.h | 81 + .../src/thrift/server/TConnectedClient.cpp | 123 + lib/cpp/src/thrift/server/TConnectedClient.h | 110 + .../src/thrift/server/TNonblockingServer.cpp | 1476 + .../src/thrift/server/TNonblockingServer.h | 862 + lib/cpp/src/thrift/server/TServer.cpp | 52 + lib/cpp/src/thrift/server/TServer.h | 273 + .../src/thrift/server/TServerFramework.cpp | 245 + lib/cpp/src/thrift/server/TServerFramework.h | 184 + lib/cpp/src/thrift/server/TSimpleServer.cpp | 107 + lib/cpp/src/thrift/server/TSimpleServer.h | 77 + .../src/thrift/server/TThreadPoolServer.cpp | 132 + lib/cpp/src/thrift/server/TThreadPoolServer.h | 101 + lib/cpp/src/thrift/server/TThreadedServer.cpp | 151 + lib/cpp/src/thrift/server/TThreadedServer.h | 143 + lib/cpp/src/thrift/stdcxx.h | 124 + lib/cpp/src/thrift/thrift-config.h | 24 + lib/cpp/src/thrift/transport/PlatformSocket.h | 130 + .../thrift/transport/TBufferTransports.cpp | 415 + .../src/thrift/transport/TBufferTransports.h | 747 + lib/cpp/src/thrift/transport/TFDTransport.cpp | 93 + lib/cpp/src/thrift/transport/TFDTransport.h | 77 + .../src/thrift/transport/TFileTransport.cpp | 1089 + lib/cpp/src/thrift/transport/TFileTransport.h | 441 + .../src/thrift/transport/THeaderTransport.cpp | 612 + .../src/thrift/transport/THeaderTransport.h | 276 + lib/cpp/src/thrift/transport/THttpClient.cpp | 123 + lib/cpp/src/thrift/transport/THttpClient.h | 50 + lib/cpp/src/thrift/transport/THttpServer.cpp | 169 + lib/cpp/src/thrift/transport/THttpServer.h | 64 + .../src/thrift/transport/THttpTransport.cpp | 267 + lib/cpp/src/thrift/transport/THttpTransport.h | 104 + .../transport/TNonblockingSSLServerSocket.cpp | 58 + .../transport/TNonblockingSSLServerSocket.h | 77 + .../transport/TNonblockingServerSocket.cpp | 548 + .../transport/TNonblockingServerSocket.h | 137 + .../transport/TNonblockingServerTransport.h | 101 + lib/cpp/src/thrift/transport/TPipe.cpp | 398 + lib/cpp/src/thrift/transport/TPipe.h | 113 + lib/cpp/src/thrift/transport/TPipeServer.cpp | 460 + lib/cpp/src/thrift/transport/TPipeServer.h | 103 + .../src/thrift/transport/TSSLServerSocket.cpp | 60 + .../src/thrift/transport/TSSLServerSocket.h | 77 + lib/cpp/src/thrift/transport/TSSLSocket.cpp | 1083 + lib/cpp/src/thrift/transport/TSSLSocket.h | 436 + .../src/thrift/transport/TServerSocket.cpp | 698 + lib/cpp/src/thrift/transport/TServerSocket.h | 185 + .../src/thrift/transport/TServerTransport.h | 114 + .../thrift/transport/TShortReadTransport.h | 82 + .../thrift/transport/TSimpleFileTransport.cpp | 67 + .../thrift/transport/TSimpleFileTransport.h | 42 + lib/cpp/src/thrift/transport/TSocket.cpp | 932 + lib/cpp/src/thrift/transport/TSocket.h | 340 + lib/cpp/src/thrift/transport/TSocketPool.cpp | 256 + lib/cpp/src/thrift/transport/TSocketPool.h | 195 + lib/cpp/src/thrift/transport/TTransport.h | 271 + .../thrift/transport/TTransportException.cpp | 59 + .../thrift/transport/TTransportException.h | 106 + .../src/thrift/transport/TTransportUtils.cpp | 181 + .../src/thrift/transport/TTransportUtils.h | 310 + .../src/thrift/transport/TVirtualTransport.h | 140 + .../src/thrift/transport/TZlibTransport.cpp | 393 + lib/cpp/src/thrift/transport/TZlibTransport.h | 242 + lib/cpp/src/thrift/windows/GetTimeOfDay.cpp | 106 + lib/cpp/src/thrift/windows/GetTimeOfDay.h | 44 + lib/cpp/src/thrift/windows/Operators.h | 40 + .../windows/OverlappedSubmissionThread.cpp | 151 + .../windows/OverlappedSubmissionThread.h | 133 + lib/cpp/src/thrift/windows/SocketPair.cpp | 100 + lib/cpp/src/thrift/windows/SocketPair.h | 37 + lib/cpp/src/thrift/windows/Sync.h | 104 + .../src/thrift/windows/TWinsockSingleton.cpp | 71 + .../src/thrift/windows/TWinsockSingleton.h | 85 + lib/cpp/src/thrift/windows/WinFcntl.cpp | 101 + lib/cpp/src/thrift/windows/WinFcntl.h | 56 + lib/cpp/src/thrift/windows/config.h | 113 + lib/cpp/test/AllProtocolTests.cpp | 47 + lib/cpp/test/AllProtocolTests.tcc | 225 + lib/cpp/test/AnnotationTest.cpp | 68 + lib/cpp/test/Base64Test.cpp | 74 + lib/cpp/test/Benchmark.cpp | 244 + lib/cpp/test/CMakeLists.txt | 399 + lib/cpp/test/DebugProtoTest.cpp | 310 + lib/cpp/test/DebugProtoTest_extras.cpp | 35 + lib/cpp/test/EnumTest.cpp | 90 + lib/cpp/test/GenericHelpers.h | 107 + lib/cpp/test/JSONProtoTest.cpp | 343 + lib/cpp/test/Makefile.am | 404 + lib/cpp/test/Makefile.in | 1690 + lib/cpp/test/OpenSSLManualInitTest.cpp | 93 + lib/cpp/test/OptionalRequiredTest.cpp | 386 + lib/cpp/test/RecursiveTest.cpp | 92 + lib/cpp/test/SecurityTest.cpp | 278 + lib/cpp/test/SpecializationTest.cpp | 103 + lib/cpp/test/TBufferBaseTest.cpp | 646 + lib/cpp/test/TFDTransportTest.cpp | 50 + lib/cpp/test/TFileTransportTest.cpp | 418 + lib/cpp/test/TMemoryBufferTest.cpp | 160 + lib/cpp/test/TNonblockingSSLServerTest.cpp | 293 + lib/cpp/test/TNonblockingServerTest.cpp | 219 + lib/cpp/test/TPipeInterruptTest.cpp | 90 + lib/cpp/test/TPipedTransportTest.cpp | 53 + lib/cpp/test/TSSLSocketInterruptTest.cpp | 282 + lib/cpp/test/TServerIntegrationTest.cpp | 536 + lib/cpp/test/TServerSocketTest.cpp | 69 + lib/cpp/test/TServerTransportTest.cpp | 58 + lib/cpp/test/TSocketInterruptTest.cpp | 146 + lib/cpp/test/TTransportCheckThrow.h | 44 + lib/cpp/test/ThriftTest_extras.cpp | 33 + lib/cpp/test/ToStringTest.cpp | 137 + lib/cpp/test/TransportTest.cpp | 1092 + lib/cpp/test/TypedefTest.cpp | 28 + lib/cpp/test/UnitTestMain.cpp | 21 + lib/cpp/test/ZlibTest.cpp | 475 + lib/cpp/test/concurrency/MutexTest.cpp | 123 + .../test/concurrency/RWMutexStarveTest.cpp | 157 + lib/cpp/test/concurrency/Tests.cpp | 226 + lib/cpp/test/concurrency/ThreadFactoryTests.h | 309 + lib/cpp/test/concurrency/ThreadManagerTests.h | 685 + lib/cpp/test/concurrency/TimerManagerTests.h | 271 + lib/cpp/test/link/LinkTest.cpp | 22 + lib/cpp/test/link/TemplatedService1.cpp | 26 + lib/cpp/test/link/TemplatedService2.cpp | 26 + lib/cpp/test/processor/EventLog.cpp | 135 + lib/cpp/test/processor/EventLog.h | 95 + lib/cpp/test/processor/Handlers.h | 338 + lib/cpp/test/processor/ProcessorTest.cpp | 929 + lib/cpp/test/processor/ServerThread.cpp | 152 + lib/cpp/test/processor/ServerThread.h | 135 + lib/cpp/test/processor/proc.thrift | 22 + lib/cpp/test/qt/CMakeLists.txt | 32 + lib/cpp/test/qt/TQTcpServerTest.cpp | 114 + lib/cpp/thrift-nb.pc.in | 30 + lib/cpp/thrift-qt.pc.in | 30 + lib/cpp/thrift-qt5.pc.in | 30 + lib/cpp/thrift-z.pc.in | 30 + lib/cpp/thrift.pc.in | 29 + lib/cpp/thrift.sln | 61 + lib/csharp/Makefile.am | 111 + lib/csharp/Makefile.in | 890 + lib/csharp/README.md | 26 + .../Properties/AssemblyInfo.cs | 60 + lib/csharp/ThriftMSBuildTask/ThriftBuild.cs | 246 + .../ThriftMSBuildTask.csproj | 118 + lib/csharp/coding_standards.md | 6 + lib/csharp/src/Collections/TCollections.cs | 94 + lib/csharp/src/Collections/THashSet.cs | 160 + lib/csharp/src/Net35/ExtensionsNet35.cs | 31 + lib/csharp/src/Properties/AssemblyInfo.cs | 55 + lib/csharp/src/Protocol/TAbstractBase.cs | 29 + lib/csharp/src/Protocol/TBase.cs | 29 + lib/csharp/src/Protocol/TBase64Utils.cs | 100 + lib/csharp/src/Protocol/TBinaryProtocol.cs | 395 + lib/csharp/src/Protocol/TCompactProtocol.cs | 851 + lib/csharp/src/Protocol/TField.cs | 62 + lib/csharp/src/Protocol/TJSONProtocol.cs | 1128 + lib/csharp/src/Protocol/TList.cs | 54 + lib/csharp/src/Protocol/TMap.cs | 62 + lib/csharp/src/Protocol/TMessage.cs | 62 + lib/csharp/src/Protocol/TMessageType.cs | 31 + .../src/Protocol/TMultiplexedProcessor.cs | 180 + .../src/Protocol/TMultiplexedProtocol.cs | 105 + lib/csharp/src/Protocol/TProtocol.cs | 140 + lib/csharp/src/Protocol/TProtocolDecorator.cs | 262 + lib/csharp/src/Protocol/TProtocolException.cs | 67 + lib/csharp/src/Protocol/TProtocolFactory.cs | 33 + lib/csharp/src/Protocol/TProtocolUtil.cs | 109 + lib/csharp/src/Protocol/TSet.cs | 59 + lib/csharp/src/Protocol/TStruct.cs | 46 + lib/csharp/src/Protocol/TType.cs | 44 + lib/csharp/src/Server/TServer.cs | 155 + lib/csharp/src/Server/TServerEventHandler.cs | 50 + lib/csharp/src/Server/TSimpleServer.cs | 180 + lib/csharp/src/Server/TThreadPoolServer.cs | 277 + lib/csharp/src/Server/TThreadedServer.cs | 268 + lib/csharp/src/TApplicationException.cs | 141 + lib/csharp/src/TAsyncProcessor.cs | 38 + lib/csharp/src/TControllingHandler.cs | 29 + lib/csharp/src/TException.cs | 40 + lib/csharp/src/TProcessor.cs | 33 + lib/csharp/src/TProcessorFactory.cs | 30 + lib/csharp/src/TPrototypeProcessorFactory.cs | 55 + lib/csharp/src/TSingletonProcessorFactory.cs | 43 + lib/csharp/src/Thrift.45.csproj | 129 + lib/csharp/src/Thrift.csproj | 156 + lib/csharp/src/Thrift.sln | 47 + .../src/Transport/TBufferedTransport.cs | 169 + lib/csharp/src/Transport/TFramedTransport.cs | 186 + lib/csharp/src/Transport/THttpClient.cs | 475 + lib/csharp/src/Transport/THttpHandler.cs | 102 + .../src/Transport/THttpTaskAsyncHandler.cs | 97 + lib/csharp/src/Transport/TMemoryBuffer.cs | 99 + .../Transport/TNamedPipeClientTransport.cs | 111 + .../Transport/TNamedPipeServerTransport.cs | 296 + lib/csharp/src/Transport/TServerSocket.cs | 176 + lib/csharp/src/Transport/TServerTransport.cs | 43 + .../src/Transport/TSilverlightSocket.cs | 393 + lib/csharp/src/Transport/TSocket.cs | 241 + .../src/Transport/TSocketVersionizer.cs | 55 + lib/csharp/src/Transport/TStreamTransport.cs | 128 + lib/csharp/src/Transport/TTLSServerSocket.cs | 223 + lib/csharp/src/Transport/TTLSSocket.cs | 371 + lib/csharp/src/Transport/TTransport.cs | 146 + .../src/Transport/TTransportException.cs | 69 + lib/csharp/src/Transport/TTransportFactory.cs | 42 + lib/csharp/test/JSON/JSONTest.csproj | 85 + lib/csharp/test/JSON/Program.cs | 95 + .../test/JSON/Properties/AssemblyInfo.cs | 55 + lib/csharp/test/JSON/app.config | 21 + .../Multiplex/Client/Multiplex.Test.Client.cs | 82 + .../Multiplex/Client/MultiplexClient.csproj | 148 + .../Client/Properties/AssemblyInfo.cs | 55 + lib/csharp/test/Multiplex/Makefile | 658 + lib/csharp/test/Multiplex/Makefile.am | 52 + lib/csharp/test/Multiplex/Makefile.in | 658 + .../test/Multiplex/Multiplex.Test.Common.cs | 40 + .../Multiplex/Server/Multiplex.Test.Server.cs | 107 + .../Multiplex/Server/MultiplexServer.csproj | 148 + .../Server/Properties/AssemblyInfo.cs | 55 + .../ThriftMVCTest/App_Start/FilterConfig.cs | 31 + .../ThriftMVCTest/App_Start/RouteConfig.cs | 39 + .../test/ThriftMVCTest/AsyncHttpHandler.cs | 32 + .../Controllers/HomeController.cs | 70 + lib/csharp/test/ThriftMVCTest/Global.asax | 19 + lib/csharp/test/ThriftMVCTest/Global.asax.cs | 34 + .../ThriftMVCTest/Properties/AssemblyInfo.cs | 53 + .../test/ThriftMVCTest/SecondServiceImpl.cs | 37 + .../test/ThriftMVCTest/SyncHttpHandler.cs | 32 + .../test/ThriftMVCTest/ThriftMVCTest.csproj | 200 + .../ThriftMVCTest/Views/Home/Index.cshtml | 25 + .../ThriftMVCTest/Views/Shared/_Layout.cshtml | 30 + .../test/ThriftMVCTest/Views/Web.config | 60 + .../ThriftMVCTest/Views/_ViewStart.cshtml | 22 + .../test/ThriftMVCTest/Web.Debug.config | 45 + .../test/ThriftMVCTest/Web.Release.config | 46 + lib/csharp/test/ThriftMVCTest/Web.config | 92 + lib/csharp/test/ThriftMVCTest/favicon.ico | Bin 0 -> 32038 bytes lib/csharp/test/ThriftMVCTest/packages.config | 25 + lib/d/Makefile | 1339 + lib/d/Makefile.am | 194 + lib/d/Makefile.in | 1339 + lib/d/README.md | 58 + lib/d/coding_standards.md | 1 + lib/d/src/thrift/async/base.d | 228 + lib/d/src/thrift/async/libevent.d | 461 + lib/d/src/thrift/async/socket.d | 357 + lib/d/src/thrift/async/ssl.d | 292 + lib/d/src/thrift/base.d | 123 + lib/d/src/thrift/codegen/async_client.d | 255 + lib/d/src/thrift/codegen/async_client_pool.d | 906 + lib/d/src/thrift/codegen/base.d | 1021 + lib/d/src/thrift/codegen/client.d | 486 + lib/d/src/thrift/codegen/client_pool.d | 262 + lib/d/src/thrift/codegen/idlgen.d | 770 + lib/d/src/thrift/codegen/processor.d | 497 + lib/d/src/thrift/index.d | 33 + lib/d/src/thrift/internal/algorithm.d | 55 + lib/d/src/thrift/internal/codegen.d | 451 + lib/d/src/thrift/internal/ctfe.d | 98 + lib/d/src/thrift/internal/endian.d | 75 + lib/d/src/thrift/internal/resource_pool.d | 431 + lib/d/src/thrift/internal/socket.d | 96 + lib/d/src/thrift/internal/ssl.d | 240 + lib/d/src/thrift/internal/ssl_bio.d | 190 + lib/d/src/thrift/internal/test/protocol.d | 183 + lib/d/src/thrift/internal/test/server.d | 110 + lib/d/src/thrift/internal/traits.d | 33 + lib/d/src/thrift/protocol/base.d | 449 + lib/d/src/thrift/protocol/binary.d | 414 + lib/d/src/thrift/protocol/compact.d | 698 + lib/d/src/thrift/protocol/json.d | 1037 + lib/d/src/thrift/protocol/processor.d | 145 + lib/d/src/thrift/server/base.d | 147 + lib/d/src/thrift/server/nonblocking.d | 1397 + lib/d/src/thrift/server/simple.d | 181 + lib/d/src/thrift/server/taskpool.d | 302 + lib/d/src/thrift/server/threaded.d | 215 + lib/d/src/thrift/server/transport/base.d | 133 + lib/d/src/thrift/server/transport/socket.d | 380 + lib/d/src/thrift/server/transport/ssl.d | 88 + lib/d/src/thrift/transport/base.d | 370 + lib/d/src/thrift/transport/buffered.d | 215 + lib/d/src/thrift/transport/file.d | 1100 + lib/d/src/thrift/transport/framed.d | 334 + lib/d/src/thrift/transport/http.d | 459 + lib/d/src/thrift/transport/memory.d | 233 + lib/d/src/thrift/transport/piped.d | 219 + lib/d/src/thrift/transport/range.d | 147 + lib/d/src/thrift/transport/socket.d | 453 + lib/d/src/thrift/transport/ssl.d | 682 + lib/d/src/thrift/transport/zlib.d | 497 + lib/d/src/thrift/util/awaitable.d | 212 + lib/d/src/thrift/util/cancellation.d | 105 + lib/d/src/thrift/util/future.d | 549 + lib/d/src/thrift/util/hashset.d | 146 + lib/d/test/Makefile | 834 + lib/d/test/Makefile.am | 127 + lib/d/test/Makefile.in | 834 + lib/d/test/async_test.d | 396 + lib/d/test/async_test_runner.sh | 28 + lib/d/test/client_pool_test.d | 416 + lib/d/test/openssl.test.cnf | 14 + lib/d/test/serialization_benchmark.d | 70 + lib/d/test/stress_test_server.d | 81 + lib/d/test/test_utils.d | 96 + lib/d/test/thrift_test_client.d | 386 + lib/d/test/thrift_test_common.d | 92 + lib/d/test/thrift_test_runner.sh | 93 + lib/d/test/thrift_test_server.d | 286 + lib/d/test/transport_test.d | 803 + lib/dart/.analysis_options | 2 + lib/dart/LICENSE_HEADER | 16 + lib/dart/Makefile | 638 + lib/dart/Makefile.am | 33 + lib/dart/Makefile.in | 638 + lib/dart/README.md | 26 + lib/dart/coding_standards.md | 6 + lib/dart/lib/src/browser/t_web_socket.dart | 130 + lib/dart/lib/src/console/t_tcp_socket.dart | 81 + lib/dart/lib/src/console/t_web_socket.dart | 89 + .../lib/src/protocol/t_binary_protocol.dart | 281 + .../lib/src/protocol/t_compact_protocol.dart | 470 + lib/dart/lib/src/protocol/t_field.dart | 26 + .../lib/src/protocol/t_json_protocol.dart | 784 + lib/dart/lib/src/protocol/t_list.dart | 25 + lib/dart/lib/src/protocol/t_map.dart | 26 + lib/dart/lib/src/protocol/t_message.dart | 35 + .../src/protocol/t_multiplexed_protocol.dart | 43 + lib/dart/lib/src/protocol/t_protocol.dart | 95 + .../src/protocol/t_protocol_decorator.dart | 150 + .../lib/src/protocol/t_protocol_error.dart | 33 + .../lib/src/protocol/t_protocol_factory.dart | 22 + .../lib/src/protocol/t_protocol_util.dart | 107 + lib/dart/lib/src/protocol/t_set.dart | 25 + lib/dart/lib/src/protocol/t_struct.dart | 24 + lib/dart/lib/src/protocol/t_type.dart | 34 + .../lib/src/serializer/t_deserializer.dart | 50 + lib/dart/lib/src/serializer/t_serializer.dart | 48 + lib/dart/lib/src/t_application_error.dart | 104 + lib/dart/lib/src/t_base.dart | 37 + lib/dart/lib/src/t_error.dart | 27 + lib/dart/lib/src/t_processor.dart | 24 + .../src/transport/t_buffered_transport.dart | 98 + .../lib/src/transport/t_framed_transport.dart | 83 + .../lib/src/transport/t_http_transport.dart | 100 + .../lib/src/transport/t_message_reader.dart | 99 + lib/dart/lib/src/transport/t_socket.dart | 38 + .../lib/src/transport/t_socket_transport.dart | 175 + lib/dart/lib/src/transport/t_transport.dart | 70 + .../lib/src/transport/t_transport_error.dart | 31 + .../src/transport/t_transport_factory.dart | 27 + lib/dart/lib/thrift.dart | 64 + lib/dart/lib/thrift_browser.dart | 22 + lib/dart/lib/thrift_console.dart | 23 + lib/dart/pubspec.yaml | 43 + lib/dart/test/protocol/t_protocol_test.dart | 406 + lib/dart/test/serializer/serializer_test.dart | 119 + .../test/serializer/serializer_test_data.dart | 342 + lib/dart/test/t_application_error_test.dart | 46 + .../test/transport/t_http_transport_test.dart | 164 + .../transport/t_socket_transport_test.dart | 311 + lib/dart/test/transport/t_transport_test.dart | 41 + lib/dart/tool/dev.dart | 33 + lib/delphi/README.md | 30 + lib/delphi/coding_standards.md | 1 + lib/delphi/src/Thrift.Collections.pas | 619 + lib/delphi/src/Thrift.Console.pas | 133 + lib/delphi/src/Thrift.Defines.inc | 50 + lib/delphi/src/Thrift.Processor.Multiplex.pas | 216 + lib/delphi/src/Thrift.Protocol.Compact.pas | 1099 + lib/delphi/src/Thrift.Protocol.JSON.pas | 1237 + lib/delphi/src/Thrift.Protocol.Multiplex.pas | 107 + lib/delphi/src/Thrift.Protocol.pas | 1388 + lib/delphi/src/Thrift.Serializer.pas | 230 + lib/delphi/src/Thrift.Server.pas | 423 + lib/delphi/src/Thrift.Socket.pas | 1617 + lib/delphi/src/Thrift.Stream.pas | 306 + lib/delphi/src/Thrift.Transport.Pipes.pas | 1026 + lib/delphi/src/Thrift.Transport.pas | 1633 + lib/delphi/src/Thrift.TypeRegistry.pas | 95 + lib/delphi/src/Thrift.Utils.pas | 251 + lib/delphi/src/Thrift.pas | 257 + lib/delphi/test/TestClient.pas | 1371 + lib/delphi/test/TestConstants.pas | 162 + lib/delphi/test/TestServer.pas | 745 + lib/delphi/test/TestServerEvents.pas | 174 + lib/delphi/test/client.dpr | 72 + lib/delphi/test/codegen/README.md | 28 + .../test/codegen/ReservedKeywords.thrift | 100 + .../codegen/run-Pascal-Codegen-Tests.bat.tmpl | 173 + lib/delphi/test/maketest.sh | 23 + .../multiplexed/Multiplex.Client.Main.pas | 131 + .../multiplexed/Multiplex.Server.Main.pas | 201 + .../multiplexed/Multiplex.Test.Client.dpr | 67 + .../multiplexed/Multiplex.Test.Common.pas | 35 + .../multiplexed/Multiplex.Test.Server.dpr | 67 + .../test/serializer/TestSerializer.Data.pas | 350 + lib/delphi/test/serializer/TestSerializer.dpr | 231 + lib/delphi/test/server.dpr | 73 + lib/delphi/test/skip/README.md | 11 + .../test/skip/idl/skiptest_version_1.thrift | 45 + .../test/skip/idl/skiptest_version_2.thrift | 69 + lib/delphi/test/skip/skiptest_version1.dpr | 201 + lib/delphi/test/skip/skiptest_version2.dpr | 228 + .../test/typeregistry/TestTypeRegistry.dpr | 90 + lib/erl/Makefile.am | 90 + lib/erl/Makefile.in | 687 + lib/erl/README.md | 51 + lib/erl/coding_standards.md | 3 + lib/erl/include/thrift_constants.hrl | 62 + lib/erl/include/thrift_protocol.hrl | 66 + lib/erl/include/thrift_protocol_behaviour.hrl | 37 + .../include/thrift_transport_behaviour.hrl | 31 + lib/erl/rebar.config | 1 + lib/erl/rebar.config.script | 7 + lib/erl/rebar.test.config | 5 + lib/erl/src/thrift.app.src | 74 + lib/erl/src/thrift_base64_transport.erl | 69 + lib/erl/src/thrift_binary_protocol.erl | 347 + lib/erl/src/thrift_buffered_transport.erl | 98 + lib/erl/src/thrift_client.erl | 162 + lib/erl/src/thrift_client_util.erl | 112 + lib/erl/src/thrift_compact_protocol.erl | 390 + lib/erl/src/thrift_disk_log_transport.erl | 123 + lib/erl/src/thrift_file_transport.erl | 115 + lib/erl/src/thrift_framed_transport.erl | 126 + lib/erl/src/thrift_http_transport.erl | 116 + lib/erl/src/thrift_json_parser.erl | 419 + lib/erl/src/thrift_json_protocol.erl | 567 + lib/erl/src/thrift_membuffer_transport.erl | 83 + lib/erl/src/thrift_memory_buffer.erl | 47 + .../src/thrift_multiplexed_map_wrapper.erl | 57 + lib/erl/src/thrift_multiplexed_protocol.erl | 83 + lib/erl/src/thrift_processor.erl | 219 + lib/erl/src/thrift_protocol.erl | 412 + lib/erl/src/thrift_reconnecting_client.erl | 258 + lib/erl/src/thrift_server.erl | 183 + lib/erl/src/thrift_service.erl | 25 + lib/erl/src/thrift_socket_server.erl | 320 + lib/erl/src/thrift_socket_transport.erl | 176 + lib/erl/src/thrift_sslsocket_transport.erl | 147 + lib/erl/src/thrift_transport.erl | 126 + lib/erl/src/thrift_transport_state_test.erl | 117 + lib/erl/test/Thrift1151.thrift | 3 + lib/erl/test/Thrift1475.thrift | 34 + lib/erl/test/Thrift_omit_with.thrift | 22 + lib/erl/test/flags/LegacyNames.thrift | 33 + lib/erl/test/flags/Thrift3214.thrift | 23 + lib/erl/test/legacy_names_test.erl | 69 + lib/erl/test/multiplexing.thrift | 7 + lib/erl/test/multiplexing_test.erl | 57 + lib/erl/test/name_conflict_test.erl | 299 + lib/erl/test/stress_server.erl | 64 + lib/erl/test/test_const.erl | 54 + lib/erl/test/test_disklog.erl | 99 + lib/erl/test/test_omit.erl | 79 + lib/erl/test/test_thrift_1151.erl | 34 + lib/erl/test/test_thrift_3214.erl | 60 + .../test/test_thrift_buffered_transport.erl | 359 + lib/erl/test/test_thrift_compact_protocol.erl | 219 + lib/erl/test/test_thrift_file_transport.erl | 213 + lib/erl/test/test_thrift_framed_transport.erl | 404 + .../test/test_thrift_membuffer_transport.erl | 167 + lib/erl/test/test_thrift_socket_transport.erl | 199 + lib/erl/test/thrift_socket_server_test.erl | 49 + lib/erl/test/thrift_test_test.erl | 643 + lib/go/Makefile.am | 47 + lib/go/Makefile.in | 828 + lib/go/README.md | 81 + lib/go/coding_standards.md | 1 + lib/go/test/BinaryKeyTest.thrift | 24 + lib/go/test/DontExportRWTest.thrift | 27 + lib/go/test/ErrorTest.thrift | 35 + lib/go/test/GoTagTest.thrift | 24 + lib/go/test/IgnoreInitialismsTest.thrift | 26 + lib/go/test/IncludesTest.thrift | 67 + lib/go/test/InitialismsTest.thrift | 24 + lib/go/test/Makefile.am | 109 + lib/go/test/Makefile.in | 709 + lib/go/test/MultiplexedProtocolTest.thrift | 27 + lib/go/test/NamesTest.thrift | 32 + lib/go/test/NamespacedTest.thrift | 40 + lib/go/test/OnewayTest.thrift | 24 + lib/go/test/OptionalFieldsTest.thrift | 50 + lib/go/test/RefAnnotationFieldsTest.thrift | 58 + lib/go/test/ServicesTest.thrift | 111 + lib/go/test/TypedefFieldTest.thrift | 39 + lib/go/test/UnionDefaultValueTest.thrift | 34 + lib/go/test/dontexportrwtest/compile_test.go | 38 + lib/go/test/tests/binary_key_test.go | 31 + lib/go/test/tests/client_error_test.go | 866 + lib/go/test/tests/encoding_json_test.go | 79 + lib/go/test/tests/go17.go | 47 + lib/go/test/tests/gotag_test.go | 53 + lib/go/test/tests/ignoreinitialisms_test.go | 51 + lib/go/test/tests/initialisms_test.go | 43 + .../test/tests/multiplexed_protocol_test.go | 184 + lib/go/test/tests/names_test.go | 35 + lib/go/test/tests/one_way_test.go | 83 + lib/go/test/tests/optional_fields_test.go | 280 + lib/go/test/tests/pre_go17.go | 48 + lib/go/test/tests/protocol_mock.go | 512 + lib/go/test/tests/protocols_test.go | 97 + lib/go/test/tests/required_fields_test.go | 95 + lib/go/test/tests/struct_args_rets_test.go | 36 + lib/go/test/tests/thrifttest_driver.go | 236 + lib/go/test/tests/thrifttest_handler.go | 213 + lib/go/test/tests/thrifttest_handler_go17.go | 212 + lib/go/test/tests/union_default_value_test.go | 33 + lib/go/thrift/application_exception.go | 164 + lib/go/thrift/application_exception_test.go | 41 + lib/go/thrift/binary_protocol.go | 514 + lib/go/thrift/binary_protocol_test.go | 28 + lib/go/thrift/buffered_transport.go | 91 + lib/go/thrift/buffered_transport_test.go | 29 + lib/go/thrift/client.go | 78 + lib/go/thrift/client_go17.go | 13 + lib/go/thrift/client_pre_go17.go | 13 + lib/go/thrift/common_test_go17.go | 32 + lib/go/thrift/common_test_pre_go17.go | 32 + lib/go/thrift/compact_protocol.go | 815 + lib/go/thrift/compact_protocol_test.go | 53 + lib/go/thrift/debug_protocol.go | 269 + lib/go/thrift/deserializer.go | 58 + lib/go/thrift/exception.go | 44 + lib/go/thrift/exception_test.go | 69 + lib/go/thrift/field.go | 79 + lib/go/thrift/framed_transport.go | 172 + lib/go/thrift/framed_transport_test.go | 29 + lib/go/thrift/go17.go | 26 + lib/go/thrift/http_client.go | 238 + lib/go/thrift/http_client_test.go | 106 + lib/go/thrift/http_transport.go | 51 + lib/go/thrift/http_transport_go17.go | 38 + lib/go/thrift/http_transport_pre_go17.go | 40 + lib/go/thrift/iostream_transport.go | 213 + lib/go/thrift/iostream_transport_test.go | 52 + lib/go/thrift/json_protocol.go | 583 + lib/go/thrift/json_protocol_test.go | 649 + lib/go/thrift/lowlevel_benchmarks_test.go | 540 + lib/go/thrift/memory_buffer.go | 79 + lib/go/thrift/memory_buffer_test.go | 29 + lib/go/thrift/messagetype.go | 31 + lib/go/thrift/multiplexed_protocol.go | 139 + lib/go/thrift/multiplexed_protocol_go17.go | 53 + .../thrift/multiplexed_protocol_pre_go17.go | 54 + lib/go/thrift/numeric.go | 164 + lib/go/thrift/pointerize.go | 50 + lib/go/thrift/pre_go17.go | 26 + lib/go/thrift/processor.go | 34 + lib/go/thrift/processor_factory.go | 58 + lib/go/thrift/processor_go17.go | 34 + lib/go/thrift/protocol.go | 178 + lib/go/thrift/protocol_exception.go | 77 + lib/go/thrift/protocol_factory.go | 25 + lib/go/thrift/protocol_test.go | 515 + lib/go/thrift/rich_transport.go | 68 + lib/go/thrift/rich_transport_test.go | 89 + lib/go/thrift/serializer.go | 75 + lib/go/thrift/serializer_test.go | 169 + lib/go/thrift/serializer_types_test.go | 633 + lib/go/thrift/server.go | 35 + lib/go/thrift/server_socket.go | 134 + lib/go/thrift/server_socket_test.go | 60 + lib/go/thrift/server_test.go | 28 + lib/go/thrift/server_transport.go | 34 + lib/go/thrift/simple_json_protocol.go | 1337 + lib/go/thrift/simple_json_protocol_test.go | 715 + lib/go/thrift/simple_server.go | 215 + lib/go/thrift/simple_server_test.go | 127 + lib/go/thrift/socket.go | 165 + lib/go/thrift/ssl_server_socket.go | 112 + lib/go/thrift/ssl_socket.go | 175 + lib/go/thrift/transport.go | 65 + lib/go/thrift/transport_exception.go | 90 + lib/go/thrift/transport_exception_test.go | 60 + lib/go/thrift/transport_factory.go | 39 + lib/go/thrift/transport_test.go | 176 + lib/go/thrift/type.go | 69 + lib/go/thrift/zlib_transport.go | 131 + lib/go/thrift/zlib_transport_test.go | 62 + lib/haxe/README.md | 164 + lib/haxe/coding_standards.md | 1 + lib/haxe/haxelib.json | 12 + .../org/apache/thrift/AbstractMethodError.hx | 40 + .../src/org/apache/thrift/ArgumentError.hx | 29 + lib/haxe/src/org/apache/thrift/Limits.hx | 44 + .../apache/thrift/TApplicationException.hx | 104 + lib/haxe/src/org/apache/thrift/TBase.hx | 73 + lib/haxe/src/org/apache/thrift/TException.hx | 36 + .../apache/thrift/TFieldRequirementType.hx | 31 + lib/haxe/src/org/apache/thrift/TProcessor.hx | 30 + .../org/apache/thrift/helper/BitConverter.hx | 170 + .../src/org/apache/thrift/helper/Int64Map.hx | 295 + .../src/org/apache/thrift/helper/IntSet.hx | 96 + .../src/org/apache/thrift/helper/ObjectSet.hx | 96 + .../src/org/apache/thrift/helper/StringSet.hx | 96 + .../src/org/apache/thrift/helper/ZigZag.hx | 158 + .../apache/thrift/meta_data/FieldMetaData.hx | 56 + .../thrift/meta_data/FieldValueMetaData.hx | 43 + .../apache/thrift/meta_data/ListMetaData.hx | 31 + .../apache/thrift/meta_data/MapMetaData.hx | 33 + .../apache/thrift/meta_data/SetMetaData.hx | 30 + .../apache/thrift/meta_data/StructMetaData.hx | 30 + .../apache/thrift/protocol/TBinaryProtocol.hx | 301 + .../thrift/protocol/TBinaryProtocolFactory.hx | 45 + .../thrift/protocol/TCompactProtocol.hx | 718 + .../protocol/TCompactProtocolFactory.hx | 40 + .../apache/thrift/protocol/TCompactTypes.hx | 41 + .../src/org/apache/thrift/protocol/TField.hx | 43 + .../apache/thrift/protocol/TJSONProtocol.hx | 1073 + .../thrift/protocol/TJSONProtocolFactory.hx | 40 + .../src/org/apache/thrift/protocol/TList.hx | 32 + .../src/org/apache/thrift/protocol/TMap.hx | 34 + .../org/apache/thrift/protocol/TMessage.hx | 41 + .../apache/thrift/protocol/TMessageType.hx | 28 + .../thrift/protocol/TMultiplexedProcessor.hx | 177 + .../thrift/protocol/TMultiplexedProtocol.hx | 97 + .../org/apache/thrift/protocol/TProtocol.hx | 85 + .../thrift/protocol/TProtocolDecorator.hx | 226 + .../thrift/protocol/TProtocolException.hx | 41 + .../thrift/protocol/TProtocolFactory.hx | 26 + .../apache/thrift/protocol/TProtocolUtil.hx | 110 + .../thrift/protocol/TRecursionTracker.hx | 48 + .../src/org/apache/thrift/protocol/TSet.hx | 32 + .../src/org/apache/thrift/protocol/TStruct.hx | 30 + .../src/org/apache/thrift/protocol/TType.hx | 37 + .../src/org/apache/thrift/server/TServer.hx | 111 + .../thrift/server/TServerEventHandler.hx | 41 + .../org/apache/thrift/server/TSimpleServer.hx | 141 + .../thrift/transport/TBufferedTransport.hx | 155 + .../transport/TBufferedTransportFactory.hx | 37 + .../apache/thrift/transport/TFileStream.hx | 101 + .../thrift/transport/TFramedTransport.hx | 158 + .../transport/TFramedTransportFactory.hx | 37 + .../thrift/transport/TFullDuplexHttpClient.hx | 253 + .../apache/thrift/transport/THttpClient.hx | 103 + .../apache/thrift/transport/TServerSocket.hx | 130 + .../thrift/transport/TServerTransport.hx | 43 + .../org/apache/thrift/transport/TSocket.hx | 318 + .../org/apache/thrift/transport/TStream.hx | 32 + .../thrift/transport/TStreamTransport.hx | 103 + .../org/apache/thrift/transport/TTransport.hx | 139 + .../thrift/transport/TTransportException.hx | 39 + .../thrift/transport/TTransportFactory.hx | 44 + .../transport/TWrappingServerTransport.hx | 47 + lib/haxe/test/HaxeTests.hxproj | 69 + lib/haxe/test/Makefile | 686 + lib/haxe/test/Makefile.am | 85 + lib/haxe/test/Makefile.in | 686 + lib/haxe/test/cpp.hxml | 41 + lib/haxe/test/csharp.hxml | 38 + lib/haxe/test/flash.hxml | 38 + lib/haxe/test/java.hxml | 38 + lib/haxe/test/javascript.hxml | 44 + lib/haxe/test/make_all.bat | 70 + lib/haxe/test/make_all.sh | 43 + lib/haxe/test/neko.hxml | 38 + lib/haxe/test/php.hxml | 39 + lib/haxe/test/project.hide | 67 + lib/haxe/test/python.hxml | 38 + lib/haxe/test/src/Main.hx | 93 + lib/haxe/test/src/MultiplexTest.hx | 224 + lib/haxe/test/src/StreamTest.hx | 95 + lib/haxe/test/src/TestBase.hx | 46 + lib/hs/CMakeLists.txt | 93 + lib/hs/LICENSE | 202 + lib/hs/Makefile.am | 50 + lib/hs/Makefile.in | 659 + lib/hs/README.md | 99 + lib/hs/Setup.lhs | 21 + lib/hs/TODO | 2 + lib/hs/coding_standards.md | 1 + lib/hs/src/Thrift.hs | 114 + lib/hs/src/Thrift/Arbitraries.hs | 55 + lib/hs/src/Thrift/Protocol.hs | 136 + lib/hs/src/Thrift/Protocol/Binary.hs | 212 + lib/hs/src/Thrift/Protocol/Compact.hs | 311 + lib/hs/src/Thrift/Protocol/Header.hs | 141 + lib/hs/src/Thrift/Protocol/JSON.hs | 362 + lib/hs/src/Thrift/Server.hs | 66 + lib/hs/src/Thrift/Transport.hs | 65 + lib/hs/src/Thrift/Transport/Empty.hs | 36 + lib/hs/src/Thrift/Transport/Framed.hs | 99 + lib/hs/src/Thrift/Transport/Handle.hs | 78 + lib/hs/src/Thrift/Transport/Header.hs | 354 + lib/hs/src/Thrift/Transport/HttpClient.hs | 101 + lib/hs/src/Thrift/Transport/IOBuffer.hs | 69 + lib/hs/src/Thrift/Transport/Memory.hs | 77 + lib/hs/src/Thrift/Types.hs | 130 + lib/hs/test/BinarySpec.hs | 91 + lib/hs/test/CompactSpec.hs | 81 + lib/hs/test/JSONSpec.hs | 225 + lib/hs/test/Spec.hs | 38 + lib/hs/thrift.cabal | 82 + lib/java/CMakeLists.txt | 80 + lib/java/Makefile.am | 48 + lib/java/Makefile.in | 655 + lib/java/README.md | 53 + lib/java/android/build.gradle | 50 + lib/java/android/settings.gradle | 1 + lib/java/android/src/main/AndroidManifest.xml | 4 + lib/java/build.properties | 31 + lib/java/build.xml | 421 + lib/java/coding_standards.md | 1 + .../apache/thrift/AsyncProcessFunction.java | 56 + .../src/org/apache/thrift/EncodingUtils.java | 148 + lib/java/src/org/apache/thrift/Option.java | 121 + .../org/apache/thrift/ProcessFunction.java | 87 + .../src/org/apache/thrift/ShortStack.java | 82 + .../apache/thrift/TApplicationException.java | 150 + .../org/apache/thrift/TAsyncProcessor.java | 35 + lib/java/src/org/apache/thrift/TBase.java | 67 + .../apache/thrift/TBaseAsyncProcessor.java | 105 + .../src/org/apache/thrift/TBaseHelper.java | 337 + .../src/org/apache/thrift/TBaseProcessor.java | 42 + .../apache/thrift/TByteArrayOutputStream.java | 56 + .../src/org/apache/thrift/TDeserializer.java | 358 + lib/java/src/org/apache/thrift/TEnum.java | 24 + .../src/org/apache/thrift/TEnumHelper.java | 57 + .../src/org/apache/thrift/TException.java | 45 + .../src/org/apache/thrift/TFieldIdEnum.java | 34 + .../apache/thrift/TFieldRequirementType.java | 30 + .../apache/thrift/TMultiplexedProcessor.java | 154 + .../thrift/TNonblockingMultiFetchClient.java | 399 + .../thrift/TNonblockingMultiFetchStats.java | 80 + .../src/org/apache/thrift/TProcessor.java | 32 + .../org/apache/thrift/TProcessorFactory.java | 43 + .../src/org/apache/thrift/TSerializable.java | 44 + .../src/org/apache/thrift/TSerializer.java | 110 + .../src/org/apache/thrift/TServiceClient.java | 91 + .../apache/thrift/TServiceClientFactory.java | 45 + lib/java/src/org/apache/thrift/TUnion.java | 279 + .../thrift/async/AsyncMethodCallback.java | 51 + .../org/apache/thrift/async/TAsyncClient.java | 102 + .../thrift/async/TAsyncClientFactory.java | 25 + .../thrift/async/TAsyncClientManager.java | 201 + .../apache/thrift/async/TAsyncMethodCall.java | 284 + .../apache/thrift/meta_data/EnumMetaData.java | 31 + .../thrift/meta_data/FieldMetaData.java | 70 + .../thrift/meta_data/FieldValueMetaData.java | 72 + .../apache/thrift/meta_data/ListMetaData.java | 29 + .../apache/thrift/meta_data/MapMetaData.java | 31 + .../apache/thrift/meta_data/SetMetaData.java | 29 + .../thrift/meta_data/StructMetaData.java | 31 + .../apache/thrift/protocol/TBase64Utils.java | 127 + .../thrift/protocol/TBinaryProtocol.java | 427 + .../thrift/protocol/TCompactProtocol.java | 908 + .../org/apache/thrift/protocol/TField.java | 66 + .../apache/thrift/protocol/TJSONProtocol.java | 1007 + .../src/org/apache/thrift/protocol/TList.java | 38 + .../src/org/apache/thrift/protocol/TMap.java | 40 + .../org/apache/thrift/protocol/TMessage.java | 76 + .../apache/thrift/protocol/TMessageType.java | 31 + .../thrift/protocol/TMultiplexedProtocol.java | 93 + .../org/apache/thrift/protocol/TProtocol.java | 162 + .../thrift/protocol/TProtocolDecorator.java | 213 + .../thrift/protocol/TProtocolException.java | 82 + .../thrift/protocol/TProtocolFactory.java | 31 + .../apache/thrift/protocol/TProtocolUtil.java | 221 + .../src/org/apache/thrift/protocol/TSet.java | 42 + .../thrift/protocol/TSimpleJSONProtocol.java | 448 + .../org/apache/thrift/protocol/TStruct.java | 36 + .../thrift/protocol/TTupleProtocol.java | 98 + .../src/org/apache/thrift/protocol/TType.java | 40 + .../src/org/apache/thrift/scheme/IScheme.java | 29 + .../apache/thrift/scheme/SchemeFactory.java | 25 + .../apache/thrift/scheme/StandardScheme.java | 25 + .../org/apache/thrift/scheme/TupleScheme.java | 25 + .../server/AbstractNonblockingServer.java | 612 + .../org/apache/thrift/server/Invocation.java | 20 + .../apache/thrift/server/ServerContext.java | 26 + .../thrift/server/TExtensibleServlet.java | 171 + .../org/apache/thrift/server/THsHaServer.java | 204 + .../thrift/server/TNonblockingServer.java | 248 + .../src/org/apache/thrift/server/TServer.java | 177 + .../thrift/server/TServerEventHandler.java | 59 + .../org/apache/thrift/server/TServlet.java | 119 + .../apache/thrift/server/TSimpleServer.java | 117 + .../thrift/server/TThreadPoolServer.java | 319 + .../server/TThreadedSelectorServer.java | 744 + .../thrift/transport/AutoExpandingBuffer.java | 52 + .../AutoExpandingBufferReadTransport.java | 84 + .../AutoExpandingBufferWriteTransport.java | 66 + .../apache/thrift/transport/TByteBuffer.java | 87 + .../transport/TFastFramedTransport.java | 197 + .../thrift/transport/TFileProcessor.java | 118 + .../thrift/transport/TFileTransport.java | 621 + .../thrift/transport/TFramedTransport.java | 181 + .../apache/thrift/transport/THttpClient.java | 362 + .../thrift/transport/TIOStreamTransport.java | 164 + .../thrift/transport/TMemoryBuffer.java | 102 + .../transport/TMemoryInputTransport.java | 96 + .../transport/TNonblockingServerSocket.java | 163 + .../TNonblockingServerTransport.java | 31 + .../thrift/transport/TNonblockingSocket.java | 210 + .../transport/TNonblockingTransport.java | 47 + .../transport/TSSLTransportFactory.java | 385 + .../transport/TSaslClientTransport.java | 113 + .../transport/TSaslServerTransport.java | 236 + .../thrift/transport/TSaslTransport.java | 578 + .../transport/TSaslTransportException.java | 43 + .../thrift/transport/TSeekableFile.java | 33 + .../thrift/transport/TServerSocket.java | 158 + .../thrift/transport/TServerTransport.java | 80 + .../transport/TSimpleFileTransport.java | 216 + .../org/apache/thrift/transport/TSocket.java | 248 + .../thrift/transport/TStandardFile.java | 60 + .../apache/thrift/transport/TTransport.java | 163 + .../thrift/transport/TTransportException.java | 81 + .../thrift/transport/TTransportFactory.java | 41 + .../thrift/transport/TZlibTransport.java | 148 + lib/java/test/.keystore | Bin 0 -> 2429 bytes lib/java/test/.truststore | Bin 0 -> 1149 bytes lib/java/test/log4j.properties | 6 + lib/java/test/org/apache/thrift/Fixtures.java | 339 + .../test/org/apache/thrift/TestDeepCopy.java | 34 + .../org/apache/thrift/TestEnumContainers.java | 81 + .../test/org/apache/thrift/TestFullCamel.java | 59 + .../thrift/TestMultiplexedProcessor.java | 86 + .../org/apache/thrift/TestOptionType.java | 66 + .../test/org/apache/thrift/TestOptionals.java | 88 + .../test/org/apache/thrift/TestReuse.java | 60 + .../org/apache/thrift/TestShortStack.java | 116 + .../test/org/apache/thrift/TestStruct.java | 396 + .../org/apache/thrift/TestTBaseHelper.java | 209 + .../org/apache/thrift/TestTDeserializer.java | 126 + .../org/apache/thrift/TestTEnumHelper.java | 41 + .../test/org/apache/thrift/TestTUnion.java | 268 + .../apache/thrift/async/TestTAsyncClient.java | 28 + .../thrift/async/TestTAsyncClientManager.java | 378 + .../thrift/protocol/BenchmarkProtocols.java | 88 + .../thrift/protocol/ProtocolTestBase.java | 427 + .../thrift/protocol/TestTCompactProtocol.java | 56 + .../thrift/protocol/TestTJSONProtocol.java | 48 + .../thrift/protocol/TestTProtocolUtil.java | 97 + .../protocol/TestTSimpleJSONProtocol.java | 98 + .../thrift/protocol/TestTTupleProtocol.java | 27 + .../thrift/scheme/TestStandardScheme.java | 40 + .../apache/thrift/server/ServerTestBase.java | 710 + .../apache/thrift/server/TestAsyncServer.java | 28 + .../apache/thrift/server/TestHsHaServer.java | 30 + .../thrift/server/TestNonblockingServer.java | 123 + .../server/TestThreadedSelectorServer.java | 30 + .../org/apache/thrift/test/EqualityTest.java | 663 + .../org/apache/thrift/test/JavaBeansTest.java | 112 + .../org/apache/thrift/test/ReadStruct.java | 62 + .../thrift/test/SerializationBenchmark.java | 80 + .../org/apache/thrift/test/TestClient.java | 806 + .../thrift/test/TestNonblockingServer.java | 76 + .../org/apache/thrift/test/TestServer.java | 310 + .../org/apache/thrift/test/WriteStruct.java | 48 + .../transport/ReadCountingTransport.java | 61 + .../transport/TestAutoExpandingBuffer.java | 37 + .../TestAutoExpandingBufferReadTransport.java | 50 + ...TestAutoExpandingBufferWriteTransport.java | 44 + .../thrift/transport/TestTByteBuffer.java | 36 + .../transport/TestTFastFramedTransport.java | 33 + .../transport/TestTFramedTransport.java | 214 + .../transport/TestTMemoryInputTransport.java | 85 + .../transport/TestTSSLTransportFactory.java | 88 + ...TestTSSLTransportFactoryCustomClient1.java | 35 + ...TestTSSLTransportFactoryCustomClient2.java | 34 + .../thrift/transport/TestTSaslTransports.java | 478 + .../transport/TestTSimpleFileTransport.java | 74 + .../thrift/transport/TestTZlibTransport.java | 140 + .../transport/WriteCountingTransport.java | 54 + lib/javame/coding_standards.md | 1 + .../apache/thrift/TApplicationException.java | 132 + lib/javame/src/org/apache/thrift/TBase.java | 46 + .../src/org/apache/thrift/TBaseHelper.java | 209 + .../apache/thrift/TByteArrayOutputStream.java | 41 + .../src/org/apache/thrift/TDeserializer.java | 95 + lib/javame/src/org/apache/thrift/TEnum.java | 24 + .../src/org/apache/thrift/TException.java | 45 + .../apache/thrift/TFieldRequirementType.java | 48 + .../src/org/apache/thrift/TProcessor.java | 32 + .../org/apache/thrift/TProcessorFactory.java | 39 + .../src/org/apache/thrift/TSerializer.java | 110 + .../src/org/apache/thrift/TServiceClient.java | 39 + .../thrift/meta_data/FieldMetaData.java | 88 + .../thrift/meta_data/FieldValueMetaData.java | 61 + .../apache/thrift/meta_data/ListMetaData.java | 49 + .../apache/thrift/meta_data/MapMetaData.java | 51 + .../apache/thrift/meta_data/SetMetaData.java | 47 + .../thrift/meta_data/StructMetaData.java | 51 + .../apache/thrift/protocol/TBase64Utils.java | 127 + .../thrift/protocol/TBinaryProtocol.java | 329 + .../org/apache/thrift/protocol/TField.java | 38 + .../apache/thrift/protocol/TJSONProtocol.java | 973 + .../src/org/apache/thrift/protocol/TList.java | 36 + .../src/org/apache/thrift/protocol/TMap.java | 38 + .../org/apache/thrift/protocol/TMessage.java | 38 + .../apache/thrift/protocol/TMessageType.java | 30 + .../org/apache/thrift/protocol/TProtocol.java | 169 + .../thrift/protocol/TProtocolException.java | 81 + .../thrift/protocol/TProtocolFactory.java | 30 + .../apache/thrift/protocol/TProtocolUtil.java | 158 + .../src/org/apache/thrift/protocol/TSet.java | 36 + .../org/apache/thrift/protocol/TStruct.java | 34 + .../src/org/apache/thrift/protocol/TType.java | 40 + .../thrift/transport/TFramedTransport.java | 122 + .../apache/thrift/transport/THttpClient.java | 163 + .../thrift/transport/TIOStreamTransport.java | 153 + .../thrift/transport/TMemoryBuffer.java | 97 + .../apache/thrift/transport/TTransport.java | 121 + .../thrift/transport/TTransportException.java | 80 + .../thrift/transport/TTransportFactory.java | 41 + lib/js/Gruntfile.js | 172 + lib/js/Makefile | 815 + lib/js/Makefile.am | 30 + lib/js/Makefile.in | 815 + lib/js/README.md | 147 + lib/js/coding_standards.md | 1 + lib/js/package.json | 19 + lib/js/src/thrift.js | 1564 + lib/js/test/Makefile | 634 + lib/js/test/Makefile.am | 29 + lib/js/test/Makefile.in | 634 + lib/js/test/README.md | 68 + lib/js/test/build.xml | 227 + lib/js/test/deep-constructor.test.js | 195 + lib/js/test/jsTestDriver.conf | 17 + lib/js/test/phantom-client.js | 382 + lib/js/test/phantomjs-qunit.js | 91 + lib/js/test/server_http.js | 49 + lib/js/test/server_https.js | 57 + lib/js/test/src/test/Httpd.java | 323 + lib/js/test/test-async.js | 348 + lib/js/test/test-deep-constructor.html | 49 + lib/js/test/test-jq.js | 158 + lib/js/test/test-nojq.html | 52 + lib/js/test/test-nojq.js | 49 + lib/js/test/test.html | 59 + lib/js/test/test.js | 412 + lib/js/test/test_handler.js | 199 + lib/js/test/testws.html | 62 + lib/json/Makefile.am | 29 + lib/json/Makefile.in | 811 + lib/json/schema.json | 344 + lib/json/test/Makefile | 630 + lib/json/test/Makefile.am | 26 + lib/json/test/Makefile.in | 630 + lib/json/test/build.properties | 10 + lib/json/test/build.xml | 144 + lib/lua/Makefile.am | 73 + lib/lua/Makefile.in | 1129 + lib/lua/TBinaryProtocol.lua | 264 + lib/lua/TBufferedTransport.lua | 91 + lib/lua/TCompactProtocol.lua | 457 + lib/lua/TFramedTransport.lua | 118 + lib/lua/THttpTransport.lua | 182 + lib/lua/TJsonProtocol.lua | 727 + lib/lua/TMemoryBuffer.lua | 91 + lib/lua/TProtocol.lua | 162 + lib/lua/TServer.lua | 140 + lib/lua/TSocket.lua | 132 + lib/lua/TTransport.lua | 93 + lib/lua/Thrift.lua | 281 + lib/lua/coding_standards.md | 1 + lib/lua/src/longnumberutils.c | 47 + lib/lua/src/luabitwise.c | 83 + lib/lua/src/luabpack.c | 308 + lib/lua/src/lualongnumber.c | 228 + lib/lua/src/luasocket.c | 380 + lib/lua/src/socket.h | 78 + lib/lua/src/usocket.c | 376 + lib/netcore/Makefile.am | 105 + lib/netcore/Makefile.in | 885 + lib/netcore/README.md | 21 + .../CassandraTest.thrift | 705 + .../Properties/AssemblyInfo.cs | 40 + ...rift.PublicInterfaces.Compile.Tests.csproj | 21 + lib/netcore/Thrift.sln | 55 + .../Thrift/Collections/TCollections.cs | 101 + lib/netcore/Thrift/Collections/THashSet.cs | 67 + lib/netcore/Thrift/ITAsyncProcessor.cs | 29 + lib/netcore/Thrift/ITProcessorFactory.cs | 28 + lib/netcore/Thrift/Properties/AssemblyInfo.cs | 56 + .../Thrift/Protocols/Entities/TField.cs | 37 + .../Thrift/Protocols/Entities/TList.cs | 33 + lib/netcore/Thrift/Protocols/Entities/TMap.cs | 36 + .../Thrift/Protocols/Entities/TMessage.cs | 37 + .../Thrift/Protocols/Entities/TMessageType.cs | 28 + lib/netcore/Thrift/Protocols/Entities/TSet.cs | 38 + .../Thrift/Protocols/Entities/TStruct.cs | 30 + .../Thrift/Protocols/Entities/TType.cs | 37 + .../Thrift/Protocols/ITProtocolFactory.cs | 27 + lib/netcore/Thrift/Protocols/TAbstractBase.cs | 28 + lib/netcore/Thrift/Protocols/TBase.cs | 28 + .../Thrift/Protocols/TBinaryProtocol.cs | 608 + .../Thrift/Protocols/TCompactProtocol.cs | 922 + lib/netcore/Thrift/Protocols/TJSONProtocol.cs | 1170 + .../Thrift/Protocols/TMultiplexedProtocol.cs | 100 + lib/netcore/Thrift/Protocols/TProtocol.cs | 377 + .../Thrift/Protocols/TProtocolDecorator.cs | 252 + .../Thrift/Protocols/TProtocolException.cs | 58 + .../Protocols/Utilities/TBase64Utils.cs | 101 + .../Protocols/Utilities/TProtocolUtil.cs | 110 + lib/netcore/Thrift/Server/AsyncBaseServer.cs | 184 + lib/netcore/Thrift/Server/TBaseServer.cs | 86 + .../Thrift/Server/TServerEventHandler.cs | 54 + .../Thrift/SingletonTProcessorFactory.cs | 38 + lib/netcore/Thrift/TApplicationException.cs | 149 + lib/netcore/Thrift/TBaseClient.cs | 102 + lib/netcore/Thrift/TException.cs | 34 + lib/netcore/Thrift/TMultiplexedProcessor.cs | 143 + lib/netcore/Thrift/Thrift.csproj | 31 + .../Client/TBufferedClientTransport.cs | 210 + .../Client/TFramedClientTransport.cs | 205 + .../Transports/Client/THttpClientTransport.cs | 228 + .../Client/TMemoryBufferClientTransport.cs | 97 + .../Client/TNamedPipeClientTransport.cs | 95 + .../Client/TSocketClientTransport.cs | 144 + .../Client/TStreamClientTransport.cs | 110 + .../Client/TTlsSocketClientTransport.cs | 236 + .../Transports/Server/THttpServerTransport.cs | 113 + .../Server/TNamedPipeServerTransport.cs | 191 + .../Server/TServerFramedTransport.cs | 150 + .../Server/TServerSocketTransport.cs | 162 + .../Server/TTlsServerSocketTransport.cs | 156 + .../Thrift/Transports/TClientTransport.cs | 178 + .../Thrift/Transports/TServerTransport.cs | 54 + .../Thrift/Transports/TTransportException.cs | 58 + .../Thrift/Transports/TTransportFactory.cs | 35 + lib/nodejs/Makefile.am | 42 + lib/nodejs/Makefile.in | 647 + lib/nodejs/README.md | 68 + lib/nodejs/coding_standards.md | 1 + lib/nodejs/examples/Makefile | 24 + lib/nodejs/examples/README.md | 40 + lib/nodejs/examples/client.js | 49 + lib/nodejs/examples/client_multitransport.js | 58 + lib/nodejs/examples/hello.html | 65 + lib/nodejs/examples/hello.js | 63 + lib/nodejs/examples/hello.thrift | 27 + lib/nodejs/examples/httpClient.js | 23 + lib/nodejs/examples/httpServer.js | 31 + lib/nodejs/examples/httpServer.py | 18 + lib/nodejs/examples/parse.js | 46 + lib/nodejs/examples/server.js | 39 + lib/nodejs/examples/server_http.js | 53 + lib/nodejs/examples/server_multitransport.js | 46 + lib/nodejs/examples/user.thrift | 27 + lib/nodejs/lib/thrift/binary.js | 168 + lib/nodejs/lib/thrift/binary_protocol.js | 364 + lib/nodejs/lib/thrift/browser.js | 34 + lib/nodejs/lib/thrift/buffered_transport.js | 175 + lib/nodejs/lib/thrift/compact_protocol.js | 917 + lib/nodejs/lib/thrift/connection.js | 357 + lib/nodejs/lib/thrift/create_client.js | 54 + lib/nodejs/lib/thrift/framed_transport.js | 182 + lib/nodejs/lib/thrift/http_connection.js | 256 + lib/nodejs/lib/thrift/index.js | 72 + .../lib/thrift/input_buffer_underrun_error.js | 30 + lib/nodejs/lib/thrift/int64_util.js | 91 + lib/nodejs/lib/thrift/json_parse.js | 299 + lib/nodejs/lib/thrift/json_protocol.js | 742 + lib/nodejs/lib/thrift/log.js | 87 + .../lib/thrift/multiplexed_processor.js | 63 + lib/nodejs/lib/thrift/multiplexed_protocol.js | 73 + lib/nodejs/lib/thrift/protocol.js | 22 + lib/nodejs/lib/thrift/server.js | 113 + lib/nodejs/lib/thrift/thrift.js | 232 + lib/nodejs/lib/thrift/transport.js | 22 + lib/nodejs/lib/thrift/web_server.js | 559 + lib/nodejs/lib/thrift/ws_connection.js | 286 + lib/nodejs/lib/thrift/ws_transport.js | 206 + lib/nodejs/lib/thrift/xhr_connection.js | 280 + lib/nodejs/test/binary.test.js | 137 + lib/nodejs/test/browser_client.js | 45 + lib/nodejs/test/certificates.README | 7 + lib/nodejs/test/client.js | 136 + lib/nodejs/test/deep-constructor.test.js | 333 + lib/nodejs/test/exceptions.js | 74 + lib/nodejs/test/helpers.js | 32 + lib/nodejs/test/server.crt | 25 + lib/nodejs/test/server.js | 106 + lib/nodejs/test/server.key | 28 + lib/nodejs/test/test-cases.js | 163 + lib/nodejs/test/testAll.sh | 108 + lib/nodejs/test/test_driver.js | 327 + lib/nodejs/test/test_handler.js | 227 + lib/ocaml/DEVELOPMENT | 76 + lib/ocaml/README.md | 119 + lib/ocaml/TODO | 5 + lib/ocaml/_oasis | 19 + lib/ocaml/coding_standards.md | 1 + lib/ocaml/descr | 1 + lib/ocaml/opam | 8 + lib/ocaml/src/Makefile | 26 + lib/ocaml/src/TBinaryProtocol.ml | 171 + lib/ocaml/src/TChannelTransport.ml | 39 + lib/ocaml/src/TFramedTransport.ml | 93 + lib/ocaml/src/TServer.ml | 42 + lib/ocaml/src/TServerSocket.ml | 41 + lib/ocaml/src/TSimpleServer.ml | 40 + lib/ocaml/src/TSocket.ml | 59 + lib/ocaml/src/TThreadedServer.ml | 45 + lib/ocaml/src/Thrift.ml | 383 + lib/ocaml/url | 2 + lib/perl/Makefile.PL | 31 + lib/perl/Makefile.am | 108 + lib/perl/Makefile.in | 896 + lib/perl/README.md | 124 + lib/perl/build-cpan-dist.sh | 9 + lib/perl/coding_standards.md | 2 + lib/perl/lib/Thrift.pm | 36 + lib/perl/lib/Thrift/BinaryProtocol.pm | 514 + lib/perl/lib/Thrift/BufferedTransport.pm | 139 + lib/perl/lib/Thrift/Exception.pm | 160 + lib/perl/lib/Thrift/FramedTransport.pm | 194 + lib/perl/lib/Thrift/HttpClient.pm | 203 + lib/perl/lib/Thrift/MemoryBuffer.pm | 148 + lib/perl/lib/Thrift/MessageType.pm | 37 + lib/perl/lib/Thrift/MultiplexedProcessor.pm | 133 + lib/perl/lib/Thrift/MultiplexedProtocol.pm | 68 + lib/perl/lib/Thrift/Protocol.pm | 549 + lib/perl/lib/Thrift/ProtocolDecorator.pm | 363 + lib/perl/lib/Thrift/SSLServerSocket.pm | 76 + lib/perl/lib/Thrift/SSLSocket.pm | 126 + lib/perl/lib/Thrift/Server.pm | 300 + lib/perl/lib/Thrift/ServerSocket.pm | 115 + lib/perl/lib/Thrift/Socket.pm | 325 + lib/perl/lib/Thrift/Transport.pm | 180 + lib/perl/lib/Thrift/Type.pm | 50 + lib/perl/lib/Thrift/UnixServerSocket.pm | 84 + lib/perl/lib/Thrift/UnixSocket.pm | 67 + lib/perl/test.pl | 25 + lib/perl/test/Makefile.am | 20 + lib/perl/test/Makefile.in | 623 + lib/perl/test/memory_buffer.t | 53 + lib/perl/test/multiplex.t | 201 + lib/perl/test/processor.t | 104 + lib/php/Makefile.am | 149 + lib/php/Makefile.in | 1334 + lib/php/README.apache.md | 74 + lib/php/README.md | 53 + lib/php/coding_standards.md | 1 + lib/php/lib/Thrift/Base/TBase.php | 380 + .../Thrift/ClassLoader/ThriftClassLoader.php | 210 + .../Exception/TApplicationException.php | 76 + lib/php/lib/Thrift/Exception/TException.php | 383 + .../Thrift/Exception/TProtocolException.php | 50 + .../Thrift/Exception/TTransportException.php | 40 + .../Thrift/Factory/TBinaryProtocolFactory.php | 45 + .../Factory/TCompactProtocolFactory.php | 40 + .../Thrift/Factory/TJSONProtocolFactory.php | 40 + .../lib/Thrift/Factory/TProtocolFactory.php | 36 + .../lib/Thrift/Factory/TStringFuncFactory.php | 66 + .../lib/Thrift/Factory/TTransportFactory.php | 18 + .../lib/Thrift/Protocol/JSON/BaseContext.php | 39 + .../lib/Thrift/Protocol/JSON/ListContext.php | 54 + .../Thrift/Protocol/JSON/LookaheadReader.php | 57 + .../lib/Thrift/Protocol/JSON/PairContext.php | 64 + .../SimpleJSON/CollectionMapKeyException.php | 33 + .../Thrift/Protocol/SimpleJSON/Context.php | 36 + .../Protocol/SimpleJSON/ListContext.php | 45 + .../Thrift/Protocol/SimpleJSON/MapContext.php | 51 + .../Protocol/SimpleJSON/StructContext.php | 53 + .../lib/Thrift/Protocol/TBinaryProtocol.php | 453 + .../Protocol/TBinaryProtocolAccelerated.php | 65 + .../lib/Thrift/Protocol/TCompactProtocol.php | 739 + lib/php/lib/Thrift/Protocol/TJSONProtocol.php | 807 + .../Thrift/Protocol/TMultiplexedProtocol.php | 85 + lib/php/lib/Thrift/Protocol/TProtocol.php | 352 + .../Thrift/Protocol/TProtocolDecorator.php | 284 + .../Thrift/Protocol/TSimpleJSONProtocol.php | 371 + .../Thrift/Serializer/TBinarySerializer.php | 85 + lib/php/lib/Thrift/Server/TForkingServer.php | 120 + .../lib/Thrift/Server/TSSLServerSocket.php | 94 + lib/php/lib/Thrift/Server/TServer.php | 100 + lib/php/lib/Thrift/Server/TServerSocket.php | 122 + .../lib/Thrift/Server/TServerTransport.php | 56 + lib/php/lib/Thrift/Server/TSimpleServer.php | 58 + lib/php/lib/Thrift/StringFunc/Core.php | 40 + lib/php/lib/Thrift/StringFunc/Mbstring.php | 46 + lib/php/lib/Thrift/StringFunc/TStringFunc.php | 28 + lib/php/lib/Thrift/TMultiplexedProcessor.php | 143 + .../Thrift/Transport/TBufferedTransport.php | 181 + lib/php/lib/Thrift/Transport/TCurlClient.php | 249 + .../lib/Thrift/Transport/TFramedTransport.php | 193 + lib/php/lib/Thrift/Transport/THttpClient.php | 229 + .../lib/Thrift/Transport/TMemoryBuffer.php | 100 + .../lib/Thrift/Transport/TNullTransport.php | 51 + lib/php/lib/Thrift/Transport/TPhpStream.php | 123 + lib/php/lib/Thrift/Transport/TSSLSocket.php | 112 + lib/php/lib/Thrift/Transport/TSocket.php | 340 + lib/php/lib/Thrift/Transport/TSocketPool.php | 300 + lib/php/lib/Thrift/Transport/TTransport.php | 95 + lib/php/lib/Thrift/Type/TConstant.php | 50 + lib/php/lib/Thrift/Type/TMessageType.php | 34 + lib/php/lib/Thrift/Type/TType.php | 47 + lib/php/src/TStringUtils.php | 90 + lib/php/src/Thrift.php | 821 + lib/php/src/autoload.php | 51 + lib/php/src/ext/thrift_protocol/config.m4 | 34 + lib/php/src/ext/thrift_protocol/config.w32 | 8 + .../thrift_protocol/php_thrift_protocol.cpp | 1151 + .../ext/thrift_protocol/php_thrift_protocol.h | 28 + lib/php/src/ext/thrift_protocol/run-tests.php | 2928 ++ lib/php/test/Makefile.am | 59 + lib/php/test/Makefile.in | 657 + lib/php/test/Test/Thrift/Fixtures.php | 194 + .../JsonSerialize/JsonSerializeTest.php | 116 + .../Thrift/Protocol/TestBinarySerializer.php | 64 + .../Thrift/Protocol/TestTJSONProtocol.php | 583 + .../Protocol/TestTSimpleJSONProtocol.php | 300 + lib/php/test/Test/Thrift/TestValidators.php | 156 + lib/php/test/TestValidators.thrift | 31 + lib/php/thrift_protocol.ini | 1 + lib/py/CMakeLists.txt | 31 + lib/py/MANIFEST.in | 1 + lib/py/Makefile.am | 59 + lib/py/Makefile.in | 663 + lib/py/README.md | 35 + lib/py/coding_standards.md | 7 + lib/py/compat/win32/stdint.h | 247 + lib/py/setup.cfg | 6 + lib/py/setup.py | 136 + lib/py/src/TMultiplexedProcessor.py | 55 + lib/py/src/TRecursive.py | 83 + lib/py/src/TSCons.py | 36 + lib/py/src/TSerialization.py | 38 + lib/py/src/TTornado.py | 188 + lib/py/src/Thrift.py | 192 + lib/py/src/__init__.py | 20 + lib/py/src/compat.py | 40 + lib/py/src/ext/binary.cpp | 38 + lib/py/src/ext/binary.h | 217 + lib/py/src/ext/compact.cpp | 107 + lib/py/src/ext/compact.h | 368 + lib/py/src/ext/endian.h | 92 + lib/py/src/ext/module.cpp | 203 + lib/py/src/ext/protocol.h | 96 + lib/py/src/ext/protocol.tcc | 913 + lib/py/src/ext/types.cpp | 113 + lib/py/src/ext/types.h | 192 + lib/py/src/protocol/TBase.py | 82 + lib/py/src/protocol/TBinaryProtocol.py | 301 + lib/py/src/protocol/TCompactProtocol.py | 475 + lib/py/src/protocol/TJSONProtocol.py | 677 + lib/py/src/protocol/TMultiplexedProtocol.py | 40 + lib/py/src/protocol/TProtocol.py | 419 + lib/py/src/protocol/TProtocolDecorator.py | 50 + lib/py/src/protocol/__init__.py | 21 + lib/py/src/server/THttpServer.py | 87 + lib/py/src/server/TNonblockingServer.py | 370 + lib/py/src/server/TProcessPoolServer.py | 123 + lib/py/src/server/TServer.py | 276 + lib/py/src/server/__init__.py | 20 + lib/py/src/transport/THttpClient.py | 194 + lib/py/src/transport/TSSLSocket.py | 396 + lib/py/src/transport/TSocket.py | 192 + lib/py/src/transport/TTransport.py | 454 + lib/py/src/transport/TTwisted.py | 329 + lib/py/src/transport/TZlibTransport.py | 248 + lib/py/src/transport/__init__.py | 20 + lib/py/src/transport/sslcompat.py | 100 + lib/py/test/_import_local_thrift.py | 30 + lib/py/test/test_sslsocket.py | 343 + lib/py/test/thrift_json.py | 51 + lib/rb/Gemfile | 4 + lib/rb/Makefile.am | 51 + lib/rb/Makefile.in | 658 + lib/rb/README.md | 43 + lib/rb/Rakefile | 119 + lib/rb/benchmark/Benchmark.thrift | 24 + lib/rb/benchmark/benchmark.rb | 271 + lib/rb/benchmark/client.rb | 74 + lib/rb/benchmark/server.rb | 82 + lib/rb/benchmark/thin_server.rb | 44 + lib/rb/coding_standards.md | 1 + lib/rb/ext/binary_protocol_accelerated.c | 460 + lib/rb/ext/binary_protocol_accelerated.h | 20 + lib/rb/ext/bytes.c | 36 + lib/rb/ext/bytes.h | 31 + lib/rb/ext/compact_protocol.c | 637 + lib/rb/ext/compact_protocol.h | 20 + lib/rb/ext/constants.h | 99 + lib/rb/ext/extconf.rb | 34 + lib/rb/ext/macros.h | 41 + lib/rb/ext/memory_buffer.c | 134 + lib/rb/ext/memory_buffer.h | 20 + lib/rb/ext/protocol.c | 0 lib/rb/ext/protocol.h | 0 lib/rb/ext/strlcpy.c | 41 + lib/rb/ext/strlcpy.h | 34 + lib/rb/ext/struct.c | 711 + lib/rb/ext/struct.h | 25 + lib/rb/ext/thrift_native.c | 201 + lib/rb/lib/thrift.rb | 70 + lib/rb/lib/thrift/bytes.rb | 131 + lib/rb/lib/thrift/client.rb | 71 + lib/rb/lib/thrift/core_ext.rb | 23 + lib/rb/lib/thrift/core_ext/fixnum.rb | 29 + lib/rb/lib/thrift/exceptions.rb | 87 + lib/rb/lib/thrift/multiplexed_processor.rb | 76 + lib/rb/lib/thrift/processor.rb | 75 + lib/rb/lib/thrift/protocol/base_protocol.rb | 379 + lib/rb/lib/thrift/protocol/binary_protocol.rb | 237 + .../protocol/binary_protocol_accelerated.rb | 39 + .../lib/thrift/protocol/compact_protocol.rb | 435 + lib/rb/lib/thrift/protocol/json_protocol.rb | 778 + .../thrift/protocol/multiplexed_protocol.rb | 40 + .../lib/thrift/protocol/protocol_decorator.rb | 194 + lib/rb/lib/thrift/serializer/deserializer.rb | 33 + lib/rb/lib/thrift/serializer/serializer.rb | 34 + lib/rb/lib/thrift/server/base_server.rb | 31 + .../lib/thrift/server/mongrel_http_server.rb | 60 + .../lib/thrift/server/nonblocking_server.rb | 305 + lib/rb/lib/thrift/server/simple_server.rb | 43 + lib/rb/lib/thrift/server/thin_http_server.rb | 91 + .../lib/thrift/server/thread_pool_server.rb | 75 + lib/rb/lib/thrift/server/threaded_server.rb | 47 + lib/rb/lib/thrift/struct.rb | 237 + lib/rb/lib/thrift/struct_union.rb | 192 + lib/rb/lib/thrift/thrift_native.rb | 24 + .../thrift/transport/base_server_transport.rb | 37 + lib/rb/lib/thrift/transport/base_transport.rb | 109 + .../thrift/transport/buffered_transport.rb | 114 + .../lib/thrift/transport/framed_transport.rb | 117 + .../thrift/transport/http_client_transport.rb | 57 + .../thrift/transport/io_stream_transport.rb | 39 + .../transport/memory_buffer_transport.rb | 125 + lib/rb/lib/thrift/transport/server_socket.rb | 63 + lib/rb/lib/thrift/transport/socket.rb | 141 + .../lib/thrift/transport/ssl_server_socket.rb | 37 + lib/rb/lib/thrift/transport/ssl_socket.rb | 47 + .../thrift/transport/unix_server_socket.rb | 60 + lib/rb/lib/thrift/transport/unix_socket.rb | 40 + lib/rb/lib/thrift/types.rb | 101 + lib/rb/lib/thrift/union.rb | 176 + lib/rb/script/proto_benchmark.rb | 121 + lib/rb/script/read_struct.rb | 43 + lib/rb/script/write_struct.rb | 30 + lib/rb/spec/BaseService.thrift | 27 + lib/rb/spec/ExtendedService.thrift | 25 + lib/rb/spec/Referenced.thrift | 44 + lib/rb/spec/ThriftNamespacedSpec.thrift | 53 + lib/rb/spec/ThriftSpec.thrift | 183 + lib/rb/spec/base_protocol_spec.rb | 217 + lib/rb/spec/base_transport_spec.rb | 350 + .../spec/binary_protocol_accelerated_spec.rb | 42 + lib/rb/spec/binary_protocol_spec.rb | 66 + lib/rb/spec/binary_protocol_spec_shared.rb | 455 + lib/rb/spec/bytes_spec.rb | 160 + lib/rb/spec/client_spec.rb | 99 + lib/rb/spec/compact_protocol_spec.rb | 143 + lib/rb/spec/exception_spec.rb | 141 + lib/rb/spec/flat_spec.rb | 62 + lib/rb/spec/http_client_spec.rb | 135 + lib/rb/spec/json_protocol_spec.rb | 544 + lib/rb/spec/namespaced_spec.rb | 67 + lib/rb/spec/nonblocking_server_spec.rb | 263 + lib/rb/spec/processor_spec.rb | 80 + lib/rb/spec/serializer_spec.rb | 67 + lib/rb/spec/server_socket_spec.rb | 79 + lib/rb/spec/server_spec.rb | 148 + lib/rb/spec/socket_spec.rb | 61 + lib/rb/spec/socket_spec_shared.rb | 104 + lib/rb/spec/spec_helper.rb | 64 + lib/rb/spec/ssl_socket_spec.rb | 74 + lib/rb/spec/struct_nested_containers_spec.rb | 191 + lib/rb/spec/struct_spec.rb | 293 + lib/rb/spec/thin_http_server_spec.rb | 141 + lib/rb/spec/types_spec.rb | 115 + lib/rb/spec/union_spec.rb | 215 + lib/rb/spec/unix_socket_spec.rb | 107 + lib/rb/thrift.gemspec | 37 + lib/rs/Cargo.toml | 19 + lib/rs/Makefile.am | 46 + lib/rs/Makefile.in | 827 + lib/rs/README.md | 60 + lib/rs/src/autogen.rs | 45 + lib/rs/src/errors.rs | 712 + lib/rs/src/lib.rs | 89 + lib/rs/src/protocol/binary.rs | 926 + lib/rs/src/protocol/compact.rs | 2380 ++ lib/rs/src/protocol/mod.rs | 1009 + lib/rs/src/protocol/multiplexed.rs | 237 + lib/rs/src/protocol/stored.rs | 198 + lib/rs/src/server/mod.rs | 124 + lib/rs/src/server/multiplexed.rs | 344 + lib/rs/src/server/threaded.rs | 240 + lib/rs/src/transport/buffered.rs | 442 + lib/rs/src/transport/framed.rs | 264 + lib/rs/src/transport/mem.rs | 393 + lib/rs/src/transport/mod.rs | 280 + lib/rs/src/transport/socket.rs | 165 + lib/rs/test/Cargo.toml | 15 + lib/rs/test/Makefile.am | 54 + lib/rs/test/Makefile.in | 655 + lib/rs/test/src/bin/kitchen_sink_client.rs | 280 + lib/rs/test/src/bin/kitchen_sink_server.rs | 304 + lib/rs/test/src/lib.rs | 57 + lib/rs/test/thrifts/Base_One.thrift | 81 + lib/rs/test/thrifts/Base_Two.thrift | 44 + lib/rs/test/thrifts/Midlayer.thrift | 62 + lib/rs/test/thrifts/Ultimate.thrift | 49 + lib/st/README.md | 39 + lib/st/coding_standards.md | 1 + lib/st/package.xml | 26 + lib/st/thrift.st | 815 + lib/ts/coding_standards.md | 1 + lib/ts/thrift.d.ts | 699 + lib/xml/Makefile.am | 29 + lib/xml/Makefile.in | 811 + lib/xml/test/Makefile | 630 + lib/xml/test/Makefile.am | 26 + lib/xml/test/Makefile.in | 630 + lib/xml/test/build.xml | 112 + lib/xml/thrift-idl.xsd | 283 + ltmain.sh | 11156 ++++++ missing | 215 + package.json | 58 + sonar-project.properties | 140 + test/AnnotationTest.thrift | 72 + test/BrokenConstants.thrift | 25 + test/ConstantsDemo.thrift | 75 + test/DebugProtoTest.thrift | 378 + test/DenseLinkingTest.thrift | 98 + test/DocTest.thrift | 287 + test/EnumContainersTest.thrift | 46 + test/EnumTest.thrift | 119 + test/FullCamelTest.thrift | 38 + test/Include.thrift | 24 + test/JavaBeansTest.thrift | 39 + test/JavaDeepCopyTest.thrift | 19 + test/JavaTypes.thrift | 98 + test/JsDeepConstructorTest.thrift | 18 + test/Makefile.am | 162 + test/Makefile.in | 908 + test/ManyOptionals.thrift | 231 + test/ManyTypedefs.thrift | 50 + test/NameConflictTest.thrift | 110 + test/OptionalRequiredTest.thrift | 88 + test/README.md | 185 + test/Recursive.thrift | 47 + test/ReuseObjects.thrift | 30 + test/SmallTest.thrift | 60 + test/StressTest.thrift | 35 + test/ThriftTest.thrift | 411 + test/TypedefTest.thrift | 36 + test/audit/README.md | 40 + test/audit/break1.thrift | 188 + test/audit/break10.thrift | 190 + test/audit/break11.thrift | 190 + test/audit/break12.thrift | 191 + test/audit/break13.thrift | 191 + test/audit/break14.thrift | 190 + test/audit/break15.thrift | 190 + test/audit/break16.thrift | 191 + test/audit/break17.thrift | 191 + test/audit/break18.thrift | 191 + test/audit/break19.thrift | 191 + test/audit/break2.thrift | 190 + test/audit/break20.thrift | 190 + test/audit/break21.thrift | 190 + test/audit/break22.thrift | 190 + test/audit/break23.thrift | 192 + test/audit/break24.thrift | 191 + test/audit/break25.thrift | 191 + test/audit/break26.thrift | 191 + test/audit/break27.thrift | 190 + test/audit/break28.thrift | 190 + test/audit/break29.thrift | 191 + test/audit/break3.thrift | 191 + test/audit/break30.thrift | 190 + test/audit/break31.thrift | 191 + test/audit/break32.thrift | 191 + test/audit/break33.thrift | 191 + test/audit/break34.thrift | 192 + test/audit/break4.thrift | 190 + test/audit/break5.thrift | 190 + test/audit/break6.thrift | 191 + test/audit/break7.thrift | 190 + test/audit/break8.thrift | 191 + test/audit/break9.thrift | 190 + test/audit/test.thrift | 189 + test/audit/thrift_audit_test.pl | 261 + test/audit/warning.thrift | 190 + test/c_glib/Makefile | 896 + test/c_glib/Makefile.am | 74 + test/c_glib/Makefile.in | 896 + test/c_glib/src/test_client.c | 1804 + test/c_glib/src/test_server.c | 290 + .../src/thrift_second_service_handler.c | 69 + .../src/thrift_second_service_handler.h | 73 + test/c_glib/src/thrift_test_handler.c | 837 + test/c_glib/src/thrift_test_handler.h | 245 + test/cpp/CMakeLists.txt | 89 + test/cpp/Makefile | 1016 + test/cpp/Makefile.am | 125 + test/cpp/Makefile.in | 1016 + test/cpp/src/StressTest.cpp | 606 + test/cpp/src/StressTestNonBlocking.cpp | 544 + test/cpp/src/TestClient.cpp | 1170 + test/cpp/src/TestServer.cpp | 807 + test/cpp/src/ThriftTest_extras.cpp | 33 + test/crossrunner/__init__.py | 23 + test/crossrunner/collect.py | 162 + test/crossrunner/compat.py | 24 + test/crossrunner/report.py | 434 + test/crossrunner/run.py | 389 + test/crossrunner/setup.cfg | 2 + test/crossrunner/test.py | 143 + test/crossrunner/util.py | 31 + test/csharp/Makefile.am | 95 + test/csharp/Makefile.in | 692 + test/csharp/Program.cs | 71 + test/csharp/Properties/AssemblyInfo.cs | 55 + test/csharp/TestClient.cs | 868 + test/csharp/TestServer.cs | 533 + test/csharp/ThriftTest.csproj | 141 + test/csharp/ThriftTest.sln | 17 + test/dart/Makefile | 646 + test/dart/Makefile.am | 42 + test/dart/Makefile.in | 646 + test/dart/test_client/.analysis_options | 2 + test/dart/test_client/bin/main.dart | 337 + test/dart/test_client/pubspec.yaml | 36 + test/erl/Makefile | 638 + test/erl/Makefile.am | 41 + test/erl/Makefile.in | 638 + test/erl/rebar.config | 6 + test/erl/src/test_client.erl | 174 + test/erl/src/test_thrift_server.erl | 233 + test/erl/src/thrift_test.app.src | 54 + test/features/Makefile.am | 30 + test/features/Makefile.in | 634 + test/features/container_limit.py | 72 + test/features/index.html | 51 + test/features/known_failures_Linux.json | 46 + test/features/local_thrift/__init__.py | 32 + test/features/nosslv3.sh | 52 + test/features/setup.cfg | 2 + test/features/string_limit.py | 62 + test/features/tests.json | 114 + test/features/theader_binary.py | 70 + test/features/tls.sh | 71 + test/features/util.py | 40 + test/go/Makefile.am | 70 + test/go/Makefile.in | 674 + test/go/src/bin/stress/go17.go | 62 + test/go/src/bin/stress/main.go | 218 + test/go/src/bin/stress/pre_go17.go | 63 + test/go/src/bin/testclient/go17.go | 26 + test/go/src/bin/testclient/main.go | 313 + test/go/src/bin/testclient/pre_go17.go | 26 + test/go/src/bin/testserver/main.go | 70 + test/go/src/common/client.go | 109 + test/go/src/common/clientserver_test.go | 333 + test/go/src/common/go17.go | 26 + test/go/src/common/pre_go17.go | 26 + test/go/src/common/printing_handler.go | 387 + test/go/src/common/printing_handler_go17.go | 386 + test/go/src/common/server.go | 111 + test/go/src/common/simple_handler.go | 155 + test/haxe/Makefile.am | 104 + test/haxe/Makefile.in | 703 + test/haxe/TestClientServer.hxproj | 67 + test/haxe/cpp.hxml | 41 + test/haxe/csharp.hxml | 38 + test/haxe/flash.hxml | 41 + test/haxe/java.hxml | 38 + test/haxe/javascript.hxml | 44 + test/haxe/make_all.bat | 68 + test/haxe/make_all.sh | 41 + test/haxe/neko.hxml | 38 + test/haxe/php-web-server.hxml | 43 + test/haxe/php.hxml | 40 + test/haxe/project.hide | 76 + test/haxe/python.hxml | 38 + test/haxe/router.php | 31 + test/haxe/src/Arguments.hx | 335 + test/haxe/src/Main.hx | 83 + test/haxe/src/TestClient.hx | 937 + test/haxe/src/TestMacro.hx | 40 + test/haxe/src/TestServer.hx | 131 + test/haxe/src/TestServerEventHandler.hx | 53 + test/haxe/src/TestServerHandler.hx | 479 + test/hs/CMakeLists.txt | 114 + test/hs/ConstantsDemo_Main.hs | 68 + test/hs/DebugProtoTest_Main.hs | 168 + test/hs/Include_Main.hs | 7 + test/hs/Makefile | 646 + test/hs/Makefile.am | 41 + test/hs/Makefile.in | 646 + test/hs/TestClient.hs | 306 + test/hs/TestServer.hs | 312 + test/hs/ThriftTestUtils.hs | 65 + test/hs/ThriftTest_Main.hs | 214 + test/hs/run-test.sh | 43 + test/index.html | 51 + test/keys/CA.pem | 82 + test/keys/README.md | 102 + test/keys/client.crt | 23 + test/keys/client.key | 27 + test/keys/client.p12 | Bin 0 -> 2589 bytes test/keys/client.pem | 60 + test/keys/client_v3.crt | 24 + test/keys/client_v3.key | 27 + test/keys/server.crt | 25 + test/keys/server.key | 28 + test/keys/server.p12 | Bin 0 -> 2685 bytes test/keys/server.pem | 53 + test/known_failures_Linux.json | 336 + test/lua/Makefile | 633 + test/lua/Makefile.am | 31 + test/lua/Makefile.in | 633 + test/lua/test_basic_client.lua | 179 + test/lua/test_basic_server.lua | 142 + test/netcore/Makefile.am | 59 + test/netcore/Makefile.in | 839 + test/netcore/README.md | 17 + test/netcore/ThriftTest.sln | 50 + test/netcore/ThriftTest/Program.cs | 76 + .../ThriftTest/Properties/AssemblyInfo.cs | 43 + .../ThriftTest/Properties/launchSettings.json | 7 + test/netcore/ThriftTest/TestClient.cs | 898 + test/netcore/ThriftTest/TestServer.cs | 560 + test/netcore/ThriftTest/ThriftTest.csproj | 27 + test/netcore/build.cmd | 30 + test/netcore/build.sh | 31 + test/ocaml/Makefile | 24 + test/ocaml/client/Makefile | 26 + test/ocaml/client/TestClient.ml | 82 + test/ocaml/server/Makefile | 27 + test/ocaml/server/TestServer.ml | 137 + test/perl/Makefile | 632 + test/perl/Makefile.am | 29 + test/perl/Makefile.in | 632 + test/perl/TestClient.pl | 463 + test/perl/TestServer.pl | 430 + test/php/Makefile | 643 + test/php/Makefile.am | 39 + test/php/Makefile.in | 643 + test/php/TestClient.php | 556 + test/php/TestInline.php | 24 + test/php/TestPsr4.php | 23 + test/php/test_php.ini | 2 + test/py.tornado/Makefile | 632 + test/py.tornado/Makefile.am | 30 + test/py.tornado/Makefile.in | 632 + test/py.tornado/setup.cfg | 3 + test/py.tornado/test_suite.py | 236 + test/py.twisted/Makefile | 634 + test/py.twisted/Makefile.am | 30 + test/py.twisted/Makefile.in | 634 + test/py.twisted/setup.cfg | 3 + test/py.twisted/test_suite.py | 198 + test/py/CMakeLists.txt | 34 + test/py/FastbinaryTest.py | 256 + test/py/Makefile | 812 + test/py/Makefile.am | 90 + test/py/Makefile.in | 812 + test/py/RunClientServer.py | 321 + test/py/SerializationTest.py | 457 + test/py/TSimpleJSONProtocolTest.py | 108 + test/py/TestClient.py | 349 + test/py/TestEof.py | 132 + test/py/TestFrozen.py | 123 + test/py/TestServer.py | 316 + test/py/TestSocket.py | 78 + test/py/TestSyntax.py | 24 + test/py/explicit_module/runtest.sh | 35 + test/py/explicit_module/test1.thrift | 24 + test/py/explicit_module/test2.thrift | 24 + test/py/explicit_module/test3.thrift | 25 + test/py/generate.cmake | 29 + test/py/setup.cfg | 2 + test/py/util.py | 32 + test/rb/Gemfile | 7 + test/rb/Makefile | 632 + test/rb/Makefile.am | 31 + test/rb/Makefile.in | 632 + test/rb/benchmarks/protocol_benchmark.rb | 174 + test/rb/core/test_backwards_compatability.rb | 30 + test/rb/core/test_exceptions.rb | 30 + test/rb/core/transport/test_transport.rb | 70 + test/rb/fixtures/structs.rb | 298 + test/rb/generation/test_enum.rb | 34 + test/rb/generation/test_struct.rb | 48 + test/rb/integration/TestClient.rb | 353 + test/rb/integration/TestServer.rb | 159 + test/rb/test_helper.rb | 35 + test/rb/test_suite.rb | 20 + test/rebuild_known_failures.sh | 24 + test/result.js | 64 + test/rs/Cargo.toml | 17 + test/rs/Makefile | 643 + test/rs/Makefile.am | 40 + test/rs/Makefile.in | 643 + test/rs/src/bin/test_client.rs | 605 + test/rs/src/bin/test_server.rs | 398 + test/rs/src/lib.rs | 23 + test/test.py | 171 + test/tests.json | 689 + test/threads/Makefile | 63 + test/threads/ThreadsClient.cpp | 69 + test/threads/ThreadsServer.cpp | 148 + test/threads/ThreadsTest.thrift | 28 + test/valgrind.suppress | 53 + tutorial/Makefile.am | 106 + tutorial/Makefile.in | 852 + tutorial/README.md | 42 + tutorial/as3/build.xml | 50 + tutorial/as3/src/CalculatorUI.as | 142 + tutorial/c_glib/Makefile.am | 84 + tutorial/c_glib/Makefile.in | 936 + tutorial/c_glib/c_glib_client.c | 190 + tutorial/c_glib/c_glib_server.c | 527 + tutorial/cpp/CMakeLists.txt | 56 + tutorial/cpp/CppClient.cpp | 81 + tutorial/cpp/CppServer.cpp | 180 + tutorial/cpp/Makefile.am | 86 + tutorial/cpp/Makefile.in | 918 + tutorial/csharp/CsharpClient/CsharpClient.cs | 92 + .../csharp/CsharpClient/CsharpClient.csproj | 110 + .../CsharpClient/Properties/AssemblyInfo.cs | 55 + tutorial/csharp/CsharpServer/CsharpServer.cs | 129 + .../csharp/CsharpServer/CsharpServer.csproj | 111 + .../CsharpServer/Properties/AssemblyInfo.cs | 55 + tutorial/csharp/tutorial.sln | 39 + tutorial/d/Makefile | 644 + tutorial/d/Makefile.am | 46 + tutorial/d/Makefile.in | 644 + tutorial/d/async_client.d | 86 + tutorial/d/client.d | 64 + tutorial/d/server.d | 111 + tutorial/dart/Makefile.am | 73 + tutorial/dart/Makefile.in | 681 + tutorial/dart/build.sh | 56 + tutorial/dart/client/.analysis_options | 2 + tutorial/dart/client/pubspec.yaml | 34 + tutorial/dart/client/web/client.dart | 278 + tutorial/dart/client/web/index.html | 36 + tutorial/dart/client/web/styles.css | 33 + .../dart/console_client/.analysis_options | 2 + tutorial/dart/console_client/bin/main.dart | 149 + tutorial/dart/console_client/pubspec.yaml | 36 + tutorial/dart/server/.analysis_options | 2 + tutorial/dart/server/bin/main.dart | 163 + tutorial/dart/server/pubspec.yaml | 34 + tutorial/delphi/DelphiClient/DelphiClient.dpr | 114 + .../delphi/DelphiClient/DelphiClient.dproj | 119 + tutorial/delphi/DelphiServer/DelphiServer.dpr | 173 + .../delphi/DelphiServer/DelphiServer.dproj | 118 + tutorial/delphi/Tutorial.groupproj | 48 + tutorial/erl/README.md | 8 + tutorial/erl/client.erl | 78 + tutorial/erl/client.sh | 37 + tutorial/erl/json_client.erl | 89 + tutorial/erl/server.erl | 82 + tutorial/erl/server.sh | 37 + tutorial/go/Makefile.am | 69 + tutorial/go/Makefile.in | 670 + tutorial/go/server.crt | 25 + tutorial/go/server.key | 28 + tutorial/go/src/client.go | 105 + tutorial/go/src/go17.go | 26 + tutorial/go/src/handler.go | 105 + tutorial/go/src/handler_go17.go | 104 + tutorial/go/src/main.go | 82 + tutorial/go/src/pre_go17.go | 26 + tutorial/go/src/server.go | 54 + tutorial/haxe/Makefile.am | 97 + tutorial/haxe/Makefile.in | 701 + tutorial/haxe/Tutorial.hxproj | 67 + tutorial/haxe/cpp.hxml | 41 + tutorial/haxe/csharp.hxml | 38 + tutorial/haxe/flash.hxml | 41 + tutorial/haxe/java.hxml | 38 + tutorial/haxe/javascript.hxml | 44 + tutorial/haxe/make_all.bat | 68 + tutorial/haxe/make_all.sh | 41 + tutorial/haxe/neko.hxml | 38 + tutorial/haxe/php-web-server.hxml | 43 + tutorial/haxe/php.hxml | 39 + tutorial/haxe/project.hide | 105 + tutorial/haxe/python.hxml | 38 + tutorial/haxe/router.php | 31 + tutorial/haxe/src/CalculatorHandler.hx | 101 + tutorial/haxe/src/Main.hx | 375 + tutorial/hs/HaskellClient.hs | 76 + tutorial/hs/HaskellServer.hs | 103 + tutorial/hs/LICENSE | 239 + tutorial/hs/Makefile | 649 + tutorial/hs/Makefile.am | 42 + tutorial/hs/Makefile.in | 649 + tutorial/hs/Setup.lhs | 21 + tutorial/hs/ThriftTutorial.cabal | 73 + tutorial/java/Makefile.am | 45 + tutorial/java/Makefile.in | 651 + tutorial/java/README.md | 24 + tutorial/java/build.xml | 113 + tutorial/java/src/CalculatorHandler.java | 92 + tutorial/java/src/JavaClient.java | 106 + tutorial/java/src/JavaServer.java | 110 + tutorial/js/Makefile.am | 39 + tutorial/js/Makefile.in | 645 + tutorial/js/build.xml | 90 + tutorial/js/src/Httpd.java | 299 + tutorial/js/tutorial.html | 109 + tutorial/netcore/Client/Client.csproj | 19 + tutorial/netcore/Client/Program.cs | 355 + .../netcore/Client/Properties/AssemblyInfo.cs | 40 + .../Client/Properties/launchSettings.json | 8 + tutorial/netcore/Client/ThriftTest.pfx | Bin 0 -> 2661 bytes tutorial/netcore/Interfaces/Interfaces.csproj | 20 + .../Interfaces/Properties/AssemblyInfo.cs | 40 + tutorial/netcore/Makefile.am | 75 + tutorial/netcore/Makefile.in | 854 + tutorial/netcore/README.md | 281 + tutorial/netcore/Server/Program.cs | 431 + .../netcore/Server/Properties/AssemblyInfo.cs | 40 + .../Server/Properties/launchSettings.json | 8 + tutorial/netcore/Server/Server.csproj | 26 + tutorial/netcore/Server/ThriftTest.pfx | Bin 0 -> 2661 bytes tutorial/netcore/Tutorial.sln | 68 + tutorial/netcore/build.cmd | 30 + tutorial/netcore/build.sh | 31 + tutorial/nodejs/Makefile.am | 45 + tutorial/nodejs/Makefile.in | 649 + tutorial/nodejs/NodeClient.js | 77 + tutorial/nodejs/NodeClientPromise.js | 80 + tutorial/nodejs/NodeServer.js | 85 + tutorial/nodejs/NodeServerPromise.js | 80 + tutorial/ocaml/CalcClient.ml | 74 + tutorial/ocaml/CalcServer.ml | 89 + tutorial/ocaml/README.md | 15 + tutorial/ocaml/_oasis | 32 + tutorial/perl/PerlClient.pl | 82 + tutorial/perl/PerlServer.pl | 124 + tutorial/php/PhpClient.php | 91 + tutorial/php/PhpServer.php | 130 + tutorial/php/runserver.py | 33 + tutorial/py.tornado/Makefile.am | 36 + tutorial/py.tornado/Makefile.in | 641 + tutorial/py.tornado/PythonClient.py | 108 + tutorial/py.tornado/PythonServer.py | 100 + tutorial/py.twisted/Makefile.am | 37 + tutorial/py.twisted/Makefile.in | 642 + tutorial/py.twisted/PythonClient.py | 79 + tutorial/py.twisted/PythonServer.py | 96 + tutorial/py.twisted/PythonServer.tac | 53 + tutorial/py/Makefile.am | 37 + tutorial/py/Makefile.in | 642 + tutorial/py/PythonClient.py | 89 + tutorial/py/PythonServer.py | 103 + tutorial/py/setup.cfg | 2 + tutorial/rb/Makefile.am | 36 + tutorial/rb/Makefile.in | 641 + tutorial/rb/RubyClient.rb | 75 + tutorial/rb/RubyServer.rb | 95 + tutorial/rs/Cargo.toml | 16 + tutorial/rs/Makefile.am | 52 + tutorial/rs/Makefile.in | 654 + tutorial/rs/README.md | 317 + tutorial/rs/src/bin/tutorial_client.rs | 131 + tutorial/rs/src/bin/tutorial_server.rs | 176 + tutorial/rs/src/lib.rs | 23 + tutorial/shared.thrift | 41 + tutorial/tutorial.thrift | 155 + ylwrap | 247 + 2500 files changed, 584894 insertions(+) create mode 100644 .clang-format create mode 100644 .dockerignore create mode 100755 .editorconfig create mode 100644 .rustfmt.toml create mode 100644 .travis.yml create mode 100644 CHANGES create mode 100644 CMakeLists.txt create mode 100644 CONTRIBUTING.md create mode 100644 LANGUAGES.md create mode 100644 LICENSE create mode 100755 Makefile.am create mode 100644 Makefile.in create mode 100644 NOTICE create mode 100644 README.md create mode 100644 Thrift.podspec create mode 100644 aclocal.m4 create mode 100644 aclocal/ac_prog_bison.m4 create mode 100644 aclocal/ax_boost_base.m4 create mode 100644 aclocal/ax_check_openssl.m4 create mode 100644 aclocal/ax_compare_version.m4 create mode 100644 aclocal/ax_cxx_compile_stdcxx.m4 create mode 100644 aclocal/ax_cxx_compile_stdcxx_11.m4 create mode 100644 aclocal/ax_dmd.m4 create mode 100644 aclocal/ax_javac_and_java.m4 create mode 100644 aclocal/ax_lib_event.m4 create mode 100644 aclocal/ax_lib_zlib.m4 create mode 100644 aclocal/ax_lua.m4 create mode 100644 aclocal/ax_prog_dotnetcore_version.m4 create mode 100644 aclocal/ax_prog_haxe_version.m4 create mode 100644 aclocal/ax_prog_perl_modules.m4 create mode 100644 aclocal/ax_signed_right_shift.m4 create mode 100644 aclocal/ax_thrift_internal.m4 create mode 100644 aclocal/libtool.m4 create mode 100644 aclocal/ltoptions.m4 create mode 100644 aclocal/ltsugar.m4 create mode 100644 aclocal/ltversion.m4 create mode 100644 aclocal/lt~obsolete.m4 create mode 100755 appveyor.yml create mode 100755 bootstrap.sh create mode 100644 bower.json create mode 100644 build/appveyor/MING-appveyor-build.bat create mode 100644 build/appveyor/MING-appveyor-install.bat create mode 100644 build/appveyor/MING-appveyor-test.bat create mode 100644 build/appveyor/MSVC-appveyor-build.bat create mode 100644 build/appveyor/MSVC-appveyor-install.bat create mode 100644 build/appveyor/MSVC-appveyor-test.bat create mode 100644 build/appveyor/MSYS-appveyor-build.bat create mode 100644 build/appveyor/MSYS-appveyor-install.bat create mode 100644 build/appveyor/MSYS-appveyor-test.bat create mode 100644 build/appveyor/README.md create mode 100644 build/appveyor/build-libevent.bat create mode 100644 build/appveyor/build-zlib.bat create mode 100644 build/appveyor/cl_banner_apache_thrift.bat create mode 100644 build/appveyor/cl_banner_build.bat create mode 100644 build/appveyor/cl_banner_install.bat create mode 100644 build/appveyor/cl_banner_test.bat create mode 100644 build/appveyor/cl_setcompiler.bat create mode 100644 build/appveyor/cl_setenv.bat create mode 100644 build/appveyor/cl_setgenerator.bat create mode 100644 build/appveyor/cl_showenv.bat create mode 100644 build/appveyor/simulate-appveyor.bat create mode 100644 build/cmake/CPackConfig.cmake create mode 100644 build/cmake/ConfigureChecks.cmake create mode 100644 build/cmake/DefineCMakeDefaults.cmake create mode 100644 build/cmake/DefineInstallationPaths.cmake create mode 100644 build/cmake/DefineOptions.cmake create mode 100644 build/cmake/DefinePlatformSpecifc.cmake create mode 100644 build/cmake/FindAnt.cmake create mode 100644 build/cmake/FindCabal.cmake create mode 100644 build/cmake/FindGHC.cmake create mode 100644 build/cmake/FindGLIB.cmake create mode 100644 build/cmake/FindGradle.cmake create mode 100644 build/cmake/FindInttypes.cmake create mode 100644 build/cmake/FindLibevent.cmake create mode 100644 build/cmake/NewPlatformDebug.cmake create mode 100644 build/cmake/README-MSYS2.md create mode 100644 build/cmake/README.md create mode 100644 build/cmake/ThriftMacros.cmake create mode 100644 build/cmake/android-toolchain.cmake create mode 100644 build/cmake/config.h.in create mode 100644 build/cmake/mingw32-toolchain.cmake create mode 100644 build/docker/README.md create mode 100644 build/docker/Vagrantfile create mode 100644 build/docker/centos-7.3/Dockerfile create mode 100644 build/docker/debian-jessie/Dockerfile create mode 100644 build/docker/debian-stretch/Dockerfile create mode 100755 build/docker/refresh.sh create mode 100755 build/docker/run.sh create mode 100755 build/docker/scripts/autotools.sh create mode 100755 build/docker/scripts/cmake.sh create mode 100755 build/docker/scripts/cross-test.sh create mode 100755 build/docker/scripts/dpkg.sh create mode 100755 build/docker/scripts/make-dist.sh create mode 100755 build/docker/scripts/sca.sh create mode 100755 build/docker/scripts/ubsan.sh create mode 100644 build/docker/ubuntu-artful/Dockerfile create mode 100644 build/docker/ubuntu-trusty/Dockerfile create mode 100644 build/docker/ubuntu-trusty/Dockerfile.orig create mode 100644 build/docker/ubuntu-xenial/Dockerfile create mode 100755 build/travis/installCXXDependencies.sh create mode 100755 build/travis/installDependencies.sh create mode 100644 build/wincpp/README.md create mode 100644 build/wincpp/build-thrift-compiler.bat create mode 100644 build/wincpp/build-thrift.bat create mode 100644 build/wincpp/scripts/cl_setarch.bat create mode 100644 build/wincpp/scripts/cl_setcompiler.bat create mode 100644 build/wincpp/scripts/cl_setgenerator.bat create mode 100644 build/wincpp/scripts/tpversions.bat create mode 100644 build/wincpp/thirdparty/src/build-libevent.bat create mode 100644 build/wincpp/thirdparty/src/build-openssl.bat create mode 100644 build/wincpp/thirdparty/src/build-zlib.bat create mode 100755 cleanup.sh create mode 100755 compile create mode 100644 compiler/cpp/CMakeLists.txt create mode 100644 compiler/cpp/Makefile.am create mode 100644 compiler/cpp/Makefile.in create mode 100644 compiler/cpp/README.md create mode 100644 compiler/cpp/coding_standards.md create mode 100644 compiler/cpp/compiler.sln create mode 100644 compiler/cpp/compiler.vcxproj create mode 100644 compiler/cpp/compiler.vcxproj.filters create mode 100644 compiler/cpp/src/Makefile.am create mode 100644 compiler/cpp/src/Makefile.in create mode 100644 compiler/cpp/src/thrift/audit/t_audit.cpp create mode 100644 compiler/cpp/src/thrift/audit/t_audit.h create mode 100644 compiler/cpp/src/thrift/common.cc create mode 100644 compiler/cpp/src/thrift/common.h create mode 100644 compiler/cpp/src/thrift/generate/t_as3_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_c_glib_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_cocoa_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_cpp_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_csharp_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_d_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_dart_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_delphi_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_erl_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_generator.h create mode 100644 compiler/cpp/src/thrift/generate/t_generator_registry.h create mode 100644 compiler/cpp/src/thrift/generate/t_go_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_gv_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_haxe_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_hs_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_html_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_html_generator.h create mode 100644 compiler/cpp/src/thrift/generate/t_java_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_javame_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_js_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_json_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_lua_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_netcore_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_ocaml_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_oop_generator.h create mode 100644 compiler/cpp/src/thrift/generate/t_perl_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_php_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_py_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_rb_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_rs_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_st_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_swift_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_xml_generator.cc create mode 100644 compiler/cpp/src/thrift/generate/t_xsd_generator.cc create mode 100644 compiler/cpp/src/thrift/globals.h create mode 100644 compiler/cpp/src/thrift/logging.cc create mode 100644 compiler/cpp/src/thrift/logging.h create mode 100644 compiler/cpp/src/thrift/main.cc create mode 100644 compiler/cpp/src/thrift/main.h create mode 100644 compiler/cpp/src/thrift/parse/parse.cc create mode 100644 compiler/cpp/src/thrift/parse/t_base_type.h create mode 100644 compiler/cpp/src/thrift/parse/t_const.h create mode 100644 compiler/cpp/src/thrift/parse/t_const_value.h create mode 100644 compiler/cpp/src/thrift/parse/t_container.h create mode 100644 compiler/cpp/src/thrift/parse/t_doc.h create mode 100644 compiler/cpp/src/thrift/parse/t_enum.h create mode 100644 compiler/cpp/src/thrift/parse/t_enum_value.h create mode 100644 compiler/cpp/src/thrift/parse/t_field.h create mode 100644 compiler/cpp/src/thrift/parse/t_function.h create mode 100644 compiler/cpp/src/thrift/parse/t_list.h create mode 100644 compiler/cpp/src/thrift/parse/t_map.h create mode 100644 compiler/cpp/src/thrift/parse/t_program.h create mode 100644 compiler/cpp/src/thrift/parse/t_scope.h create mode 100644 compiler/cpp/src/thrift/parse/t_service.h create mode 100644 compiler/cpp/src/thrift/parse/t_set.h create mode 100644 compiler/cpp/src/thrift/parse/t_struct.h create mode 100644 compiler/cpp/src/thrift/parse/t_type.h create mode 100644 compiler/cpp/src/thrift/parse/t_typedef.cc create mode 100644 compiler/cpp/src/thrift/parse/t_typedef.h create mode 100644 compiler/cpp/src/thrift/platform.h create mode 100644 compiler/cpp/src/thrift/plugin/Makefile.am create mode 100644 compiler/cpp/src/thrift/plugin/Makefile.in create mode 100644 compiler/cpp/src/thrift/plugin/plugin.cc create mode 100644 compiler/cpp/src/thrift/plugin/plugin.h create mode 100644 compiler/cpp/src/thrift/plugin/plugin.thrift create mode 100644 compiler/cpp/src/thrift/plugin/plugin_output.cc create mode 100644 compiler/cpp/src/thrift/plugin/plugin_output.h create mode 100644 compiler/cpp/src/thrift/plugin/type_util.h create mode 100644 compiler/cpp/src/thrift/thriftl.cc create mode 100644 compiler/cpp/src/thrift/thriftl.ll create mode 100644 compiler/cpp/src/thrift/thrifty.cc create mode 100644 compiler/cpp/src/thrift/thrifty.hh create mode 100644 compiler/cpp/src/thrift/thrifty.yy create mode 100644 compiler/cpp/src/thrift/version.h create mode 100644 compiler/cpp/src/thrift/version.h.in create mode 100644 compiler/cpp/src/thrift/windows/config.h create mode 100644 compiler/cpp/test/CMakeLists.txt create mode 100644 compiler/cpp/test/Makefile create mode 100644 compiler/cpp/test/Makefile.am create mode 100644 compiler/cpp/test/Makefile.in create mode 100644 compiler/cpp/test/cpp_plugin_test.cmake create mode 100755 compiler/cpp/test/cpp_plugin_test.sh create mode 100644 compiler/cpp/test/plugin/conversion_test.cc create mode 100644 compiler/cpp/test/plugin/cpp_plugin.cc create mode 100644 compiler/cpp/test/plugin/t_cpp_generator.cc create mode 100644 composer.json create mode 100755 config.guess create mode 100644 config.h create mode 100644 config.hin create mode 100755 config.sub create mode 100755 configure create mode 100755 configure.ac create mode 100644 contrib/Rebus/App.config create mode 100644 contrib/Rebus/Program.cs create mode 100644 contrib/Rebus/Properties/AssemblyInfo.cs create mode 100644 contrib/Rebus/README.md create mode 100644 contrib/Rebus/RebusSample.csproj create mode 100644 contrib/Rebus/RebusSample.sln create mode 100644 contrib/Rebus/ServiceImpl/Both.cs create mode 100644 contrib/Rebus/ServiceImpl/Client.cs create mode 100644 contrib/Rebus/ServiceImpl/Server.cs create mode 100644 contrib/Rebus/sample.thrift create mode 100644 contrib/Stomp/README.md create mode 100644 contrib/Stomp/Thrift.Transport.STOMP.pas create mode 100644 contrib/Vagrantfile create mode 100644 contrib/async-test/Makefile create mode 100644 contrib/async-test/aggr.thrift create mode 100755 contrib/async-test/test-leaf.py create mode 100644 contrib/async-test/test-server.cpp create mode 100644 contrib/fb303/LICENSE create mode 100644 contrib/fb303/Makefile.am create mode 100644 contrib/fb303/README.md create mode 100644 contrib/fb303/TClientInfo.cpp create mode 100644 contrib/fb303/TClientInfo.h create mode 100644 contrib/fb303/acinclude.m4 create mode 100644 contrib/fb303/aclocal/ax_boost_base.m4 create mode 100644 contrib/fb303/aclocal/ax_cxx_compile_stdcxx_11.m4 create mode 100644 contrib/fb303/aclocal/ax_javac_and_java.m4 create mode 100644 contrib/fb303/aclocal/ax_thrift_internal.m4 create mode 100755 contrib/fb303/bootstrap.sh create mode 100644 contrib/fb303/configure.ac create mode 100644 contrib/fb303/cpp/FacebookBase.cpp create mode 100644 contrib/fb303/cpp/FacebookBase.h create mode 100644 contrib/fb303/cpp/Makefile.am create mode 100644 contrib/fb303/cpp/ServiceTracker.cpp create mode 100644 contrib/fb303/cpp/ServiceTracker.h create mode 100644 contrib/fb303/global_footer.mk create mode 100644 contrib/fb303/global_header.mk create mode 100644 contrib/fb303/if/fb303.thrift create mode 100755 contrib/fb303/java/build.xml create mode 100644 contrib/fb303/java/src/FacebookBase.java create mode 100644 contrib/fb303/php/FacebookBase.php create mode 100644 contrib/fb303/py/Makefile.am create mode 100644 contrib/fb303/py/fb303/FacebookBase.py create mode 100644 contrib/fb303/py/fb303_scripts/__init__.py create mode 100644 contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py create mode 100644 contrib/fb303/py/setup.py create mode 100755 contrib/mingw-cross-compile.sh create mode 100755 contrib/parse_profiling.py create mode 100644 contrib/thrift-maven-plugin/pom.xml create mode 100644 contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/AbstractThriftMojo.java create mode 100644 contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/Thrift.java create mode 100644 contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftCompileMojo.java create mode 100644 contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftTestCompileMojo.java create mode 100644 contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestAbstractThriftMojo.java create mode 100644 contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestThrift.java create mode 100644 contrib/thrift-maven-plugin/src/test/resources/idl/shared.thrift create mode 100644 contrib/thrift-maven-plugin/src/test/resources/idl/tutorial.thrift create mode 100644 contrib/thrift.el create mode 100644 contrib/thrift.spec create mode 100644 contrib/thrift.vim create mode 100644 contrib/thrift_dump.cpp create mode 100644 contrib/transport-sample/Makefile create mode 100644 contrib/transport-sample/README.md create mode 100644 contrib/transport-sample/Sample.thrift create mode 100644 contrib/transport-sample/ThriftCommon.cpp create mode 100644 contrib/transport-sample/ThriftCommon.h create mode 100644 contrib/transport-sample/client/ReadMe.txt create mode 100644 contrib/transport-sample/client/client.cpp create mode 100644 contrib/transport-sample/client/client.vcxproj create mode 100644 contrib/transport-sample/client/client.vcxproj.filters create mode 100644 contrib/transport-sample/client/stdafx.cpp create mode 100644 contrib/transport-sample/client/stdafx.h create mode 100644 contrib/transport-sample/client/targetver.h create mode 100644 contrib/transport-sample/config.h create mode 100644 contrib/transport-sample/server/ReadMe.txt create mode 100644 contrib/transport-sample/server/server.cpp create mode 100644 contrib/transport-sample/server/server.vcxproj create mode 100644 contrib/transport-sample/server/server.vcxproj.filters create mode 100644 contrib/transport-sample/server/stdafx.cpp create mode 100644 contrib/transport-sample/server/stdafx.h create mode 100644 contrib/transport-sample/server/targetver.h create mode 100644 contrib/transport-sample/thriftme.bat create mode 100644 contrib/transport-sample/thriftme.sh create mode 100644 contrib/transport-sample/transport-sample.sln create mode 100644 contrib/vagrant/centos-6.5/README.md create mode 100644 contrib/vagrant/centos-6.5/Vagrantfile create mode 100644 contrib/zeromq/Makefile create mode 100644 contrib/zeromq/README.md create mode 100644 contrib/zeromq/TZmqClient.cpp create mode 100644 contrib/zeromq/TZmqClient.h create mode 100644 contrib/zeromq/TZmqClient.py create mode 100644 contrib/zeromq/TZmqServer.cpp create mode 100644 contrib/zeromq/TZmqServer.h create mode 100644 contrib/zeromq/TZmqServer.py create mode 100644 contrib/zeromq/csharp/AssemblyInfo.cs create mode 100644 contrib/zeromq/csharp/Main.cs create mode 100644 contrib/zeromq/csharp/TZmqClient.cs create mode 100644 contrib/zeromq/csharp/TZmqServer.cs create mode 100755 contrib/zeromq/csharp/ThriftZMQ.csproj create mode 100755 contrib/zeromq/csharp/ThriftZMQ.sln create mode 100644 contrib/zeromq/storage.thrift create mode 100644 contrib/zeromq/test-client.cpp create mode 100755 contrib/zeromq/test-client.py create mode 100644 contrib/zeromq/test-receiver.cpp create mode 100644 contrib/zeromq/test-sender.cpp create mode 100644 contrib/zeromq/test-server.cpp create mode 100755 contrib/zeromq/test-server.py create mode 100644 debian/README.md create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/dirs create mode 100644 debian/docs create mode 100644 debian/libthrift-dev.install create mode 100644 debian/libthrift0.install create mode 100644 debian/php5-thrift.dirs create mode 100755 debian/rules create mode 100644 debian/substvars create mode 100644 debian/thrift-doc.docs create mode 100644 debian/thrift-doc.install create mode 100755 depcomp create mode 100755 doap.rdf create mode 100644 doc/coding_standards.md create mode 100644 doc/committers.md create mode 100644 doc/images/cgrn.png create mode 100644 doc/images/cred.png create mode 100644 doc/images/credfull.png create mode 100644 doc/images/cyel.png create mode 100644 doc/images/thrift-layers.png create mode 100644 doc/install/README.md create mode 100644 doc/install/centos.md create mode 100644 doc/install/debian.md create mode 100644 doc/install/os_x.md create mode 100644 doc/install/windows.md create mode 100644 doc/licenses/lgpl-2.1.txt create mode 100644 doc/licenses/otp-base-license.txt create mode 100644 doc/specs/HeaderFormat.md create mode 100644 doc/specs/idl.md create mode 100644 doc/specs/thrift-binary-protocol.md create mode 100644 doc/specs/thrift-compact-protocol.md create mode 100644 doc/specs/thrift-protocol-spec.md create mode 100644 doc/specs/thrift-rpc.md create mode 100644 doc/specs/thrift-sasl-spec.txt create mode 100644 doc/specs/thrift.tex create mode 100755 install-sh create mode 100644 lib/Makefile.am create mode 100644 lib/Makefile.in create mode 100755 lib/as3/build.xml create mode 100644 lib/as3/coding_standards.md create mode 100644 lib/as3/src/org/apache/thrift/AbstractMethodError.as create mode 100644 lib/as3/src/org/apache/thrift/Set.as create mode 100644 lib/as3/src/org/apache/thrift/TApplicationError.as create mode 100644 lib/as3/src/org/apache/thrift/TBase.as create mode 100644 lib/as3/src/org/apache/thrift/TError.as create mode 100644 lib/as3/src/org/apache/thrift/TFieldRequirementType.as create mode 100644 lib/as3/src/org/apache/thrift/TProcessor.as create mode 100644 lib/as3/src/org/apache/thrift/meta_data/FieldMetaData.as create mode 100644 lib/as3/src/org/apache/thrift/meta_data/FieldValueMetaData.as create mode 100644 lib/as3/src/org/apache/thrift/meta_data/ListMetaData.as create mode 100644 lib/as3/src/org/apache/thrift/meta_data/MapMetaData.as create mode 100644 lib/as3/src/org/apache/thrift/meta_data/SetMetaData.as create mode 100644 lib/as3/src/org/apache/thrift/meta_data/StructMetaData.as create mode 100644 lib/as3/src/org/apache/thrift/protocol/TBinaryProtocol.as create mode 100644 lib/as3/src/org/apache/thrift/protocol/TField.as create mode 100644 lib/as3/src/org/apache/thrift/protocol/TList.as create mode 100644 lib/as3/src/org/apache/thrift/protocol/TMap.as create mode 100644 lib/as3/src/org/apache/thrift/protocol/TMessage.as create mode 100644 lib/as3/src/org/apache/thrift/protocol/TMessageType.as create mode 100644 lib/as3/src/org/apache/thrift/protocol/TProtocol.as create mode 100644 lib/as3/src/org/apache/thrift/protocol/TProtocolError.as create mode 100644 lib/as3/src/org/apache/thrift/protocol/TProtocolFactory.as create mode 100644 lib/as3/src/org/apache/thrift/protocol/TProtocolUtil.as create mode 100644 lib/as3/src/org/apache/thrift/protocol/TSet.as create mode 100644 lib/as3/src/org/apache/thrift/protocol/TStruct.as create mode 100644 lib/as3/src/org/apache/thrift/protocol/TType.as create mode 100644 lib/as3/src/org/apache/thrift/transport/TFullDuplexHttpClient.as create mode 100644 lib/as3/src/org/apache/thrift/transport/THttpClient.as create mode 100644 lib/as3/src/org/apache/thrift/transport/TSocket.as create mode 100644 lib/as3/src/org/apache/thrift/transport/TTransport.as create mode 100644 lib/as3/src/org/apache/thrift/transport/TTransportError.as create mode 100644 lib/c_glib/CMakeLists.txt create mode 100755 lib/c_glib/Makefile.am create mode 100644 lib/c_glib/Makefile.in create mode 100644 lib/c_glib/README.md create mode 100644 lib/c_glib/coding_standards.md create mode 100644 lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.c create mode 100644 lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.h create mode 100644 lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.c create mode 100644 lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.h create mode 100644 lib/c_glib/src/thrift/c_glib/processor/thrift_processor.c create mode 100644 lib/c_glib/src/thrift/c_glib/processor/thrift_processor.h create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.c create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.h create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol_factory.c create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol_factory.h create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.h create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.c create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.h create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_multiplexed_protocol.c create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_multiplexed_protocol.h create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol.c create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol.h create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_decorator.c create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_decorator.h create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_factory.c create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_factory.h create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.c create mode 100644 lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.h create mode 100644 lib/c_glib/src/thrift/c_glib/server/thrift_server.c create mode 100644 lib/c_glib/src/thrift/c_glib/server/thrift_server.h create mode 100644 lib/c_glib/src/thrift/c_glib/server/thrift_simple_server.c create mode 100644 lib/c_glib/src/thrift/c_glib/server/thrift_simple_server.h create mode 100644 lib/c_glib/src/thrift/c_glib/thrift.c create mode 100644 lib/c_glib/src/thrift/c_glib/thrift.h create mode 100644 lib/c_glib/src/thrift/c_glib/thrift_application_exception.c create mode 100644 lib/c_glib/src/thrift/c_glib/thrift_application_exception.h create mode 100644 lib/c_glib/src/thrift/c_glib/thrift_struct.c create mode 100644 lib/c_glib/src/thrift/c_glib/thrift_struct.h create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport.c create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport.h create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.c create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.h create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_fd_transport.c create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_fd_transport.h create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport.c create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport.h create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.c create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.h create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_memory_buffer.c create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_memory_buffer.h create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_platform_socket.h create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.c create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.h create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_server_transport.c create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_server_transport.h create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_socket.h create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.c create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.h create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_transport.h create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_transport_factory.c create mode 100644 lib/c_glib/src/thrift/c_glib/transport/thrift_transport_factory.h create mode 100644 lib/c_glib/test/CMakeLists.txt create mode 100644 lib/c_glib/test/ContainerTest.thrift create mode 100755 lib/c_glib/test/Makefile.am create mode 100644 lib/c_glib/test/Makefile.in create mode 100644 lib/c_glib/test/glib.suppress create mode 100644 lib/c_glib/test/testapplicationexception.c create mode 100755 lib/c_glib/test/testbinaryprotocol.c create mode 100755 lib/c_glib/test/testbufferedtransport.c create mode 100755 lib/c_glib/test/testcompactprotocol.c create mode 100644 lib/c_glib/test/testcontainertest.c create mode 100644 lib/c_glib/test/testdebugproto.c create mode 100755 lib/c_glib/test/testfdtransport.c create mode 100755 lib/c_glib/test/testframedtransport.c create mode 100755 lib/c_glib/test/testmemorybuffer.c create mode 100755 lib/c_glib/test/testoptionalrequired.c create mode 100644 lib/c_glib/test/testserialization.c create mode 100755 lib/c_glib/test/testsimpleserver.c create mode 100755 lib/c_glib/test/teststruct.c create mode 100755 lib/c_glib/test/testthrifttest.c create mode 100755 lib/c_glib/test/testthrifttestclient.cpp create mode 100755 lib/c_glib/test/testtransportsocket.c create mode 100644 lib/c_glib/test/testtransportsslsocket.c create mode 100644 lib/c_glib/thrift_c_glib.pc.in create mode 100644 lib/cocoa/README.md create mode 100644 lib/cocoa/coding_standards.md create mode 100644 lib/cocoa/src/TApplicationError.h create mode 100644 lib/cocoa/src/TApplicationError.m create mode 100644 lib/cocoa/src/TBaseClient.h create mode 100644 lib/cocoa/src/TBaseClient.m create mode 100644 lib/cocoa/src/TBinary.swift create mode 100644 lib/cocoa/src/TEnum.swift create mode 100644 lib/cocoa/src/TError.h create mode 100644 lib/cocoa/src/TError.m create mode 100644 lib/cocoa/src/TList.swift create mode 100644 lib/cocoa/src/TMap.swift create mode 100644 lib/cocoa/src/TProcessor.h create mode 100644 lib/cocoa/src/TProcessorFactory.h create mode 100644 lib/cocoa/src/TProtocol.swift create mode 100644 lib/cocoa/src/TSerializable.swift create mode 100644 lib/cocoa/src/TSet.swift create mode 100644 lib/cocoa/src/TSharedProcessorFactory.h create mode 100644 lib/cocoa/src/TSharedProcessorFactory.m create mode 100644 lib/cocoa/src/TStruct.swift create mode 100644 lib/cocoa/src/Thrift.h create mode 100644 lib/cocoa/src/protocol/TBase.h create mode 100644 lib/cocoa/src/protocol/TBinaryProtocol.h create mode 100644 lib/cocoa/src/protocol/TBinaryProtocol.m create mode 100644 lib/cocoa/src/protocol/TCompactProtocol.h create mode 100644 lib/cocoa/src/protocol/TCompactProtocol.m create mode 100644 lib/cocoa/src/protocol/TMultiplexedProtocol.h create mode 100644 lib/cocoa/src/protocol/TMultiplexedProtocol.m create mode 100644 lib/cocoa/src/protocol/TProtocol.h create mode 100644 lib/cocoa/src/protocol/TProtocolDecorator.h create mode 100644 lib/cocoa/src/protocol/TProtocolDecorator.m create mode 100644 lib/cocoa/src/protocol/TProtocolError.h create mode 100644 lib/cocoa/src/protocol/TProtocolError.m create mode 100644 lib/cocoa/src/protocol/TProtocolFactory.h create mode 100644 lib/cocoa/src/protocol/TProtocolUtil.h create mode 100644 lib/cocoa/src/protocol/TProtocolUtil.m create mode 100644 lib/cocoa/src/server/TSocketServer.h create mode 100644 lib/cocoa/src/server/TSocketServer.m create mode 100644 lib/cocoa/src/transport/TAsyncTransport.h create mode 100644 lib/cocoa/src/transport/TFramedTransport.h create mode 100644 lib/cocoa/src/transport/TFramedTransport.m create mode 100644 lib/cocoa/src/transport/THTTPSessionTransport.h create mode 100644 lib/cocoa/src/transport/THTTPSessionTransport.m create mode 100644 lib/cocoa/src/transport/THTTPTransport.h create mode 100644 lib/cocoa/src/transport/THTTPTransport.m create mode 100644 lib/cocoa/src/transport/TMemoryBuffer.h create mode 100644 lib/cocoa/src/transport/TMemoryBuffer.m create mode 100644 lib/cocoa/src/transport/TNSFileHandleTransport.h create mode 100644 lib/cocoa/src/transport/TNSFileHandleTransport.m create mode 100644 lib/cocoa/src/transport/TNSStreamTransport.h create mode 100644 lib/cocoa/src/transport/TNSStreamTransport.m create mode 100644 lib/cocoa/src/transport/TSSLSocketTransport.h create mode 100644 lib/cocoa/src/transport/TSSLSocketTransport.m create mode 100644 lib/cocoa/src/transport/TSSLSocketTransportError.h create mode 100644 lib/cocoa/src/transport/TSSLSocketTransportError.m create mode 100644 lib/cocoa/src/transport/TSocketTransport.h create mode 100644 lib/cocoa/src/transport/TSocketTransport.m create mode 100644 lib/cocoa/src/transport/TTransport.h create mode 100644 lib/cocoa/src/transport/TTransportError.h create mode 100644 lib/cocoa/src/transport/TTransportError.m create mode 100644 lib/cpp/3rdparty.props create mode 100755 lib/cpp/CMakeLists.txt create mode 100755 lib/cpp/Makefile.am create mode 100644 lib/cpp/Makefile.in create mode 100755 lib/cpp/README.md create mode 100644 lib/cpp/coding_standards.md create mode 100644 lib/cpp/libthrift.vcxproj create mode 100644 lib/cpp/libthrift.vcxproj.filters create mode 100755 lib/cpp/libthriftnb.vcxproj create mode 100644 lib/cpp/libthriftnb.vcxproj.filters create mode 100644 lib/cpp/src/thrift/TApplicationException.cpp create mode 100644 lib/cpp/src/thrift/TApplicationException.h create mode 100644 lib/cpp/src/thrift/TBase.h create mode 100644 lib/cpp/src/thrift/TDispatchProcessor.h create mode 100644 lib/cpp/src/thrift/TLogging.h create mode 100644 lib/cpp/src/thrift/TOutput.cpp create mode 100644 lib/cpp/src/thrift/TOutput.h create mode 100644 lib/cpp/src/thrift/TProcessor.h create mode 100644 lib/cpp/src/thrift/TToString.h create mode 100644 lib/cpp/src/thrift/Thrift.h create mode 100644 lib/cpp/src/thrift/VirtualProfiling.cpp create mode 100644 lib/cpp/src/thrift/async/TAsyncBufferProcessor.h create mode 100644 lib/cpp/src/thrift/async/TAsyncChannel.cpp create mode 100644 lib/cpp/src/thrift/async/TAsyncChannel.h create mode 100644 lib/cpp/src/thrift/async/TAsyncDispatchProcessor.h create mode 100644 lib/cpp/src/thrift/async/TAsyncProcessor.h create mode 100644 lib/cpp/src/thrift/async/TAsyncProtocolProcessor.cpp create mode 100644 lib/cpp/src/thrift/async/TAsyncProtocolProcessor.h create mode 100644 lib/cpp/src/thrift/async/TConcurrentClientSyncInfo.cpp create mode 100644 lib/cpp/src/thrift/async/TConcurrentClientSyncInfo.h create mode 100644 lib/cpp/src/thrift/async/TEvhttpClientChannel.cpp create mode 100644 lib/cpp/src/thrift/async/TEvhttpClientChannel.h create mode 100644 lib/cpp/src/thrift/async/TEvhttpServer.cpp create mode 100644 lib/cpp/src/thrift/async/TEvhttpServer.h create mode 100644 lib/cpp/src/thrift/concurrency/BoostMonitor.cpp create mode 100644 lib/cpp/src/thrift/concurrency/BoostMutex.cpp create mode 100644 lib/cpp/src/thrift/concurrency/BoostThreadFactory.cpp create mode 100644 lib/cpp/src/thrift/concurrency/BoostThreadFactory.h create mode 100644 lib/cpp/src/thrift/concurrency/Exception.h create mode 100644 lib/cpp/src/thrift/concurrency/FunctionRunner.h create mode 100644 lib/cpp/src/thrift/concurrency/Monitor.cpp create mode 100644 lib/cpp/src/thrift/concurrency/Monitor.h create mode 100644 lib/cpp/src/thrift/concurrency/Mutex.cpp create mode 100644 lib/cpp/src/thrift/concurrency/Mutex.h create mode 100644 lib/cpp/src/thrift/concurrency/PlatformThreadFactory.h create mode 100644 lib/cpp/src/thrift/concurrency/PosixThreadFactory.cpp create mode 100644 lib/cpp/src/thrift/concurrency/PosixThreadFactory.h create mode 100644 lib/cpp/src/thrift/concurrency/StdMonitor.cpp create mode 100644 lib/cpp/src/thrift/concurrency/StdMutex.cpp create mode 100644 lib/cpp/src/thrift/concurrency/StdThreadFactory.cpp create mode 100644 lib/cpp/src/thrift/concurrency/StdThreadFactory.h create mode 100644 lib/cpp/src/thrift/concurrency/Thread.h create mode 100644 lib/cpp/src/thrift/concurrency/ThreadManager.cpp create mode 100644 lib/cpp/src/thrift/concurrency/ThreadManager.h create mode 100644 lib/cpp/src/thrift/concurrency/TimerManager.cpp create mode 100644 lib/cpp/src/thrift/concurrency/TimerManager.h create mode 100644 lib/cpp/src/thrift/concurrency/Util.cpp create mode 100644 lib/cpp/src/thrift/concurrency/Util.h create mode 100644 lib/cpp/src/thrift/processor/PeekProcessor.cpp create mode 100644 lib/cpp/src/thrift/processor/PeekProcessor.h create mode 100644 lib/cpp/src/thrift/processor/StatsProcessor.h create mode 100644 lib/cpp/src/thrift/processor/TMultiplexedProcessor.h create mode 100644 lib/cpp/src/thrift/protocol/TBase64Utils.cpp create mode 100644 lib/cpp/src/thrift/protocol/TBase64Utils.h create mode 100644 lib/cpp/src/thrift/protocol/TBinaryProtocol.h create mode 100644 lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc create mode 100644 lib/cpp/src/thrift/protocol/TCompactProtocol.h create mode 100644 lib/cpp/src/thrift/protocol/TCompactProtocol.tcc create mode 100644 lib/cpp/src/thrift/protocol/TDebugProtocol.cpp create mode 100644 lib/cpp/src/thrift/protocol/TDebugProtocol.h create mode 100644 lib/cpp/src/thrift/protocol/THeaderProtocol.cpp create mode 100644 lib/cpp/src/thrift/protocol/THeaderProtocol.h create mode 100644 lib/cpp/src/thrift/protocol/TJSONProtocol.cpp create mode 100644 lib/cpp/src/thrift/protocol/TJSONProtocol.h create mode 100644 lib/cpp/src/thrift/protocol/TMultiplexedProtocol.cpp create mode 100644 lib/cpp/src/thrift/protocol/TMultiplexedProtocol.h create mode 100644 lib/cpp/src/thrift/protocol/TProtocol.cpp create mode 100644 lib/cpp/src/thrift/protocol/TProtocol.h create mode 100644 lib/cpp/src/thrift/protocol/TProtocolDecorator.h create mode 100644 lib/cpp/src/thrift/protocol/TProtocolException.h create mode 100644 lib/cpp/src/thrift/protocol/TProtocolTap.h create mode 100644 lib/cpp/src/thrift/protocol/TProtocolTypes.h create mode 100644 lib/cpp/src/thrift/protocol/TVirtualProtocol.h create mode 100644 lib/cpp/src/thrift/qt/CMakeLists.txt create mode 100644 lib/cpp/src/thrift/qt/TQIODeviceTransport.cpp create mode 100644 lib/cpp/src/thrift/qt/TQIODeviceTransport.h create mode 100644 lib/cpp/src/thrift/qt/TQTcpServer.cpp create mode 100644 lib/cpp/src/thrift/qt/TQTcpServer.h create mode 100644 lib/cpp/src/thrift/server/TConnectedClient.cpp create mode 100644 lib/cpp/src/thrift/server/TConnectedClient.h create mode 100644 lib/cpp/src/thrift/server/TNonblockingServer.cpp create mode 100644 lib/cpp/src/thrift/server/TNonblockingServer.h create mode 100644 lib/cpp/src/thrift/server/TServer.cpp create mode 100644 lib/cpp/src/thrift/server/TServer.h create mode 100644 lib/cpp/src/thrift/server/TServerFramework.cpp create mode 100644 lib/cpp/src/thrift/server/TServerFramework.h create mode 100644 lib/cpp/src/thrift/server/TSimpleServer.cpp create mode 100644 lib/cpp/src/thrift/server/TSimpleServer.h create mode 100644 lib/cpp/src/thrift/server/TThreadPoolServer.cpp create mode 100644 lib/cpp/src/thrift/server/TThreadPoolServer.h create mode 100644 lib/cpp/src/thrift/server/TThreadedServer.cpp create mode 100644 lib/cpp/src/thrift/server/TThreadedServer.h create mode 100644 lib/cpp/src/thrift/stdcxx.h create mode 100644 lib/cpp/src/thrift/thrift-config.h create mode 100644 lib/cpp/src/thrift/transport/PlatformSocket.h create mode 100644 lib/cpp/src/thrift/transport/TBufferTransports.cpp create mode 100644 lib/cpp/src/thrift/transport/TBufferTransports.h create mode 100644 lib/cpp/src/thrift/transport/TFDTransport.cpp create mode 100644 lib/cpp/src/thrift/transport/TFDTransport.h create mode 100644 lib/cpp/src/thrift/transport/TFileTransport.cpp create mode 100644 lib/cpp/src/thrift/transport/TFileTransport.h create mode 100644 lib/cpp/src/thrift/transport/THeaderTransport.cpp create mode 100644 lib/cpp/src/thrift/transport/THeaderTransport.h create mode 100644 lib/cpp/src/thrift/transport/THttpClient.cpp create mode 100644 lib/cpp/src/thrift/transport/THttpClient.h create mode 100644 lib/cpp/src/thrift/transport/THttpServer.cpp create mode 100644 lib/cpp/src/thrift/transport/THttpServer.h create mode 100644 lib/cpp/src/thrift/transport/THttpTransport.cpp create mode 100644 lib/cpp/src/thrift/transport/THttpTransport.h create mode 100644 lib/cpp/src/thrift/transport/TNonblockingSSLServerSocket.cpp create mode 100644 lib/cpp/src/thrift/transport/TNonblockingSSLServerSocket.h create mode 100644 lib/cpp/src/thrift/transport/TNonblockingServerSocket.cpp create mode 100644 lib/cpp/src/thrift/transport/TNonblockingServerSocket.h create mode 100644 lib/cpp/src/thrift/transport/TNonblockingServerTransport.h create mode 100644 lib/cpp/src/thrift/transport/TPipe.cpp create mode 100644 lib/cpp/src/thrift/transport/TPipe.h create mode 100644 lib/cpp/src/thrift/transport/TPipeServer.cpp create mode 100644 lib/cpp/src/thrift/transport/TPipeServer.h create mode 100644 lib/cpp/src/thrift/transport/TSSLServerSocket.cpp create mode 100644 lib/cpp/src/thrift/transport/TSSLServerSocket.h create mode 100644 lib/cpp/src/thrift/transport/TSSLSocket.cpp create mode 100644 lib/cpp/src/thrift/transport/TSSLSocket.h create mode 100644 lib/cpp/src/thrift/transport/TServerSocket.cpp create mode 100644 lib/cpp/src/thrift/transport/TServerSocket.h create mode 100644 lib/cpp/src/thrift/transport/TServerTransport.h create mode 100644 lib/cpp/src/thrift/transport/TShortReadTransport.h create mode 100644 lib/cpp/src/thrift/transport/TSimpleFileTransport.cpp create mode 100644 lib/cpp/src/thrift/transport/TSimpleFileTransport.h create mode 100644 lib/cpp/src/thrift/transport/TSocket.cpp create mode 100644 lib/cpp/src/thrift/transport/TSocket.h create mode 100644 lib/cpp/src/thrift/transport/TSocketPool.cpp create mode 100644 lib/cpp/src/thrift/transport/TSocketPool.h create mode 100644 lib/cpp/src/thrift/transport/TTransport.h create mode 100644 lib/cpp/src/thrift/transport/TTransportException.cpp create mode 100644 lib/cpp/src/thrift/transport/TTransportException.h create mode 100644 lib/cpp/src/thrift/transport/TTransportUtils.cpp create mode 100644 lib/cpp/src/thrift/transport/TTransportUtils.h create mode 100644 lib/cpp/src/thrift/transport/TVirtualTransport.h create mode 100644 lib/cpp/src/thrift/transport/TZlibTransport.cpp create mode 100644 lib/cpp/src/thrift/transport/TZlibTransport.h create mode 100644 lib/cpp/src/thrift/windows/GetTimeOfDay.cpp create mode 100644 lib/cpp/src/thrift/windows/GetTimeOfDay.h create mode 100644 lib/cpp/src/thrift/windows/Operators.h create mode 100644 lib/cpp/src/thrift/windows/OverlappedSubmissionThread.cpp create mode 100644 lib/cpp/src/thrift/windows/OverlappedSubmissionThread.h create mode 100644 lib/cpp/src/thrift/windows/SocketPair.cpp create mode 100644 lib/cpp/src/thrift/windows/SocketPair.h create mode 100644 lib/cpp/src/thrift/windows/Sync.h create mode 100644 lib/cpp/src/thrift/windows/TWinsockSingleton.cpp create mode 100644 lib/cpp/src/thrift/windows/TWinsockSingleton.h create mode 100644 lib/cpp/src/thrift/windows/WinFcntl.cpp create mode 100644 lib/cpp/src/thrift/windows/WinFcntl.h create mode 100644 lib/cpp/src/thrift/windows/config.h create mode 100644 lib/cpp/test/AllProtocolTests.cpp create mode 100644 lib/cpp/test/AllProtocolTests.tcc create mode 100644 lib/cpp/test/AnnotationTest.cpp create mode 100644 lib/cpp/test/Base64Test.cpp create mode 100644 lib/cpp/test/Benchmark.cpp create mode 100644 lib/cpp/test/CMakeLists.txt create mode 100644 lib/cpp/test/DebugProtoTest.cpp create mode 100644 lib/cpp/test/DebugProtoTest_extras.cpp create mode 100644 lib/cpp/test/EnumTest.cpp create mode 100644 lib/cpp/test/GenericHelpers.h create mode 100644 lib/cpp/test/JSONProtoTest.cpp create mode 100755 lib/cpp/test/Makefile.am create mode 100644 lib/cpp/test/Makefile.in create mode 100644 lib/cpp/test/OpenSSLManualInitTest.cpp create mode 100644 lib/cpp/test/OptionalRequiredTest.cpp create mode 100644 lib/cpp/test/RecursiveTest.cpp create mode 100644 lib/cpp/test/SecurityTest.cpp create mode 100644 lib/cpp/test/SpecializationTest.cpp create mode 100644 lib/cpp/test/TBufferBaseTest.cpp create mode 100644 lib/cpp/test/TFDTransportTest.cpp create mode 100644 lib/cpp/test/TFileTransportTest.cpp create mode 100644 lib/cpp/test/TMemoryBufferTest.cpp create mode 100644 lib/cpp/test/TNonblockingSSLServerTest.cpp create mode 100644 lib/cpp/test/TNonblockingServerTest.cpp create mode 100644 lib/cpp/test/TPipeInterruptTest.cpp create mode 100644 lib/cpp/test/TPipedTransportTest.cpp create mode 100644 lib/cpp/test/TSSLSocketInterruptTest.cpp create mode 100644 lib/cpp/test/TServerIntegrationTest.cpp create mode 100644 lib/cpp/test/TServerSocketTest.cpp create mode 100644 lib/cpp/test/TServerTransportTest.cpp create mode 100644 lib/cpp/test/TSocketInterruptTest.cpp create mode 100644 lib/cpp/test/TTransportCheckThrow.h create mode 100644 lib/cpp/test/ThriftTest_extras.cpp create mode 100644 lib/cpp/test/ToStringTest.cpp create mode 100644 lib/cpp/test/TransportTest.cpp create mode 100644 lib/cpp/test/TypedefTest.cpp create mode 100644 lib/cpp/test/UnitTestMain.cpp create mode 100644 lib/cpp/test/ZlibTest.cpp create mode 100644 lib/cpp/test/concurrency/MutexTest.cpp create mode 100644 lib/cpp/test/concurrency/RWMutexStarveTest.cpp create mode 100644 lib/cpp/test/concurrency/Tests.cpp create mode 100644 lib/cpp/test/concurrency/ThreadFactoryTests.h create mode 100644 lib/cpp/test/concurrency/ThreadManagerTests.h create mode 100644 lib/cpp/test/concurrency/TimerManagerTests.h create mode 100644 lib/cpp/test/link/LinkTest.cpp create mode 100644 lib/cpp/test/link/TemplatedService1.cpp create mode 100644 lib/cpp/test/link/TemplatedService2.cpp create mode 100644 lib/cpp/test/processor/EventLog.cpp create mode 100644 lib/cpp/test/processor/EventLog.h create mode 100644 lib/cpp/test/processor/Handlers.h create mode 100644 lib/cpp/test/processor/ProcessorTest.cpp create mode 100644 lib/cpp/test/processor/ServerThread.cpp create mode 100644 lib/cpp/test/processor/ServerThread.h create mode 100644 lib/cpp/test/processor/proc.thrift create mode 100644 lib/cpp/test/qt/CMakeLists.txt create mode 100644 lib/cpp/test/qt/TQTcpServerTest.cpp create mode 100755 lib/cpp/thrift-nb.pc.in create mode 100755 lib/cpp/thrift-qt.pc.in create mode 100755 lib/cpp/thrift-qt5.pc.in create mode 100755 lib/cpp/thrift-z.pc.in create mode 100755 lib/cpp/thrift.pc.in create mode 100644 lib/cpp/thrift.sln create mode 100644 lib/csharp/Makefile.am create mode 100644 lib/csharp/Makefile.in create mode 100644 lib/csharp/README.md create mode 100644 lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs create mode 100644 lib/csharp/ThriftMSBuildTask/ThriftBuild.cs create mode 100644 lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj create mode 100644 lib/csharp/coding_standards.md create mode 100644 lib/csharp/src/Collections/TCollections.cs create mode 100644 lib/csharp/src/Collections/THashSet.cs create mode 100644 lib/csharp/src/Net35/ExtensionsNet35.cs create mode 100644 lib/csharp/src/Properties/AssemblyInfo.cs create mode 100644 lib/csharp/src/Protocol/TAbstractBase.cs create mode 100644 lib/csharp/src/Protocol/TBase.cs create mode 100644 lib/csharp/src/Protocol/TBase64Utils.cs create mode 100644 lib/csharp/src/Protocol/TBinaryProtocol.cs create mode 100644 lib/csharp/src/Protocol/TCompactProtocol.cs create mode 100644 lib/csharp/src/Protocol/TField.cs create mode 100644 lib/csharp/src/Protocol/TJSONProtocol.cs create mode 100644 lib/csharp/src/Protocol/TList.cs create mode 100644 lib/csharp/src/Protocol/TMap.cs create mode 100644 lib/csharp/src/Protocol/TMessage.cs create mode 100644 lib/csharp/src/Protocol/TMessageType.cs create mode 100644 lib/csharp/src/Protocol/TMultiplexedProcessor.cs create mode 100644 lib/csharp/src/Protocol/TMultiplexedProtocol.cs create mode 100644 lib/csharp/src/Protocol/TProtocol.cs create mode 100644 lib/csharp/src/Protocol/TProtocolDecorator.cs create mode 100644 lib/csharp/src/Protocol/TProtocolException.cs create mode 100644 lib/csharp/src/Protocol/TProtocolFactory.cs create mode 100644 lib/csharp/src/Protocol/TProtocolUtil.cs create mode 100644 lib/csharp/src/Protocol/TSet.cs create mode 100644 lib/csharp/src/Protocol/TStruct.cs create mode 100644 lib/csharp/src/Protocol/TType.cs create mode 100644 lib/csharp/src/Server/TServer.cs create mode 100644 lib/csharp/src/Server/TServerEventHandler.cs create mode 100644 lib/csharp/src/Server/TSimpleServer.cs create mode 100644 lib/csharp/src/Server/TThreadPoolServer.cs create mode 100644 lib/csharp/src/Server/TThreadedServer.cs create mode 100644 lib/csharp/src/TApplicationException.cs create mode 100644 lib/csharp/src/TAsyncProcessor.cs create mode 100644 lib/csharp/src/TControllingHandler.cs create mode 100644 lib/csharp/src/TException.cs create mode 100644 lib/csharp/src/TProcessor.cs create mode 100644 lib/csharp/src/TProcessorFactory.cs create mode 100644 lib/csharp/src/TPrototypeProcessorFactory.cs create mode 100644 lib/csharp/src/TSingletonProcessorFactory.cs create mode 100644 lib/csharp/src/Thrift.45.csproj create mode 100644 lib/csharp/src/Thrift.csproj create mode 100644 lib/csharp/src/Thrift.sln create mode 100644 lib/csharp/src/Transport/TBufferedTransport.cs create mode 100644 lib/csharp/src/Transport/TFramedTransport.cs create mode 100644 lib/csharp/src/Transport/THttpClient.cs create mode 100644 lib/csharp/src/Transport/THttpHandler.cs create mode 100644 lib/csharp/src/Transport/THttpTaskAsyncHandler.cs create mode 100644 lib/csharp/src/Transport/TMemoryBuffer.cs create mode 100644 lib/csharp/src/Transport/TNamedPipeClientTransport.cs create mode 100644 lib/csharp/src/Transport/TNamedPipeServerTransport.cs create mode 100644 lib/csharp/src/Transport/TServerSocket.cs create mode 100644 lib/csharp/src/Transport/TServerTransport.cs create mode 100644 lib/csharp/src/Transport/TSilverlightSocket.cs create mode 100644 lib/csharp/src/Transport/TSocket.cs create mode 100644 lib/csharp/src/Transport/TSocketVersionizer.cs create mode 100644 lib/csharp/src/Transport/TStreamTransport.cs create mode 100644 lib/csharp/src/Transport/TTLSServerSocket.cs create mode 100644 lib/csharp/src/Transport/TTLSSocket.cs create mode 100644 lib/csharp/src/Transport/TTransport.cs create mode 100644 lib/csharp/src/Transport/TTransportException.cs create mode 100644 lib/csharp/src/Transport/TTransportFactory.cs create mode 100644 lib/csharp/test/JSON/JSONTest.csproj create mode 100644 lib/csharp/test/JSON/Program.cs create mode 100644 lib/csharp/test/JSON/Properties/AssemblyInfo.cs create mode 100644 lib/csharp/test/JSON/app.config create mode 100644 lib/csharp/test/Multiplex/Client/Multiplex.Test.Client.cs create mode 100644 lib/csharp/test/Multiplex/Client/MultiplexClient.csproj create mode 100644 lib/csharp/test/Multiplex/Client/Properties/AssemblyInfo.cs create mode 100644 lib/csharp/test/Multiplex/Makefile create mode 100644 lib/csharp/test/Multiplex/Makefile.am create mode 100644 lib/csharp/test/Multiplex/Makefile.in create mode 100644 lib/csharp/test/Multiplex/Multiplex.Test.Common.cs create mode 100644 lib/csharp/test/Multiplex/Server/Multiplex.Test.Server.cs create mode 100644 lib/csharp/test/Multiplex/Server/MultiplexServer.csproj create mode 100644 lib/csharp/test/Multiplex/Server/Properties/AssemblyInfo.cs create mode 100644 lib/csharp/test/ThriftMVCTest/App_Start/FilterConfig.cs create mode 100644 lib/csharp/test/ThriftMVCTest/App_Start/RouteConfig.cs create mode 100644 lib/csharp/test/ThriftMVCTest/AsyncHttpHandler.cs create mode 100644 lib/csharp/test/ThriftMVCTest/Controllers/HomeController.cs create mode 100644 lib/csharp/test/ThriftMVCTest/Global.asax create mode 100644 lib/csharp/test/ThriftMVCTest/Global.asax.cs create mode 100644 lib/csharp/test/ThriftMVCTest/Properties/AssemblyInfo.cs create mode 100644 lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs create mode 100644 lib/csharp/test/ThriftMVCTest/SyncHttpHandler.cs create mode 100644 lib/csharp/test/ThriftMVCTest/ThriftMVCTest.csproj create mode 100644 lib/csharp/test/ThriftMVCTest/Views/Home/Index.cshtml create mode 100644 lib/csharp/test/ThriftMVCTest/Views/Shared/_Layout.cshtml create mode 100644 lib/csharp/test/ThriftMVCTest/Views/Web.config create mode 100644 lib/csharp/test/ThriftMVCTest/Views/_ViewStart.cshtml create mode 100644 lib/csharp/test/ThriftMVCTest/Web.Debug.config create mode 100644 lib/csharp/test/ThriftMVCTest/Web.Release.config create mode 100644 lib/csharp/test/ThriftMVCTest/Web.config create mode 100644 lib/csharp/test/ThriftMVCTest/favicon.ico create mode 100644 lib/csharp/test/ThriftMVCTest/packages.config create mode 100644 lib/d/Makefile create mode 100644 lib/d/Makefile.am create mode 100644 lib/d/Makefile.in create mode 100644 lib/d/README.md create mode 100644 lib/d/coding_standards.md create mode 100644 lib/d/src/thrift/async/base.d create mode 100644 lib/d/src/thrift/async/libevent.d create mode 100644 lib/d/src/thrift/async/socket.d create mode 100644 lib/d/src/thrift/async/ssl.d create mode 100644 lib/d/src/thrift/base.d create mode 100644 lib/d/src/thrift/codegen/async_client.d create mode 100644 lib/d/src/thrift/codegen/async_client_pool.d create mode 100644 lib/d/src/thrift/codegen/base.d create mode 100644 lib/d/src/thrift/codegen/client.d create mode 100644 lib/d/src/thrift/codegen/client_pool.d create mode 100644 lib/d/src/thrift/codegen/idlgen.d create mode 100644 lib/d/src/thrift/codegen/processor.d create mode 100644 lib/d/src/thrift/index.d create mode 100644 lib/d/src/thrift/internal/algorithm.d create mode 100644 lib/d/src/thrift/internal/codegen.d create mode 100644 lib/d/src/thrift/internal/ctfe.d create mode 100644 lib/d/src/thrift/internal/endian.d create mode 100644 lib/d/src/thrift/internal/resource_pool.d create mode 100644 lib/d/src/thrift/internal/socket.d create mode 100644 lib/d/src/thrift/internal/ssl.d create mode 100644 lib/d/src/thrift/internal/ssl_bio.d create mode 100644 lib/d/src/thrift/internal/test/protocol.d create mode 100644 lib/d/src/thrift/internal/test/server.d create mode 100644 lib/d/src/thrift/internal/traits.d create mode 100644 lib/d/src/thrift/protocol/base.d create mode 100644 lib/d/src/thrift/protocol/binary.d create mode 100644 lib/d/src/thrift/protocol/compact.d create mode 100644 lib/d/src/thrift/protocol/json.d create mode 100644 lib/d/src/thrift/protocol/processor.d create mode 100644 lib/d/src/thrift/server/base.d create mode 100644 lib/d/src/thrift/server/nonblocking.d create mode 100644 lib/d/src/thrift/server/simple.d create mode 100644 lib/d/src/thrift/server/taskpool.d create mode 100644 lib/d/src/thrift/server/threaded.d create mode 100644 lib/d/src/thrift/server/transport/base.d create mode 100644 lib/d/src/thrift/server/transport/socket.d create mode 100644 lib/d/src/thrift/server/transport/ssl.d create mode 100644 lib/d/src/thrift/transport/base.d create mode 100644 lib/d/src/thrift/transport/buffered.d create mode 100644 lib/d/src/thrift/transport/file.d create mode 100644 lib/d/src/thrift/transport/framed.d create mode 100644 lib/d/src/thrift/transport/http.d create mode 100644 lib/d/src/thrift/transport/memory.d create mode 100644 lib/d/src/thrift/transport/piped.d create mode 100644 lib/d/src/thrift/transport/range.d create mode 100644 lib/d/src/thrift/transport/socket.d create mode 100644 lib/d/src/thrift/transport/ssl.d create mode 100644 lib/d/src/thrift/transport/zlib.d create mode 100644 lib/d/src/thrift/util/awaitable.d create mode 100644 lib/d/src/thrift/util/cancellation.d create mode 100644 lib/d/src/thrift/util/future.d create mode 100644 lib/d/src/thrift/util/hashset.d create mode 100644 lib/d/test/Makefile create mode 100755 lib/d/test/Makefile.am create mode 100644 lib/d/test/Makefile.in create mode 100644 lib/d/test/async_test.d create mode 100755 lib/d/test/async_test_runner.sh create mode 100644 lib/d/test/client_pool_test.d create mode 100644 lib/d/test/openssl.test.cnf create mode 100644 lib/d/test/serialization_benchmark.d create mode 100644 lib/d/test/stress_test_server.d create mode 100644 lib/d/test/test_utils.d create mode 100644 lib/d/test/thrift_test_client.d create mode 100644 lib/d/test/thrift_test_common.d create mode 100755 lib/d/test/thrift_test_runner.sh create mode 100644 lib/d/test/thrift_test_server.d create mode 100644 lib/d/test/transport_test.d create mode 100644 lib/dart/.analysis_options create mode 100644 lib/dart/LICENSE_HEADER create mode 100644 lib/dart/Makefile create mode 100644 lib/dart/Makefile.am create mode 100644 lib/dart/Makefile.in create mode 100644 lib/dart/README.md create mode 100644 lib/dart/coding_standards.md create mode 100644 lib/dart/lib/src/browser/t_web_socket.dart create mode 100644 lib/dart/lib/src/console/t_tcp_socket.dart create mode 100644 lib/dart/lib/src/console/t_web_socket.dart create mode 100644 lib/dart/lib/src/protocol/t_binary_protocol.dart create mode 100644 lib/dart/lib/src/protocol/t_compact_protocol.dart create mode 100644 lib/dart/lib/src/protocol/t_field.dart create mode 100644 lib/dart/lib/src/protocol/t_json_protocol.dart create mode 100644 lib/dart/lib/src/protocol/t_list.dart create mode 100644 lib/dart/lib/src/protocol/t_map.dart create mode 100644 lib/dart/lib/src/protocol/t_message.dart create mode 100644 lib/dart/lib/src/protocol/t_multiplexed_protocol.dart create mode 100644 lib/dart/lib/src/protocol/t_protocol.dart create mode 100644 lib/dart/lib/src/protocol/t_protocol_decorator.dart create mode 100644 lib/dart/lib/src/protocol/t_protocol_error.dart create mode 100644 lib/dart/lib/src/protocol/t_protocol_factory.dart create mode 100644 lib/dart/lib/src/protocol/t_protocol_util.dart create mode 100644 lib/dart/lib/src/protocol/t_set.dart create mode 100644 lib/dart/lib/src/protocol/t_struct.dart create mode 100644 lib/dart/lib/src/protocol/t_type.dart create mode 100644 lib/dart/lib/src/serializer/t_deserializer.dart create mode 100644 lib/dart/lib/src/serializer/t_serializer.dart create mode 100644 lib/dart/lib/src/t_application_error.dart create mode 100644 lib/dart/lib/src/t_base.dart create mode 100644 lib/dart/lib/src/t_error.dart create mode 100644 lib/dart/lib/src/t_processor.dart create mode 100644 lib/dart/lib/src/transport/t_buffered_transport.dart create mode 100644 lib/dart/lib/src/transport/t_framed_transport.dart create mode 100644 lib/dart/lib/src/transport/t_http_transport.dart create mode 100644 lib/dart/lib/src/transport/t_message_reader.dart create mode 100644 lib/dart/lib/src/transport/t_socket.dart create mode 100644 lib/dart/lib/src/transport/t_socket_transport.dart create mode 100644 lib/dart/lib/src/transport/t_transport.dart create mode 100644 lib/dart/lib/src/transport/t_transport_error.dart create mode 100644 lib/dart/lib/src/transport/t_transport_factory.dart create mode 100644 lib/dart/lib/thrift.dart create mode 100644 lib/dart/lib/thrift_browser.dart create mode 100644 lib/dart/lib/thrift_console.dart create mode 100644 lib/dart/pubspec.yaml create mode 100644 lib/dart/test/protocol/t_protocol_test.dart create mode 100644 lib/dart/test/serializer/serializer_test.dart create mode 100644 lib/dart/test/serializer/serializer_test_data.dart create mode 100644 lib/dart/test/t_application_error_test.dart create mode 100644 lib/dart/test/transport/t_http_transport_test.dart create mode 100644 lib/dart/test/transport/t_socket_transport_test.dart create mode 100644 lib/dart/test/transport/t_transport_test.dart create mode 100644 lib/dart/tool/dev.dart create mode 100644 lib/delphi/README.md create mode 100644 lib/delphi/coding_standards.md create mode 100644 lib/delphi/src/Thrift.Collections.pas create mode 100644 lib/delphi/src/Thrift.Console.pas create mode 100644 lib/delphi/src/Thrift.Defines.inc create mode 100644 lib/delphi/src/Thrift.Processor.Multiplex.pas create mode 100644 lib/delphi/src/Thrift.Protocol.Compact.pas create mode 100644 lib/delphi/src/Thrift.Protocol.JSON.pas create mode 100644 lib/delphi/src/Thrift.Protocol.Multiplex.pas create mode 100644 lib/delphi/src/Thrift.Protocol.pas create mode 100644 lib/delphi/src/Thrift.Serializer.pas create mode 100644 lib/delphi/src/Thrift.Server.pas create mode 100644 lib/delphi/src/Thrift.Socket.pas create mode 100644 lib/delphi/src/Thrift.Stream.pas create mode 100644 lib/delphi/src/Thrift.Transport.Pipes.pas create mode 100644 lib/delphi/src/Thrift.Transport.pas create mode 100644 lib/delphi/src/Thrift.TypeRegistry.pas create mode 100644 lib/delphi/src/Thrift.Utils.pas create mode 100644 lib/delphi/src/Thrift.pas create mode 100644 lib/delphi/test/TestClient.pas create mode 100644 lib/delphi/test/TestConstants.pas create mode 100644 lib/delphi/test/TestServer.pas create mode 100644 lib/delphi/test/TestServerEvents.pas create mode 100644 lib/delphi/test/client.dpr create mode 100644 lib/delphi/test/codegen/README.md create mode 100644 lib/delphi/test/codegen/ReservedKeywords.thrift create mode 100644 lib/delphi/test/codegen/run-Pascal-Codegen-Tests.bat.tmpl create mode 100755 lib/delphi/test/maketest.sh create mode 100644 lib/delphi/test/multiplexed/Multiplex.Client.Main.pas create mode 100644 lib/delphi/test/multiplexed/Multiplex.Server.Main.pas create mode 100644 lib/delphi/test/multiplexed/Multiplex.Test.Client.dpr create mode 100644 lib/delphi/test/multiplexed/Multiplex.Test.Common.pas create mode 100644 lib/delphi/test/multiplexed/Multiplex.Test.Server.dpr create mode 100644 lib/delphi/test/serializer/TestSerializer.Data.pas create mode 100644 lib/delphi/test/serializer/TestSerializer.dpr create mode 100644 lib/delphi/test/server.dpr create mode 100644 lib/delphi/test/skip/README.md create mode 100644 lib/delphi/test/skip/idl/skiptest_version_1.thrift create mode 100644 lib/delphi/test/skip/idl/skiptest_version_2.thrift create mode 100644 lib/delphi/test/skip/skiptest_version1.dpr create mode 100644 lib/delphi/test/skip/skiptest_version2.dpr create mode 100644 lib/delphi/test/typeregistry/TestTypeRegistry.dpr create mode 100644 lib/erl/Makefile.am create mode 100644 lib/erl/Makefile.in create mode 100644 lib/erl/README.md create mode 100644 lib/erl/coding_standards.md create mode 100644 lib/erl/include/thrift_constants.hrl create mode 100644 lib/erl/include/thrift_protocol.hrl create mode 100644 lib/erl/include/thrift_protocol_behaviour.hrl create mode 100644 lib/erl/include/thrift_transport_behaviour.hrl create mode 100644 lib/erl/rebar.config create mode 100644 lib/erl/rebar.config.script create mode 100644 lib/erl/rebar.test.config create mode 100644 lib/erl/src/thrift.app.src create mode 100644 lib/erl/src/thrift_base64_transport.erl create mode 100644 lib/erl/src/thrift_binary_protocol.erl create mode 100644 lib/erl/src/thrift_buffered_transport.erl create mode 100644 lib/erl/src/thrift_client.erl create mode 100644 lib/erl/src/thrift_client_util.erl create mode 100644 lib/erl/src/thrift_compact_protocol.erl create mode 100644 lib/erl/src/thrift_disk_log_transport.erl create mode 100644 lib/erl/src/thrift_file_transport.erl create mode 100644 lib/erl/src/thrift_framed_transport.erl create mode 100644 lib/erl/src/thrift_http_transport.erl create mode 100644 lib/erl/src/thrift_json_parser.erl create mode 100644 lib/erl/src/thrift_json_protocol.erl create mode 100644 lib/erl/src/thrift_membuffer_transport.erl create mode 100644 lib/erl/src/thrift_memory_buffer.erl create mode 100644 lib/erl/src/thrift_multiplexed_map_wrapper.erl create mode 100644 lib/erl/src/thrift_multiplexed_protocol.erl create mode 100644 lib/erl/src/thrift_processor.erl create mode 100644 lib/erl/src/thrift_protocol.erl create mode 100644 lib/erl/src/thrift_reconnecting_client.erl create mode 100644 lib/erl/src/thrift_server.erl create mode 100644 lib/erl/src/thrift_service.erl create mode 100644 lib/erl/src/thrift_socket_server.erl create mode 100644 lib/erl/src/thrift_socket_transport.erl create mode 100644 lib/erl/src/thrift_sslsocket_transport.erl create mode 100644 lib/erl/src/thrift_transport.erl create mode 100644 lib/erl/src/thrift_transport_state_test.erl create mode 100644 lib/erl/test/Thrift1151.thrift create mode 100644 lib/erl/test/Thrift1475.thrift create mode 100644 lib/erl/test/Thrift_omit_with.thrift create mode 100644 lib/erl/test/flags/LegacyNames.thrift create mode 100644 lib/erl/test/flags/Thrift3214.thrift create mode 100644 lib/erl/test/legacy_names_test.erl create mode 100644 lib/erl/test/multiplexing.thrift create mode 100644 lib/erl/test/multiplexing_test.erl create mode 100644 lib/erl/test/name_conflict_test.erl create mode 100644 lib/erl/test/stress_server.erl create mode 100644 lib/erl/test/test_const.erl create mode 100644 lib/erl/test/test_disklog.erl create mode 100644 lib/erl/test/test_omit.erl create mode 100644 lib/erl/test/test_thrift_1151.erl create mode 100644 lib/erl/test/test_thrift_3214.erl create mode 100644 lib/erl/test/test_thrift_buffered_transport.erl create mode 100644 lib/erl/test/test_thrift_compact_protocol.erl create mode 100644 lib/erl/test/test_thrift_file_transport.erl create mode 100644 lib/erl/test/test_thrift_framed_transport.erl create mode 100644 lib/erl/test/test_thrift_membuffer_transport.erl create mode 100644 lib/erl/test/test_thrift_socket_transport.erl create mode 100644 lib/erl/test/thrift_socket_server_test.erl create mode 100644 lib/erl/test/thrift_test_test.erl create mode 100644 lib/go/Makefile.am create mode 100644 lib/go/Makefile.in create mode 100644 lib/go/README.md create mode 100644 lib/go/coding_standards.md create mode 100644 lib/go/test/BinaryKeyTest.thrift create mode 100644 lib/go/test/DontExportRWTest.thrift create mode 100644 lib/go/test/ErrorTest.thrift create mode 100644 lib/go/test/GoTagTest.thrift create mode 100644 lib/go/test/IgnoreInitialismsTest.thrift create mode 100644 lib/go/test/IncludesTest.thrift create mode 100644 lib/go/test/InitialismsTest.thrift create mode 100644 lib/go/test/Makefile.am create mode 100644 lib/go/test/Makefile.in create mode 100644 lib/go/test/MultiplexedProtocolTest.thrift create mode 100644 lib/go/test/NamesTest.thrift create mode 100644 lib/go/test/NamespacedTest.thrift create mode 100644 lib/go/test/OnewayTest.thrift create mode 100644 lib/go/test/OptionalFieldsTest.thrift create mode 100644 lib/go/test/RefAnnotationFieldsTest.thrift create mode 100644 lib/go/test/ServicesTest.thrift create mode 100644 lib/go/test/TypedefFieldTest.thrift create mode 100644 lib/go/test/UnionDefaultValueTest.thrift create mode 100644 lib/go/test/dontexportrwtest/compile_test.go create mode 100644 lib/go/test/tests/binary_key_test.go create mode 100644 lib/go/test/tests/client_error_test.go create mode 100644 lib/go/test/tests/encoding_json_test.go create mode 100644 lib/go/test/tests/go17.go create mode 100644 lib/go/test/tests/gotag_test.go create mode 100644 lib/go/test/tests/ignoreinitialisms_test.go create mode 100644 lib/go/test/tests/initialisms_test.go create mode 100644 lib/go/test/tests/multiplexed_protocol_test.go create mode 100644 lib/go/test/tests/names_test.go create mode 100644 lib/go/test/tests/one_way_test.go create mode 100644 lib/go/test/tests/optional_fields_test.go create mode 100644 lib/go/test/tests/pre_go17.go create mode 100644 lib/go/test/tests/protocol_mock.go create mode 100644 lib/go/test/tests/protocols_test.go create mode 100644 lib/go/test/tests/required_fields_test.go create mode 100644 lib/go/test/tests/struct_args_rets_test.go create mode 100644 lib/go/test/tests/thrifttest_driver.go create mode 100644 lib/go/test/tests/thrifttest_handler.go create mode 100644 lib/go/test/tests/thrifttest_handler_go17.go create mode 100644 lib/go/test/tests/union_default_value_test.go create mode 100644 lib/go/thrift/application_exception.go create mode 100644 lib/go/thrift/application_exception_test.go create mode 100644 lib/go/thrift/binary_protocol.go create mode 100644 lib/go/thrift/binary_protocol_test.go create mode 100644 lib/go/thrift/buffered_transport.go create mode 100644 lib/go/thrift/buffered_transport_test.go create mode 100644 lib/go/thrift/client.go create mode 100644 lib/go/thrift/client_go17.go create mode 100644 lib/go/thrift/client_pre_go17.go create mode 100644 lib/go/thrift/common_test_go17.go create mode 100644 lib/go/thrift/common_test_pre_go17.go create mode 100644 lib/go/thrift/compact_protocol.go create mode 100644 lib/go/thrift/compact_protocol_test.go create mode 100644 lib/go/thrift/debug_protocol.go create mode 100644 lib/go/thrift/deserializer.go create mode 100644 lib/go/thrift/exception.go create mode 100644 lib/go/thrift/exception_test.go create mode 100644 lib/go/thrift/field.go create mode 100644 lib/go/thrift/framed_transport.go create mode 100644 lib/go/thrift/framed_transport_test.go create mode 100644 lib/go/thrift/go17.go create mode 100644 lib/go/thrift/http_client.go create mode 100644 lib/go/thrift/http_client_test.go create mode 100644 lib/go/thrift/http_transport.go create mode 100644 lib/go/thrift/http_transport_go17.go create mode 100644 lib/go/thrift/http_transport_pre_go17.go create mode 100644 lib/go/thrift/iostream_transport.go create mode 100644 lib/go/thrift/iostream_transport_test.go create mode 100644 lib/go/thrift/json_protocol.go create mode 100644 lib/go/thrift/json_protocol_test.go create mode 100644 lib/go/thrift/lowlevel_benchmarks_test.go create mode 100644 lib/go/thrift/memory_buffer.go create mode 100644 lib/go/thrift/memory_buffer_test.go create mode 100644 lib/go/thrift/messagetype.go create mode 100644 lib/go/thrift/multiplexed_protocol.go create mode 100644 lib/go/thrift/multiplexed_protocol_go17.go create mode 100644 lib/go/thrift/multiplexed_protocol_pre_go17.go create mode 100644 lib/go/thrift/numeric.go create mode 100644 lib/go/thrift/pointerize.go create mode 100644 lib/go/thrift/pre_go17.go create mode 100644 lib/go/thrift/processor.go create mode 100644 lib/go/thrift/processor_factory.go create mode 100644 lib/go/thrift/processor_go17.go create mode 100644 lib/go/thrift/protocol.go create mode 100644 lib/go/thrift/protocol_exception.go create mode 100644 lib/go/thrift/protocol_factory.go create mode 100644 lib/go/thrift/protocol_test.go create mode 100644 lib/go/thrift/rich_transport.go create mode 100644 lib/go/thrift/rich_transport_test.go create mode 100644 lib/go/thrift/serializer.go create mode 100644 lib/go/thrift/serializer_test.go create mode 100644 lib/go/thrift/serializer_types_test.go create mode 100644 lib/go/thrift/server.go create mode 100644 lib/go/thrift/server_socket.go create mode 100644 lib/go/thrift/server_socket_test.go create mode 100644 lib/go/thrift/server_test.go create mode 100644 lib/go/thrift/server_transport.go create mode 100644 lib/go/thrift/simple_json_protocol.go create mode 100644 lib/go/thrift/simple_json_protocol_test.go create mode 100644 lib/go/thrift/simple_server.go create mode 100644 lib/go/thrift/simple_server_test.go create mode 100644 lib/go/thrift/socket.go create mode 100644 lib/go/thrift/ssl_server_socket.go create mode 100644 lib/go/thrift/ssl_socket.go create mode 100644 lib/go/thrift/transport.go create mode 100644 lib/go/thrift/transport_exception.go create mode 100644 lib/go/thrift/transport_exception_test.go create mode 100644 lib/go/thrift/transport_factory.go create mode 100644 lib/go/thrift/transport_test.go create mode 100644 lib/go/thrift/type.go create mode 100644 lib/go/thrift/zlib_transport.go create mode 100644 lib/go/thrift/zlib_transport_test.go create mode 100644 lib/haxe/README.md create mode 100644 lib/haxe/coding_standards.md create mode 100644 lib/haxe/haxelib.json create mode 100644 lib/haxe/src/org/apache/thrift/AbstractMethodError.hx create mode 100644 lib/haxe/src/org/apache/thrift/ArgumentError.hx create mode 100644 lib/haxe/src/org/apache/thrift/Limits.hx create mode 100644 lib/haxe/src/org/apache/thrift/TApplicationException.hx create mode 100644 lib/haxe/src/org/apache/thrift/TBase.hx create mode 100644 lib/haxe/src/org/apache/thrift/TException.hx create mode 100644 lib/haxe/src/org/apache/thrift/TFieldRequirementType.hx create mode 100644 lib/haxe/src/org/apache/thrift/TProcessor.hx create mode 100644 lib/haxe/src/org/apache/thrift/helper/BitConverter.hx create mode 100644 lib/haxe/src/org/apache/thrift/helper/Int64Map.hx create mode 100644 lib/haxe/src/org/apache/thrift/helper/IntSet.hx create mode 100644 lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx create mode 100644 lib/haxe/src/org/apache/thrift/helper/StringSet.hx create mode 100644 lib/haxe/src/org/apache/thrift/helper/ZigZag.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/FieldMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/FieldValueMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/ListMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/MapMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/SetMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/StructMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocolFactory.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TCompactProtocolFactory.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TCompactTypes.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TField.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TJSONProtocolFactory.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TList.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TMap.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TMessage.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TMessageType.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TMultiplexedProcessor.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TMultiplexedProtocol.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TProtocolDecorator.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TProtocolException.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TProtocolFactory.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TProtocolUtil.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TRecursionTracker.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TSet.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TStruct.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TType.hx create mode 100644 lib/haxe/src/org/apache/thrift/server/TServer.hx create mode 100644 lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx create mode 100644 lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TBufferedTransport.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TBufferedTransportFactory.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TFileStream.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/THttpClient.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TSocket.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TStream.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TStreamTransport.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TTransport.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TTransportException.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TTransportFactory.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TWrappingServerTransport.hx create mode 100644 lib/haxe/test/HaxeTests.hxproj create mode 100644 lib/haxe/test/Makefile create mode 100644 lib/haxe/test/Makefile.am create mode 100644 lib/haxe/test/Makefile.in create mode 100644 lib/haxe/test/cpp.hxml create mode 100644 lib/haxe/test/csharp.hxml create mode 100644 lib/haxe/test/flash.hxml create mode 100644 lib/haxe/test/java.hxml create mode 100644 lib/haxe/test/javascript.hxml create mode 100644 lib/haxe/test/make_all.bat create mode 100644 lib/haxe/test/make_all.sh create mode 100644 lib/haxe/test/neko.hxml create mode 100644 lib/haxe/test/php.hxml create mode 100644 lib/haxe/test/project.hide create mode 100644 lib/haxe/test/python.hxml create mode 100644 lib/haxe/test/src/Main.hx create mode 100644 lib/haxe/test/src/MultiplexTest.hx create mode 100644 lib/haxe/test/src/StreamTest.hx create mode 100644 lib/haxe/test/src/TestBase.hx create mode 100644 lib/hs/CMakeLists.txt create mode 100644 lib/hs/LICENSE create mode 100644 lib/hs/Makefile.am create mode 100644 lib/hs/Makefile.in create mode 100644 lib/hs/README.md create mode 100755 lib/hs/Setup.lhs create mode 100644 lib/hs/TODO create mode 100644 lib/hs/coding_standards.md create mode 100644 lib/hs/src/Thrift.hs create mode 100644 lib/hs/src/Thrift/Arbitraries.hs create mode 100644 lib/hs/src/Thrift/Protocol.hs create mode 100644 lib/hs/src/Thrift/Protocol/Binary.hs create mode 100644 lib/hs/src/Thrift/Protocol/Compact.hs create mode 100644 lib/hs/src/Thrift/Protocol/Header.hs create mode 100644 lib/hs/src/Thrift/Protocol/JSON.hs create mode 100644 lib/hs/src/Thrift/Server.hs create mode 100644 lib/hs/src/Thrift/Transport.hs create mode 100644 lib/hs/src/Thrift/Transport/Empty.hs create mode 100644 lib/hs/src/Thrift/Transport/Framed.hs create mode 100644 lib/hs/src/Thrift/Transport/Handle.hs create mode 100644 lib/hs/src/Thrift/Transport/Header.hs create mode 100644 lib/hs/src/Thrift/Transport/HttpClient.hs create mode 100644 lib/hs/src/Thrift/Transport/IOBuffer.hs create mode 100644 lib/hs/src/Thrift/Transport/Memory.hs create mode 100644 lib/hs/src/Thrift/Types.hs create mode 100644 lib/hs/test/BinarySpec.hs create mode 100644 lib/hs/test/CompactSpec.hs create mode 100644 lib/hs/test/JSONSpec.hs create mode 100644 lib/hs/test/Spec.hs create mode 100644 lib/hs/thrift.cabal create mode 100644 lib/java/CMakeLists.txt create mode 100644 lib/java/Makefile.am create mode 100644 lib/java/Makefile.in create mode 100644 lib/java/README.md create mode 100644 lib/java/android/build.gradle create mode 100644 lib/java/android/settings.gradle create mode 100644 lib/java/android/src/main/AndroidManifest.xml create mode 100644 lib/java/build.properties create mode 100644 lib/java/build.xml create mode 100644 lib/java/coding_standards.md create mode 100644 lib/java/src/org/apache/thrift/AsyncProcessFunction.java create mode 100644 lib/java/src/org/apache/thrift/EncodingUtils.java create mode 100644 lib/java/src/org/apache/thrift/Option.java create mode 100644 lib/java/src/org/apache/thrift/ProcessFunction.java create mode 100644 lib/java/src/org/apache/thrift/ShortStack.java create mode 100644 lib/java/src/org/apache/thrift/TApplicationException.java create mode 100644 lib/java/src/org/apache/thrift/TAsyncProcessor.java create mode 100644 lib/java/src/org/apache/thrift/TBase.java create mode 100644 lib/java/src/org/apache/thrift/TBaseAsyncProcessor.java create mode 100644 lib/java/src/org/apache/thrift/TBaseHelper.java create mode 100644 lib/java/src/org/apache/thrift/TBaseProcessor.java create mode 100644 lib/java/src/org/apache/thrift/TByteArrayOutputStream.java create mode 100644 lib/java/src/org/apache/thrift/TDeserializer.java create mode 100644 lib/java/src/org/apache/thrift/TEnum.java create mode 100644 lib/java/src/org/apache/thrift/TEnumHelper.java create mode 100644 lib/java/src/org/apache/thrift/TException.java create mode 100644 lib/java/src/org/apache/thrift/TFieldIdEnum.java create mode 100644 lib/java/src/org/apache/thrift/TFieldRequirementType.java create mode 100644 lib/java/src/org/apache/thrift/TMultiplexedProcessor.java create mode 100644 lib/java/src/org/apache/thrift/TNonblockingMultiFetchClient.java create mode 100644 lib/java/src/org/apache/thrift/TNonblockingMultiFetchStats.java create mode 100644 lib/java/src/org/apache/thrift/TProcessor.java create mode 100644 lib/java/src/org/apache/thrift/TProcessorFactory.java create mode 100644 lib/java/src/org/apache/thrift/TSerializable.java create mode 100644 lib/java/src/org/apache/thrift/TSerializer.java create mode 100644 lib/java/src/org/apache/thrift/TServiceClient.java create mode 100644 lib/java/src/org/apache/thrift/TServiceClientFactory.java create mode 100644 lib/java/src/org/apache/thrift/TUnion.java create mode 100644 lib/java/src/org/apache/thrift/async/AsyncMethodCallback.java create mode 100644 lib/java/src/org/apache/thrift/async/TAsyncClient.java create mode 100644 lib/java/src/org/apache/thrift/async/TAsyncClientFactory.java create mode 100644 lib/java/src/org/apache/thrift/async/TAsyncClientManager.java create mode 100644 lib/java/src/org/apache/thrift/async/TAsyncMethodCall.java create mode 100644 lib/java/src/org/apache/thrift/meta_data/EnumMetaData.java create mode 100644 lib/java/src/org/apache/thrift/meta_data/FieldMetaData.java create mode 100644 lib/java/src/org/apache/thrift/meta_data/FieldValueMetaData.java create mode 100644 lib/java/src/org/apache/thrift/meta_data/ListMetaData.java create mode 100644 lib/java/src/org/apache/thrift/meta_data/MapMetaData.java create mode 100644 lib/java/src/org/apache/thrift/meta_data/SetMetaData.java create mode 100644 lib/java/src/org/apache/thrift/meta_data/StructMetaData.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TBase64Utils.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TBinaryProtocol.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TField.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TJSONProtocol.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TList.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TMap.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TMessage.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TMessageType.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TMultiplexedProtocol.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TProtocol.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TProtocolDecorator.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TProtocolException.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TProtocolFactory.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TProtocolUtil.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TSet.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TSimpleJSONProtocol.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TStruct.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TTupleProtocol.java create mode 100644 lib/java/src/org/apache/thrift/protocol/TType.java create mode 100644 lib/java/src/org/apache/thrift/scheme/IScheme.java create mode 100644 lib/java/src/org/apache/thrift/scheme/SchemeFactory.java create mode 100644 lib/java/src/org/apache/thrift/scheme/StandardScheme.java create mode 100644 lib/java/src/org/apache/thrift/scheme/TupleScheme.java create mode 100644 lib/java/src/org/apache/thrift/server/AbstractNonblockingServer.java create mode 100644 lib/java/src/org/apache/thrift/server/Invocation.java create mode 100644 lib/java/src/org/apache/thrift/server/ServerContext.java create mode 100644 lib/java/src/org/apache/thrift/server/TExtensibleServlet.java create mode 100644 lib/java/src/org/apache/thrift/server/THsHaServer.java create mode 100644 lib/java/src/org/apache/thrift/server/TNonblockingServer.java create mode 100644 lib/java/src/org/apache/thrift/server/TServer.java create mode 100644 lib/java/src/org/apache/thrift/server/TServerEventHandler.java create mode 100644 lib/java/src/org/apache/thrift/server/TServlet.java create mode 100644 lib/java/src/org/apache/thrift/server/TSimpleServer.java create mode 100644 lib/java/src/org/apache/thrift/server/TThreadPoolServer.java create mode 100644 lib/java/src/org/apache/thrift/server/TThreadedSelectorServer.java create mode 100644 lib/java/src/org/apache/thrift/transport/AutoExpandingBuffer.java create mode 100644 lib/java/src/org/apache/thrift/transport/AutoExpandingBufferReadTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/AutoExpandingBufferWriteTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/TByteBuffer.java create mode 100644 lib/java/src/org/apache/thrift/transport/TFastFramedTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/TFileProcessor.java create mode 100644 lib/java/src/org/apache/thrift/transport/TFileTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/TFramedTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/THttpClient.java create mode 100644 lib/java/src/org/apache/thrift/transport/TIOStreamTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/TMemoryBuffer.java create mode 100644 lib/java/src/org/apache/thrift/transport/TMemoryInputTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/TNonblockingServerSocket.java create mode 100644 lib/java/src/org/apache/thrift/transport/TNonblockingServerTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/TNonblockingSocket.java create mode 100644 lib/java/src/org/apache/thrift/transport/TNonblockingTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/TSSLTransportFactory.java create mode 100644 lib/java/src/org/apache/thrift/transport/TSaslClientTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/TSaslServerTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/TSaslTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/TSaslTransportException.java create mode 100644 lib/java/src/org/apache/thrift/transport/TSeekableFile.java create mode 100644 lib/java/src/org/apache/thrift/transport/TServerSocket.java create mode 100644 lib/java/src/org/apache/thrift/transport/TServerTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/TSimpleFileTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/TSocket.java create mode 100644 lib/java/src/org/apache/thrift/transport/TStandardFile.java create mode 100644 lib/java/src/org/apache/thrift/transport/TTransport.java create mode 100644 lib/java/src/org/apache/thrift/transport/TTransportException.java create mode 100644 lib/java/src/org/apache/thrift/transport/TTransportFactory.java create mode 100644 lib/java/src/org/apache/thrift/transport/TZlibTransport.java create mode 100644 lib/java/test/.keystore create mode 100644 lib/java/test/.truststore create mode 100644 lib/java/test/log4j.properties create mode 100644 lib/java/test/org/apache/thrift/Fixtures.java create mode 100644 lib/java/test/org/apache/thrift/TestDeepCopy.java create mode 100644 lib/java/test/org/apache/thrift/TestEnumContainers.java create mode 100644 lib/java/test/org/apache/thrift/TestFullCamel.java create mode 100644 lib/java/test/org/apache/thrift/TestMultiplexedProcessor.java create mode 100644 lib/java/test/org/apache/thrift/TestOptionType.java create mode 100644 lib/java/test/org/apache/thrift/TestOptionals.java create mode 100644 lib/java/test/org/apache/thrift/TestReuse.java create mode 100644 lib/java/test/org/apache/thrift/TestShortStack.java create mode 100644 lib/java/test/org/apache/thrift/TestStruct.java create mode 100644 lib/java/test/org/apache/thrift/TestTBaseHelper.java create mode 100644 lib/java/test/org/apache/thrift/TestTDeserializer.java create mode 100644 lib/java/test/org/apache/thrift/TestTEnumHelper.java create mode 100644 lib/java/test/org/apache/thrift/TestTUnion.java create mode 100644 lib/java/test/org/apache/thrift/async/TestTAsyncClient.java create mode 100644 lib/java/test/org/apache/thrift/async/TestTAsyncClientManager.java create mode 100644 lib/java/test/org/apache/thrift/protocol/BenchmarkProtocols.java create mode 100644 lib/java/test/org/apache/thrift/protocol/ProtocolTestBase.java create mode 100644 lib/java/test/org/apache/thrift/protocol/TestTCompactProtocol.java create mode 100644 lib/java/test/org/apache/thrift/protocol/TestTJSONProtocol.java create mode 100644 lib/java/test/org/apache/thrift/protocol/TestTProtocolUtil.java create mode 100644 lib/java/test/org/apache/thrift/protocol/TestTSimpleJSONProtocol.java create mode 100644 lib/java/test/org/apache/thrift/protocol/TestTTupleProtocol.java create mode 100644 lib/java/test/org/apache/thrift/scheme/TestStandardScheme.java create mode 100644 lib/java/test/org/apache/thrift/server/ServerTestBase.java create mode 100644 lib/java/test/org/apache/thrift/server/TestAsyncServer.java create mode 100644 lib/java/test/org/apache/thrift/server/TestHsHaServer.java create mode 100644 lib/java/test/org/apache/thrift/server/TestNonblockingServer.java create mode 100644 lib/java/test/org/apache/thrift/server/TestThreadedSelectorServer.java create mode 100644 lib/java/test/org/apache/thrift/test/EqualityTest.java create mode 100644 lib/java/test/org/apache/thrift/test/JavaBeansTest.java create mode 100644 lib/java/test/org/apache/thrift/test/ReadStruct.java create mode 100644 lib/java/test/org/apache/thrift/test/SerializationBenchmark.java create mode 100644 lib/java/test/org/apache/thrift/test/TestClient.java create mode 100644 lib/java/test/org/apache/thrift/test/TestNonblockingServer.java create mode 100644 lib/java/test/org/apache/thrift/test/TestServer.java create mode 100644 lib/java/test/org/apache/thrift/test/WriteStruct.java create mode 100644 lib/java/test/org/apache/thrift/transport/ReadCountingTransport.java create mode 100644 lib/java/test/org/apache/thrift/transport/TestAutoExpandingBuffer.java create mode 100644 lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferReadTransport.java create mode 100644 lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferWriteTransport.java create mode 100644 lib/java/test/org/apache/thrift/transport/TestTByteBuffer.java create mode 100644 lib/java/test/org/apache/thrift/transport/TestTFastFramedTransport.java create mode 100644 lib/java/test/org/apache/thrift/transport/TestTFramedTransport.java create mode 100644 lib/java/test/org/apache/thrift/transport/TestTMemoryInputTransport.java create mode 100644 lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactory.java create mode 100644 lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient1.java create mode 100644 lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient2.java create mode 100644 lib/java/test/org/apache/thrift/transport/TestTSaslTransports.java create mode 100644 lib/java/test/org/apache/thrift/transport/TestTSimpleFileTransport.java create mode 100644 lib/java/test/org/apache/thrift/transport/TestTZlibTransport.java create mode 100644 lib/java/test/org/apache/thrift/transport/WriteCountingTransport.java create mode 100644 lib/javame/coding_standards.md create mode 100644 lib/javame/src/org/apache/thrift/TApplicationException.java create mode 100644 lib/javame/src/org/apache/thrift/TBase.java create mode 100644 lib/javame/src/org/apache/thrift/TBaseHelper.java create mode 100644 lib/javame/src/org/apache/thrift/TByteArrayOutputStream.java create mode 100644 lib/javame/src/org/apache/thrift/TDeserializer.java create mode 100644 lib/javame/src/org/apache/thrift/TEnum.java create mode 100644 lib/javame/src/org/apache/thrift/TException.java create mode 100644 lib/javame/src/org/apache/thrift/TFieldRequirementType.java create mode 100644 lib/javame/src/org/apache/thrift/TProcessor.java create mode 100644 lib/javame/src/org/apache/thrift/TProcessorFactory.java create mode 100644 lib/javame/src/org/apache/thrift/TSerializer.java create mode 100644 lib/javame/src/org/apache/thrift/TServiceClient.java create mode 100644 lib/javame/src/org/apache/thrift/meta_data/FieldMetaData.java create mode 100644 lib/javame/src/org/apache/thrift/meta_data/FieldValueMetaData.java create mode 100644 lib/javame/src/org/apache/thrift/meta_data/ListMetaData.java create mode 100644 lib/javame/src/org/apache/thrift/meta_data/MapMetaData.java create mode 100644 lib/javame/src/org/apache/thrift/meta_data/SetMetaData.java create mode 100644 lib/javame/src/org/apache/thrift/meta_data/StructMetaData.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TBase64Utils.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TBinaryProtocol.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TField.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TJSONProtocol.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TList.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TMap.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TMessage.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TMessageType.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TProtocol.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TProtocolException.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TProtocolFactory.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TProtocolUtil.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TSet.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TStruct.java create mode 100644 lib/javame/src/org/apache/thrift/protocol/TType.java create mode 100644 lib/javame/src/org/apache/thrift/transport/TFramedTransport.java create mode 100644 lib/javame/src/org/apache/thrift/transport/THttpClient.java create mode 100644 lib/javame/src/org/apache/thrift/transport/TIOStreamTransport.java create mode 100644 lib/javame/src/org/apache/thrift/transport/TMemoryBuffer.java create mode 100644 lib/javame/src/org/apache/thrift/transport/TTransport.java create mode 100644 lib/javame/src/org/apache/thrift/transport/TTransportException.java create mode 100644 lib/javame/src/org/apache/thrift/transport/TTransportFactory.java create mode 100644 lib/js/Gruntfile.js create mode 100644 lib/js/Makefile create mode 100644 lib/js/Makefile.am create mode 100644 lib/js/Makefile.in create mode 100644 lib/js/README.md create mode 100644 lib/js/coding_standards.md create mode 100644 lib/js/package.json create mode 100644 lib/js/src/thrift.js create mode 100644 lib/js/test/Makefile create mode 100755 lib/js/test/Makefile.am create mode 100644 lib/js/test/Makefile.in create mode 100644 lib/js/test/README.md create mode 100755 lib/js/test/build.xml create mode 100644 lib/js/test/deep-constructor.test.js create mode 100755 lib/js/test/jsTestDriver.conf create mode 100644 lib/js/test/phantom-client.js create mode 100755 lib/js/test/phantomjs-qunit.js create mode 100644 lib/js/test/server_http.js create mode 100644 lib/js/test/server_https.js create mode 100644 lib/js/test/src/test/Httpd.java create mode 100644 lib/js/test/test-async.js create mode 100755 lib/js/test/test-deep-constructor.html create mode 100644 lib/js/test/test-jq.js create mode 100644 lib/js/test/test-nojq.html create mode 100644 lib/js/test/test-nojq.js create mode 100755 lib/js/test/test.html create mode 100755 lib/js/test/test.js create mode 100644 lib/js/test/test_handler.js create mode 100644 lib/js/test/testws.html create mode 100644 lib/json/Makefile.am create mode 100644 lib/json/Makefile.in create mode 100644 lib/json/schema.json create mode 100644 lib/json/test/Makefile create mode 100644 lib/json/test/Makefile.am create mode 100644 lib/json/test/Makefile.in create mode 100644 lib/json/test/build.properties create mode 100644 lib/json/test/build.xml create mode 100644 lib/lua/Makefile.am create mode 100644 lib/lua/Makefile.in create mode 100644 lib/lua/TBinaryProtocol.lua create mode 100644 lib/lua/TBufferedTransport.lua create mode 100644 lib/lua/TCompactProtocol.lua create mode 100644 lib/lua/TFramedTransport.lua create mode 100644 lib/lua/THttpTransport.lua create mode 100644 lib/lua/TJsonProtocol.lua create mode 100644 lib/lua/TMemoryBuffer.lua create mode 100644 lib/lua/TProtocol.lua create mode 100644 lib/lua/TServer.lua create mode 100644 lib/lua/TSocket.lua create mode 100644 lib/lua/TTransport.lua create mode 100644 lib/lua/Thrift.lua create mode 100644 lib/lua/coding_standards.md create mode 100644 lib/lua/src/longnumberutils.c create mode 100644 lib/lua/src/luabitwise.c create mode 100644 lib/lua/src/luabpack.c create mode 100644 lib/lua/src/lualongnumber.c create mode 100644 lib/lua/src/luasocket.c create mode 100644 lib/lua/src/socket.h create mode 100644 lib/lua/src/usocket.c create mode 100644 lib/netcore/Makefile.am create mode 100644 lib/netcore/Makefile.in create mode 100644 lib/netcore/README.md create mode 100644 lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/CassandraTest.thrift create mode 100644 lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Properties/AssemblyInfo.cs create mode 100644 lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj create mode 100644 lib/netcore/Thrift.sln create mode 100644 lib/netcore/Thrift/Collections/TCollections.cs create mode 100644 lib/netcore/Thrift/Collections/THashSet.cs create mode 100644 lib/netcore/Thrift/ITAsyncProcessor.cs create mode 100644 lib/netcore/Thrift/ITProcessorFactory.cs create mode 100644 lib/netcore/Thrift/Properties/AssemblyInfo.cs create mode 100644 lib/netcore/Thrift/Protocols/Entities/TField.cs create mode 100644 lib/netcore/Thrift/Protocols/Entities/TList.cs create mode 100644 lib/netcore/Thrift/Protocols/Entities/TMap.cs create mode 100644 lib/netcore/Thrift/Protocols/Entities/TMessage.cs create mode 100644 lib/netcore/Thrift/Protocols/Entities/TMessageType.cs create mode 100644 lib/netcore/Thrift/Protocols/Entities/TSet.cs create mode 100644 lib/netcore/Thrift/Protocols/Entities/TStruct.cs create mode 100644 lib/netcore/Thrift/Protocols/Entities/TType.cs create mode 100644 lib/netcore/Thrift/Protocols/ITProtocolFactory.cs create mode 100644 lib/netcore/Thrift/Protocols/TAbstractBase.cs create mode 100644 lib/netcore/Thrift/Protocols/TBase.cs create mode 100644 lib/netcore/Thrift/Protocols/TBinaryProtocol.cs create mode 100644 lib/netcore/Thrift/Protocols/TCompactProtocol.cs create mode 100644 lib/netcore/Thrift/Protocols/TJSONProtocol.cs create mode 100644 lib/netcore/Thrift/Protocols/TMultiplexedProtocol.cs create mode 100644 lib/netcore/Thrift/Protocols/TProtocol.cs create mode 100644 lib/netcore/Thrift/Protocols/TProtocolDecorator.cs create mode 100644 lib/netcore/Thrift/Protocols/TProtocolException.cs create mode 100644 lib/netcore/Thrift/Protocols/Utilities/TBase64Utils.cs create mode 100644 lib/netcore/Thrift/Protocols/Utilities/TProtocolUtil.cs create mode 100644 lib/netcore/Thrift/Server/AsyncBaseServer.cs create mode 100644 lib/netcore/Thrift/Server/TBaseServer.cs create mode 100644 lib/netcore/Thrift/Server/TServerEventHandler.cs create mode 100644 lib/netcore/Thrift/SingletonTProcessorFactory.cs create mode 100644 lib/netcore/Thrift/TApplicationException.cs create mode 100644 lib/netcore/Thrift/TBaseClient.cs create mode 100644 lib/netcore/Thrift/TException.cs create mode 100644 lib/netcore/Thrift/TMultiplexedProcessor.cs create mode 100644 lib/netcore/Thrift/Thrift.csproj create mode 100644 lib/netcore/Thrift/Transports/Client/TBufferedClientTransport.cs create mode 100644 lib/netcore/Thrift/Transports/Client/TFramedClientTransport.cs create mode 100644 lib/netcore/Thrift/Transports/Client/THttpClientTransport.cs create mode 100644 lib/netcore/Thrift/Transports/Client/TMemoryBufferClientTransport.cs create mode 100644 lib/netcore/Thrift/Transports/Client/TNamedPipeClientTransport.cs create mode 100644 lib/netcore/Thrift/Transports/Client/TSocketClientTransport.cs create mode 100644 lib/netcore/Thrift/Transports/Client/TStreamClientTransport.cs create mode 100644 lib/netcore/Thrift/Transports/Client/TTlsSocketClientTransport.cs create mode 100644 lib/netcore/Thrift/Transports/Server/THttpServerTransport.cs create mode 100644 lib/netcore/Thrift/Transports/Server/TNamedPipeServerTransport.cs create mode 100644 lib/netcore/Thrift/Transports/Server/TServerFramedTransport.cs create mode 100644 lib/netcore/Thrift/Transports/Server/TServerSocketTransport.cs create mode 100644 lib/netcore/Thrift/Transports/Server/TTlsServerSocketTransport.cs create mode 100644 lib/netcore/Thrift/Transports/TClientTransport.cs create mode 100644 lib/netcore/Thrift/Transports/TServerTransport.cs create mode 100644 lib/netcore/Thrift/Transports/TTransportException.cs create mode 100644 lib/netcore/Thrift/Transports/TTransportFactory.cs create mode 100755 lib/nodejs/Makefile.am create mode 100644 lib/nodejs/Makefile.in create mode 100644 lib/nodejs/README.md create mode 100644 lib/nodejs/coding_standards.md create mode 100644 lib/nodejs/examples/Makefile create mode 100644 lib/nodejs/examples/README.md create mode 100644 lib/nodejs/examples/client.js create mode 100644 lib/nodejs/examples/client_multitransport.js create mode 100644 lib/nodejs/examples/hello.html create mode 100644 lib/nodejs/examples/hello.js create mode 100644 lib/nodejs/examples/hello.thrift create mode 100644 lib/nodejs/examples/httpClient.js create mode 100644 lib/nodejs/examples/httpServer.js create mode 100644 lib/nodejs/examples/httpServer.py create mode 100644 lib/nodejs/examples/parse.js create mode 100644 lib/nodejs/examples/server.js create mode 100644 lib/nodejs/examples/server_http.js create mode 100644 lib/nodejs/examples/server_multitransport.js create mode 100644 lib/nodejs/examples/user.thrift create mode 100644 lib/nodejs/lib/thrift/binary.js create mode 100644 lib/nodejs/lib/thrift/binary_protocol.js create mode 100644 lib/nodejs/lib/thrift/browser.js create mode 100644 lib/nodejs/lib/thrift/buffered_transport.js create mode 100644 lib/nodejs/lib/thrift/compact_protocol.js create mode 100644 lib/nodejs/lib/thrift/connection.js create mode 100644 lib/nodejs/lib/thrift/create_client.js create mode 100644 lib/nodejs/lib/thrift/framed_transport.js create mode 100644 lib/nodejs/lib/thrift/http_connection.js create mode 100644 lib/nodejs/lib/thrift/index.js create mode 100644 lib/nodejs/lib/thrift/input_buffer_underrun_error.js create mode 100644 lib/nodejs/lib/thrift/int64_util.js create mode 100644 lib/nodejs/lib/thrift/json_parse.js create mode 100644 lib/nodejs/lib/thrift/json_protocol.js create mode 100644 lib/nodejs/lib/thrift/log.js create mode 100644 lib/nodejs/lib/thrift/multiplexed_processor.js create mode 100644 lib/nodejs/lib/thrift/multiplexed_protocol.js create mode 100644 lib/nodejs/lib/thrift/protocol.js create mode 100644 lib/nodejs/lib/thrift/server.js create mode 100644 lib/nodejs/lib/thrift/thrift.js create mode 100644 lib/nodejs/lib/thrift/transport.js create mode 100644 lib/nodejs/lib/thrift/web_server.js create mode 100644 lib/nodejs/lib/thrift/ws_connection.js create mode 100644 lib/nodejs/lib/thrift/ws_transport.js create mode 100644 lib/nodejs/lib/thrift/xhr_connection.js create mode 100644 lib/nodejs/test/binary.test.js create mode 100644 lib/nodejs/test/browser_client.js create mode 100644 lib/nodejs/test/certificates.README create mode 100644 lib/nodejs/test/client.js create mode 100644 lib/nodejs/test/deep-constructor.test.js create mode 100644 lib/nodejs/test/exceptions.js create mode 100644 lib/nodejs/test/helpers.js create mode 100644 lib/nodejs/test/server.crt create mode 100644 lib/nodejs/test/server.js create mode 100644 lib/nodejs/test/server.key create mode 100644 lib/nodejs/test/test-cases.js create mode 100755 lib/nodejs/test/testAll.sh create mode 100644 lib/nodejs/test/test_driver.js create mode 100644 lib/nodejs/test/test_handler.js create mode 100644 lib/ocaml/DEVELOPMENT create mode 100644 lib/ocaml/README.md create mode 100644 lib/ocaml/TODO create mode 100644 lib/ocaml/_oasis create mode 100644 lib/ocaml/coding_standards.md create mode 100644 lib/ocaml/descr create mode 100644 lib/ocaml/opam create mode 100644 lib/ocaml/src/Makefile create mode 100644 lib/ocaml/src/TBinaryProtocol.ml create mode 100644 lib/ocaml/src/TChannelTransport.ml create mode 100644 lib/ocaml/src/TFramedTransport.ml create mode 100644 lib/ocaml/src/TServer.ml create mode 100644 lib/ocaml/src/TServerSocket.ml create mode 100644 lib/ocaml/src/TSimpleServer.ml create mode 100644 lib/ocaml/src/TSocket.ml create mode 100644 lib/ocaml/src/TThreadedServer.ml create mode 100644 lib/ocaml/src/Thrift.ml create mode 100644 lib/ocaml/url create mode 100644 lib/perl/Makefile.PL create mode 100644 lib/perl/Makefile.am create mode 100644 lib/perl/Makefile.in create mode 100644 lib/perl/README.md create mode 100755 lib/perl/build-cpan-dist.sh create mode 100644 lib/perl/coding_standards.md create mode 100644 lib/perl/lib/Thrift.pm create mode 100644 lib/perl/lib/Thrift/BinaryProtocol.pm create mode 100644 lib/perl/lib/Thrift/BufferedTransport.pm create mode 100644 lib/perl/lib/Thrift/Exception.pm create mode 100644 lib/perl/lib/Thrift/FramedTransport.pm create mode 100644 lib/perl/lib/Thrift/HttpClient.pm create mode 100644 lib/perl/lib/Thrift/MemoryBuffer.pm create mode 100644 lib/perl/lib/Thrift/MessageType.pm create mode 100644 lib/perl/lib/Thrift/MultiplexedProcessor.pm create mode 100644 lib/perl/lib/Thrift/MultiplexedProtocol.pm create mode 100644 lib/perl/lib/Thrift/Protocol.pm create mode 100644 lib/perl/lib/Thrift/ProtocolDecorator.pm create mode 100644 lib/perl/lib/Thrift/SSLServerSocket.pm create mode 100644 lib/perl/lib/Thrift/SSLSocket.pm create mode 100644 lib/perl/lib/Thrift/Server.pm create mode 100644 lib/perl/lib/Thrift/ServerSocket.pm create mode 100644 lib/perl/lib/Thrift/Socket.pm create mode 100644 lib/perl/lib/Thrift/Transport.pm create mode 100644 lib/perl/lib/Thrift/Type.pm create mode 100644 lib/perl/lib/Thrift/UnixServerSocket.pm create mode 100644 lib/perl/lib/Thrift/UnixSocket.pm create mode 100644 lib/perl/test.pl create mode 100644 lib/perl/test/Makefile.am create mode 100644 lib/perl/test/Makefile.in create mode 100644 lib/perl/test/memory_buffer.t create mode 100644 lib/perl/test/multiplex.t create mode 100644 lib/perl/test/processor.t create mode 100755 lib/php/Makefile.am create mode 100644 lib/php/Makefile.in create mode 100644 lib/php/README.apache.md create mode 100644 lib/php/README.md create mode 100644 lib/php/coding_standards.md create mode 100644 lib/php/lib/Thrift/Base/TBase.php create mode 100644 lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php create mode 100644 lib/php/lib/Thrift/Exception/TApplicationException.php create mode 100644 lib/php/lib/Thrift/Exception/TException.php create mode 100644 lib/php/lib/Thrift/Exception/TProtocolException.php create mode 100644 lib/php/lib/Thrift/Exception/TTransportException.php create mode 100644 lib/php/lib/Thrift/Factory/TBinaryProtocolFactory.php create mode 100644 lib/php/lib/Thrift/Factory/TCompactProtocolFactory.php create mode 100644 lib/php/lib/Thrift/Factory/TJSONProtocolFactory.php create mode 100644 lib/php/lib/Thrift/Factory/TProtocolFactory.php create mode 100644 lib/php/lib/Thrift/Factory/TStringFuncFactory.php create mode 100644 lib/php/lib/Thrift/Factory/TTransportFactory.php create mode 100644 lib/php/lib/Thrift/Protocol/JSON/BaseContext.php create mode 100644 lib/php/lib/Thrift/Protocol/JSON/ListContext.php create mode 100644 lib/php/lib/Thrift/Protocol/JSON/LookaheadReader.php create mode 100644 lib/php/lib/Thrift/Protocol/JSON/PairContext.php create mode 100644 lib/php/lib/Thrift/Protocol/SimpleJSON/CollectionMapKeyException.php create mode 100644 lib/php/lib/Thrift/Protocol/SimpleJSON/Context.php create mode 100644 lib/php/lib/Thrift/Protocol/SimpleJSON/ListContext.php create mode 100644 lib/php/lib/Thrift/Protocol/SimpleJSON/MapContext.php create mode 100644 lib/php/lib/Thrift/Protocol/SimpleJSON/StructContext.php create mode 100644 lib/php/lib/Thrift/Protocol/TBinaryProtocol.php create mode 100644 lib/php/lib/Thrift/Protocol/TBinaryProtocolAccelerated.php create mode 100644 lib/php/lib/Thrift/Protocol/TCompactProtocol.php create mode 100644 lib/php/lib/Thrift/Protocol/TJSONProtocol.php create mode 100644 lib/php/lib/Thrift/Protocol/TMultiplexedProtocol.php create mode 100644 lib/php/lib/Thrift/Protocol/TProtocol.php create mode 100644 lib/php/lib/Thrift/Protocol/TProtocolDecorator.php create mode 100644 lib/php/lib/Thrift/Protocol/TSimpleJSONProtocol.php create mode 100644 lib/php/lib/Thrift/Serializer/TBinarySerializer.php create mode 100644 lib/php/lib/Thrift/Server/TForkingServer.php create mode 100644 lib/php/lib/Thrift/Server/TSSLServerSocket.php create mode 100644 lib/php/lib/Thrift/Server/TServer.php create mode 100644 lib/php/lib/Thrift/Server/TServerSocket.php create mode 100644 lib/php/lib/Thrift/Server/TServerTransport.php create mode 100644 lib/php/lib/Thrift/Server/TSimpleServer.php create mode 100644 lib/php/lib/Thrift/StringFunc/Core.php create mode 100644 lib/php/lib/Thrift/StringFunc/Mbstring.php create mode 100644 lib/php/lib/Thrift/StringFunc/TStringFunc.php create mode 100644 lib/php/lib/Thrift/TMultiplexedProcessor.php create mode 100644 lib/php/lib/Thrift/Transport/TBufferedTransport.php create mode 100644 lib/php/lib/Thrift/Transport/TCurlClient.php create mode 100644 lib/php/lib/Thrift/Transport/TFramedTransport.php create mode 100644 lib/php/lib/Thrift/Transport/THttpClient.php create mode 100644 lib/php/lib/Thrift/Transport/TMemoryBuffer.php create mode 100644 lib/php/lib/Thrift/Transport/TNullTransport.php create mode 100644 lib/php/lib/Thrift/Transport/TPhpStream.php create mode 100644 lib/php/lib/Thrift/Transport/TSSLSocket.php create mode 100644 lib/php/lib/Thrift/Transport/TSocket.php create mode 100644 lib/php/lib/Thrift/Transport/TSocketPool.php create mode 100644 lib/php/lib/Thrift/Transport/TTransport.php create mode 100644 lib/php/lib/Thrift/Type/TConstant.php create mode 100644 lib/php/lib/Thrift/Type/TMessageType.php create mode 100644 lib/php/lib/Thrift/Type/TType.php create mode 100644 lib/php/src/TStringUtils.php create mode 100644 lib/php/src/Thrift.php create mode 100644 lib/php/src/autoload.php create mode 100644 lib/php/src/ext/thrift_protocol/config.m4 create mode 100644 lib/php/src/ext/thrift_protocol/config.w32 create mode 100644 lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp create mode 100644 lib/php/src/ext/thrift_protocol/php_thrift_protocol.h create mode 100644 lib/php/src/ext/thrift_protocol/run-tests.php create mode 100755 lib/php/test/Makefile.am create mode 100644 lib/php/test/Makefile.in create mode 100644 lib/php/test/Test/Thrift/Fixtures.php create mode 100644 lib/php/test/Test/Thrift/JsonSerialize/JsonSerializeTest.php create mode 100644 lib/php/test/Test/Thrift/Protocol/TestBinarySerializer.php create mode 100755 lib/php/test/Test/Thrift/Protocol/TestTJSONProtocol.php create mode 100755 lib/php/test/Test/Thrift/Protocol/TestTSimpleJSONProtocol.php create mode 100644 lib/php/test/Test/Thrift/TestValidators.php create mode 100644 lib/php/test/TestValidators.thrift create mode 100644 lib/php/thrift_protocol.ini create mode 100644 lib/py/CMakeLists.txt create mode 100644 lib/py/MANIFEST.in create mode 100644 lib/py/Makefile.am create mode 100644 lib/py/Makefile.in create mode 100644 lib/py/README.md create mode 100644 lib/py/coding_standards.md create mode 100644 lib/py/compat/win32/stdint.h create mode 100644 lib/py/setup.cfg create mode 100644 lib/py/setup.py create mode 100644 lib/py/src/TMultiplexedProcessor.py create mode 100644 lib/py/src/TRecursive.py create mode 100644 lib/py/src/TSCons.py create mode 100644 lib/py/src/TSerialization.py create mode 100644 lib/py/src/TTornado.py create mode 100644 lib/py/src/Thrift.py create mode 100644 lib/py/src/__init__.py create mode 100644 lib/py/src/compat.py create mode 100644 lib/py/src/ext/binary.cpp create mode 100644 lib/py/src/ext/binary.h create mode 100644 lib/py/src/ext/compact.cpp create mode 100644 lib/py/src/ext/compact.h create mode 100644 lib/py/src/ext/endian.h create mode 100644 lib/py/src/ext/module.cpp create mode 100644 lib/py/src/ext/protocol.h create mode 100644 lib/py/src/ext/protocol.tcc create mode 100644 lib/py/src/ext/types.cpp create mode 100644 lib/py/src/ext/types.h create mode 100644 lib/py/src/protocol/TBase.py create mode 100644 lib/py/src/protocol/TBinaryProtocol.py create mode 100644 lib/py/src/protocol/TCompactProtocol.py create mode 100644 lib/py/src/protocol/TJSONProtocol.py create mode 100644 lib/py/src/protocol/TMultiplexedProtocol.py create mode 100644 lib/py/src/protocol/TProtocol.py create mode 100644 lib/py/src/protocol/TProtocolDecorator.py create mode 100644 lib/py/src/protocol/__init__.py create mode 100644 lib/py/src/server/THttpServer.py create mode 100644 lib/py/src/server/TNonblockingServer.py create mode 100644 lib/py/src/server/TProcessPoolServer.py create mode 100644 lib/py/src/server/TServer.py create mode 100644 lib/py/src/server/__init__.py create mode 100644 lib/py/src/transport/THttpClient.py create mode 100644 lib/py/src/transport/TSSLSocket.py create mode 100644 lib/py/src/transport/TSocket.py create mode 100644 lib/py/src/transport/TTransport.py create mode 100644 lib/py/src/transport/TTwisted.py create mode 100644 lib/py/src/transport/TZlibTransport.py create mode 100644 lib/py/src/transport/__init__.py create mode 100644 lib/py/src/transport/sslcompat.py create mode 100644 lib/py/test/_import_local_thrift.py create mode 100644 lib/py/test/test_sslsocket.py create mode 100644 lib/py/test/thrift_json.py create mode 100644 lib/rb/Gemfile create mode 100755 lib/rb/Makefile.am create mode 100644 lib/rb/Makefile.in create mode 100644 lib/rb/README.md create mode 100644 lib/rb/Rakefile create mode 100644 lib/rb/benchmark/Benchmark.thrift create mode 100644 lib/rb/benchmark/benchmark.rb create mode 100644 lib/rb/benchmark/client.rb create mode 100644 lib/rb/benchmark/server.rb create mode 100644 lib/rb/benchmark/thin_server.rb create mode 100644 lib/rb/coding_standards.md create mode 100644 lib/rb/ext/binary_protocol_accelerated.c create mode 100644 lib/rb/ext/binary_protocol_accelerated.h create mode 100644 lib/rb/ext/bytes.c create mode 100644 lib/rb/ext/bytes.h create mode 100644 lib/rb/ext/compact_protocol.c create mode 100644 lib/rb/ext/compact_protocol.h create mode 100644 lib/rb/ext/constants.h create mode 100644 lib/rb/ext/extconf.rb create mode 100644 lib/rb/ext/macros.h create mode 100644 lib/rb/ext/memory_buffer.c create mode 100644 lib/rb/ext/memory_buffer.h create mode 100644 lib/rb/ext/protocol.c create mode 100644 lib/rb/ext/protocol.h create mode 100644 lib/rb/ext/strlcpy.c create mode 100644 lib/rb/ext/strlcpy.h create mode 100644 lib/rb/ext/struct.c create mode 100644 lib/rb/ext/struct.h create mode 100644 lib/rb/ext/thrift_native.c create mode 100644 lib/rb/lib/thrift.rb create mode 100644 lib/rb/lib/thrift/bytes.rb create mode 100644 lib/rb/lib/thrift/client.rb create mode 100644 lib/rb/lib/thrift/core_ext.rb create mode 100644 lib/rb/lib/thrift/core_ext/fixnum.rb create mode 100644 lib/rb/lib/thrift/exceptions.rb create mode 100644 lib/rb/lib/thrift/multiplexed_processor.rb create mode 100644 lib/rb/lib/thrift/processor.rb create mode 100644 lib/rb/lib/thrift/protocol/base_protocol.rb create mode 100644 lib/rb/lib/thrift/protocol/binary_protocol.rb create mode 100644 lib/rb/lib/thrift/protocol/binary_protocol_accelerated.rb create mode 100644 lib/rb/lib/thrift/protocol/compact_protocol.rb create mode 100644 lib/rb/lib/thrift/protocol/json_protocol.rb create mode 100644 lib/rb/lib/thrift/protocol/multiplexed_protocol.rb create mode 100644 lib/rb/lib/thrift/protocol/protocol_decorator.rb create mode 100644 lib/rb/lib/thrift/serializer/deserializer.rb create mode 100644 lib/rb/lib/thrift/serializer/serializer.rb create mode 100644 lib/rb/lib/thrift/server/base_server.rb create mode 100644 lib/rb/lib/thrift/server/mongrel_http_server.rb create mode 100644 lib/rb/lib/thrift/server/nonblocking_server.rb create mode 100644 lib/rb/lib/thrift/server/simple_server.rb create mode 100644 lib/rb/lib/thrift/server/thin_http_server.rb create mode 100644 lib/rb/lib/thrift/server/thread_pool_server.rb create mode 100644 lib/rb/lib/thrift/server/threaded_server.rb create mode 100644 lib/rb/lib/thrift/struct.rb create mode 100644 lib/rb/lib/thrift/struct_union.rb create mode 100644 lib/rb/lib/thrift/thrift_native.rb create mode 100644 lib/rb/lib/thrift/transport/base_server_transport.rb create mode 100644 lib/rb/lib/thrift/transport/base_transport.rb create mode 100644 lib/rb/lib/thrift/transport/buffered_transport.rb create mode 100644 lib/rb/lib/thrift/transport/framed_transport.rb create mode 100644 lib/rb/lib/thrift/transport/http_client_transport.rb create mode 100644 lib/rb/lib/thrift/transport/io_stream_transport.rb create mode 100644 lib/rb/lib/thrift/transport/memory_buffer_transport.rb create mode 100644 lib/rb/lib/thrift/transport/server_socket.rb create mode 100644 lib/rb/lib/thrift/transport/socket.rb create mode 100644 lib/rb/lib/thrift/transport/ssl_server_socket.rb create mode 100644 lib/rb/lib/thrift/transport/ssl_socket.rb create mode 100644 lib/rb/lib/thrift/transport/unix_server_socket.rb create mode 100644 lib/rb/lib/thrift/transport/unix_socket.rb create mode 100644 lib/rb/lib/thrift/types.rb create mode 100644 lib/rb/lib/thrift/union.rb create mode 100644 lib/rb/script/proto_benchmark.rb create mode 100644 lib/rb/script/read_struct.rb create mode 100644 lib/rb/script/write_struct.rb create mode 100644 lib/rb/spec/BaseService.thrift create mode 100644 lib/rb/spec/ExtendedService.thrift create mode 100644 lib/rb/spec/Referenced.thrift create mode 100644 lib/rb/spec/ThriftNamespacedSpec.thrift create mode 100644 lib/rb/spec/ThriftSpec.thrift create mode 100644 lib/rb/spec/base_protocol_spec.rb create mode 100644 lib/rb/spec/base_transport_spec.rb create mode 100644 lib/rb/spec/binary_protocol_accelerated_spec.rb create mode 100644 lib/rb/spec/binary_protocol_spec.rb create mode 100644 lib/rb/spec/binary_protocol_spec_shared.rb create mode 100644 lib/rb/spec/bytes_spec.rb create mode 100644 lib/rb/spec/client_spec.rb create mode 100644 lib/rb/spec/compact_protocol_spec.rb create mode 100644 lib/rb/spec/exception_spec.rb create mode 100644 lib/rb/spec/flat_spec.rb create mode 100644 lib/rb/spec/http_client_spec.rb create mode 100644 lib/rb/spec/json_protocol_spec.rb create mode 100644 lib/rb/spec/namespaced_spec.rb create mode 100644 lib/rb/spec/nonblocking_server_spec.rb create mode 100644 lib/rb/spec/processor_spec.rb create mode 100644 lib/rb/spec/serializer_spec.rb create mode 100644 lib/rb/spec/server_socket_spec.rb create mode 100644 lib/rb/spec/server_spec.rb create mode 100644 lib/rb/spec/socket_spec.rb create mode 100644 lib/rb/spec/socket_spec_shared.rb create mode 100644 lib/rb/spec/spec_helper.rb create mode 100644 lib/rb/spec/ssl_socket_spec.rb create mode 100644 lib/rb/spec/struct_nested_containers_spec.rb create mode 100644 lib/rb/spec/struct_spec.rb create mode 100644 lib/rb/spec/thin_http_server_spec.rb create mode 100644 lib/rb/spec/types_spec.rb create mode 100644 lib/rb/spec/union_spec.rb create mode 100644 lib/rb/spec/unix_socket_spec.rb create mode 100644 lib/rb/thrift.gemspec create mode 100644 lib/rs/Cargo.toml create mode 100644 lib/rs/Makefile.am create mode 100644 lib/rs/Makefile.in create mode 100644 lib/rs/README.md create mode 100644 lib/rs/src/autogen.rs create mode 100644 lib/rs/src/errors.rs create mode 100644 lib/rs/src/lib.rs create mode 100644 lib/rs/src/protocol/binary.rs create mode 100644 lib/rs/src/protocol/compact.rs create mode 100644 lib/rs/src/protocol/mod.rs create mode 100644 lib/rs/src/protocol/multiplexed.rs create mode 100644 lib/rs/src/protocol/stored.rs create mode 100644 lib/rs/src/server/mod.rs create mode 100644 lib/rs/src/server/multiplexed.rs create mode 100644 lib/rs/src/server/threaded.rs create mode 100644 lib/rs/src/transport/buffered.rs create mode 100644 lib/rs/src/transport/framed.rs create mode 100644 lib/rs/src/transport/mem.rs create mode 100644 lib/rs/src/transport/mod.rs create mode 100644 lib/rs/src/transport/socket.rs create mode 100644 lib/rs/test/Cargo.toml create mode 100644 lib/rs/test/Makefile.am create mode 100644 lib/rs/test/Makefile.in create mode 100644 lib/rs/test/src/bin/kitchen_sink_client.rs create mode 100644 lib/rs/test/src/bin/kitchen_sink_server.rs create mode 100644 lib/rs/test/src/lib.rs create mode 100644 lib/rs/test/thrifts/Base_One.thrift create mode 100644 lib/rs/test/thrifts/Base_Two.thrift create mode 100644 lib/rs/test/thrifts/Midlayer.thrift create mode 100644 lib/rs/test/thrifts/Ultimate.thrift create mode 100644 lib/st/README.md create mode 100644 lib/st/coding_standards.md create mode 100644 lib/st/package.xml create mode 100644 lib/st/thrift.st create mode 100644 lib/ts/coding_standards.md create mode 100644 lib/ts/thrift.d.ts create mode 100644 lib/xml/Makefile.am create mode 100644 lib/xml/Makefile.in create mode 100644 lib/xml/test/Makefile create mode 100644 lib/xml/test/Makefile.am create mode 100644 lib/xml/test/Makefile.in create mode 100644 lib/xml/test/build.xml create mode 100644 lib/xml/thrift-idl.xsd create mode 100644 ltmain.sh create mode 100755 missing create mode 100644 package.json create mode 100755 sonar-project.properties create mode 100644 test/AnnotationTest.thrift create mode 100644 test/BrokenConstants.thrift create mode 100644 test/ConstantsDemo.thrift create mode 100644 test/DebugProtoTest.thrift create mode 100644 test/DenseLinkingTest.thrift create mode 100644 test/DocTest.thrift create mode 100644 test/EnumContainersTest.thrift create mode 100644 test/EnumTest.thrift create mode 100644 test/FullCamelTest.thrift create mode 100644 test/Include.thrift create mode 100644 test/JavaBeansTest.thrift create mode 100644 test/JavaDeepCopyTest.thrift create mode 100644 test/JavaTypes.thrift create mode 100644 test/JsDeepConstructorTest.thrift create mode 100755 test/Makefile.am create mode 100644 test/Makefile.in create mode 100644 test/ManyOptionals.thrift create mode 100644 test/ManyTypedefs.thrift create mode 100644 test/NameConflictTest.thrift create mode 100644 test/OptionalRequiredTest.thrift create mode 100755 test/README.md create mode 100644 test/Recursive.thrift create mode 100644 test/ReuseObjects.thrift create mode 100644 test/SmallTest.thrift create mode 100644 test/StressTest.thrift create mode 100644 test/ThriftTest.thrift create mode 100644 test/TypedefTest.thrift create mode 100644 test/audit/README.md create mode 100644 test/audit/break1.thrift create mode 100644 test/audit/break10.thrift create mode 100644 test/audit/break11.thrift create mode 100644 test/audit/break12.thrift create mode 100644 test/audit/break13.thrift create mode 100644 test/audit/break14.thrift create mode 100644 test/audit/break15.thrift create mode 100644 test/audit/break16.thrift create mode 100644 test/audit/break17.thrift create mode 100644 test/audit/break18.thrift create mode 100644 test/audit/break19.thrift create mode 100644 test/audit/break2.thrift create mode 100644 test/audit/break20.thrift create mode 100644 test/audit/break21.thrift create mode 100644 test/audit/break22.thrift create mode 100644 test/audit/break23.thrift create mode 100644 test/audit/break24.thrift create mode 100644 test/audit/break25.thrift create mode 100644 test/audit/break26.thrift create mode 100644 test/audit/break27.thrift create mode 100644 test/audit/break28.thrift create mode 100644 test/audit/break29.thrift create mode 100644 test/audit/break3.thrift create mode 100644 test/audit/break30.thrift create mode 100644 test/audit/break31.thrift create mode 100644 test/audit/break32.thrift create mode 100644 test/audit/break33.thrift create mode 100644 test/audit/break34.thrift create mode 100644 test/audit/break4.thrift create mode 100644 test/audit/break5.thrift create mode 100644 test/audit/break6.thrift create mode 100644 test/audit/break7.thrift create mode 100644 test/audit/break8.thrift create mode 100644 test/audit/break9.thrift create mode 100644 test/audit/test.thrift create mode 100644 test/audit/thrift_audit_test.pl create mode 100644 test/audit/warning.thrift create mode 100644 test/c_glib/Makefile create mode 100755 test/c_glib/Makefile.am create mode 100644 test/c_glib/Makefile.in create mode 100644 test/c_glib/src/test_client.c create mode 100644 test/c_glib/src/test_server.c create mode 100644 test/c_glib/src/thrift_second_service_handler.c create mode 100644 test/c_glib/src/thrift_second_service_handler.h create mode 100644 test/c_glib/src/thrift_test_handler.c create mode 100644 test/c_glib/src/thrift_test_handler.h create mode 100755 test/cpp/CMakeLists.txt create mode 100644 test/cpp/Makefile create mode 100755 test/cpp/Makefile.am create mode 100644 test/cpp/Makefile.in create mode 100644 test/cpp/src/StressTest.cpp create mode 100644 test/cpp/src/StressTestNonBlocking.cpp create mode 100644 test/cpp/src/TestClient.cpp create mode 100644 test/cpp/src/TestServer.cpp create mode 100644 test/cpp/src/ThriftTest_extras.cpp create mode 100644 test/crossrunner/__init__.py create mode 100644 test/crossrunner/collect.py create mode 100644 test/crossrunner/compat.py create mode 100644 test/crossrunner/report.py create mode 100644 test/crossrunner/run.py create mode 100644 test/crossrunner/setup.cfg create mode 100644 test/crossrunner/test.py create mode 100644 test/crossrunner/util.py create mode 100644 test/csharp/Makefile.am create mode 100644 test/csharp/Makefile.in create mode 100644 test/csharp/Program.cs create mode 100644 test/csharp/Properties/AssemblyInfo.cs create mode 100644 test/csharp/TestClient.cs create mode 100644 test/csharp/TestServer.cs create mode 100644 test/csharp/ThriftTest.csproj create mode 100644 test/csharp/ThriftTest.sln create mode 100644 test/dart/Makefile create mode 100644 test/dart/Makefile.am create mode 100644 test/dart/Makefile.in create mode 100644 test/dart/test_client/.analysis_options create mode 100644 test/dart/test_client/bin/main.dart create mode 100644 test/dart/test_client/pubspec.yaml create mode 100644 test/erl/Makefile create mode 100644 test/erl/Makefile.am create mode 100644 test/erl/Makefile.in create mode 100644 test/erl/rebar.config create mode 100644 test/erl/src/test_client.erl create mode 100644 test/erl/src/test_thrift_server.erl create mode 100644 test/erl/src/thrift_test.app.src create mode 100644 test/features/Makefile.am create mode 100644 test/features/Makefile.in create mode 100644 test/features/container_limit.py create mode 100644 test/features/index.html create mode 100644 test/features/known_failures_Linux.json create mode 100644 test/features/local_thrift/__init__.py create mode 100755 test/features/nosslv3.sh create mode 100644 test/features/setup.cfg create mode 100644 test/features/string_limit.py create mode 100644 test/features/tests.json create mode 100644 test/features/theader_binary.py create mode 100755 test/features/tls.sh create mode 100644 test/features/util.py create mode 100644 test/go/Makefile.am create mode 100644 test/go/Makefile.in create mode 100644 test/go/src/bin/stress/go17.go create mode 100644 test/go/src/bin/stress/main.go create mode 100644 test/go/src/bin/stress/pre_go17.go create mode 100644 test/go/src/bin/testclient/go17.go create mode 100644 test/go/src/bin/testclient/main.go create mode 100644 test/go/src/bin/testclient/pre_go17.go create mode 100644 test/go/src/bin/testserver/main.go create mode 100644 test/go/src/common/client.go create mode 100644 test/go/src/common/clientserver_test.go create mode 100644 test/go/src/common/go17.go create mode 100644 test/go/src/common/pre_go17.go create mode 100644 test/go/src/common/printing_handler.go create mode 100644 test/go/src/common/printing_handler_go17.go create mode 100644 test/go/src/common/server.go create mode 100644 test/go/src/common/simple_handler.go create mode 100644 test/haxe/Makefile.am create mode 100644 test/haxe/Makefile.in create mode 100644 test/haxe/TestClientServer.hxproj create mode 100644 test/haxe/cpp.hxml create mode 100644 test/haxe/csharp.hxml create mode 100644 test/haxe/flash.hxml create mode 100644 test/haxe/java.hxml create mode 100644 test/haxe/javascript.hxml create mode 100644 test/haxe/make_all.bat create mode 100644 test/haxe/make_all.sh create mode 100644 test/haxe/neko.hxml create mode 100644 test/haxe/php-web-server.hxml create mode 100644 test/haxe/php.hxml create mode 100644 test/haxe/project.hide create mode 100644 test/haxe/python.hxml create mode 100644 test/haxe/router.php create mode 100644 test/haxe/src/Arguments.hx create mode 100644 test/haxe/src/Main.hx create mode 100644 test/haxe/src/TestClient.hx create mode 100644 test/haxe/src/TestMacro.hx create mode 100644 test/haxe/src/TestServer.hx create mode 100644 test/haxe/src/TestServerEventHandler.hx create mode 100644 test/haxe/src/TestServerHandler.hx create mode 100644 test/hs/CMakeLists.txt create mode 100644 test/hs/ConstantsDemo_Main.hs create mode 100644 test/hs/DebugProtoTest_Main.hs create mode 100644 test/hs/Include_Main.hs create mode 100644 test/hs/Makefile create mode 100644 test/hs/Makefile.am create mode 100644 test/hs/Makefile.in create mode 100644 test/hs/TestClient.hs create mode 100644 test/hs/TestServer.hs create mode 100644 test/hs/ThriftTestUtils.hs create mode 100644 test/hs/ThriftTest_Main.hs create mode 100755 test/hs/run-test.sh create mode 100644 test/index.html create mode 100644 test/keys/CA.pem create mode 100755 test/keys/README.md create mode 100644 test/keys/client.crt create mode 100644 test/keys/client.key create mode 100644 test/keys/client.p12 create mode 100644 test/keys/client.pem create mode 100644 test/keys/client_v3.crt create mode 100644 test/keys/client_v3.key create mode 100644 test/keys/server.crt create mode 100644 test/keys/server.key create mode 100644 test/keys/server.p12 create mode 100644 test/keys/server.pem create mode 100644 test/known_failures_Linux.json create mode 100644 test/lua/Makefile create mode 100644 test/lua/Makefile.am create mode 100644 test/lua/Makefile.in create mode 100644 test/lua/test_basic_client.lua create mode 100644 test/lua/test_basic_server.lua create mode 100644 test/netcore/Makefile.am create mode 100644 test/netcore/Makefile.in create mode 100644 test/netcore/README.md create mode 100644 test/netcore/ThriftTest.sln create mode 100644 test/netcore/ThriftTest/Program.cs create mode 100644 test/netcore/ThriftTest/Properties/AssemblyInfo.cs create mode 100644 test/netcore/ThriftTest/Properties/launchSettings.json create mode 100644 test/netcore/ThriftTest/TestClient.cs create mode 100644 test/netcore/ThriftTest/TestServer.cs create mode 100644 test/netcore/ThriftTest/ThriftTest.csproj create mode 100644 test/netcore/build.cmd create mode 100755 test/netcore/build.sh create mode 100644 test/ocaml/Makefile create mode 100644 test/ocaml/client/Makefile create mode 100644 test/ocaml/client/TestClient.ml create mode 100644 test/ocaml/server/Makefile create mode 100644 test/ocaml/server/TestServer.ml create mode 100644 test/perl/Makefile create mode 100644 test/perl/Makefile.am create mode 100644 test/perl/Makefile.in create mode 100755 test/perl/TestClient.pl create mode 100644 test/perl/TestServer.pl create mode 100644 test/php/Makefile create mode 100755 test/php/Makefile.am create mode 100644 test/php/Makefile.in create mode 100755 test/php/TestClient.php create mode 100644 test/php/TestInline.php create mode 100644 test/php/TestPsr4.php create mode 100644 test/php/test_php.ini create mode 100644 test/py.tornado/Makefile create mode 100644 test/py.tornado/Makefile.am create mode 100644 test/py.tornado/Makefile.in create mode 100644 test/py.tornado/setup.cfg create mode 100755 test/py.tornado/test_suite.py create mode 100644 test/py.twisted/Makefile create mode 100644 test/py.twisted/Makefile.am create mode 100644 test/py.twisted/Makefile.in create mode 100644 test/py.twisted/setup.cfg create mode 100755 test/py.twisted/test_suite.py create mode 100644 test/py/CMakeLists.txt create mode 100755 test/py/FastbinaryTest.py create mode 100644 test/py/Makefile create mode 100644 test/py/Makefile.am create mode 100644 test/py/Makefile.in create mode 100755 test/py/RunClientServer.py create mode 100755 test/py/SerializationTest.py create mode 100644 test/py/TSimpleJSONProtocolTest.py create mode 100755 test/py/TestClient.py create mode 100755 test/py/TestEof.py create mode 100755 test/py/TestFrozen.py create mode 100755 test/py/TestServer.py create mode 100755 test/py/TestSocket.py create mode 100755 test/py/TestSyntax.py create mode 100755 test/py/explicit_module/runtest.sh create mode 100644 test/py/explicit_module/test1.thrift create mode 100644 test/py/explicit_module/test2.thrift create mode 100644 test/py/explicit_module/test3.thrift create mode 100644 test/py/generate.cmake create mode 100644 test/py/setup.cfg create mode 100644 test/py/util.py create mode 100644 test/rb/Gemfile create mode 100644 test/rb/Makefile create mode 100644 test/rb/Makefile.am create mode 100644 test/rb/Makefile.in create mode 100644 test/rb/benchmarks/protocol_benchmark.rb create mode 100644 test/rb/core/test_backwards_compatability.rb create mode 100644 test/rb/core/test_exceptions.rb create mode 100644 test/rb/core/transport/test_transport.rb create mode 100644 test/rb/fixtures/structs.rb create mode 100644 test/rb/generation/test_enum.rb create mode 100644 test/rb/generation/test_struct.rb create mode 100755 test/rb/integration/TestClient.rb create mode 100755 test/rb/integration/TestServer.rb create mode 100644 test/rb/test_helper.rb create mode 100644 test/rb/test_suite.rb create mode 100644 test/rebuild_known_failures.sh create mode 100644 test/result.js create mode 100644 test/rs/Cargo.toml create mode 100644 test/rs/Makefile create mode 100644 test/rs/Makefile.am create mode 100644 test/rs/Makefile.in create mode 100644 test/rs/src/bin/test_client.rs create mode 100644 test/rs/src/bin/test_server.rs create mode 100644 test/rs/src/lib.rs create mode 100755 test/test.py create mode 100644 test/tests.json create mode 100644 test/threads/Makefile create mode 100644 test/threads/ThreadsClient.cpp create mode 100644 test/threads/ThreadsServer.cpp create mode 100644 test/threads/ThreadsTest.thrift create mode 100644 test/valgrind.suppress create mode 100755 tutorial/Makefile.am create mode 100644 tutorial/Makefile.in create mode 100644 tutorial/README.md create mode 100644 tutorial/as3/build.xml create mode 100644 tutorial/as3/src/CalculatorUI.as create mode 100755 tutorial/c_glib/Makefile.am create mode 100644 tutorial/c_glib/Makefile.in create mode 100644 tutorial/c_glib/c_glib_client.c create mode 100644 tutorial/c_glib/c_glib_server.c create mode 100644 tutorial/cpp/CMakeLists.txt create mode 100644 tutorial/cpp/CppClient.cpp create mode 100644 tutorial/cpp/CppServer.cpp create mode 100755 tutorial/cpp/Makefile.am create mode 100644 tutorial/cpp/Makefile.in create mode 100644 tutorial/csharp/CsharpClient/CsharpClient.cs create mode 100644 tutorial/csharp/CsharpClient/CsharpClient.csproj create mode 100644 tutorial/csharp/CsharpClient/Properties/AssemblyInfo.cs create mode 100644 tutorial/csharp/CsharpServer/CsharpServer.cs create mode 100644 tutorial/csharp/CsharpServer/CsharpServer.csproj create mode 100644 tutorial/csharp/CsharpServer/Properties/AssemblyInfo.cs create mode 100644 tutorial/csharp/tutorial.sln create mode 100644 tutorial/d/Makefile create mode 100644 tutorial/d/Makefile.am create mode 100644 tutorial/d/Makefile.in create mode 100644 tutorial/d/async_client.d create mode 100644 tutorial/d/client.d create mode 100644 tutorial/d/server.d create mode 100644 tutorial/dart/Makefile.am create mode 100644 tutorial/dart/Makefile.in create mode 100644 tutorial/dart/build.sh create mode 100644 tutorial/dart/client/.analysis_options create mode 100644 tutorial/dart/client/pubspec.yaml create mode 100644 tutorial/dart/client/web/client.dart create mode 100644 tutorial/dart/client/web/index.html create mode 100644 tutorial/dart/client/web/styles.css create mode 100644 tutorial/dart/console_client/.analysis_options create mode 100644 tutorial/dart/console_client/bin/main.dart create mode 100644 tutorial/dart/console_client/pubspec.yaml create mode 100644 tutorial/dart/server/.analysis_options create mode 100644 tutorial/dart/server/bin/main.dart create mode 100644 tutorial/dart/server/pubspec.yaml create mode 100644 tutorial/delphi/DelphiClient/DelphiClient.dpr create mode 100644 tutorial/delphi/DelphiClient/DelphiClient.dproj create mode 100644 tutorial/delphi/DelphiServer/DelphiServer.dpr create mode 100644 tutorial/delphi/DelphiServer/DelphiServer.dproj create mode 100644 tutorial/delphi/Tutorial.groupproj create mode 100644 tutorial/erl/README.md create mode 100644 tutorial/erl/client.erl create mode 100755 tutorial/erl/client.sh create mode 100644 tutorial/erl/json_client.erl create mode 100644 tutorial/erl/server.erl create mode 100755 tutorial/erl/server.sh create mode 100644 tutorial/go/Makefile.am create mode 100644 tutorial/go/Makefile.in create mode 100644 tutorial/go/server.crt create mode 100644 tutorial/go/server.key create mode 100644 tutorial/go/src/client.go create mode 100644 tutorial/go/src/go17.go create mode 100644 tutorial/go/src/handler.go create mode 100644 tutorial/go/src/handler_go17.go create mode 100644 tutorial/go/src/main.go create mode 100644 tutorial/go/src/pre_go17.go create mode 100644 tutorial/go/src/server.go create mode 100644 tutorial/haxe/Makefile.am create mode 100644 tutorial/haxe/Makefile.in create mode 100644 tutorial/haxe/Tutorial.hxproj create mode 100644 tutorial/haxe/cpp.hxml create mode 100644 tutorial/haxe/csharp.hxml create mode 100644 tutorial/haxe/flash.hxml create mode 100644 tutorial/haxe/java.hxml create mode 100644 tutorial/haxe/javascript.hxml create mode 100644 tutorial/haxe/make_all.bat create mode 100644 tutorial/haxe/make_all.sh create mode 100644 tutorial/haxe/neko.hxml create mode 100644 tutorial/haxe/php-web-server.hxml create mode 100644 tutorial/haxe/php.hxml create mode 100644 tutorial/haxe/project.hide create mode 100644 tutorial/haxe/python.hxml create mode 100644 tutorial/haxe/router.php create mode 100644 tutorial/haxe/src/CalculatorHandler.hx create mode 100644 tutorial/haxe/src/Main.hx create mode 100644 tutorial/hs/HaskellClient.hs create mode 100644 tutorial/hs/HaskellServer.hs create mode 100644 tutorial/hs/LICENSE create mode 100644 tutorial/hs/Makefile create mode 100755 tutorial/hs/Makefile.am create mode 100644 tutorial/hs/Makefile.in create mode 100644 tutorial/hs/Setup.lhs create mode 100755 tutorial/hs/ThriftTutorial.cabal create mode 100755 tutorial/java/Makefile.am create mode 100644 tutorial/java/Makefile.in create mode 100644 tutorial/java/README.md create mode 100644 tutorial/java/build.xml create mode 100644 tutorial/java/src/CalculatorHandler.java create mode 100644 tutorial/java/src/JavaClient.java create mode 100644 tutorial/java/src/JavaServer.java create mode 100755 tutorial/js/Makefile.am create mode 100644 tutorial/js/Makefile.in create mode 100644 tutorial/js/build.xml create mode 100644 tutorial/js/src/Httpd.java create mode 100755 tutorial/js/tutorial.html create mode 100644 tutorial/netcore/Client/Client.csproj create mode 100644 tutorial/netcore/Client/Program.cs create mode 100644 tutorial/netcore/Client/Properties/AssemblyInfo.cs create mode 100644 tutorial/netcore/Client/Properties/launchSettings.json create mode 100644 tutorial/netcore/Client/ThriftTest.pfx create mode 100644 tutorial/netcore/Interfaces/Interfaces.csproj create mode 100644 tutorial/netcore/Interfaces/Properties/AssemblyInfo.cs create mode 100644 tutorial/netcore/Makefile.am create mode 100644 tutorial/netcore/Makefile.in create mode 100644 tutorial/netcore/README.md create mode 100644 tutorial/netcore/Server/Program.cs create mode 100644 tutorial/netcore/Server/Properties/AssemblyInfo.cs create mode 100644 tutorial/netcore/Server/Properties/launchSettings.json create mode 100644 tutorial/netcore/Server/Server.csproj create mode 100644 tutorial/netcore/Server/ThriftTest.pfx create mode 100644 tutorial/netcore/Tutorial.sln create mode 100644 tutorial/netcore/build.cmd create mode 100755 tutorial/netcore/build.sh create mode 100644 tutorial/nodejs/Makefile.am create mode 100644 tutorial/nodejs/Makefile.in create mode 100644 tutorial/nodejs/NodeClient.js create mode 100644 tutorial/nodejs/NodeClientPromise.js create mode 100644 tutorial/nodejs/NodeServer.js create mode 100644 tutorial/nodejs/NodeServerPromise.js create mode 100755 tutorial/ocaml/CalcClient.ml create mode 100755 tutorial/ocaml/CalcServer.ml create mode 100644 tutorial/ocaml/README.md create mode 100644 tutorial/ocaml/_oasis create mode 100644 tutorial/perl/PerlClient.pl create mode 100644 tutorial/perl/PerlServer.pl create mode 100755 tutorial/php/PhpClient.php create mode 100755 tutorial/php/PhpServer.php create mode 100755 tutorial/php/runserver.py create mode 100755 tutorial/py.tornado/Makefile.am create mode 100644 tutorial/py.tornado/Makefile.in create mode 100755 tutorial/py.tornado/PythonClient.py create mode 100755 tutorial/py.tornado/PythonServer.py create mode 100755 tutorial/py.twisted/Makefile.am create mode 100644 tutorial/py.twisted/Makefile.in create mode 100755 tutorial/py.twisted/PythonClient.py create mode 100755 tutorial/py.twisted/PythonServer.py create mode 100755 tutorial/py.twisted/PythonServer.tac create mode 100755 tutorial/py/Makefile.am create mode 100644 tutorial/py/Makefile.in create mode 100755 tutorial/py/PythonClient.py create mode 100755 tutorial/py/PythonServer.py create mode 100644 tutorial/py/setup.cfg create mode 100755 tutorial/rb/Makefile.am create mode 100644 tutorial/rb/Makefile.in create mode 100755 tutorial/rb/RubyClient.rb create mode 100755 tutorial/rb/RubyServer.rb create mode 100644 tutorial/rs/Cargo.toml create mode 100644 tutorial/rs/Makefile.am create mode 100644 tutorial/rs/Makefile.in create mode 100644 tutorial/rs/README.md create mode 100644 tutorial/rs/src/bin/tutorial_client.rs create mode 100644 tutorial/rs/src/bin/tutorial_server.rs create mode 100644 tutorial/rs/src/lib.rs create mode 100644 tutorial/shared.thrift create mode 100644 tutorial/tutorial.thrift create mode 100755 ylwrap diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..a62eef8 --- /dev/null +++ b/.clang-format @@ -0,0 +1,56 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +ConstructorInitializerIndentWidth: 2 +AlignEscapedNewlinesLeft: false +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AlwaysBreakTemplateDeclarations: true +AlwaysBreakBeforeMultilineStrings: true +BreakBeforeBinaryOperators: true +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BinPackParameters: false +ColumnLimit: 100 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +DerivePointerAlignment: false +IndentCaseLabels: false +IndentWrappedFunctionNames: false +IndentFunctionDeclarationAfterType: false +MaxEmptyLinesToKeep: 1 +KeepEmptyLinesAtTheStartOfBlocks: true +NamespaceIndentation: None +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 190 +PenaltyBreakComment: 300 +PenaltyBreakString: 10000 +PenaltyBreakFirstLessLess: 120 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 1200 +PointerAlignment: Left +SpacesBeforeTrailingComments: 1 +Cpp11BracedListStyle: true +Standard: Auto +IndentWidth: 2 +TabWidth: 4 +UseTab: Never +BreakBeforeBraces: Attach +SpacesInParentheses: false +SpacesInAngles: false +SpaceInEmptyParentheses: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: true +SpaceBeforeAssignmentOperators: true +ContinuationIndentWidth: 4 +CommentPragmas: '^ IWYU pragma:' +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +SpaceBeforeParens: ControlStatements +DisableFormat: false +... + diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2d2ecd6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.git/ diff --git a/.editorconfig b/.editorconfig new file mode 100755 index 0000000..3611762 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,112 @@ +# +## Licensed to the Apache Software Foundation (ASF) under one +## or more contributor license agreements. See the NOTICE file +## distributed with this work for additional information +## regarding copyright ownership. The ASF licenses this file +## to you under the Apache License, Version 2.0 (the +## "License"); you may not use this file except in compliance +## with the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, +## software distributed under the License is distributed on an +## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +## KIND, either express or implied. See the License for the +## specific language governing permissions and limitations +## under the License. +## +# + +# EditorConfig: http://editorconfig.org +# see doc/coding_standards.md + +root = true + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +# ActionScript +# [*.as] + +# C +# [*.c] + +# C++ +[*.cpp] +indent_style = space +indent_size = 2 + +# C-Sharp +# [*.cs] + +# D +# [*.d] + +# Erlang +# [*.erl] + +# Go-lang +[*.go] +indent_style = tab +indent_size = 8 + +# C header files +# [*.h] + +# Haskell +# [*.hs] + +# Haxe +# [*.hx] + +# Java +# [*.java] + +# Javascript +[*.js] +indent_style = space +indent_size = 2 + +# JSON +[*.json] +indent_style = space +indent_size = 2 + +# Lua +# [*.lua] + +[*.markdown] +indent_style = space +trim_trailing_whitespace = false + +[*.md] +indent_style = space +trim_trailing_whitespace = false + +# OCaml +# [*.ml] + +# Delphi Pascal +# [*.pas] + +# PHP +# [*.php] + +# Perl +# [*.pm] + +# Python +# [*.py] + +# Ruby +# [*.rb] + +# Typescript +# [*.ts] + +# XML +# [*.xml] diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..2962d47 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,7 @@ +max_width = 100 +fn_args_layout = "Block" +array_layout = "Block" +where_style = "Rfc" +generics_indent = "Block" +fn_call_style = "Block" +reorder_imported_names = true diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..9a94e36 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,196 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# build Apache Thrift on Travis CI - https://travis-ci.org/ + +# +# Docker Integration +# see: build/docker/README.md +# + +sudo: required +dist: trusty +language: cpp + +services: + - docker + +install: + - if [[ `uname` == "Linux" ]]; then build/docker/refresh.sh; fi + +stages: +# - osx # up front for now (for testing) + - docker # docker images + - thrift # thrift build jobs + +env: + global: + - SCRIPT="cmake.sh" + - BUILD_ARG="" + - BUILD_ENV="-e CC=clang -e CXX=clang++" + - DISTRO=ubuntu-xenial + - BUILD_LIBS="CPP C_GLIB HASKELL JAVA PYTHON TESTING TUTORIALS" # only meaningful for CMake builds + - TRAVIS_BUILD_STAGE=test + # DOCKER_REPO (this works for all builds as a source for docker images - you can override for fork builds in your Travis settings) + - DOCKER_REPO="thrift/thrift-build" + # DOCKER_USER (provide in your Travis settings if you want to build and update docker images once, instead of on every job) + # DOCKER_PASS (same) + +jobs: + include: + # ------------------------- phase: osx -------------------------- + # - stage: osx + # os: osx + # osx_image: xcode9 + # script: build/docker/scripts/autotools.sh + + # ========================= stage: docker ========================= + - stage: docker + script: true + env: + - JOB="Docker Build ubuntu-trusty 14.04" + - DISTRO=ubuntu-trusty + - TRAVIS_BUILD_STAGE=docker + - script: true + env: + - JOB="Docker Build ubuntu-xenial 16.04" + - DISTRO=ubuntu-xenial + - TRAVIS_BUILD_STAGE=docker + - script: true + env: + - JOB="Docker Build ubuntu-artful 17.10" + - DISTRO=ubuntu-artful + - TRAVIS_BUILD_STAGE=docker + + # ========================= stage: thrift ======================= + # ------------------------- phase: cross ------------------------ + # apache/thrift official PR builds can exceed 50 minutes per job so combine all cross tests + - stage: thrift + script: build/docker/run.sh + if: repo = apache/thrift + env: + - JOB="Cross Language Tests" + - SCRIPT="cross-test.sh" + - BUILD_ARG="" + - BUILD_ENV="-e CC=clang -e CXX=clang++ -e THRIFT_CROSSTEST_CONCURRENCY=4" + + # fork based PR builds cannot exceed 50 minutes per job + - stage: thrift + script: build/docker/run.sh + if: repo != apache/thrift + env: + - JOB="Cross Language Tests (Binary Protocol)" + - SCRIPT="cross-test.sh" + - BUILD_ARG="-'(binary)'" + - BUILD_ENV="-e CC=clang -e CXX=clang++ -e THRIFT_CROSSTEST_CONCURRENCY=4" + + - stage: thrift + script: build/docker/run.sh + if: repo != apache/thrift + env: + - JOB="Cross Language Tests (Header, JSON Protocols)" + - SCRIPT="cross-test.sh" + - BUILD_ARG="-'(header|json)'" + - BUILD_ENV="-e CC=clang -e CXX=clang++ -e THRIFT_CROSSTEST_CONCURRENCY=4" + + - stage: thrift + script: build/docker/run.sh + if: repo != apache/thrift + env: + - JOB="Cross Language Tests (Compact and Multiplexed Protocols)" + - SCRIPT="cross-test.sh" + - BUILD_ARG="-'(compact|multiplexed)'" + - BUILD_ENV="-e CC=clang -e CXX=clang++ -e THRIFT_CROSSTEST_CONCURRENCY=4" + + # ------------------------- phase: sca -------------------------- + # QA jobs for code analytics and metrics + - stage: thrift + script: build/docker/run.sh + env: + - JOB="Static Code Analysis" + - SCRIPT="sca.sh" + - DISTRO=ubuntu-artful + + # C and C++ undefined behavior. + # A binary crashes if undefined behavior occurs and produces a stack trace. + # python is disabled, see: THRIFT-4360 + - script: build/docker/run.sh + env: + - JOB="UBSan" + - SCRIPT="ubsan.sh" + - DISTRO=ubuntu-artful + - BUILD_ARG="--without-python --without-py3" + + # ------------------------- phase: cmake ------------------------ + - script: build/docker/run.sh + env: + - JOB="CMake (Ubuntu Xenial)" + + # C++ specific options: compiler plug-in, threading model + - script: build/docker/run.sh + env: + - JOB="C++98 (Boost Thread)" + - SCRIPT="cmake.sh" + - BUILD_LIBS="CPP TESTING TUTORIALS" + - BUILD_ARG="-DCMAKE_CXX_STANDARD=98 -DCMAKE_CXX_STANDARD_REQUIRED=ON -DCMAKE_CXX_EXTENSIONS=OFF --DWITH_BOOSTTHREADS=ON -DWITH_PYTHON=OFF -DWITH_C_GLIB=OFF -DWITH_JAVA=OFF -DWITH_HASKELL=OFF" + - BUILD_ENV="" + + - script: build/docker/run.sh + env: + - JOB="C++ (Std Thread) and Plugin" + - SCRIPT="cmake.sh" + - BUILD_LIBS="CPP TESTING TUTORIALS" + - BUILD_ARG="-DWITH_PLUGIN=ON -DWITH_STDTHREADS=ON -DWITH_PYTHON=OFF -DWITH_C_GLIB=OFF -DWITH_JAVA=OFF -DWITH_HASKELL=OFF" + - BUILD_ENV="-e CC=clang -e CXX=clang++" + + # ------------------------- phase: autotools -------------------- + # TODO: Remove them once migrated to CMake + - script: build/docker/run.sh + env: + - JOB="Autotools (Ubuntu Artful)" + - DISTRO=ubuntu-artful + - SCRIPT="autotools.sh" + - BUILD_ENV="-e CC=gcc -e CXX=g++" + + - script: build/docker/run.sh + env: + - JOB="Autotools (Ubuntu Xenial)" + - DISTRO=ubuntu-xenial + - SCRIPT="autotools.sh" + - BUILD_ENV="-e CC=gcc -e CXX=g++" + + - script: build/docker/run.sh + env: + - JOB="Autotools (Ubuntu Trusty)" + - DISTRO=ubuntu-trusty + - SCRIPT="autotools.sh" + - BUILD_ENV="-e CC=gcc -e CXX=g++" + + # ------------------------- phase: dist ------------------------- + - script: build/docker/run.sh + env: + - JOB="make dist" + - SCRIPT="make-dist.sh" + - BUILD_ENV="-e CC=gcc -e CXX=g++" + + - script: build/docker/run.sh + env: + - JOB="Debian Packages" + - SCRIPT="dpkg.sh" + - BUILD_ENV="-e CC=gcc -e CXX=g++" diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..4009f26 --- /dev/null +++ b/CHANGES @@ -0,0 +1,2656 @@ +Apache Thrift Changelog + +Thrift 0.11.0 +-------------------------------------------------------------------------------- +## Sub-task + * [THRIFT-2733] - Erlang coding standards + * [THRIFT-2740] - Perl coding standards + * [THRIFT-3610] - Streamline exception handling in Python server handler + * [THRIFT-3686] - Java processor should report internal error on uncaught exception + * [THRIFT-4049] - Skip() should throw TProtocolException.INVALID_DATA on unknown data types + * [THRIFT-4053] - Skip() should throw TProtocolException.INVALID_DATA on unknown data types + * [THRIFT-4136] - Align is_binary() method with is_string() to simplify those checks + * [THRIFT-4137] - Fix remaining undefined behavior invalid vptr casts in Thrift Compiler + * [THRIFT-4138] - Fix remaining undefined behavior invalid vptr casts in C++ library + * [THRIFT-4296] - Fix Ubuntu Xenial build environment for the python language + * [THRIFT-4298] - Fix Ubuntu Xenial build environment for the go 1.6 language + * [THRIFT-4299] - Fix Ubuntu Xenial build environment for the D language + * [THRIFT-4300] - Fix make cross in Ubuntu Xenial docker environment, once all language support issues are fixed + * [THRIFT-4302] - Fix Ubuntu Xenial make cross testing for lua and php7 + * [THRIFT-4398] - Update EXTRA_DIST for "make dist" + +## Bug + * [THRIFT-381] - Fail fast if configure detects C++ problems + * [THRIFT-1677] - MinGW support broken + * [THRIFT-1805] - Thrift should not swallow ALL exceptions + * [THRIFT-2026] - Fix TCompactProtocol 64 bit builds + * [THRIFT-2642] - Recursive structs don't work in python + * [THRIFT-2889] - stable release 0.9.2, erlang tutorial broken + * [THRIFT-2913] - Ruby Server Thrift::ThreadPoolServer should serve inside a thread + * [THRIFT-2998] - Node.js: Missing header from http request + * [THRIFT-3000] - .NET implementation has trouble with mixed IP modes + * [THRIFT-3281] - Travis CI build passed but the log says BUILD FAILED + * [THRIFT-3358] - Makefile:1362: *** missing separator. Stop. + * [THRIFT-3600] - Make TTwisted server send exception on unexpected handler error + * [THRIFT-3602] - Make Tornado server send exception on unexpected handler error + * [THRIFT-3657] - D TFileWriterTransport close should use non-priority send + * [THRIFT-3700] - Go Map has wrong default value when optional + * [THRIFT-3703] - Unions Field Count Does Not Consider Map/Set/List Fields + * [THRIFT-3730] - server log error twice + * [THRIFT-3778] - go client can not pass method parameter to server of other language if no field_id is given + * [THRIFT-3784] - thrift-maven-plugin generates invalid include directories for IDL in dependency JARs + * [THRIFT-3801] - Node Thrift client throws exception with multiplexer and responses that are bigger than a single buffer + * [THRIFT-3821] - TMemoryBuffer buffer may overflow when resizing + * [THRIFT-3832] - Thrift version 0.9.3 example on Windows, Visual Studio, linking errors during compiling + * [THRIFT-3847] - thrift/config.h includes a #define for VERSION which will likely conflict with existing user environment or code + * [THRIFT-3873] - Fix various build warnings when using Visual Studio + * [THRIFT-3891] - TNonblockingServer configured with more than one IO threads does not always return from serve() upon stop() + * [THRIFT-3892] - Thrift uses TLS SNI extension provided by OpenSSL library. Older version of OpenSSL(< 0.9.8f) may create problem because they do not support 'SSL_set_tlsext_host_name()'. + * [THRIFT-3895] - Build fails using Java 1.8 with Ant < 1.9 + * [THRIFT-3896] - map data with number string key cannot access that deserialized by php extension + * [THRIFT-3938] - Python TNonblockingServer does not work with SSL + * [THRIFT-3944] - TSSLSocket has dead code in checkHandshake + * [THRIFT-3946] - Java 1.5 compatibility broken for binary fields (java5 option) + * [THRIFT-3960] - Inherited services in Lua generator are not named correctly + * [THRIFT-3962] - Ant build.xml broken on Windows for Java library + * [THRIFT-3963] - Thrift.cabal filename does not match module name + * [THRIFT-3967] - gobject/gparam.h:166:33: warning: enumerator value for ‘G_PARAM_DEPRECATED’ is not an integer constant expression + * [THRIFT-3968] - Deserializing empty string/binary fields + * [THRIFT-3974] - Using clang-3.8 and ThreadSanitizer on the concurrency_test claims bad PThread behavior + * [THRIFT-3984] - PHP7 extension causes segfault + * [THRIFT-4008] - broken ci due to upstream dependency versioning break + * [THRIFT-4009] - Use @implementer instead of implements in TTwisted.py + * [THRIFT-4010] - Q.fcall messing up with *this* pointer inside called function + * [THRIFT-4011] - Sets of Thrift structs generate Go code that can't be serialized to JSON + * [THRIFT-4012] - Python Twisted implementation uses implements, not compatible with Py3 + * [THRIFT-4014] - align C# meta data in AssemblyInfo.cs + * [THRIFT-4015] - Fix wrongly spelled "Thirft"s + * [THRIFT-4016] - testInsanity() impl does not conform to test spec in ThriftTest.thrift + * [THRIFT-4023] - Skip unexpected field types on read/write + * [THRIFT-4024] - Skip() should throw on unknown data types + * [THRIFT-4026] - TSSLSocket doesn't work with Python < 2.7.9 + * [THRIFT-4029] - Accelerated protocols do not build from thrift-py 0.10.0 on PyPI + * [THRIFT-4031] - Go plugin generates invalid code for lists of typedef'ed built-in types + * [THRIFT-4033] - Default build WITH_PLUGIN=ON for all builds results in packaging errors + * [THRIFT-4034] - CMake doesn't work to build compiler on MacOS + * [THRIFT-4036] - Add .NET Core environment/build support to the docker image + * [THRIFT-4038] - socket check: checking an unsigned number against >= 0 never fails + * [THRIFT-4042] - ExtractionError when using accelerated thrift in a multiprocess test + * [THRIFT-4043] - thrift perl debian package is placing files in the wrong place + * [THRIFT-4044] - Build job 17 failing on every pull request; hspec core (haskell) 2.4 issue + * [THRIFT-4046] - MinGW with gcc 6.2 does not compile on Windows + * [THRIFT-4060] - Thrift printTo ostream overload mechanism breaks down when types are nested + * [THRIFT-4062] - Remove debug print from TServiceClient + * [THRIFT-4065] - Document Perl ForkingServer signal restriction imposed by THRIFT-3848 and remove unnecessary code + * [THRIFT-4068] - A code comment in Java ServerSocket is wrong around accept() + * [THRIFT-4073] - enum files are still being generated with unused imports + * [THRIFT-4076] - Appveyor builds failing because ant 1.9.8 was removed from apache servers + * [THRIFT-4077] - AI_ADDRCONFIG redefined after recent change to PlatformSocket header + * [THRIFT-4079] - Generated perl code that returns structures from included thrift files is missing a necessary use clause + * [THRIFT-4087] - Spurious exception destroying TThreadedServer because of incorrect join() call + * [THRIFT-4102] - TBufferedTransport performance issue since 0.10.0 + * [THRIFT-4106] - concurrency_test fails randomly + * [THRIFT-4108] - c_glib thrift ssl has multiple bugs and deprecated functions + * [THRIFT-4109] - Configure Script uses string comparison for versions + * [THRIFT-4129] - C++ TNonblockingServer fd leak when failing to dispatch new connections + * [THRIFT-4131] - Javascript with WebSocket handles oneway methods wrong + * [THRIFT-4134] - Fix remaining undefined behavior invalid vptr casts + * [THRIFT-4140] - Use of non-thread-safe function gmtime() + * [THRIFT-4141] - Installation of haxe in docker files refers to a redirect link and fails + * [THRIFT-4147] - Rust: protocol should accept transports with non-static lifetime + * [THRIFT-4148] - [maven-thrift-plugin] compile error while import a thrift in dependency jar file. + * [THRIFT-4149] - System.out pollutes log files + * [THRIFT-4154] - PHP close() of a TSocket needs to close any type of socket + * [THRIFT-4158] - minor issue in README-MSYS2.md + * [THRIFT-4159] - Building tests fails on MSYS2 (MinGW64) due to a (small?) linker error + * [THRIFT-4160] - TNonblocking server fix use of closed/freed connections + * [THRIFT-4161] - TNonBlocking server using uninitialized event in error paths + * [THRIFT-4162] - TNonBlocking handling of TSockets in error state is incorrect after fd is closed + * [THRIFT-4164] - Core in TSSLSocket cleanupOpenSSL when destroying a mutex used by openssl + * [THRIFT-4165] - C++ build has many warnings under c++03 due to recent changes, cmake needs better platform-independent language level control + * [THRIFT-4166] - Recent fix to remove boost::lexical_cast usage broke VS2010 + * [THRIFT-4167] - Missing compile flag + * [THRIFT-4170] - Support lua 5.1 or earlier properly for object length determination + * [THRIFT-4172] - node.js tutorial client does not import assert, connection issues are not handled properly + * [THRIFT-4177] - Java compiler produces deep copy constructor that could make shallow copy instead + * [THRIFT-4184] - Building on Appveyor: invalid escape sequence \L + * [THRIFT-4185] - fb303 counter encoding fix + * [THRIFT-4189] - Framed/buffered transport Dispose() does not dispose the nested transport + * [THRIFT-4193] - Lower the default maxReadBufferBytes for non-blocking servers + * [THRIFT-4195] - Compilation to GO produces broken code + * [THRIFT-4196] - Cannot generate recursive Rust types + * [THRIFT-4204] - typo in compact spec + * [THRIFT-4206] - Strings in container fields are not decoded properly with py:dynamic and py:utf8strings + * [THRIFT-4208] - C# NamedPipesServer not really working in some scenarios + * [THRIFT-4211] - Fix GError glib management under Thrift + * [THRIFT-4212] - c_glib flush tries to close SSL even if socket is invalid + * [THRIFT-4213] - Travis build fails at curl -sSL https://www.npmjs.com/install.sh | sh + * [THRIFT-4215] - Golang TTransportFactory Pattern Squelches Errors + * [THRIFT-4216] - Golang Http Clients Do Not Respect User Options + * [THRIFT-4218] - Set TCP_NODELAY for PHP client socket + * [THRIFT-4219] - Golang HTTP clients created with Nil buffer + * [THRIFT-4231] - TJSONProtocol throws unexpected non-Thrift-exception on null strings + * [THRIFT-4232] - ./configure does bad ant version check + * [THRIFT-4234] - Travis build fails cross language tests with "Unsupported security protocol type" + * [THRIFT-4237] - Go TServerSocket Race Conditions + * [THRIFT-4240] - Go TSimpleServer does not close properly + * [THRIFT-4243] - Go TSimpleServer race on wait in Stop() method + * [THRIFT-4245] - Golang TFramedTransport's writeBuffer increases if writes to transport failed + * [THRIFT-4246] - Sequence number mismatch on multiplexed clients + * [THRIFT-4247] - Compile fails with openssl 1.1 + * [THRIFT-4248] - Compile fails - strncpy, memcmp, memset not declared in src/thrift/transport/TSSLSocket.cpp + * [THRIFT-4251] - Java Epoll Selector Bug + * [THRIFT-4257] - Typescript async callbacks do not provide the correct types + * [THRIFT-4258] - Boost/std thread wrapping faultiness + * [THRIFT-4260] - Go context generation issue. Context is parameter in Interface not in implementation + * [THRIFT-4261] - Go context generation issue: breaking change in generated code regarding thrift.TProcessorFunction interface + * [THRIFT-4262] - Invalid binding to InterlockedCompareExchange64() with 64-bit targets + * [THRIFT-4263] - Fix use after free bug for thrown exceptions + * [THRIFT-4266] - Erlang library throws during skipping fields of composite type (maps, lists, structs, sets) + * [THRIFT-4268] - Erlang library emits debugging output in transport layer + * [THRIFT-4273] - erlang:now/0: Deprecated BIF. + * [THRIFT-4274] - Python feature tests for SSL/TLS failing + * [THRIFT-4279] - Wrong path in include directive in generated Thrift sources + * [THRIFT-4283] - TNamedPipeServer race condition in interrupt + * [THRIFT-4284] - File contains a NBSP: lib/nodejs/lib/thrift/web_server.js + * [THRIFT-4290] - C# nullable option generates invalid code for non-required enum field with default value + * [THRIFT-4292] - TimerManager::remove() is not implemented + * [THRIFT-4307] - Make ssl-open timeout effective in golang client + * [THRIFT-4312] - Erlang client cannot connect to Python server: exception error: econnrefused + * [THRIFT-4313] - Program code of the Erlang tutorial files contain syntax errors + * [THRIFT-4316] - TByteBuffer.java will read too much data if a previous read returns fewer bytes than requested + * [THRIFT-4319] - command line switch for "evhttp" incorrectly resolved to anon pipes + * [THRIFT-4323] - range check errors or NPE in edge cases + * [THRIFT-4324] - field names can conflict with local vars in generated code + * [THRIFT-4328] - Travis CI builds are timing out (job 1) and haxe builds are failing since 9/11 + * [THRIFT-4329] - c_glib Doesn't have a multiplexed processor + * [THRIFT-4331] - C++: TSSLSockets bug in handling huge messages, bug in handling polling + * [THRIFT-4332] - Binary protocol has memory leaks + * [THRIFT-4334] - Perl indentation incorrect when defaulting field attribute to a struct + * [THRIFT-4339] - Thrift Framed Transport in Erlang crashes server when client disconnects + * [THRIFT-4340] - Erlang fix a crash on client close + * [THRIFT-4355] - Javascript indentation incorrect when defaulting field attribute to a struct + * [THRIFT-4356] - thrift_protocol call Transport cause Segmentation fault + * [THRIFT-4359] - Haxe compiler looks like it is producing incorrect code for map or set key that is binary type + * [THRIFT-4362] - Missing size-check can lead to huge memory allocation + * [THRIFT-4364] - Website contributing guide erroneously recommends submitting patches in JIRA + * [THRIFT-4365] - Perl generated code uses indirect object syntax, which occasionally causes compilation errors. + * [THRIFT-4367] - python TProcessor.process is missing "self" + * [THRIFT-4370] - Ubuntu Artful cppcheck and flake8 are more stringent and causing SCA build job failures + * [THRIFT-4372] - Pipe write operations across a network are limited to 65,535 bytes per write. + * [THRIFT-4374] - cannot load thrift_protocol due to undefined symbol: _ZTVN10__cxxabiv120__si_class_type_infoE + * [THRIFT-4376] - Coverity high impact issue resolution + * [THRIFT-4377] - haxe. socket handles leak in TSimpleServer + * [THRIFT-4381] - Wrong isset bitfield value after transmission + * [THRIFT-4385] - Go remote client -u flag is broken + * [THRIFT-4392] - compiler/..../plugin.thrift structs mis-ordered blows up ocaml generator + * [THRIFT-4395] - Unable to build in the ubuntu-xenial docker image: clap 2.28 requires Rust 1.20 + * [THRIFT-4396] - inconsistent (or plain wrong) version numbers in master/trunk + +## Documentation + * [THRIFT-4157] - outdated readme about Haxe installation on Linux + +## Improvement + * [THRIFT-105] - make a thrift_spec for a structures with negative tags + * [THRIFT-281] - Cocoa library code needs comments, badly + * [THRIFT-775] - performance improvements for Perl + * [THRIFT-2221] - Generate c++ code with std::shared_ptr instead of boost::shared_ptr. + * [THRIFT-2364] - OCaml: Use Oasis exclusively for build process + * [THRIFT-2504] - TMultiplexedProcessor should allow registering default processor called if no service name is present + * [THRIFT-3207] - Enable build with OpenSSL 1.1.0 series + * [THRIFT-3272] - Perl SSL Authentication Support + * [THRIFT-3357] - Generate EnumSet/EnumMap where elements/keys are enums + * [THRIFT-3369] - Implement SSL/TLS support on C with c_glib + * [THRIFT-3467] - Go Maps for Thrift Sets Should Have Values of Type struct{} + * [THRIFT-3580] - THeader for Haskell + * [THRIFT-3627] - Missing basic code style consistency of JavaScript. + * [THRIFT-3706] - There's no support for Multiplexed protocol on c_glib library + * [THRIFT-3766] - Add getUnderlyingTransport() to TZlibTransport + * [THRIFT-3776] - Go code from multiple thrift files with the same namespace + * [THRIFT-3823] - Escape documentation while generating non escaped documetation + * [THRIFT-3854] - allow users to clear read buffers + * [THRIFT-3859] - Unix Domain Socket Support in Objective-C + * [THRIFT-3921] - C++ code should print enums as strings + * [THRIFT-3926] - There should be an error emitted when http status code is not 200 + * [THRIFT-4007] - Micro-optimization of TTransport.py + * [THRIFT-4040] - Add real cause of TNonblockingServerSocket error to exception + * [THRIFT-4064] - Update node library dependencies + * [THRIFT-4069] - All perl packages should have proper namespace, version syntax, and use proper thrift exceptions + * [THRIFT-4071] - Consolidate the Travis CI jobs where possible to put less stress on the Apache Foundation's allocation of CI build slaves + * [THRIFT-4072] - Add the possibility to send custom headers in TCurlClient + * [THRIFT-4075] - Better MinGW support for headers-only boost (without thread library) + * [THRIFT-4081] - Provide a MinGW 64-bit Appveyor CI build for better pull request validation + * [THRIFT-4084] - Improve SSL security in thrift by adding a make cross client that checks to make sure SSLv3 protocol cannot be negotiated + * [THRIFT-4095] - Add multiplexed protocol to Travis CI for make cross + * [THRIFT-4099] - Auto-derive Hash for generated Rust structs + * [THRIFT-4110] - The debian build files do not produce a "-dbg" package for debug symbols of libthrift0 + * [THRIFT-4114] - Space after '///' in doc comments + * [THRIFT-4126] - Validate objects in php extension + * [THRIFT-4130] - Ensure Apache Http connection is released back to pool after use + * [THRIFT-4151] - Thrift Mutex Contention Profiling (pthreads) should be disabled by default + * [THRIFT-4176] - Implement a threaded and threadpool server type for Rust + * [THRIFT-4183] - Named pipe client blocks forever on Open() when there is no server at the other end + * [THRIFT-4190] - improve C# TThreadPoolServer defaults + * [THRIFT-4197] - Implement transparent gzip compression for HTTP transport + * [THRIFT-4198] - Ruby should log Thrift internal errors to global logger + * [THRIFT-4203] - thrift server stop gracefully + * [THRIFT-4205] - c_glib is not linking against glib + gobject + * [THRIFT-4209] - warning CS0414 in T[TLS]ServerSocket.cs + * [THRIFT-4210] - include Thrift.45.csproj into CI runs + * [THRIFT-4217] - HttpClient should support gzip and deflate + * [THRIFT-4222] - Support Unix Domain Sockets in Golang TServerSocket + * [THRIFT-4233] - Make THsHaServer.invoker available (get method only) in inherited classes + * [THRIFT-4236] - Support context in go generated code. + * [THRIFT-4238] - JSON generator: make annotation-aware + * [THRIFT-4269] - Don't append '.' to Erlang namespace if it ends in '_'. + * [THRIFT-4270] - Generate Erlang mapping functions for const maps and lists + * [THRIFT-4275] - Add support for zope.interface only, apart from twisted support. + * [THRIFT-4285] - Pull generated send/recv into library to allow behaviour to be customised + * [THRIFT-4287] - Add c++ compiler "no_skeleton" flag option + * [THRIFT-4288] - Implement logging levels properly for node.js + * [THRIFT-4295] - Refresh the Docker image file suite for Ubuntu, Debian, and CentOS + * [THRIFT-4305] - Emit ddoc for generated items + * [THRIFT-4306] - Thrift imports not replicated to D service output + * [THRIFT-4315] - Add default message for TApplicationException + * [THRIFT-4318] - Delphi performance improvements + * [THRIFT-4325] - Simplify automake cross compilation by relying on one global THRIFT compiler path + * [THRIFT-4327] - Improve TimerManager API to allow removing specific task + * [THRIFT-4330] - Allow unused crates in Rust files + * [THRIFT-4333] - Erlang tutorial examples are using a different port (9999) + * [THRIFT-4343] - Change CI builds to use node.js 8.x LTS once available + * [THRIFT-4345] - Create a docker build environment that uses the minimum supported language levels + * [THRIFT-4346] - Allow Zlib transport factory to wrap other transports + * [THRIFT-4348] - Perl HTTP Client custom HTTP headers + * [THRIFT-4350] - Update netcore build for dotnet 2.0 sdk and make cross validation + * [THRIFT-4351] - Use Travis CI Build Stages to optimize the CI build + * [THRIFT-4353] - cannot read via thrift_protocol at server side + * [THRIFT-4378] - add set stopTimeoutUnit method to TThreadPoolServer + +## New Feature + * [THRIFT-750] - C++ Compiler Virtual Function Option + * [THRIFT-2945] - Implement support for Rust language + * [THRIFT-3857] - thrift js:node complier support an object as parameter not an instance of struct + * [THRIFT-3933] - Port official C# .NET library for Thrift to C# .NET Core libary + * [THRIFT-4039] - Update of Apache Thrift .Net Core lib + * [THRIFT-4113] - Provide a buffer transport for reading/writing in memory byte stream + +## Question + * [THRIFT-2956] - autoconf - possibly undefined macro - AC_PROG_BISON + * [THRIFT-4223] - Add support to the isServing() method for the C++ library + +## Task + * [THRIFT-3622] - Fix deprecated uses of std::auto_ptr + * [THRIFT-4028] - Please remove System.out.format from the source code + * [THRIFT-4186] - Build and test rust client in Travis + +## Test + * [THRIFT-4264] - PHP - Support both shared & static linking of sockets library + +## Wish + * [THRIFT-4344] - Define and maintain the minimum language level for all languages in one place + + +Thrift 0.10.0 +-------------------------------------------------------------------------------- +## Bug + * [THRIFT-1840] - Thrift Generated Code Causes Global Variable Leaks + * [THRIFT-1828] - moc_TQTcpServer.cpp was removed from source tree but is in thrift-0.9.0.tar.gz + * [THRIFT-1790] - cocoa: Duplicate interface definition error + * [THRIFT-1776] - TPipeServer should implement "listen", so that TServerEventHandler preServe will work right + * [THRIFT-1351] - Compiler does not care about binary strings + * [THRIFT-1229] - Python fastbinary.c can not handle unicode as generated python code + * [THRIFT-749] - C++ TBufferedTransports do not flush their buffers on delete + * [THRIFT-747] - C++ TSocket->close calls shutdown breaking forked parent process + * [THRIFT-732] - server exits abnormally when client calls send_xxx function without calling recv_xxx function + * [THRIFT-3942] - TSSLSocket does not honor send and receive timeouts + * [THRIFT-3941] - WinXP version of thrift_poll() relies on undefined behavior by passing a destructed variable to select() + * [THRIFT-3940] - Visual Studio project file for compiler is broken + * [THRIFT-3943] - Coverity Scan identified some high severity defects + * [THRIFT-3929] - PHP "nsglobal" Option Results in Syntax Error in Generated Code (Trailing Backslash) + * [THRIFT-3936] - Cannot compile 0.10.0 development tip with VS2013 and earlier (snprintf, uint32_t) + * [THRIFT-3935] - Incorrect skipping of map and set + * [THRIFT-3920] - Ruby: Ensuring that HTTP failures will clear the http transport outbuf var + * [THRIFT-3919] - C# TTLSServerSocket does not use clientTimeout + * [THRIFT-3917] - Check backports.ssl_match_hostname module version + * [THRIFT-3909] - Fix c_glib static lib CMake build + * [THRIFT-3904] - Typo in node tutorial leads to wrong transport being used + * [THRIFT-3848] - As an implementer of a perl socket server, I do not want to have to remember to ignore SIGCHLD for it to work properly + * [THRIFT-3844] - thrift_protocol cannot compile in 7.0.7 + * [THRIFT-3843] - integer issues with Haxe PHP targets cause ZigZag encoding to fail + * [THRIFT-3842] - Dart generates incorrect code for a const struct + * [THRIFT-3841] - dart compact protocol incorrectly serializes/deserialized doubles + * [THRIFT-3708] - NameError: global name 'TProtocol' is not defined + * [THRIFT-3704] - "TConnectedClient died: Could not refill buffer" message shown when using HTTP Server + * [THRIFT-3678] - Fix javadoc errors on JDK 8 + * [THRIFT-3014] - AppVeyor support + * [THRIFT-2994] - Node.js TJSONProtocol cannot be used for object serialization. + * [THRIFT-2974] - writeToParcel throws NPE for optional enum fields + * [THRIFT-2948] - Python TJSONProtocol doesn't handle structs with binary fields containing invalid unicode. + * [THRIFT-2845] - ChildService.Plo: No such file or directory + * [THRIFT-3276] - Binary data does not decode correctly using the TJSONProtocol when the base64 encoded data is padded. + * [THRIFT-3253] - Using latest version of D gives deprecation notices + * [THRIFT-2883] - TTwisted.py, during ConnectionLost processing: exceptions.RuntimeError: dictionary changed size during iteration + * [THRIFT-2019] - Writing on a disconnected socket on Mac causes SIG PIPE + * [THRIFT-2020] - Thrift library has some empty files that haven't really been deleted + * [THRIFT-2049] - Go compiler doesn't build on native Windows + * [THRIFT-2024] - TServer.cpp warns on 64-bit platforms about truncating an rlim_t into an int + * [THRIFT-2023] - gettimeofday implementation on Windows errors when no time zone is passed in. + * [THRIFT-2022] - CoB and dense code generation still uses TR1 bind, even though that doesn't work with clang + * [THRIFT-2027] - Minor 64-bit and NOMINMAX issues in C++ library + * [THRIFT-2156] - TServerSocket::listen() is throwing exceptions with misleading information + * [THRIFT-2154] - Missing #deepCopy should return T + * [THRIFT-3157] - TBase signature should be TBase, F extends TFieldIdEnum> + * [THRIFT-3156] - Node TLS: server executes processing logic two full times + * [THRIFT-3154] - tutorial/py.tornado throw EOF exception + * [THRIFT-3063] - C++ build -Wunused-parameter warnings on processor_test, TransportTest + * [THRIFT-3056] - Add string/collection length limits for Python protocol readers + * [THRIFT-3237] - Fix TNamedPipeServer::createNamedPipe memory leak + * [THRIFT-3233] - Fix C++ ThreadManager::Impl::removeWorker worker join + * [THRIFT-3232] - Cannot deserialize json messages created with fieldNamesAsString + * [THRIFT-3206] - Fix Visual Studio build failure due 'pthread_self': identifier not found + * [THRIFT-3200] - JS and nodejs do not encode JSON protocol binary fields as base64 + * [THRIFT-3199] - Exception field has basic metadata + * [THRIFT-3182] - TFramedTransport is in an invalid state after frame size exception + * [THRIFT-2536] - new TSocket, uninitialised value reported by valgrind + * [THRIFT-2527] - Apache Thrift IDL Compiler code generated for Node.js should be jshint clean + * [THRIFT-2519] - "processor" class is not being generated + * [THRIFT-2431] - TFileTransportTest fails with "check delta < XXX failed" + * [THRIFT-2708] - Erlang library does not support "oneway" message type + * [THRIFT-3377] - Deep copy is actually shallow when using typedef members + * [THRIFT-3376] - C# and Python JSON protocol double values lose precision + * [THRIFT-3373] - Various fixes for cross test servers and clients + * [THRIFT-3370] - errno extern variable redefined. Not compiling for Android + * [THRIFT-3379] - Potential out of range panic in Go JSON protocols + * [THRIFT-3371] - Abstract namespace Unix domain sockets broken in C++ + * [THRIFT-3380] - nodejs: 0.9.2 -> 0.9.3 upgrade breaks Protocol and Transport requires + * [THRIFT-3367] - Fix bad links to coding_standards.md #634 + * [THRIFT-3401] - Nested collections emit Objective-C code that cannot compile + * [THRIFT-3403] - JSON String reader doesn't recognize UTF-16 surrogate pairs + * [THRIFT-3362] - make check fails for C++ at the SecurityTest + * [THRIFT-3395] - Cocoa compiler produces corrupt code when boxing enums inside map. + * [THRIFT-3394] - compiler generates uncompilable code + * [THRIFT-3388] - hash doesn't work on set/list + * [THRIFT-3391] - Wrong bool formatting in test server + * [THRIFT-3390] - TTornado server doesn't handle closed connections properly + * [THRIFT-3382] - TBase class for C++ Library + * [THRIFT-3392] - Java TZlibTransport does not close its wrapper streams upon close() + * [THRIFT-3383] - i64 related warnings + * [THRIFT-3386] - misc. warnings with make check + * [THRIFT-3385] - warning: format ‘%lu’ expects ‘long unsigned int’, but has type ‘std::basic_string::size_type {aka unsigned int} + * [THRIFT-3355] - npm WARN package.json thrift@1.0.0-dev No license field. + * [THRIFT-3360] - Improve cross test servers and clients further + * [THRIFT-3359] - Binary field incompatibilities + * [THRIFT-3354] - Fix word-extraction substr bug in initialism code + * [THRIFT-3350] - Python JSON protocol does not encode binary as Base64 + * [THRIFT-3577] - assertion failed at line 512 of testcontainertest.c + * [THRIFT-3576] - Boost test --log_format arg does not accept lowercase + * [THRIFT-3575] - Go compiler tries to use unexported library methods when using read_write_private + * [THRIFT-3574] - Cocoa generator makes uncompilable imports + * [THRIFT-3570] - Remove duplicate instances that are added by upstream + * [THRIFT-3571] - Make feature test result browsable + * [THRIFT-3569] - c_glib protocols do not check number of bytes read by transport + * [THRIFT-3568] - THeader server crashes on readSlow + * [THRIFT-3567] - GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed + * [THRIFT-3566] - C++/Qt: TQTcpServerTest::test_communicate() is never executed + * [THRIFT-3564] - C++/Qt: potential core dump in TQTcpServer in case an exception occurs in TAsyncProcessor::process() + * [THRIFT-3558] - typos in c_glib tests + * [THRIFT-3559] - Fix awkward extra semi-colons with Cocoa container literals + * [THRIFT-3555] - 'configure' script does not honor --with-openssl= for libcrypto for BN_init + * [THRIFT-3554] - Constant decls may lead to "Error: internal error: prepare_member_name_mapping() already active for different struct" + * [THRIFT-3552] - glib_c Memory Leak + * [THRIFT-3551] - Thrift perl library missing package declaration + * [THRIFT-3549] - Exceptions are not properly stringified in Perl library + * [THRIFT-3546] - NodeJS code should not be namespaced (and is currently not strict-mode compliant) + * [THRIFT-3545] - Container type literals do not compile + * [THRIFT-3538] - Remove UnboundMethodType in TProtocolDecorator + * [THRIFT-3536] - Error 'char' does not contain a definition for 'IsLowSurrogate' for WP7 target + * [THRIFT-3534] - Link error when building with Qt5 + * [THRIFT-3533] - Can not send nil pointer as service method argument + * [THRIFT-3507] - THttpClient does not use proxy from http_proxy, https_proxy environment variables + * [THRIFT-3502] - C++ TServerSocket passes small buffer to getsockname + * [THRIFT-3501] - Forward slash in comment causes compiler error + * [THRIFT-3498] - C++ library assumes optional function pthread_attr_setschedpolicy is available + * [THRIFT-3497] - Build fails with "invalid use of incomplete type" + * [THRIFT-3496] - C++: Cob style client fails when sending a consecutive request + * [THRIFT-3493] - libthrift does not compile on windows using visual studio + * [THRIFT-3488] - warning: unused variable 'program' + * [THRIFT-3489] - warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings] + * [THRIFT-3487] - Full support for newer Delphi versions + * [THRIFT-3528] - Fix warnings in thrift.ll + * [THRIFT-3527] - -gen py:dynamic,utf8strings ignores utf8strings option + * [THRIFT-3526] - Code generated by py:utf8strings does not work for Python3 + * [THRIFT-3524] - dcc32 warning "W1000 Symbol 'IsLowSurrogate' is deprecated: 'Use TCharHelper'" in Thrift.Protocol.JSON.pas + * [THRIFT-3525] - py:dynamic fails to handle binary list/set/map element + * [THRIFT-3521] - TSimpleJSONProtocolTest is not deterministic (fails when run on JDK 8) + * [THRIFT-3520] - Dart TSocket onError stream should be typed as Object + * [THRIFT-3519] - fastbinary does not work with -gen py:utf8strings + * [THRIFT-3518] - TConcurrentClientSyncInfo files were missing for Visual Studio + * [THRIFT-3512] - c_glib: Build fails due to missing features.h + * [THRIFT-3483] - Incorrect empty binary handling introduced by THRIFT-3359 + * [THRIFT-3479] - Oneway calls should not return exceptions to clients + * [THRIFT-3478] - Restore dropped method to THsHaServer.java + * [THRIFT-3477] - Parser fails on enum item that starts with 'E' letter and continues with number + * [THRIFT-3476] - Missing include in ./src/thrift/protocol/TJSONProtocol.cpp + * [THRIFT-3474] - Docker: thrift-compiler + * [THRIFT-3473] - When "optional' is used with a struct member, C++ server seems to not return it correctly + * [THRIFT-3468] - Dart TSocketTransport onError handler is too restrictive + * [THRIFT-3451] - thrift_protocol PHP extension missing config.m4 file + * [THRIFT-3456] - rounding issue in static assert + * [THRIFT-3455] - struct write method's return value is incorrect + * [THRIFT-3454] - Python Tornado tutorial is broken + * [THRIFT-3463] - Java can't be disabled in CMake build + * [THRIFT-3450] - NPE when using SSL + * [THRIFT-3449] - TBaseAsyncProcessor fb.responseReady() never called for oneway functions + * [THRIFT-3471] - Dart generator does not handle uppercase argument names + * [THRIFT-3470] - Sporadic timeouts with pipes + * [THRIFT-3465] - Go Code With Complex Const Initializer Compilation Depends On Struct Order + * [THRIFT-3464] - Fix several defects in c_glib code generator + * [THRIFT-3462] - Cocoa generates Incorrect #import header names + * [THRIFT-3453] - remove rat_exclude + * [THRIFT-3418] - Use of ciphers in ssl.wrap_socket() breaks python 2.6 compatibility + * [THRIFT-3417] - "namespace xsd" is not really working + * [THRIFT-3413] - Thrift code generation bug in Go when extending service + * [THRIFT-3420] - C++: TSSLSockets are not interruptable + * [THRIFT-3415] - include unistd.h conditionally + * [THRIFT-3414] - #include in THeaderTransport.h breaks windows build + * [THRIFT-3411] - Go generates remotes with wrong package qualifiers when including + * [THRIFT-3430] - Go THttpClient does not read HTTP response body to completion when closing + * [THRIFT-3423] - First call to thrift_transport:read_exact fails to dispatch correct function + * [THRIFT-3422] - Go TServerSocket doesn't close on Interrupt + * [THRIFT-3421] - rebar as dependency instead of bundling (was: rebar fails if PWD contains Unicode) + * [THRIFT-3428] - Go test fails when running make check + * [THRIFT-3445] - Throwable messages are hidden from JVM stack trace output + * [THRIFT-3443] - Thrift include can generate uncompilable code + * [THRIFT-3444] - Large 64 bit Integer does not preserve value through Node.js JSONProtocol + * [THRIFT-3436] - misc. cross test issues with UTF-8 path names + * [THRIFT-3435] - Put generated Java code for fullcamel tests in a separate package/namespace + * [THRIFT-3433] - Doubles aren't interpreted correctly + * [THRIFT-3437] - Mingw-w64 build fail + * [THRIFT-3434] - Dart generator produces empty name in pubspec.yaml for includes without namespaces + * [THRIFT-3408] - JSON generator emits incorrect types + * [THRIFT-3406] - Cocoa client should not schedule streams on main runloop + * [THRIFT-3404] - JSON String reader doesn't recognize UTF-16 surrogate pair + * [THRIFT-3636] - Double precision is not fully preserved in C++ TJSONProtocol + * [THRIFT-3632] - c_glib testserialization fails with glib assertion + * [THRIFT-3619] - Using Thrift 0.9.3 with googletest on Linux gcc 4.9 / C++11 + * [THRIFT-3617] - CMake does not build gv/xml generators + * [THRIFT-3615] - Fix Python SSL client resource leak on connection failure + * [THRIFT-3616] - lib/py/test/test_sslsocket.py is flaky + * [THRIFT-3643] - Perl SSL server crushes if a client disconnect without handshake + * [THRIFT-3639] - C# Thrift library forces TLS 1.0, thwarting TLS 1.2 usage + * [THRIFT-3633] - Travis "C C++ - GCC" build was using clang + * [THRIFT-3634] - Fix Python TSocket resource leak on connection failure + * [THRIFT-3630] - Debian/Ubuntu install docs need an update + * [THRIFT-3629] - Parser sets exitcode on errors, but generator does not + * [THRIFT-3608] - lib/cpp/test/SecurityTest is flaky in jenkins Thrift-precommit build. + * [THRIFT-3601] - Better conformance to PEP8 for generated code + * [THRIFT-3599] - Validate client IP address against cert's SubjectAltName + * [THRIFT-3598] - TBufferedTransport doesn't instantiate client connection + * [THRIFT-3597] - `make check` hangs in go tests + * [THRIFT-3589] - Dart generator uses wrong name in constructor for uppercase arguments with defaults + * [THRIFT-3588] - Using TypeScript with --noImplicitAny fails + * [THRIFT-3584] - boolean false value cannot be transferred + * [THRIFT-3578] - Make THeaderTransport detect TCompact framed and unframed + * [THRIFT-3323] - Python library does not handle escaped forward slash ("/") in JSON + * [THRIFT-3322] - CMake generated "make check" failes on python_test + * [THRIFT-3321] - Thrift can't be added as a subdirectory of another CMake-based project + * [THRIFT-3314] - Dots in file names of includes causes dots in javascript variable names + * [THRIFT-3307] - Segfault in Ruby serializer + * [THRIFT-3309] - Missing TConstant.php in /lib/php/Makefile.am + * [THRIFT-3810] - unresolved external symbol public: virtual void __cdecl apache::thrift::server::TServerFramework::serve(void) + * [THRIFT-3736] - C++ library build fails if OpenSSL does not surrpot SSLv3 + * [THRIFT-3878] - Compile error in TSSLSocket.cpp with new OpenSSL [CRYPTO_num_locks] + * [THRIFT-3949] - missing make dist entry for compiler/cpp/test + * [THRIFT-449] - The wire format of the JSON Protocol may not always be valid JSON if it contains non-UTF8 encoded strings + * [THRIFT-162] - Thrift structures are unhashable, preventing them from being used as set elements + * [THRIFT-3961] - TConnectedClient does not terminate the connection to the client if an exception while processing the received message occures. + * [THRIFT-3881] - Travis CI builds are failing due to docker failures (three retries, and gives up) + * [THRIFT-3937] - Cannot compile 0.10.0 development tip with gcc-4.6.x + * [THRIFT-3964] - Unsupported mechanism type ????? due to dependency on default OS-dependent charset + * [THRIFT-3038] - Use of volatile in cpp library + * [THRIFT-3301] - Java generated code uses imports that can lead to class name collisions with IDL defined types + * [THRIFT-3348] - PHP TCompactProtocol bool&int64 readvalue bug + * [THRIFT-3955] - TThreadedServer Memory Leak + * [THRIFT-3829] - Thrift does not install Python Libraries if Twisted is not installed + * [THRIFT-3932] - C++ ThreadManager has a rare termination race + * [THRIFT-3828] - cmake fails when Boost_INCLUDE_DIRS (and other variables passed to include_directories()) is empty + * [THRIFT-3958] - CMake WITH_MT option for windows static runtime linking does not support the cmake build type RelWithDebInfo + * [THRIFT-3957] - TConnectedClient does not disconnect from clients when their timeout is reached. + * [THRIFT-3953] - TSSLSocket::close should handle exceptions from waitForEvent because it is called by the destructor. + * [THRIFT-3977] - PHP extension creates undefined values when deserializing sets + * [THRIFT-3947] - sockaddr type isn't always large enough for the return of getsockname + * [THRIFT-2755] - ThreadSanitizer reports data race in ThreadManager::Impl::addWorker + * [THRIFT-3948] - errno is not the correct method of getting the error in windows + * [THRIFT-4008] - broken ci due to upstream dependency versioning break + * [THRIFT-3999] - Fix Debian & Ubuntu package dependencies + * [THRIFT-3886] - PHP cross test client returns 0 even when failing + * [THRIFT-3997] - building thrift libs does not support new openssl + +## Documentation + * [THRIFT-3867] - Specify BinaryProtocol and CompactProtocol + +## Epic + * [THRIFT-3049] - As an iOS developer, I want a generator and library that produces Swift code + * [THRIFT-2336] - UTF-8 sent by PHP as JSON is not understood by TJsonProtocol + +## Improvement + * [THRIFT-1867] - Python client/server should support client-side certificates. + * [THRIFT-1313] - c_glib compact support + * [THRIFT-1385] - make install doesn't install java library in the setted folder + * [THRIFT-1437] - Update RPM spec + * [THRIFT-847] - Test Framework harmonization across all languages + * [THRIFT-819] - add Enumeration for protocol, transport and server types + * [THRIFT-3927] - Emit an error instead of throw an error in the async callback + * [THRIFT-3931] - TSimpleServer: If process request encounter UNKNOWN_METHOD, don't close transport. + * [THRIFT-3934] - Automatically resolve OpenSSL binary version on Windows CI + * [THRIFT-3918] - Run subset of make cross + * [THRIFT-3908] - Remove redundant dependencies from Dockerfile + * [THRIFT-3907] - Skip Docker image build on CI when unchanged + * [THRIFT-3868] - Java struct equals should do identity check before field comparison + * [THRIFT-3849] - Port Go serializer and deserializer to dart + * [THRIFT-2989] - Complete CMake build for Apache Thrift + * [THRIFT-2980] - ThriftMemoryBuffer doesn't have a constructor option to take an existing buffer + * [THRIFT-2856] - refactor erlang basic transports and unify interfaces + * [THRIFT-2877] - Optimize generated hashCode + * [THRIFT-2869] - JSON: run schema validation from tests + * [THRIFT-3112] - [Java] AsyncMethodCallback should be typed in generated AsyncIface + * [THRIFT-3263] - PHP jsonSerialize() should cast scalar types + * [THRIFT-2905] - Cocoa compiler should have option to produce "modern" Objective-C + * [THRIFT-2821] - Enable the use of custom HTTP-Header in the Transport + * [THRIFT-2093] - added the ability to set compression level in C++ zlib transport + * [THRIFT-2089] - Compiler ignores duplicate typenames + * [THRIFT-2056] - Moved all #include config.h statements to #include + * [THRIFT-2031] - Make SO_KEEPALIVE configurable for C++ lib + * [THRIFT-2021] - Improve large binary protocol string performance + * [THRIFT-2028] - Cleanup threading headers / libraries + * [THRIFT-2014] - Change C++ lib includes to use style throughout + * [THRIFT-2312] - travis.yml: build everything + * [THRIFT-1915] - Multiplexing Services + * [THRIFT-1736] - Visual Studio top level project files within msvc + * [THRIFT-1735] - integrate tutorial into regular build + * [THRIFT-1533] - Make TTransport should be Closeable + * [THRIFT-35] - Move language tests into their appropriate library directory + * [THRIFT-1079] - Support i64 in AS3 + * [THRIFT-1108] - SSL support for the Ruby library + * [THRIFT-3856] - update debian package deependencies + * [THRIFT-3833] - haxe http server implementation (by embeding into php web server) + * [THRIFT-3839] - Performance issue with big message deserialization using php extension + * [THRIFT-3820] - Erlang: Detect OTP >= 18 to use new time correction + * [THRIFT-3816] - Reduce docker build duration on Travis-CI + * [THRIFT-3815] - Put appveyor dependency versions to one place + * [THRIFT-3788] - Compatibility improvements and Win64 support + * [THRIFT-3792] - Timeouts for anonymous pipes should be configurable + * [THRIFT-3794] - Split Delphi application, protocol and transport exception subtypes into separate exceptions + * [THRIFT-3774] - The generated code should have exception_names meta info + * [THRIFT-3762] - Fix build warnings for deprecated Thrift "byte" fields + * [THRIFT-3756] - Improve requiredness documentation + * [THRIFT-3761] - Add debian package for Python3 + * [THRIFT-3742] - haxe php cli support + * [THRIFT-3733] - Socket timeout improvements + * [THRIFT-3728] - http transport for thrift-lua + * [THRIFT-3905] - Dart compiler does not initialize bool, int, and double properties + * [THRIFT-3911] - Loosen Ruby dev dependency version requirements + * [THRIFT-3906] - Run C# tests with make check + * [THRIFT-3900] - Add Python SSL flags + * [THRIFT-3897] - Provide meaningful exception type based on WebExceptionStatus in case of timeout + * [THRIFT-3808] - Missing `DOUBLE` in thrift type enumeration + * [THRIFT-3803] - Remove "file" attribute from XML generator + * [THRIFT-3660] - Add V4 mapped address to test client cert's altname + * [THRIFT-3661] - Use https to download meck in erlang test build + * [THRIFT-3659] - Check configure result of CMake on CI + * [THRIFT-3667] - Add TLS SNI support to clients + * [THRIFT-3651] - Make backports.match_hostname and ipaddress optional + * [THRIFT-3666] - Build D tutorial as part of Autotools build + * [THRIFT-3665] - Add D libevent and OpenSSL to docker images + * [THRIFT-3664] - Remove md5.c + * [THRIFT-3662] - Add Haskell to debian docker image + * [THRIFT-3711] - Add D to cross language test + * [THRIFT-3691] - Run flake8 Python style check on Travis-CI + * [THRIFT-3692] - (Re)enable Appveyor C++ and Python build + * [THRIFT-3677] - Improve CMake Java build + * [THRIFT-3679] - Add stdout log to testBinary in Java test server + * [THRIFT-3718] - Reduce size of docker image for build environment + * [THRIFT-3698] - [Travis-CI] Introduce retry to apt commands + * [THRIFT-3127] - switch -recurse to --recurse and reserve -r + * [THRIFT-3087] - Pass on errors like "connection closed" + * [THRIFT-3240] - Thrift Python client should support subjectAltName and wildcard certs in TSSLSocket + * [THRIFT-3213] - make cross should indicate when it skips a known failing test + * [THRIFT-3208] - Fix Visual Studio solution build failure due to missing source + * [THRIFT-3186] - Add TServerHTTP to Go library + * [THRIFT-2342] - Add __FILE__ and __LINE__ to Thrift C++ excpetions + * [THRIFT-3372] - Add dart generator to Visual Studio project + * [THRIFT-3366] - ThriftTest to implement standard return values + * [THRIFT-3402] - Provide a perl Unix Socket implementation + * [THRIFT-3361] - Improve C# library + * [THRIFT-3393] - Introduce i8 to provide consistent set of Thrift IDL integer types + * [THRIFT-3339] - Support for database/sql + * [THRIFT-3565] - C++: T[Async]Processor::getEventHandler() should be declared as const member functions + * [THRIFT-3563] - C++/Qt: removed usage of macro QT_PREPEND_NAMESPACE as it isn't consequently used for all references to Qt types. + * [THRIFT-3562] - Removed unused TAsyncProcessor::getAsyncServer() + * [THRIFT-3561] - C++/Qt: make use of Q_DISABLE_COPY() to get rid of copy ctor and assignment operator + * [THRIFT-3556] - c_glib file descriptor transport + * [THRIFT-3544] - Make cross test fail when server process died unexpectedly + * [THRIFT-3540] - Make python tutorial more in line with PEP8 + * [THRIFT-3535] - Dart generator argument to produce a file structure usable in parent library + * [THRIFT-3505] - Enhance Python TSSLSocket + * [THRIFT-3506] - Eliminate old style classes from library code + * [THRIFT-3503] - Enable py:utf8string by default + * [THRIFT-3499] - Add package_prefix to python generator + * [THRIFT-3495] - Minor enhancements and fixes for cross test + * [THRIFT-3486] - Java generated `getFieldValue` is incompatible with `setFieldValue` for binary values. + * [THRIFT-3484] - Consolidate temporary buffers in Java's TCompactProtocol + * [THRIFT-3516] - Add feature test for THeader TBinaryProtocol interop + * [THRIFT-3515] - Python 2.6 compatibility and test on CI + * [THRIFT-3514] - PHP 7 compatible version of binary protocol + * [THRIFT-3469] - Docker: Debian support + * [THRIFT-3416] - Retire old "xxx_namespace" declarations from the IDL + * [THRIFT-3426] - Align autogen comment in XSD + * [THRIFT-3424] - Add CMake android build option + * [THRIFT-3439] - Run make cross using Python3 when available + * [THRIFT-3440] - Python make check takes too much time + * [THRIFT-3441] - Stabilize Travis-CI builds + * [THRIFT-3431] - Avoid "schemes" HashMap lookups during struct reads/writes + * [THRIFT-3432] - Add a TByteBuffer transport to the Java library + * [THRIFT-3438] - Enable py:new_style by default + * [THRIFT-3405] - Go THttpClient misuses http.Client objects + * [THRIFT-3614] - Improve logging of test_sslsocket.py + * [THRIFT-3647] - Fix php extension build warnings + * [THRIFT-3642] - Speed up cross test runner + * [THRIFT-3637] - Implement compact protocol for dart + * [THRIFT-3613] - Port Python C extension to Python 3 + * [THRIFT-3612] - Add Python C extension for compact protocol + * [THRIFT-3611] - Add --regex filter to cross test runner + * [THRIFT-3631] - JSON protocol implementation for Lua + * [THRIFT-3609] - Remove or replace TestPortFixture.h + * [THRIFT-3605] - Have the compiler complain about invalid arguments and options + * [THRIFT-3596] - Better conformance to PEP8 + * [THRIFT-3585] - Compact protocol implementation for Lua + * [THRIFT-3582] - Erlang libraries should have service metadata + * [THRIFT-3579] - Introduce retry to make cross + * [THRIFT-3306] - Java: TBinaryProtocol: Use 1 temp buffer instead of allocating 8 + * [THRIFT-3910] - Do not invoke pip as part of build process + * [THRIFT-1857] - Python 3.X Support + * [THRIFT-1944] - Binding to zero port + * [THRIFT-3954] - Enable the usage of structs called "Object" in Java + * [THRIFT-3981] - Enable analyzer strong mode in Dart library + * [THRIFT-3998] - Document ability to add custom tags to thrift structs + * [THRIFT-4006] - Add a removeEventListener method on TSocket + +## New Feature + * [THRIFT-640] - Support deprecation + * [THRIFT-948] - SSL socket support for PHP + * [THRIFT-764] - add Support for Vala language + * [THRIFT-3046] - Allow PSR4 class loading for generated classes (PHP) + * [THRIFT-2113] - Erlang SSL Socket Support + * [THRIFT-1482] - Unix domain socket support under PHP + * [THRIFT-519] - Support collections of types without having to explicitly define it + * [THRIFT-468] - Rack Middleware Application for Rails + * [THRIFT-1708] - Add event handlers for processor events + * [THRIFT-3834] - Erlang namespacing and exception metadata + * [THRIFT-2510] - Implement TNonblockingServer's ability to listen on unix domain sockets + * [THRIFT-3397] - Implement TProcessorFactory in C# to enable per-client processors + * [THRIFT-3523] - XML Generator + * [THRIFT-3510] - Add HttpTaskAsyncHandler implementation + * [THRIFT-3318] - PHP: SimpleJSONProtocol Implementation + * [THRIFT-3299] - Dart language bindings in Thrift + * [THRIFT-2835] - Add possibility to distribute generators separately from thrift core, and load them dynamically + * [THRIFT-184] - Add OSGi Manifest headers to the libthrift java library to be able to use Thrift in the OSGi runtime + * [THRIFT-141] - If a required field is not present on serialization, throw an exception + * [THRIFT-1891] - Add Windows ALPC transport which is right counterpart of Unix domain sockets + +## Question + * [THRIFT-1808] - The Thrift struct should be considered self-contained? + * [THRIFT-2895] - Tutorial cpp + * [THRIFT-3860] - Elephant-bird application Test fails for Thrift + * [THRIFT-3811] - HTTPS Support for C++ applications + * [THRIFT-3509] - "make check" error + +## Story + * [THRIFT-3452] - .travis.yml: Migrating from legacy to container-based infrastructure + +## Sub-task + * [THRIFT-1811] - ruby tutorial as part of the regular build + * [THRIFT-2779] - PHP TJSONProtocol encode unicode into UCS-4LE which can't be parsed by other language bindings + * [THRIFT-2110] - Erlang: Support for Multiplexing Services on any Transport, Protocol and Server + * [THRIFT-3852] - A Travis-CI job fails with "write error" + * [THRIFT-3740] - Fix haxelib.json classpath + * [THRIFT-3653] - incorrect union serialization + * [THRIFT-3652] - incorrect serialization of optionals + * [THRIFT-3655] - incorrect union serialization + * [THRIFT-3654] - incorrect serialization of optionals + * [THRIFT-3656] - incorrect serialization of optionals + * [THRIFT-3699] - Fix integer limit symbol includes in Python C extension + * [THRIFT-3693] - Fix include issue in C++ TSSLSocketInterruptTest on Windows + * [THRIFT-3694] - [Windows] Disable tests of a few servers that are not supported + * [THRIFT-3696] - Install pip to CentOS Docker images to fix Python builds + * [THRIFT-3638] - Fix haxelib.json + * [THRIFT-3251] - Add http transport for server to Go lib + * [THRIFT-2424] - Recursive Types + * [THRIFT-2423] - THeader + * [THRIFT-2413] - Python: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol + * [THRIFT-2409] - Java: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol + * [THRIFT-2412] - D: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol + * [THRIFT-2411] - C++: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol + * [THRIFT-2410] - JavaMe: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol + * [THRIFT-2668] - TestSuite: detailed result on passed tests by feature + * [THRIFT-2659] - python Test Server fails when throwing TException + * [THRIFT-3398] - Add CMake build for Haskell library and tests + * [THRIFT-3396] - DART: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol + * [THRIFT-3364] - Fix ruby binary field encoding in TJSONProtocol + * [THRIFT-3381] - Fix for misc. codegen issues with THRIFT-2905 + * [THRIFT-3573] - No rule to make target `../../../test/c_glib/src/.deps/testthrifttest-thrift_test_handler.Po'. + * [THRIFT-3572] - "Unable to determine the behavior of a signed right shift" + * [THRIFT-3542] - Add length limit support to Java test server + * [THRIFT-3537] - Remove the (now obsolete) csharp:asyncctp flag + * [THRIFT-3532] - Add configurable string and container read size limit to Python protocols + * [THRIFT-3531] - Create cross lang feature test for string and container read length limit + * [THRIFT-3482] - Haskell JSON protocol does not encode binary field as Base64 + * [THRIFT-3425] - Minor fixes + simplification for CentOS Dockerfile + * [THRIFT-3442] - Run CMake tests on Appveyor + * [THRIFT-3409] - NodeJS binary field issues + * [THRIFT-3621] - Fix lib/cpp/test/SecurityTest.cpp to use ephemeral ports + * [THRIFT-3628] - Fix lib/cpp/test/TServerIntegrationTest.cpp to use ephemeral ports + * [THRIFT-3625] - Kill unused #include "TestPortFixture.h" in lib/cpp/test/TServerTransportTest.cpp. + * [THRIFT-3646] - Fix Python extension build warnings + * [THRIFT-3626] - Fix lib/cpp/test/TSocketInterruptTest.cpp to use ephemeral ports. + * [THRIFT-3624] - Fix lib/cpp/test/TServerSocketTest.cpp to use ephemeral ports + * [THRIFT-3623] - Fix Fix cpp/lib/test/TSSLSocketInterruptTest.cpp to use ephemeral ports + * [THRIFT-3592] - Add basic test client + * [THRIFT-3980] - add TExtendedBinaryProtocol.java + +## Task + * [THRIFT-1801] - Sync up TApplicationException codes across languages and thrift implementations + * [THRIFT-1259] - Automate versioning + +## Test + * [THRIFT-3400] - Add Erlang to cross test + * [THRIFT-3504] - Fix FastbinaryTest.py + +## Wish + * [THRIFT-3923] - Maybe remove Aereo from the "Powered by" list + * [THRIFT-2149] - Add an option to disable the generation of default operators + + + +Thrift 0.9.3 +-------------------------------------------------------------------------------- +## Bug + * [THRIFT-2441] - Cannot shutdown TThreadedServer when clients are still connected + * [THRIFT-2465] - TBinaryProtocolT breaks if copied/moved + * [THRIFT-2474] - thrift.h causes a compile failure + * [THRIFT-2540] - Running configure from outside the source directory fails + * [THRIFT-2598] - Add check for minimum Go version to configure.ac + * [THRIFT-2647] - compiler-hs: don't decapitalize field names, do decapitalize argument bindings + * [THRIFT-2773] - Generated Java code for 'oneway' methods is incorrect. + * [THRIFT-2789] - TNonblockingServer leaks socket FD's under load + * [THRIFT-2682] - TThreadedServer leaks per-thread memory + * [THRIFT-2674] - JavaScript: declare Accept: and Content-Type: in request + * [THRIFT-3078] - TNonblockingServerSocket's logger is not named after TNonblockingServerSocket + * [THRIFT-3077] - C++ TFileTransport ignores return code from ftruncate + * [THRIFT-3067] - C++ cppcheck performance related warnings + * [THRIFT-3066] - C++ TDenseProtocol assert modifies instead of checks + * [THRIFT-3071] - bootstrap.sh on Ubuntu 12.04 (Precise) automake error + * [THRIFT-3069] - C++ TServerSocket leaks socket on fcntl get or set flags error + * [THRIFT-3079] - TNonblockingServerSocket's logger is not named after TNonblockingServerSocket + * [THRIFT-3080] - C++ TNonblockingServer connection leak while accept huge number connections. + * [THRIFT-3086] - C++ Valgrind Error Cleanup + * [THRIFT-3085] - thrift_reconnecting_client never try to reconnect + * [THRIFT-3123] - Missing include in compiler/cpp/src/main.h breaks build in some environments + * [THRIFT-3125] - Fix the list of exported headers in automake input + * [THRIFT-3126] - PHP JSON serializer converts empty or int-indexed maps to lists + * [THRIFT-3132] - Properly format date in Java @Generated annotations + * [THRIFT-3137] - Travis build hangs after failure + * [THRIFT-3138] - "make check" parallel execution is underministic + * [THRIFT-3139] - JS library test is flaky + * [THRIFT-3140] - ConcurrentModificationException is thrown by JavaScript test server + * [THRIFT-3124] - Some signed/unsigned warnings while building compiler + * [THRIFT-3128] - Go generated code produces name collisions between services + * [THRIFT-3146] - Graphviz generates function name collisions between services + * [THRIFT-3147] - Segfault while receiving data + * [THRIFT-3148] - Markdown links to coding_standards are dead + * [THRIFT-3090] - cmake build is broken on MacOSX + * [THRIFT-3097] - cmake targets unconditionally depend on optional libraries + * [THRIFT-3094] - master as of 2015-APR-13 fails -DBOOST_THREADS cmake build + * [THRIFT-3099] - cmake build is broken on FreeBSD + * [THRIFT-3089] - Assigning default ENUM values results in non-compilable java code if java namespace is not defined + * [THRIFT-3093] - mingw compile fixes for c++ library 0.9.2 + * [THRIFT-3098] - Thrift does not pretty print binary typedefs the way it does binary fields + * [THRIFT-3091] - c_glib service method should return result from handler method + * [THRIFT-3088] - TThreadPoolServer with Sasl auth may leak CLOSE_WAIT socket + * [THRIFT-3109] - Cross test log file cannot be browsed when served in HTTP server + * [THRIFT-3113] - m4 C++11 macro issue + * [THRIFT-3105] - C++ libthriftnb library on Windows build failure + * [THRIFT-3115] - Uncompileable code due to name collision with predefined used types + * [THRIFT-3117] - Java TSSLTransportFactory can't load certificates within JAR archive + * [THRIFT-3102] - could not make check for Go Library + * [THRIFT-3120] - Minor spelling errors and an outdated URL + * [THRIFT-3121] - Librt does not exist on OS X + * [THRIFT-3152] - Compiler error on Mac OSX (missing #include ) + * [THRIFT-3162] - make fails for dmd 2.067 + * [THRIFT-3164] - Thrift C++ library SSL socket by default allows for unsecure SSLv3 negotiation + * [THRIFT-3168] - Fix Maven POM + * [THRIFT-3170] - Initialism code in the Go compiler causes chaos + * [THRIFT-3169] - Do not export thrift.TestStruct and thrift.TestEnum in thrift Go library + * [THRIFT-3191] - Perl compiler does not add support for unexpected exception handling + * [THRIFT-3178] - glib C does not compile + * [THRIFT-3189] - Perl ServerSocket should allow a specific interface to be listened to + * [THRIFT-3252] - Missing TConcurrentClientSyncInfo.h in cpp Makefile, so doesn't install + * [THRIFT-3255] - Thrift generator doesn't exclude 'package' keyword for thrift property names breaking java builds + * [THRIFT-3260] - multiple warnings in c_glib tutorial + * [THRIFT-3256] - Some D test timings are too aggressive for slow machines + * [THRIFT-3257] - warning: extra tokens at end of #endif directive + * [THRIFT-3184] - Thrift Go leaves file descriptors open + * [THRIFT-3203] - DOAP - please fix "Ocaml" => "OCaml" + * [THRIFT-3210] - (uncompileable) code generated for server events while are events not enabled + * [THRIFT-3215] - TJSONProtocol '(c++) uses "throw new" to throw exceptions instead of "throw" + * [THRIFT-3202] - Allow HSHAServer to configure min and max worker threads separately. + * [THRIFT-3205] - TCompactProtocol return a wrong error when the io.EOF happens + * [THRIFT-3209] - LGPL mentioned in license file + * [THRIFT-3197] - keepAliveTime is hard coded as 60 sec in TThreadPoolServer + * [THRIFT-3196] - Misspelling in lua TBinaryProtocol (stirctWrite => strictWrite) + * [THRIFT-3198] - Allow construction of TTransportFactory with a specified maxLength + * [THRIFT-3192] - Go import paths changed in 1.4, and expired June 1 + * [THRIFT-3271] - Could not find or load main class configtest_ax_javac_and_java on some non-english systems + * [THRIFT-3273] - c_glib: Generated code tries to convert between function and void pointers + * [THRIFT-3264] - Fix Erlang 16 namespaced types + * [THRIFT-3270] - reusing TNonblockingServer::TConnection cause dirty TSocket + * [THRIFT-3267] - c_glib: "Critical" failure during unit tests + * [THRIFT-3277] - THttpClient leaks connections if it's used for multiple requests + * [THRIFT-3278] - NodeJS: Fix exception stack traces and names + * [THRIFT-3279] - Fix a bug in retry_max_delay (NodeJS) + * [THRIFT-3280] - Initialize retry variables on construction + * [THRIFT-3283] - c_glib: Tutorial server always exits with warning + * [THRIFT-3284] - c_glib: Empty service produces unused-variable warning + * [THRIFT-1925] - c_glib generated code does not compile + * [THRIFT-1849] - after transport->open() opens isOpen returns true and next open() goes thru when it shall not + * [THRIFT-1866] - java compiler generates non-compiling code with const's defined in a thrift when name includes non-identifier chars + * [THRIFT-1938] - FunctionRunner.h -- uses wrong path for Thread.h when installed + * [THRIFT-1844] - Password string not cleared + * [THRIFT-2004] - Thrift::Union violates :== method contract and crashes + * [THRIFT-2073] - Thrift C++ THttpClient error: cannot refill buffer + * [THRIFT-2127] - Autoconf scripting does not properly account for cross-compile + * [THRIFT-2180] - Integer types issues in Cocoa lib on ARM64 + * [THRIFT-2189] - Go needs "isset" to fully support "union" type (and optionals) + * [THRIFT-2192] - autotools on Redhat based systems + * [THRIFT-2546] - cross language tests fails at 'TestMultiException' when using nodejs server + * [THRIFT-2547] - nodejs servers and clients fails to connect with cpp using compact protocol + * [THRIFT-2548] - Nodejs servers and clients does not work properly with -ssl + * [THRIFT-1471] - toString() does not print ByteBuffer values when nested in a List + * [THRIFT-1201] - getaddrinfo resource leak + * [THRIFT-615] - TThreadPoolServer doesn't call task_done after pulling tasks from it's clients queue + * [THRIFT-162] - Thrift structures are unhashable, preventing them from being used as set elements + * [THRIFT-810] - Crashed client on TSocket::close under loads + * [THRIFT-557] - charset problem with file Autogenerated by Thrift + * [THRIFT-233] - IDL doesn't support negative hex literals + * [THRIFT-1649] - contrib/zeromq does not build in 0.8.0 + * [THRIFT-1642] - Miscalculation lead to throw unexpected "TTransportException::TIMED_OUT"(or called "EAGAIN (timed out)") exception + * [THRIFT-1587] - TSocket::setRecvTimeout error + * [THRIFT-1248] - pointer subtraction in TMemoryBuffer relies on undefined behavior + * [THRIFT-1774] - Sasl Transport client would hang when trying to connect non-sasl transport server + * [THRIFT-1754] - RangeError in buffer handling + * [THRIFT-1618] - static structMap in FieldMetaData is not thread safe and can lead to deadlocks + * [THRIFT-2335] - thrift incompatibility with py:tornado as server, java as client + * [THRIFT-2803] - TCP_DEFER_ACCEPT not supported with domain sockets + * [THRIFT-2799] - Build Problem(s): ld: library not found for -l:libboost_unit_test_framework.a + * [THRIFT-2801] - C++ test suite compilation warnings + * [THRIFT-2802] - C++ tutorial compilation warnings + * [THRIFT-2795] - thrift_binary_protocol.c: 'dereferencing type-punned pointer will break strict-aliasing rules' + * [THRIFT-2817] - TSimpleJSONProtocol reads beyond end of message + * [THRIFT-2826] - html:standalone sometimes ignored + * [THRIFT-2829] - Support haxelib installation via github + * [THRIFT-2828] - slightly wrong help screen indent + * [THRIFT-2831] - Removes dead code in web_server.js introduced in THRIFT-2819 + * [THRIFT-2823] - All JS-tests are failing when run with grunt test + * [THRIFT-2827] - Thrift 0.9.2 fails to compile on Yosemite due to tr1/functional include in ProcessorTest.cpp + * [THRIFT-2843] - Automake configure.ac has possible typo related to Java + * [THRIFT-2813] - multiple haxe library fixes/improvements + * [THRIFT-2825] - Supplying unicode to python Thrift client can cause next request arguments to get overwritten + * [THRIFT-2840] - Cabal file points to LICENSE file outside the path of the Haskell project. + * [THRIFT-2818] - Trailing commas in array + * [THRIFT-2830] - Clean up ant warnings in tutorial dir + * [THRIFT-2842] - Erlang thrift client has infinite timeout + * [THRIFT-2810] - Do not leave the underlying ServerSocket open if construction of TServerSocket fails + * [THRIFT-2812] - Go server adding redundant buffering layer + * [THRIFT-2839] - TFramedTransport read bug + * [THRIFT-2844] - Nodejs support broken when running under Browserify + * [THRIFT-2814] - args/result classes not found when no namespace is set + * [THRIFT-2847] - function IfValue() is a duplicate of System.StrUtils.IfThen + * [THRIFT-2848] - certain Delphi tests do not build if TypeRegistry is used + * [THRIFT-2854] - Go Struct writer and reader looses important error information + * [THRIFT-2858] - Enable header field case insensitive match in THttpServer + * [THRIFT-2857] - C# generator creates uncompilable code for struct constants + * [THRIFT-2860] - Delphi server closes connection on unexpected exceptions + * [THRIFT-2868] - Enhance error handling in the Go client + * [THRIFT-2879] - TMemoryBuffer: using lua string in wrong way + * [THRIFT-2851] - Remove strange public Peek() from Go transports + * [THRIFT-2852] - Better Open/IsOpen/Close behavior for StreamTransport. + * [THRIFT-2871] - Missing semicolon in thrift.js + * [THRIFT-2872] - ThreadManager deadlock for task expiration + * [THRIFT-2881] - Handle errors from Accept() correctly + * [THRIFT-2849] - Spell errors reported by codespell tool + * [THRIFT-2870] - C++ TJSONProtocol using locale dependent formatting + * [THRIFT-2882] - Lua Generator: using string.len funtion to get struct(map,list,set) size + * [THRIFT-2864] - JSON generator missing from Visual Studio build project + * [THRIFT-2878] - Go validation support of required fields + * [THRIFT-2873] - TPipe and TPipeServer don't compile on Windows with UNICODE enabled + * [THRIFT-2888] - import of is missing in JSON generator + * [THRIFT-2900] - Python THttpClient does not reset socket timeout on exception + * [THRIFT-2907] - 'ntohll' macro redefined + * [THRIFT-2884] - Map does not serialize correctly for JSON protocol in Go library + * [THRIFT-2887] - --with-openssl configure flag is ignored + * [THRIFT-2894] - PHP json serializer skips maps with int/bool keys + * [THRIFT-2904] - json_protocol_test.go fails + * [THRIFT-2906] - library not found for -l:libboost_unit_test_framework.a + * [THRIFT-2890] - binary data may lose bytes with JSON transport under specific circumstances + * [THRIFT-2891] - binary data may cause a failure with JSON transport under specific circumstances + * [THRIFT-2901] - Fix for generated TypeScript functions + indentation of JavaScript maps + * [THRIFT-2916] - make check fails for D language + * [THRIFT-2918] - Race condition in Python TProcessPoolServer test + * [THRIFT-2920] - Erlang Thrift test uses wrong IDL file + * [THRIFT-2922] - $TRIAL is used with Python tests but not tested accordingly + * [THRIFT-2912] - Autotool build for C++ Qt library is invalid + * [THRIFT-2914] - explicit dependency to Lua5.2 fails on some systems + * [THRIFT-2910] - libevent is not really optional + * [THRIFT-2911] - fix c++ version zeromq transport, the old version cannot work + * [THRIFT-2915] - Lua generator missing from Visual Studio build project + * [THRIFT-2917] - "make clean" breaks test/c_glib + * [THRIFT-2919] - Haxe test server timeout too large + * [THRIFT-2923] - JavaScript client assumes a message being written + * [THRIFT-2924] - TNonblockingServer crashes when user-provided event_base is used + * [THRIFT-2925] - CMake build does not work with OpenSSL nor anything installed in non-system location + * [THRIFT-2931] - Access to undeclared static property: Thrift\Protocol\TProtocol::$TBINARYPROTOCOLACCELERATED + * [THRIFT-2893] - CMake build fails with boost thread or std thread + * [THRIFT-2902] - Generated c_glib code does not compile with clang + * [THRIFT-2903] - Qt4 library built with CMake does not work + * [THRIFT-2942] - CSharp generate invalid code for property named read or write + * [THRIFT-2932] - Node.js Thrift connection libraries throw Exceptions into event emitter + * [THRIFT-2933] - v0.9.2: doubles encoded in node with compact protocol cannot be decoded by python + * [THRIFT-2934] - createServer signature mismatch + * [THRIFT-2981] - IDL with no namespace produces unparsable PHP + * [THRIFT-2999] - Addition of .gitattributes text auto in THRIFT-2724 causes modified files on checkout + * [THRIFT-2949] - typo in compiler/cpp/README.md + * [THRIFT-2957] - warning: source file %s is in a subdirectory, but option 'subdir-objects' is disabled + * [THRIFT-2953] - TNamedPipeServerTransport is not Stop()able + * [THRIFT-2962] - Docker Thrift env for development and testing + * [THRIFT-2971] - C++ test and tutorial parallel build is unstable + * [THRIFT-2972] - Missing backslash in lib/cpp/test/Makefile.am + * [THRIFT-2951] - Fix Erlang name conflict test + * [THRIFT-2955] - Using list of typedefs does not compile on Go + * [THRIFT-2960] - namespace regression for Ruby + * [THRIFT-2959] - nodejs: fix binary unit tests + * [THRIFT-2966] - nodejs: Fix bad references to TProtocolException and TProtocolExceptionType + * [THRIFT-2970] - grunt-jsdoc fails due to dependency issues + * [THRIFT-3001] - C# Equals fails for binary fields (byte[]) + * [THRIFT-3003] - Missing LICENSE file prevents package from being installed + * [THRIFT-3008] - Node.js server does not fully support exception + * [THRIFT-3007] - Travis build is broken because of directory conflict + * [THRIFT-3009] - TSSLSocket does not use the correct hostname (breaks certificate checks) + * [THRIFT-3011] - C# test server testException() not implemented according to specs + * [THRIFT-3012] - Timing problems in NamedPipe implementation due to unnecessary open/close + * [THRIFT-3019] - Golang generator missing docstring for structs + * [THRIFT-3021] - Service remote tool does not import stub package with package prefix + * [THRIFT-3026] - TMultiplexedProcessor does not have a constructor + * [THRIFT-3028] - Regression caused by THRIFT-2180 + * [THRIFT-3017] - order of map key/value types incorrect for one CTOR + * [THRIFT-3020] - Cannot compile thrift as C++03 + * [THRIFT-3024] - User-Agent "BattleNet" used in some Thrift library files + * [THRIFT-3047] - Uneven calls to indent_up and indent_down in Cocoa generator + * [THRIFT-3048] - NodeJS decoding of I64 is inconsistent across protocols + * [THRIFT-3043] - go compiler generator uses non C++98 code + * [THRIFT-3044] - Docker README.md paths to Dockerfiles are incorrect + * [THRIFT-3040] - bower.json wrong "main" path + * [THRIFT-3051] - Go Thrift generator creates bad go code + * [THRIFT-3057] - Java compiler build is broken + * [THRIFT-3061] - C++ TSSLSocket shutdown delay/vulnerability + * [THRIFT-3062] - C++ TServerSocket invalid port number (over 999999) causes stack corruption + * [THRIFT-3065] - Update libthrift dependencies (slf4j, httpcore, httpclient) + * [THRIFT-3244] - TypeScript: fix namespace of included types + * [THRIFT-3246] - Reduce the number of trivial warnings in Windows C++ CMake builds + * [THRIFT-3224] - Fix TNamedPipeServer unpredictable behavior on accept + * [THRIFT-3230] - Python compiler generates wrong code if there is function throwing a typedef of exception with another namespace + * [THRIFT-3236] - MaxSkipDepth never checked + * [THRIFT-3239] - Limit recursion depth + * [THRIFT-3241] - fatal error: runtime: cannot map pages in arena address space + * [THRIFT-3242] - OSGi Import-Package directive is missing the Apache HTTP packages + * [THRIFT-3234] - Limit recursion depth + * [THRIFT-3222] - TypeScript: Generated Enums are quoted + * [THRIFT-3229] - unexpected Timeout exception when desired bytes are only partially available + * [THRIFT-3231] - CPP: Limit recursion depth to 64 + * [THRIFT-3235] - Limit recursion depth + * [THRIFT-3175] - fastbinary.c python deserialize can cause huge allocations from garbage + * [THRIFT-3176] - Union incorrectly implements == + * [THRIFT-3177] - Fails to run rake test + * [THRIFT-3180] - lua plugin: framed transport do not work + * [THRIFT-3179] - lua plugin cant connect to remote server because function l_socket_create_and_connect always bind socket to localhost + * [THRIFT-3248] - TypeScript: additional comma in method signature without parameters + * [THRIFT-3302] - Go JSON protocol should encode Thrift byte type as signed integer string + * [THRIFT-3297] - c_glib: an abstract base class is not generated + * [THRIFT-3294] - TZlibTransport for Java does not write data correctly + * [THRIFT-3296] - Go cross test does not conform to spec + * [THRIFT-3295] - C# library does not build on Mono 4.0.2.5 or later + * [THRIFT-3293] - JavaScript: null values turn into empty structs in constructor + * [THRIFT-3310] - lib/erl/README.md has incorrect formatting + * [THRIFT-3319] - CSharp tutorial will not build using the *.sln + * [THRIFT-3335] - Ruby server does not handle processor exception + * [THRIFT-3338] - Stray underscore in generated go when service name starts with "New" + * [THRIFT-3324] - Update Go Docs for pulling all packages + * [THRIFT-3345] - Clients blocked indefinitely when a java.lang.Error is thrown + * [THRIFT-3332] - make dist fails on clean build + * [THRIFT-3326] - Tests do not compile under *BSD + * [THRIFT-3334] - Markdown notation of protocol spec is malformed + * [THRIFT-3331] - warning: ‘etype’ may be used uninitialized in this function + * [THRIFT-3349] - Python server does not handle processor exception + * [THRIFT-3343] - Fix haskell README + * [THRIFT-3340] - Python: enable json tests again + * [THRIFT-3311] - Top level README.md has incorrect formmating + * [THRIFT-2936] - Minor memory leak in SSL + * [THRIFT-3290] - Using from in variable names causes the generated Python code to have errors + * [THRIFT-3225] - Fix TPipeServer unpredictable behavior on interrupt() + * [THRIFT-3354] - Fix word-extraction substr bug in initialism code + * [THRIFT-2006] - TBinaryProtocol message header call name length is not validated and can be used to core the server + * [THRIFT-3329] - C++ library unit tests don't compile against the new boost-1.59 unit test framework + * [THRIFT-2630] - windows7 64bit pc. ipv4 and ipv6 pc.can't use + * [THRIFT-3336] - Thrift generated streaming operators added in 0.9.2 cannot be overridden + * [THRIFT-2681] - Core of unwind_cleanup + * [THRIFT-3317] - cpp namespace org.apache issue appears in 0.9 + +## Documentation + * [THRIFT-3286] - Apache Ant is a necessary dependency + +## Improvement + * [THRIFT-227] - Byte[] in collections aren't pretty printed like regular binary fields + * [THRIFT-2744] - Vagrantfile for Centos 6.5 + * [THRIFT-2644] - Haxe support + * [THRIFT-2756] - register Media Type @ IANA + * [THRIFT-3076] - Compatibility with Haxe 3.2.0 + * [THRIFT-3081] - C++ Consolidate client processing loops in TServers + * [THRIFT-3083] - C++ Consolidate server processing loops in TSimpleServer, TThreadedServer, TThreadPoolServer + * [THRIFT-3084] - C++ add concurrent client limit to threaded servers + * [THRIFT-3074] - Add compiler/cpp/lex.yythriftl.cc to gitignore. + * [THRIFT-3134] - Remove use of deprecated "phantom.args" + * [THRIFT-3133] - Allow "make cross" and "make precross" to run without building all languages + * [THRIFT-3142] - Make JavaScript use downloaded libraries + * [THRIFT-3141] - Improve logging of JavaScript test + * [THRIFT-3144] - Proposal: make String representation of enums in generated go code less verbose + * [THRIFT-3130] - Remove the last vestiges of THRIFT_OVERLOAD_IF from THRIFT-1316 + * [THRIFT-3131] - Consolidate suggested import path for go thrift library to git.apache.org in docs and code + * [THRIFT-3092] - Generated Haskell types should derive Generic + * [THRIFT-3110] - Print error log after cross test failures on Travis + * [THRIFT-3114] - Using local temp variables to not pollute the global table + * [THRIFT-3106] - CMake summary should give more information why a library is set to off + * [THRIFT-3119] - Java's TThreadedSelectorServer has indistinguishable log messages in run() + * [THRIFT-3122] - Javascript struct constructor should properly initialize struct and container members from plain js arguments + * [THRIFT-3151] - Fix links to git-wip* - should be git.apache.org + * [THRIFT-3167] - Windows build from source instructions need to be revised + * [THRIFT-3155] - move contrib/mingw32-toolchain.cmake to build/cmake/ + * [THRIFT-3160] - Make generated go enums implement TextMarshaller and TextUnmarshaller interfaces + * [THRIFT-3150] - Add an option to thrift go generator to make Read and Write methods private + * [THRIFT-3149] - Make ReadFieldN methods in generated Go code private + * [THRIFT-3172] - Add tutorial to Thrift web site + * [THRIFT-3214] - Add Erlang option for using maps instead of dicts + * [THRIFT-3201] - Capture github test artifacts for failed builds + * [THRIFT-3266] - c_glib: Multiple compiler warnings building unit tests + * [THRIFT-3285] - c_glib: Build library with all warnings enabled, no warnings generated + * [THRIFT-1954] - Allow for a separate connection timeout value + * [THRIFT-2098] - Add support for Qt5+ + * [THRIFT-2199] - Remove Dense protocol (was: move to Contrib) + * [THRIFT-406] - C++ Test suite cleanup + * [THRIFT-902] - socket and connect timeout in TSocket should be distinguished + * [THRIFT-388] - Use a separate wire format for async calls + * [THRIFT-727] - support native C++ language specific exception message + * [THRIFT-1784] - pep-3110 compliance for exception handling + * [THRIFT-1025] - C++ ServerSocket should inherit from Socket with the necessary Ctor to listen on connections from a specific host + * [THRIFT-2269] - Can deploy libthrift-source.jar to maven center repository + * [THRIFT-2804] - Pull an interface out of TBaseAsyncProcessor + * [THRIFT-2806] - more whitespace fixups + * [THRIFT-2811] - Make remote socket address accessible + * [THRIFT-2809] - .gitignore update for compiler's visual project + * [THRIFT-2846] - Expose ciphers parameter from ssl.wrap_socket() + * [THRIFT-2859] - JSON generator: output complete descriptors + * [THRIFT-2861] - add buffered transport + * [THRIFT-2865] - Test case for Go: SeqId out of sequence + * [THRIFT-2866] - Go generator source code is hard to read and maintain + * [THRIFT-2880] - Read the network address from the listener if available. + * [THRIFT-2875] - Typo in TDenseProtocol.h comment + * [THRIFT-2874] - TBinaryProtocol member variable "string_buf_" is never used. + * [THRIFT-2855] - Move contributing.md to the root of the repository + * [THRIFT-2862] - Enable RTTI and/or build macros for generated code + * [THRIFT-2876] - Add test for THRIFT-2526 Assignment operators and copy constructors in c++ don't copy the __isset struct + * [THRIFT-2897] - Generate -isEqual: and -hash methods + * [THRIFT-2909] - Improve travis build + * [THRIFT-2921] - Make Erlang impl ready for OTP 18 release (dict/0 and set/0 are deprecated) + * [THRIFT-2928] - Rename the erlang test_server module + * [THRIFT-2940] - Allow installing Thrift from git as NPM module by providing package.json in top level directory + * [THRIFT-2937] - Allow setting a maximum frame size in TFramedTransport + * [THRIFT-2976] - nodejs: xhr and websocket support for browserify + * [THRIFT-2996] - Test for Haxe 3.1.3 or better + * [THRIFT-2969] - nodejs: DRY up library tests + * [THRIFT-2973] - Update Haxe lib readme regarding Haxe 3.1.3 + * [THRIFT-2952] - Improve handling of Server.Stop() + * [THRIFT-2964] - nodejs: move protocols and transports into separate files + * [THRIFT-2963] - nodejs - add test coverage + * [THRIFT-3006] - Attach 'omitempty' json tag for optional fields in Go + * [THRIFT-3027] - Go compiler does not ensure common initialisms have consistent case + * [THRIFT-3030] - TThreadedServer: Property for number of clientThreads + * [THRIFT-3023] - Go compiler is a little overly conservative with names of attributes + * [THRIFT-3018] - Compact protocol for Delphi + * [THRIFT-3025] - Change pure Int constants into @enums (where possible) + * [THRIFT-3031] - migrate "shouldStop" flag to TServer + * [THRIFT-3022] - Compact protocol for Haxe + * [THRIFT-3041] - Generate asynchronous clients for Cocoa + * [THRIFT-3053] - Perl SSL Socket Support (Encryption) + * [THRIFT-3247] - Generate a C++ thread-safe client + * [THRIFT-3217] - Provide a little endian variant of the binary protocol in C++ + * [THRIFT-3223] - TypeScript: Add initial support for Enum Maps + * [THRIFT-3220] - Option to suppress @Generated Annotation entirely + * [THRIFT-3300] - Reimplement TZlibTransport in Java using streams + * [THRIFT-3288] - c_glib: Build unit tests with all warnings enabled, no warnings generated + * [THRIFT-3347] - Improve cross test servers and clients + * [THRIFT-3342] - Improve ruby cross test client and server compatibility + * [THRIFT-2296] - Add C++ Base class for service + * [THRIFT-3337] - Add testBool method to cross tests + * [THRIFT-3303] - Disable concurrent cabal jobs on Travis to avoid GHC crash + * [THRIFT-2623] - Docker container for Thrift + * [THRIFT-3298] - thrift endian converters may conflict with other libraries + * [THRIFT-1559] - Provide memory pool for TBinaryProtocol to eliminate memory fragmentation + * [THRIFT-424] - Steal ProtocolBuffers' VarInt implementation for C++ + +## New Feature + * [THRIFT-3070] - Add ability to set the LocalCertificateSelectionCallback + * [THRIFT-1909] - Java: Add compiler flag to use the "option pattern" for optional fields + * [THRIFT-2099] - Stop TThreadPoolServer with alive connections. + * [THRIFT-123] - implement TZlibTransport in Java + * [THRIFT-2368] - New option: reuse-objects for Java generator + * [THRIFT-2836] - Optionally generate C++11 MoveConstructible types + * [THRIFT-2824] - Flag to disable html escaping doctext + * [THRIFT-2819] - Add WebsSocket client to node.js + * [THRIFT-3050] - Client certificate authentication for non-http TLS in C# + * [THRIFT-3292] - Implement TZlibTransport in Go + +## Question + * [THRIFT-2583] - Thrift on xPC target (SpeedGoat) + * [THRIFT-2592] - thrift server using c_glib + * [THRIFT-2832] - c_glib: Handle string lists correctly + * [THRIFT-3136] - thrift installation problem on mac + * [THRIFT-3346] - c_glib: Tutorials example crashes saying Calculator.ping implementation returned FALSE but did not set an error + +## Sub-task + * [THRIFT-2578] - Moving 'make cross' from test.sh to test.py + * [THRIFT-2734] - Go coding standards + * [THRIFT-2748] - Add Vagrantfile for Centos 6.5 + * [THRIFT-2753] - Misc. Haxe improvements + * [THRIFT-2640] - Compact Protocol in Cocoa + * [THRIFT-3262] - warning: overflow in implicit constant conversion in DenseProtoTest.cpp + * [THRIFT-3194] - Can't build with go enabled. gomock SCC path incorrect. + * [THRIFT-3275] - c_glib tutorial warnings in generated code + * [THRIFT-1125] - Multiplexing support for the Ruby Library + * [THRIFT-2807] - PHP Code Style + * [THRIFT-2841] - Add comprehensive integration tests for the whole Go stack + * [THRIFT-2815] - Haxe: Support for Multiplexing Services on any Transport, Protocol and Server + * [THRIFT-2886] - Integrate binary type in standard Thrift cross test + * [THRIFT-2946] - Enhance usability of cross test framework + * [THRIFT-2967] - Add .editorconfig to root + * [THRIFT-3033] - Perl: Support for Multiplexing Services on any Transport, Protocol and Server + * [THRIFT-3174] - Initialism code in the Go compiler doesn't check first word + * [THRIFT-3193] - Option to supress date value in @Generated annotation + * [THRIFT-3305] - Missing dist files for 0.9.3 release candidate + * [THRIFT-3341] - Add testBool methods + * [THRIFT-3308] - Fix broken test cases for 0.9.3 release candidate + +## Task + * [THRIFT-2834] - Remove semi-colons from python code generator + * [THRIFT-2853] - Adjust comments not applying anymore after THRIFT-2852 + +## Test + * [THRIFT-3211] - Add make cross support for php TCompactProtocol + +## Wish + * [THRIFT-2838] - TNonblockingServer can bind to port 0 (i.e., get an OS-assigned port) but there is no way to get the port number + + + +Thrift 0.9.2 +-------------------------------------------------------------------------------- +## Bug + * [THRIFT-2793] - Go compiler produces uncompilable code + * [THRIFT-1481] - Unix domain sockets in C++ do not support the abstract namespace + * [THRIFT-1455] - TBinaryProtocolT::writeString casts from size_t to uint32_t, which is not safe on 64-bit platforms + * [THRIFT-1579] - PHP Extention - function thrift_protocol_read_binary not working from TBinarySerializer::deserialize + * [THRIFT-1584] - Error: could not SetMinThreads in ThreadPool on single-core machines + * [THRIFT-1614] - Thrift build from svn repo sources fails with automake-1.12 + * [THRIFT-1047] - rb_thrift_memory_buffer_write treats arg as string without check, segfaults if you pass non-string + * [THRIFT-1639] - Java/Python: Serialization/Deserialization of double type using CompactProtocol + * [THRIFT-1647] - NodeJS BufferedTransport does not work beyond the hello-world example + * [THRIFT-2130] - Thrift's D library/test: parts of "make check" code do not compile with recent dmd-2.062 through dmd-2.064alpha + * [THRIFT-2140] - Error compiling cpp tutorials + * [THRIFT-2139] - MSVC 2012 Error - Cannot compile due to BoostThreadFactory + * [THRIFT-2138] - pkgconfig file created with wrong include path + * [THRIFT-2160] - Warning in thrift.h when compiling with -Wunused and NDEBUG + * [THRIFT-2158] - Compact, JSON, and SimpleJSON protocols are not working correctly + * [THRIFT-2167] - nodejs lib throws error if options argument isn't passed + * [THRIFT-2288] - Go impl of Thrift JSON protocol wrongly writes/expects true/false for bools + * [THRIFT-2147] - Thrift IDL grammar allows for dotted identifier names + * [THRIFT-2145] - Rack and Thin are not just development dependencies + * [THRIFT-2267] - Should be able to choose socket family in Python TSocket + * [THRIFT-2276] - java path in spec file needs updating + * [THRIFT-2281] - Generated send/recv code ignores errors returned by the underlying protocol + * [THRIFT-2280] - TJSONProtocol.Flush() does not really flush the transport + * [THRIFT-2274] - TNonblockingServer and TThreadedSelectorServer do not close their channel selectors on exit and leak file descriptors + * [THRIFT-2265] - php library doesn't build + * [THRIFT-2232] - IsSet* broken in Go + * [THRIFT-2246] - Unset enum value is printed by ToString() + * [THRIFT-2240] - thrift.vim (contrib) does not correctly handle 'union' + * [THRIFT-2243] - TNonblockingServer in thrift crashes when TFramedTransport opens + * [THRIFT-2230] - Cannot Build on RHEL/Centos/Amazon Linux 6.x + * [THRIFT-2247] - Go generator doesn't deal well with map keys of type binary + * [THRIFT-2253] - Python Tornado TTornadoServer base class change + * [THRIFT-2261] - java: error: unmappable character for encoding ASCII + * [THRIFT-2259] - C#: unexpected null logDelegate() pointer causes AV in TServer.serve() + * [THRIFT-2225] - SSLContext destroy before cleanupOpenSSL + * [THRIFT-2224] - TSSLSocket.h and TSSLServerSocket.h should use the platfromsocket too + * [THRIFT-2229] - thrift failed to build on OSX 10.9 GM + * [THRIFT-2227] - Thrift compiler generates spurious warnings with Xlint + * [THRIFT-2219] - Thrift gem fails to build on OS X Mavericks with 1.9.3 rubies + * [THRIFT-2226] - TServerSocket - keepAlive wrong initialization order + * [THRIFT-2285] - TJsonProtocol implementation for Java doesn't allow a slash (/) to be escaped (\/) + * [THRIFT-2216] - Extraneous semicolon in TProtocolUtil.h makes clang mad + * [THRIFT-2215] - Generated HTML/Graphviz lists referenced enum identifiers as UNKNOWN. + * [THRIFT-2211] - Exception constructor does not contain namespace prefix. + * [THRIFT-2210] - lib/java TSimpleJSONProtocol can emit invalid JSON + * [THRIFT-2209] - Ruby generator -- please namespace classes + * [THRIFT-2202] - Delphi TServerImpl.DefaultLogDelegate may stop the server with I/O-Error 105 + * [THRIFT-2201] - Ternary operator returns different types (build error for some compilers) + * [THRIFT-2200] - nested structs cause generate_fingerprint() to slow down at excessive CPU load + * [THRIFT-2197] - fix jar output directory in rpm spec file + * [THRIFT-2196] - Fix invalid dependency in Makefile.am + * [THRIFT-2194] - Node: Not actually prepending residual data in TFramedTransport.receiver + * [THRIFT-2193] - Java code generator emits spurious semicolon when deep copying binary data + * [THRIFT-2191] - Fix charp JSONProtocol.ReadJSONDouble (specify InvariantCulture) + * [THRIFT-2214] - System header sys/param.h is included inside the Thrift namespace + * [THRIFT-2178] - Thrift generator returns error exit code on --version + * [THRIFT-2171] - NodeJS implementation has extremely low test coverage + * [THRIFT-2183] - gem install fails on zsh + * [THRIFT-2182] - segfault in regression tests (GC bug in rb_thrift_memory_buffer_write) + * [THRIFT-2181] - oneway calls don't work in NodeJS + * [THRIFT-2169] - JavaME Thrift Library causes "java.io.IOException: No Response Entries Available" after using the Thrift client for some time + * [THRIFT-2168] - Node.js appears broken (at least, examples don't work as intended) + * [THRIFT-2293] - TSSLTransportFactory.createSSLContext() leaves files open + * [THRIFT-2279] - TSerializer only returns the first 1024 bytes serialized + * [THRIFT-2278] - Buffered transport doesn't support writes > buffer size + * [THRIFT-2275] - Fix memory leak in golang compact_protocol. + * [THRIFT-2282] - Incorect code generated for some typedefs + * [THRIFT-2009] - Go redeclaration error + * [THRIFT-1964] - 'Isset' causes problems with C#/.NET serializers + * [THRIFT-2026] - Fix TCompactProtocol 64 bit builds + * [THRIFT-2108] - Fix TAsyncClientManager timeout race + * [THRIFT-2068] - Multiple calls from same connection are not processed in node + * [THRIFT-1750] - Make compiler build cleanly under visual studio 10 + * [THRIFT-1755] - Comment parsing bug + * [THRIFT-1771] - "make check" fails on x64 for libboost_unit_test_framework.a + * [THRIFT-1841] - NodeJS Thrift incorrectly parses non-UTF8-string types + * [THRIFT-1908] - Using php thrift_protocol accelerated transfer causes core dump + * [THRIFT-1892] - Socket timeouts are declared in milli-seconds, but are actually set in micro-seconds + * [THRIFT-2303] - TBufferredTransport not properly closing underlying transport + * [THRIFT-2313] - nodejs server crash after processing the first request when using MultiplexedProcessor/FramedBuffer/BinaryProtocol + * [THRIFT-2311] - Go: invalid code generated when exception name is a go keyword + * [THRIFT-2308] - node: TJSONProtocol parse error when reading from buffered message + * [THRIFT-2316] - ccp: TFileTransportTest + * [THRIFT-2352] - msvc failed to compile thrift tests + * [THRIFT-2337] - Golang does not report TIMED_OUT exceptions + * [THRIFT-2340] - Generated server implementation does not send response type EXCEPTION on the Thrift.TApplicationExceptionType.UNKNOWN_METHOD exception + * [THRIFT-2354] - Connection errors can lead to case_clause exceptions + * [THRIFT-2339] - Uncaught exception in thrift c# driver + * [THRIFT-2356] - c++ thrift client not working with ssl (SSL_connect hangs) + * [THRIFT-2331] - Missing call to ReadStructBegin() in TApplicationException.Read() + * [THRIFT-2323] - Uncompileable Delphi code generated for typedef'd structs + * [THRIFT-2322] - Correctly show the number of times ExecutorService (java) has rejected the client. + * [THRIFT-2389] - namespaces handled wrongly in acrionscript 3.0 implementation + * [THRIFT-2388] - GoLang - Fix data races in simple_server and server_socket + * [THRIFT-2386] - Thrift refuses to link yylex + * [THRIFT-2375] - Excessive
's in generated HTML + * [THRIFT-2373] - warning CS0414 in THttpClient.cs: private field 'Thrift.Transport.THttpClient.connection' assigned but never used + * [THRIFT-2372] - thrift/json_protocol.go:160: function ends without a return statement + * [THRIFT-2371] - ruby bundler version fails on ~1.3.1, remove and take latest avail + * [THRIFT-2370] - Compiler SEGFAULTs generating HTML documentation for complex strucre + * [THRIFT-2384] - Binary map keys produce uncompilable code in go + * [THRIFT-2380] - unreachable code (CID 1174546, CID 1174679) + * [THRIFT-2378] - service method arguments of binary type lead to uncompileable Go code + * [THRIFT-2363] - Issue with character encoding of Success returned from Login using Thrift Proxy and NodeJS + * [THRIFT-2359] - TBufferedTransport doesn't clear it's buffer on a failed flush call + * [THRIFT-2428] - Python 3 setup.py support + * [THRIFT-2367] - Build failure: stdlib and boost both define uint64_t + * [THRIFT-2365] - C# decodes too many binary bytes from JSON + * [THRIFT-2402] - byte count of FrameBuffer in AWAITING_CLOSE state is not subtracted from readBufferBytesAllocated + * [THRIFT-2396] - Build Error on MacOSX + * [THRIFT-2395] - thrift Ruby gem requires development dependency 'thin' regardless of environment + * [THRIFT-2414] - c_glib fix several bug. + * [THRIFT-2420] - Go argument parser for methods without arguments does not skip fields + * [THRIFT-2439] - Bug in TProtocolDecorator Class causes parsing errors + * [THRIFT-2419] - golang - Fix fmt.Errorf in generated code + * [THRIFT-2418] - Go handler function panics on internal error + * [THRIFT-2405] - Node.js Multiplexer tests fail (silently) + * [THRIFT-2581] - TFDTransport destructor should not throw + * [THRIFT-2575] - Thrift includes siginfo_t within apache::thrift::protocol namespace + * [THRIFT-2577] - TFileTransport missuse of closesocket on windows platform + * [THRIFT-2576] - Implement Thrift.Protocol.prototype.skip method in JavaScript library + * [THRIFT-2588] - Thrift compiler is not buildable in Visual Studio 2010 + * [THRIFT-2594] - JS Compiler: Single quotes are not being escaped in constants. + * [THRIFT-2591] - TFramedTransport does not handle payloads split across packets correctly + * [THRIFT-2599] - Uncompileable Delphi code due to naming conflicts with IDL + * [THRIFT-2590] - C++ Visual Studio solution doesn't include Multiplexing support + * [THRIFT-2595] - Node.js: Fix global leaks and copy-paste errors + * [THRIFT-2565] - autoconf fails to find mingw-g++ cross compiler on travis CI + * [THRIFT-2555] - excessive "unused field" comments + * [THRIFT-2554] - double initialization in generated Read() method + * [THRIFT-2551] - OutOfMemoryError "unable to create new native thread" kills serve thread + * [THRIFT-2543] - Generated enum type in haskell should be qualified + * [THRIFT-2560] - Thrift compiler generator tries to concat ints with strings using + + * [THRIFT-2559] - Centos 6.5 unable to "make" with Thrift 0.9.1 + * [THRIFT-2526] - Assignment operators and copy constructors in c++ don't copy the __isset struct + * [THRIFT-2454] - c_glib: There is no gethostbyname_r() in some OS. + * [THRIFT-2451] - Do not use pointers for optional fields with defaults. Do not write such fields if its value set to default. Also, do not use pointers for any optional fields mapped to go map or slice. generate Get accessors + * [THRIFT-2450] - include HowToContribute in the src repo + * [THRIFT-2448] - thrift/test/test.sh has incorrect Node.js test path + * [THRIFT-2460] - unopened socket fd must be less than zero. + * [THRIFT-2459] - --version should not exit 1 + * [THRIFT-2468] - Timestamp handling + * [THRIFT-2467] - Unable to build contrib/fb303 on OSX 10.9.2 + * [THRIFT-2466] - Improper error handling for SSL/TLS connections that don't complete a handshake + * [THRIFT-2463] - test/py/RunClientServer.py fails sometimes + * [THRIFT-2458] - Generated golang server code for "oneway" methods is incorrect + * [THRIFT-2456] - THttpClient fails when using async support outside Silverlight + * [THRIFT-2524] - Visual Studio project is missing TThreadedServer files + * [THRIFT-2523] - Visual Studio project is missing OverlappedSubmissionThread files + * [THRIFT-2520] - cpp:cob_style generates incorrect .tcc file + * [THRIFT-2508] - Uncompileable C# code due to language keywords in IDL + * [THRIFT-2506] - Update TProtocolException error codes to be used consistently throughout the library + * [THRIFT-2505] - go: struct should always be a pointer to avoid copying of potentially size-unbounded structs + * [THRIFT-2515] - TLS Method error during make + * [THRIFT-2503] - C++: Fix name collision when a struct has a member named "val" + * [THRIFT-2477] - thrift --help text with misplaced comma + * [THRIFT-2492] - test/cpp does not compile on mac + * [THRIFT-2500] - sending random data crashes thrift(golang) service + * [THRIFT-2475] - c_glib: buffered_transport_write function return always TRUE. + * [THRIFT-2495] - JavaScript/Node string constants lack proper escaping + * [THRIFT-2491] - unable to import generated ThriftTest service + * [THRIFT-2490] - c_glib: if fail to read a exception from server, client may be occurred double free + * [THRIFT-2470] - THttpHandler swallows exceptions from processor + * [THRIFT-2533] - Boost version in requirements should be updated + * [THRIFT-2532] - Java version in installation requirements should be updated + * [THRIFT-2529] - TBufferedTransport split Tcp data bug in nodeJs + * [THRIFT-2537] - Path for "go get" does not work (pull request 115) + * [THRIFT-2443] - Node fails cross lang tests + * [THRIFT-2437] - Author fields in Python setup.py must be strings not lists. + * [THRIFT-2435] - Java compiler doesn't like struct member names that are identical to an existing enum or struct type + * [THRIFT-2434] - Missing namespace import for php TMultiplexedProcessor implementation + * [THRIFT-2432] - Flaky parallel build + * [THRIFT-2430] - Crash during TThreadPoolServer shutdown + * [THRIFT-667] - Period should not be allowed in identifier names + * [THRIFT-1212] - Members capital case conflict + * [THRIFT-2584] - Error handler not listened on javascript client + * [THRIFT-2294] - Incorrect Makefile generation + * [THRIFT-2601] - Fix vagrant to work again for builds again + * [THRIFT-2092] - TNonblocking server should release handler as soon as connection closes + * [THRIFT-2557] - CS0542 member names cannot be the same as their enclosing type + * [THRIFT-2605] - TSocket warning on gcc 4.8.3 + * [THRIFT-2607] - ThreadManager.cpp warning on clang++ 3.4 + * [THRIFT-1998] - TCompactProtocol.tcc - one more warning on Visual 2010 + * [THRIFT-2610] - MSVC warning in TSocket.cpp + * [THRIFT-2614] - TNonblockingServer.cpp warnings on MSVC + * [THRIFT-2608] - TNonblockingServer.cpp warnings on clang 3.4 + * [THRIFT-2606] - ThreadManager.h warning in clang++ 3.4 + * [THRIFT-2609] - TFileTransport.h unused field warning (clang 3.4) + * [THRIFT-2416] - Cannot use TCompactProtocol with MSVC + * [THRIFT-1803] - Ruby Thrift 0.9.0 tries to encode UUID to UTF8 and crashes + * [THRIFT-2385] - Problem with gethostbyname2 during make check + * [THRIFT-2262] - thrift server 'MutateRow' operation gives no indication of success / failure + * [THRIFT-2048] - Prefer boolean context to nullptr_t conversion + * [THRIFT-2528] - Thrift Erlang Library: Multiple thrift applications in one bundle + * [THRIFT-1999] - warning on gcc 4.7 while compiling BoostMutex.cpp + * [THRIFT-2104] - Structs lose binary data when transferred from server to client in Java + * [THRIFT-2184] - undefined method rspec_verify for Thrift::MemoryBufferTransport + * [THRIFT-2351] - PHP TCompactProtocol has fails to decode messages + * [THRIFT-2016] - Resource Leak in thrift struct under compiler/cpp/src/parse/t_function.h + * [THRIFT-2273] - Please delete old releases from mirroring system + * [THRIFT-2270] - Faulty library version numbering at build or documentation + * [THRIFT-2203] - Tests keeping failing on Jenkins and Travis CI + * [THRIFT-2399] - thrift.el: recognize "//"-style comments in emacs thrift-mode + * [THRIFT-2582] - "FileTransport error" exception is raised when trying to use Java's TFileTransport + * [THRIFT-1682] - Multiple thread calling a Service function unsafely causes message corruption and terminates with Broken Pipe + * [THRIFT-2357] - recurse option has no effect when generating php + * [THRIFT-2248] - Go generator doesn't deal well with map keys of type binary + * [THRIFT-2426] - clarify IP rights and contributions from fbthrift + * [THRIFT-2041] - TNonblocking server compilation on windows (ARITHMETIC_RIGHT_SHIFT) + * [THRIFT-2400] - thrift.el: recognize "//"-style comments in emacs thrift-mode + * [THRIFT-1717] - Fix deb build in jenkins + * [THRIFT-2266] - ThreadManager.h:24:10: fatal error: 'tr1/functional' file not found on Mac 10.9 (Mavericks) + * [THRIFT-1300] - Test failures with parallel builds (make -j) + * [THRIFT-2487] - Tutorial requires two IDL files but only one is linked from the Thrift web site + * [THRIFT-2329] - missing release tags within git + * [THRIFT-2306] - concurent client calls with nodejs + * [THRIFT-2222] - ruby gem cannot be compiled on OS X mavericks + * [THRIFT-2381] - code which generated by thrift2/hbase.thrift compile error + * [THRIFT-2390] - no close event when connection lost + * [THRIFT-2146] - Unable to pass multiple "--gen" options to the thrift compiler + * [THRIFT-2438] - Unexpected readFieldEnd call causes JSON Parsing errors + * [THRIFT-2498] - Error message "Invalid method name" while trying to call HBase Thrift API + * [THRIFT-841] - Build cruft + * [THRIFT-2570] - Wrong URL given in http://thrift.apache.org/developers + * [THRIFT-2604] - Fix debian packaging + * [THRIFT-2618] - Unignore /aclocal files required for build + * [THRIFT-2562] - ./configure create MakeFile in lib/d with errors + * [THRIFT-2593] - Unable to build thrift on ubuntu-12.04 (Precise) + * [THRIFT-2461] - Can't install thrift-0.8.0 on OS X 10.9.2 + * [THRIFT-2602] - Fix missing dist files + * [THRIFT-2620] - Fix python packaging + * [THRIFT-2545] - Test CPP fails to build (possibly typo) + +## Documentation + * [THRIFT-2155] - Adding one liner guide to rename the version.h.in and rename thrifty.cc.h + * [THRIFT-1991] - Add exceptions to examples + * [THRIFT-2334] - add a tutorial for node JS + * [THRIFT-2392] - Actionscript tutorial + * [THRIFT-2383] - contrib: sample for connecting Thrift with Rebus + * [THRIFT-2382] - contrib: sample for connecting Thrift with STOMP + +## Improvement + * [THRIFT-1457] - Capacity of TframedTransport write buffer is never reset + * [THRIFT-1135] - Node.js tutorial + * [THRIFT-1371] - Socket timeouts (SO_RCVTIMEO and SO_SNDTIMEO) not supported on Solaris + * [THRIFT-2142] - Minor tweaks to thrift.el for better emacs package compatibility + * [THRIFT-2268] - Modify TSaslTransport to ignore TCP health checks from loadbalancers + * [THRIFT-2264] - GitHub page incorrectly states that Thrift is still incubating + * [THRIFT-2263] - Always generate good hashCode for Java + * [THRIFT-2233] - Java compiler should defensively copy its binary inputs + * [THRIFT-2239] - Address FindBugs errors + * [THRIFT-2249] - Add SMP Build option to thrift.spec (and three config defines) + * [THRIFT-2254] - Exceptions generated by Go compiler should implement error interface + * [THRIFT-2260] - Thrift imposes unneeded dependency on commons-lang3 + * [THRIFT-2258] - Add TLS v1.1/1.2 support to TSSLSocket.cpp + * [THRIFT-2205] - Node.js Test Server to support test.js JavaScript Browser test and sundry fixes + * [THRIFT-2204] - SSL client for the cocoa client + * [THRIFT-2172] - Java compiler allocates optionals array for every struct with an optional field + * [THRIFT-2185] - use cabal instead of runhaskell in haskell library + * [THRIFT-1926] - PHP Constant Generation Refactoring + * [THRIFT-2029] - Port C++ tests to Windows + * [THRIFT-2054] - TSimpleFileTransport - Java Lib has no straight forward TTransport based file transport + * [THRIFT-2040] - "uninitialized variable" warnings on MSVC/windows + * [THRIFT-2034] - Give developers' C++ code direct access to socket FDs on server side + * [THRIFT-2095] - Use print function for Python 3 compatiblity + * [THRIFT-1868] - Make the TPC backlog configurable in the Java servers + * [THRIFT-1813] - Add @Generated annotation to generated classes + * [THRIFT-1815] - Code generators line buffer output + * [THRIFT-2305] - TFramedTransport empty constructor should probably be private + * [THRIFT-2304] - Move client assignments from construtor in method + * [THRIFT-2309] - Ruby (gem) & PHP RPM subpackages + * [THRIFT-2318] - perl: dependency Class::Accessor not checked + * [THRIFT-2317] - exclude tutorial from build + * [THRIFT-2320] - Program level doctext does not get attached by parser + * [THRIFT-2349] - Golang - improve tutorial + * [THRIFT-2348] - PHP Generator: add array typehint to functions + * [THRIFT-2344] - configure.ac: compiler-only option + * [THRIFT-2343] - Golang - Return a single error for all exceptions instead of multiple return values + * [THRIFT-2341] - Enable generation of Delphi XMLDoc comments (a.k.a. "Help Insight") + * [THRIFT-2355] - Add SSL and Web Socket Support to Node and JavaScript + * [THRIFT-2350] - Add async calls to normal JavaScript + * [THRIFT-2330] - Generate PHPDoc comments + * [THRIFT-2332] - RPMBUILD: run bootstrap (if needed) + * [THRIFT-2391] - simple socket transport for actionscript 3.0 + * [THRIFT-2376] - nodejs: allow Promise style calls for client and server + * [THRIFT-2369] - Add ssl support for nodejs implementation + * [THRIFT-2401] - Haskell tutorial compiles + * [THRIFT-2417] - C# Union classes are not partial + * [THRIFT-2415] - Named pipes server performance & message mode + * [THRIFT-2404] - emit warning on (typically inefficient) list + * [THRIFT-2398] - Improve Node Server Library + * [THRIFT-2397] - Add CORS and CSP support for JavaScript and Node.js libraries + * [THRIFT-2407] - use markdown (rename README => README.md) + * [THRIFT-2300] - D configure info output should follow same format as other languages + * [THRIFT-2579] - Windows CE support + * [THRIFT-2574] - Compiler option to generate namespace directories for Ruby + * [THRIFT-2571] - Simplify cross compilation using CMake + * [THRIFT-2569] - Introduce file to specify third party library locations on Windows + * [THRIFT-2568] - Implement own certificate handler + * [THRIFT-2552] - eliminate warning from configure.ac + * [THRIFT-2549] - Generate json tag for struct members. use go.tag annotation to override the default generated tag. + * [THRIFT-2544] - Add support for socket transport for c# library when using Windows Phone projects + * [THRIFT-2453] - haskell tutorial: fix up division by 0 example + * [THRIFT-2449] - Enhance typedef structure to distinguish between forwards and real typedefs + * [THRIFT-2446] - There is no way to handle server stream errors + * [THRIFT-2455] - Allow client certificates to be used with THttpClient + * [THRIFT-2511] - Node.js needs the compact protocol + * [THRIFT-2493] - Node.js lib needs HTTP client + * [THRIFT-2502] - Optimize go implementations of binary and compact protocols for speed + * [THRIFT-2494] - Add enum toString helper function in c_glib + * [THRIFT-2471] - Make cpp.ref annotation language agnostic + * [THRIFT-2497] - server and client for test/go, also several fixes and improvements + * [THRIFT-2535] - TJSONProtocol when serialized yields TField ids rather than names + * [THRIFT-2220] - Add a new struct structv? + * [THRIFT-1352] - Thrift server + * [THRIFT-989] - Push boost m4 macros upstream + * [THRIFT-1349] - Remove unnecessary print outs + * [THRIFT-2496] - server and client for test/go, also several fixes and improvements + * [THRIFT-1114] - Maven publish shouldn't require passwords hardcoded in settings.xml + * [THRIFT-2043] - visual 2010 warnings - unreachable code + * [THRIFT-1683] - Implement alternatives to Javascript Client side Transport protocol, just as NPAPI and WebSocket. + * [THRIFT-1746] - provide a SPDX file + * [THRIFT-1772] - Serialization does not check types of embedded structures. + * [THRIFT-2387] - nodejs: external imports should be centralized in index.js + * [THRIFT-2037] - More general macro THRIFT_UNUSED_VARIABLE + +## New Feature + * [THRIFT-1012] - Transport for DataInput DataOutput interface + * [THRIFT-2256] - Using c++11/c++0x std library replace boost library + * [THRIFT-2250] - JSON and MemoryBuffer for JavaME + * [THRIFT-2114] - Python Service Remote SSL Option + * [THRIFT-1719] - SASL client support for Python + * [THRIFT-1894] - Thrift multi-threaded async Java Server using Java 7 AsynchronousChannelGroup + * [THRIFT-1893] - HTTP/JSON server/client for node js + * [THRIFT-2347] - C# TLS Transport based on THRIFT-181 + * [THRIFT-2377] - Allow addition of custom HTTP Headers to an HTTP Transport + * [THRIFT-2408] - Named Pipe Transport Option for C# + * [THRIFT-2572] - Add string/collection length limit checks (from C++) to java protocol readers + * [THRIFT-2469] - "java:fullcamel" option to automatically camel-case underscored attribute names + * [THRIFT-795] - Importing service functions (simulation multiple inheritance) + * [THRIFT-2164] - Add a Get/Post Http Server to Node along with examples + * [THRIFT-2255] - add Parent Class for generated Struct class + +## Question + * [THRIFT-2539] - Tsocket.cpp addrinfo ai_flags = AI_ADDRCONFIG + * [THRIFT-2440] - how to connect as3 to java by thrift , + * [THRIFT-2379] - Memmory leaking while using multithreading in C++ server. + * [THRIFT-2277] - Thrift: installing fb303 error + * [THRIFT-2567] - Csharp slow ? + * [THRIFT-2573] - thrift 0.9.2 release + +## Sub-task + * [THRIFT-981] - cocoa: add version Info to the library + * [THRIFT-2132] - Go: Support for Multiplexing Services on any Transport, Protocol and Server + * [THRIFT-2299] - TJsonProtocol implementation for Ruby does not allow for both possible slash (solidus) encodings + * [THRIFT-2298] - TJsonProtocol implementation for C# does not allow for both possible slash (solidus) encodings + * [THRIFT-2297] - TJsonProtocol implementation for Delphi does not allow for both possible slash (solidus) encodings + * [THRIFT-2271] - JavaScript: Support for Multiplexing Services + * [THRIFT-2251] - go test for compact protocol is not running + * [THRIFT-2195] - Delphi: Add event handlers for server and processing events + * [THRIFT-2176] - TSimpleJSONProtocol.ReadFieldBegin() does not return field type and ID + * [THRIFT-2175] - Wrong field type set for binary + * [THRIFT-2174] - Deserializing JSON fails in specific cases + * [THRIFT-2053] - NodeJS: Support for Multiplexing Services + * [THRIFT-1914] - Python: Support for Multiplexing Services on any Transport, Protocol and Server + * [THRIFT-1810] - add ruby to test/test.sh + * [THRIFT-2310] - PHP: Client-side support for Multiplexing Services + * [THRIFT-2346] - C#: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol + * [THRIFT-2345] - Delphi: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol + * [THRIFT-2338] - First doctext wrongly interpreted as program doctext in some cases + * [THRIFT-2325] - SSL test certificates + * [THRIFT-2358] - C++: add compact protocol to cross language test suite + * [THRIFT-2425] - PHP: Server-side support for Multiplexing Services + * [THRIFT-2421] - Tree/Recursive struct support in thrift + * [THRIFT-2290] - Update Go tutorial to align with THRIFT-2232 + * [THRIFT-2558] - CSharp compiler generator tries to concat ints with strings using + + * [THRIFT-2507] - Additional LUA TProtocolException error code needed? + * [THRIFT-2499] - Compiler: allow annotations without "= value" + * [THRIFT-2534] - Cross language test results should recorded to a status.md or status.html file automatically + * [THRIFT-66] - Java: Allow multiplexing multiple services over a single TCP connection + * [THRIFT-1681] - Add Lua Support + * [THRIFT-1727] - Ruby-1.9: data loss: "binary" fields are re-encoded + * [THRIFT-1726] - Ruby-1.9: "binary" fields are represented by string whose encoding is "UTF-8" + * [THRIFT-988] - perl: add version Info to the library via configure + * [THRIFT-334] - Compact Protocol for PHP + * [THRIFT-2444] - pull request 88: thrift: clean up enum value assignment + +## Task + * [THRIFT-2223] - Spam links on wiki + * [THRIFT-2566] - Please create a DOAP file for your TLP + * [THRIFT-2237] - Update archive to contain all versions + * [THRIFT-962] - Tutorial page on our website is really unhelpful + +## Test + * [THRIFT-2327] - nodejs: nodejs test suite should be bundled with the library + * [THRIFT-2445] - THRIFT-2384 (code generation for go maps with binary keys) should be tested + * [THRIFT-2501] - C# The test parameters from the TestServer and TestClient are different from the http://thrift.apache.org/test/ + +## Wish + * [THRIFT-2190] - Add the JavaScript thrift.js lib to the Bower registry + * [THRIFT-2076] - boost::optional instead of __isset + + + +Thrift 0.9.1 +-------------------------------------------------------------------------------- +## Bug + * [THRIFT-1440] - debian packaging: minor-ish policy problems + * [THRIFT-1402] - Generated Y_types.js does not require() X_types.js when an include in the IDL file was used + * [THRIFT-1551] - 2 thrift file define only struct (no service), one include another, the gen nodejs file didn't have "requires" at the top + * [THRIFT-1264] - TSocketClient is queried by run loop after deallocation in Cocoa + * [THRIFT-1600] - Thrift Go Compiler and Library out of date with Go 1 Release. + * [THRIFT-1603] - Thrift IDL allows for multiple exceptions, args or struct member names to be the same + * [THRIFT-1062] - Problems with python tutorials + * [THRIFT-864] - default value fails if identifier is a struct + * [THRIFT-930] - Ruby and Haskell bindings don't properly support DESTDIR (makes packaging painful) + * [THRIFT-820] - The readLength attribute of TBinaryProtocol is used as an instance variable and is decremented on each call of checkReadLength + * [THRIFT-1640] - None of the tutorials linked on the website contain content + * [THRIFT-1637] - NPM registry does not include version 0.8 + * [THRIFT-1648] - NodeJS clients always receive 0 for 'double' values. + * [THRIFT-1660] - Python Thrift library can be installed with pip but not easy_install + * [THRIFT-1657] - Chrome browser sending OPTIONS method before POST in xmlHttpRequest + * [THRIFT-2118] - Certificate error handling still incorrect + * [THRIFT-2137] - Ruby test lib fails jenkins build #864 + * [THRIFT-2136] - Vagrant build not compiling java, ruby, php, go libs due to missing dependencies + * [THRIFT-2135] - GO lib leaves behind test files that are auto generated + * [THRIFT-2134] - mingw-cross-compile script failing with strip errors + * [THRIFT-2133] - java TestTBinaryProtocol.java test failing + * [THRIFT-2126] - lib/cpp/src/thrift/concurrency/STD* files missing from DIST + * [THRIFT-2125] - debian missing from DIST + * [THRIFT-2124] - .o, .so, .la, .deps, .libs, gen-* files left tutorials, test and lib/cpp when making DIST + * [THRIFT-2123] - GO lib missing files in DIST build + * [THRIFT-2121] - Compilation bug for Node.js + * [THRIFT-2129] - php ext missing from dist + * [THRIFT-2128] - lib GO tests fail with funct ends without a return statement + * [THRIFT-2286] - Failed to compile Thrift0.9.1 with boost1.55 by VS2010 if select Debug-mt&x64 mode. + * [THRIFT-1973] - TCompactProtocol in C# lib does not serialize and deserialize negative int32 and int64 number correctly + * [THRIFT-1992] - casts in TCompactProtocol.tcc causing "dereferencing type-punned pointer will break strict-aliasing rules" warnings from gcc + * [THRIFT-1930] - C# generates unsigned byte for Thrift "byte" type + * [THRIFT-1929] - Update website to use Mirrors for downloads + * [THRIFT-1928] - Race may still exist in TFileTransport::flush() + * [THRIFT-1934] - Tabs in Example section on main page are not working + * [THRIFT-1933] - Delphi generator crashes when a typedef references another typedef from an included file + * [THRIFT-1942] - Binary accelerated cpp extension does not use Thrift namespaces for Exceptions + * [THRIFT-1959] - C#: Add Union TMemoryBuffer support + * [THRIFT-1958] - C#: Use static Object.Equals instead of .Equals() calls in equals + * [THRIFT-1957] - NodeJS TFramedTransport and TBufferedTransport read bytes as unsigned + * [THRIFT-1955] - Union Type writer generated in C# does not WriteStructBegin + * [THRIFT-1952] - Travis CI + * [THRIFT-1949] - WP7 build broken + * [THRIFT-1943] - docstrings for enum values are ignored + * [THRIFT-2070] - Improper `HexChar' and 'HexVal' implementation in TJSONProtocol.cs + * [THRIFT-2017] - Resource Leak in thrift struct under compiler/cpp/src/parse/t_program.h + * [THRIFT-2032] - C# client leaks sockets/handles + * [THRIFT-1996] - JavaME Constants generation is broken / inconsistent with regular Java generation + * [THRIFT-2002] - Haskell: Test use Data.Maybe instead of Maybe + * [THRIFT-2051] - Vagrant fails to build erlang + * [THRIFT-2050] - Vagrant C# lib compile fails with TException missing + * [THRIFT-1978] - Ruby: Thrift should allow for the SSL verify mode to be set + * [THRIFT-1984] - namespace collision in python bindings + * [THRIFT-1988] - When trying to build a debian package it fails as the file NEWS doesn't exist + * [THRIFT-1975] - TBinaryProtocol CheckLength can't be used for a client + * [THRIFT-1995] - '.' allowed at end of identifier generates non-compilable code + * [THRIFT-2112] - Error in Go generator when using typedefs in map keys + * [THRIFT-2088] - Typos in Thrift compiler help text + * [THRIFT-2080] - C# multiplex processor does not catch IOException + * [THRIFT-2082] - Executing "gmake clean" is broken + * [THRIFT-2102] - constants are not referencing to correct type when included from another thrift file + * [THRIFT-2100] - typedefs are not correctly referenced when including from other thrift files + * [THRIFT-2066] - 'make install' does not install two headers required for C++ bindings + * [THRIFT-2065] - Not valid constants filename in Java + * [THRIFT-2047] - Thrift.Protocol.TCompactProtocol, intToZigZag data lost (TCompactProtocol.cs) + * [THRIFT-2036] - Thrift gem warns about class variable access from top level + * [THRIFT-2057] - Vagrant fails on php tests + * [THRIFT-2105] - Generated code for default values of collections ignores t_field::T_REQUIRED + * [THRIFT-2091] - Unnecessary 'friend' declaration causes warning in TWinsockSingleton + * [THRIFT-2090] - Go generator, fix including of other thrift files + * [THRIFT-2106] - Fix support for namespaces in GO generator + * [THRIFT-1783] - C# doesn't handle required fields correctly + * [THRIFT-1782] - async only defined in silverlight + * [THRIFT-1779] - Missing process_XXXX method in generated TProcessor implementation for all 'oneway' service functions + * [THRIFT-1692] - SO_REUSEADDR allows for socket hijacking on Windows + * [THRIFT-1720] - JRuby times out on successful connection + * [THRIFT-1713] - Named and Anonymous Pipe transport (Delphi) + * [THRIFT-1699] - Native Union#read has extra read_field_end call + * [THRIFT-1749] - Python TSSLSocket error handling obscures actual error + * [THRIFT-1748] - Guard and RWGuard macros defined in global namespace + * [THRIFT-1734] - Front webpage is still advertising v0.8 as current release + * [THRIFT-1729] - C glib refactor left empty folders in svn + * [THRIFT-1767] - unions can't have required fields (Delphi) + * [THRIFT-1765] - Incorrect error message printed for null or negative keys + * [THRIFT-1778] - Configure requires manual intervention due to tar failure + * [THRIFT-1777] - TPipeServer is UNSTOPPABLE + * [THRIFT-1753] - Multiple C++ Windows, OSX, and iOS portability issues + * [THRIFT-1756] - 'make -j 8' fails with "unterminated #ifdef" error + * [THRIFT-1773] - Python library should run on python 2.4 + * [THRIFT-1769] - unions can't have required fields (C++) + * [THRIFT-1768] - unions can't have required fields (Compiler) + * [THRIFT-1666] - htonll usage in TBinaryProtocol.tcc generates warning with MSVC2010 + * [THRIFT-1919] - libthrift depends on httpcore-4.1.3 (directly) and httpcore-4.1.4 (transitively) + * [THRIFT-1864] - implement event handler for non-blocking server + * [THRIFT-1859] - Generated error c++ code with -out and include_prefix param + * [THRIFT-1869] - TThreadPoolServer (java) dies when threadpool is consumed + * [THRIFT-1842] - Memory leak with Pipes + * [THRIFT-1838] - Can't build compiler on OS X because of missing thrifty.h + * [THRIFT-1846] - Restore socket.h header to support builds with Android NDK + * [THRIFT-1850] - make check hangs on TSocket tests in TransportTest.cpp + * [THRIFT-1873] - Binary protocol factory ignores struct read/write flags + * [THRIFT-1872] - issues with TBufferedTransport buffer + * [THRIFT-1904] - Incorrect code is generated for typedefs which use included types + * [THRIFT-1903] - PHP namespaces cause binary protocols to not be used + * [THRIFT-1895] - Delphi: reserved variable name "result" not detected properly + * [THRIFT-1881] - TNonblockingServer does not release open connections or threads on shutdown + * [THRIFT-1888] - Java Thrift client can't connect to Python Thrift server on same host + * [THRIFT-1831] - Bug in list deserializer + * [THRIFT-1824] - many compile warning, becase Thread.h includes config.h + * [THRIFT-1823] - Missing parenthesis breaks "IS_..." macro in generated code + * [THRIFT-1806] - Python generation always truncates __init__.py files + * [THRIFT-1795] - Race condition in TThreadedServerPool java implementation + * [THRIFT-1794] - C# asyncctp broken + * [THRIFT-1804] - Binary+compact protocol single byte error in Ruby library (ARM architecture): caused by different char signedness + * [THRIFT-1800] - Documentation text not always escaped correctly when rendered to HTML + * [THRIFT-1788] - C#: Constants static constructor does not compile + * [THRIFT-1816] - Need "require" included thrift files in "xxx_types.js" + * [THRIFT-1907] - Compiling namespace and sub-namespace directives for unrecognized generators should only be a warning + * [THRIFT-1913] - skipping unknown fields in java unions + * [THRIFT-2553] - C++ linker error - transport/TSocket + * [THRIFT-274] - Towards a working release/versioning process + +## Documentation + * [THRIFT-1971] - [Graphviz] Adds tutorial/general description documentation + * [THRIFT-2001] - http://thrift.apache.org/ Example "C++ Server" tab is broken + +## Improvement + * [THRIFT-1574] - Apache project branding requirements: DOAP file [PATCH] + * [THRIFT-1347] - Unify the exceptions returned in generated Go code + * [THRIFT-1353] - Switch to performance branch, get rid of BinaryParser + * [THRIFT-1629] - Ruby 1.9 Compatibility during Thrift configure, make, install + * [THRIFT-991] - Refactor Haskell code and generator + * [THRIFT-990] - Sanify gettimeofday usage codebase-wide + * [THRIFT-791] - Let C++ TSimpleServer be driven by an external main loop + * [THRIFT-2117] - Cocoa TBinaryProtocol strictWrite should be set to true by default + * [THRIFT-2014] - Change C++ lib includes to use style throughout + * [THRIFT-1972] - Add support for async processors + * [THRIFT-1970] - [Graphviz] Adds option to render exceptions relationships + * [THRIFT-1966] - Support different files for SSL certificates and keys + * [THRIFT-1965] - Adds Graphviz (graph description language) generator + * [THRIFT-1956] - Switch to Apache Commons Lang 3 + * [THRIFT-1962] - Multiplex processor should send any TApplicationException back to client + * [THRIFT-1960] - main() declares 22 unused gen bools + * [THRIFT-1951] - libthrift.jar has source files in it + * [THRIFT-1997] - Add accept backlog configuration method to TServerSocket + * [THRIFT-2003] - Deprecate senum + * [THRIFT-2052] - Vagrant machine image defaults to only 384MB of RAM + * [THRIFT-1980] - Modernize Go tooling, fix go client libary. + * [THRIFT-1977] - C# compiler should generate constant files prefixed with thrift file name + * [THRIFT-1985] - add a Vagrantfile to build and test Apache Thrift fully reproducable + * [THRIFT-1994] - Deprecate slist + * [THRIFT-1993] - Factory to create instances from known (generated) interface types with Delphi + * [THRIFT-2081] - Specified timeout should be used in TSocket.Open() + * [THRIFT-2084] - Delphi: Ability to create entity Thrift-generated instances based on TypeInfo + * [THRIFT-2083] - Improve the go lib: buffered Transport, save memory allocation, handle concurrent request + * [THRIFT-2109] - Secure connections should be supported in Go + * [THRIFT-2107] - minor Go generator fixes + * [THRIFT-1695] - allow warning-free compilation in VS 2012 and GNU 4.6 + * [THRIFT-1735] - integrate tutorial into regular build + * [THRIFT-1716] - max allowed connections should be PIPE_UNLIMITED_INSTANCES + * [THRIFT-1715] - Allow excluding python parts when building contrib/fb303 + * [THRIFT-1733] - Fix RPM build issues on RHEL6/OL6 systems + * [THRIFT-1728] - Upgradation of httpcomponents + * [THRIFT-1876] - Use enum names instead of casted integers in assignments + * [THRIFT-1874] - timeout for the server-side end of a named pipe + * [THRIFT-1897] - Support validation of required fields + * [THRIFT-1896] - Add TBase protocol for Cocoa + * [THRIFT-1880] - Make named pipes server work asynchronously (overlapped) to allow for clean server stops + * [THRIFT-1878] - Add the possibility to send custom headers + * [THRIFT-1882] - Use single include + * [THRIFT-1793] - C#: Use static read instead of instance read + * [THRIFT-1799] - Option to generate HTML in "standalone mode" + * [THRIFT-1815] - Code generators line buffer output + * [THRIFT-1890] - C++: Make named pipes server work asynchronously + * [THRIFT-474] - Generating Ruby on Rails friendly code + +## New Feature + * [THRIFT-801] - Provide an interactive shell (irb) when generating ruby bindings + * [THRIFT-2292] - Android Library Project + * [THRIFT-2012] - Modernizing Go + * [THRIFT-1969] - C#: Tests not properly linked from the solution + * [THRIFT-1785] - C#: Add TMemoryBuffer serializer/deserializer + * [THRIFT-1780] - Add option to generate nullable values + * [THRIFT-1786] - C# Union Typing + * [THRIFT-591] - Make the C++ runtime library be compatible with Windows and Visual Studio + * [THRIFT-514] - Add option to configure compiler output directory + +## Question + * [THRIFT-1764] - how to get the context of client when on a rpc call in server side? + * [THRIFT-1791] - thrift's namespace directive when generating haskell code + +## Sub-task + * [THRIFT-1594] - Java test clients should have a return codes that reflect whether it succeeds or not. + * [THRIFT-1595] - Java test server should follow the documented behavior as of THRIFT-1590 + * [THRIFT-986] - st: add version Info to the library + * [THRIFT-985] - php: add version Info to the library + * [THRIFT-984] - ocaml: add version Info to the library + * [THRIFT-1924] - Delphi: Inconsistency in serialization of optional fields + * [THRIFT-1922] - C#: Inconsistency in serialization of optional fields + * [THRIFT-1961] - C# tests should be in lib/csharp/test/... + * [THRIFT-1822] - PHP unit test does not work + * [THRIFT-1902] - C++: Support for Multiplexing Services on any Transport, Protocol and Server + * [THRIFT-1901] - C#: Support for Multiplexing Services on any Transport, Protocol and Server + * [THRIFT-1899] - Delphi: Support for Multiplexing Services on any Transport, Protocol and Server + * [THRIFT-563] - Support for Multiplexing Services on any Transport, Protocol and Server + + + +Thrift 0.9 +-------------------------------------------------------------------------------- +## Bug + * [THRIFT-1438] - lib/cpp/src/windows/config.h should read version from configure.ac rather than a #define + * [THRIFT-1446] - Compile error with Delphi 2009 in constant initializer + * [THRIFT-1450] - Problems building thrift 0.8.0 for Python and Ruby + * [THRIFT-1449] - Ruby client does not work on solaris (?) + * [THRIFT-1447] - NullpointerException in ProcessFunction.class :in "oneway" method + * [THRIFT-1433] - TServerSocket fix for MSVC + * [THRIFT-1429] - The nonblocking servers is supposed to use TransportFactory to read the data + * [THRIFT-1427] - PHP library uses non-multibyte safe functions with mbstring function overloading + * [THRIFT-1421] - Debian Packages can not be built + * [THRIFT-1394] - Treatment of optional fields is not consistent between C++ and Java + * [THRIFT-1511] - Server with oneway support ( JAVA ) + * [THRIFT-1496] - PHP compiler not namespacing enums + * [THRIFT-1495] - PHP TestClient fatals on missing class + * [THRIFT-1508] - TServerSocket does not allow for the user to specify the IP address to bind to + * [THRIFT-1504] - Cocoa Generator should use local file imports for base Thrift headers + * [THRIFT-1512] - Thrift socket support for Windows XP + * [THRIFT-1502] - TSimpleServer::serve(): Do not print out error message if server was stopped. + * [THRIFT-1501] - PHP old namespaces not generated for enums + * [THRIFT-1483] - java compiler does not generate type parameters for services in extended clauses + * [THRIFT-1479] - Compiled PHP process functions missing writeMessageEnd() + * [THRIFT-1492] - enabling c_glib render thrift unusable (even for C++ code) + * [THRIFT-1491] - Uninitialize processorFactory_ member in TServer.h + * [THRIFT-1475] - Incomplete records generation for Erlang + * [THRIFT-1486] - Javascript manual testserver not returning content types + * [THRIFT-1488] - src/concurrency/Thread.h:91:58: error: invalid conversion from 'pthread_t {aka _opaque_pthread_t*}' to 'apache::thrift::concurrency::Thread::id_t {aka long long unsigned int}' [-fpermissive] + * [THRIFT-1490] - Windows-specific header files - fixes & tweaks + * [THRIFT-1526] - Union TupleSchemeFactory returns StandardSchemes + * [THRIFT-1527] - Generated implementation of tupleReadStruct in unions return null when the setfield is unrecognized + * [THRIFT-1524] - TNonBlockingServer does not compile in Visual Studio 2010 + * [THRIFT-1529] - TupleProtocol can unintentionally include an extra byte in bit vectors when number of optional fields is an integral of 8 + * [THRIFT-1473] - JSON context stack may be left in an incorrect state when an exception is thrown during read or write operations + * [THRIFT-1456] - System.Net.HttpWebRequest' does not contain a definition for 'Proxy' + * [THRIFT-1468] - Memory leak in TSaslServerTransport + * [THRIFT-1461] - Recent TNonblockingServer changes broke --enable-boostthreads=yes, Windows + * [THRIFT-1460] - why not add unicode strings support to python directly? + * [THRIFT-1464] - AbstractNonblockingServer.FrameBuffer TNonblockingTransport accessor changed from public to private + * [THRIFT-1467] - Possible AV with empty strings when using JSON protocol + * [THRIFT-1523] - clientTimeout not worked as expected in TServerSocket created by TSSLTransportFactory + * [THRIFT-1537] - TFramedTransport issues + * [THRIFT-1519] - Thirft Build Failure referencing rb_intern2 symbol + * [THRIFT-1518] - Generated C++ code only sends the first optional field in the write() function for a struct. + * [THRIFT-1515] - NameError: global name 'TApplicationException' is not defined + * [THRIFT-1554] - Inherited service methods are not resolved in derived service implementations + * [THRIFT-1553] - thrift nodejs service side can't read map structure, key as enum, value as Object + * [THRIFT-1575] - Typo in server/TThreadPoolServer.h + * [THRIFT-1327] - Fix Spec Suite under Ruby-1.8.7 (works for MRI Ruby-1.9.2) + * [THRIFT-1326] - on some platforms, #include is necessary to be included in Thrift.h + * [THRIFT-1159] - THttpClient->Flush() issue (connection thru proxy) + * [THRIFT-1277] - Node.js serializes false booleans as null + * [THRIFT-1224] - Cannot insert UTF-8 text + * [THRIFT-1267] - Node.js can't throw exceptions. + * [THRIFT-1338] - Do not use an unpatched autoconf 2.65 to generate release tarball + * [THRIFT-1128] - MAC OS X: thrift.h incompatibility with Thrift.h + * [THRIFT-1631] - Fix C++ server constructor typos + * [THRIFT-1602] - PHP C Extension is not Compatible with PHP 5.4 + * [THRIFT-1610] - IWebProxy not available on WP7 platform + * [THRIFT-1606] - Race condition in BoostThreadFactory.cpp + * [THRIFT-1604] - Python exception handeling for changes from PEP 3110 + * [THRIFT-1607] - Incorrect file modes for several source files + * [THRIFT-1583] - c_glib leaks memory + * [THRIFT-1582] - Bad includes of nested thrift files in c_glib + * [THRIFT-1578] - C_GLib generated code does not compile + * [THRIFT-1597] - TJSONProtocol.php is missing from Makefile.am + * [THRIFT-1591] - Enable TCP_NODELAY for ruby gem + * [THRIFT-1624] - Isset Generated differently on different platforms + * [THRIFT-1622] - Incorrect size returned on read + * [THRIFT-1621] - Memory leaks + * [THRIFT-1612] - Base64 encoding is broken + * [THRIFT-1627] - compiler built using compilers.vcxproj cannot be used to build some test .thrift files + * [THRIFT-1571] - Update Ruby HTTP transport for recent Ruby versions + * [THRIFT-1023] - Thrift encoding (UTF-8) issue with Ruby 1.9.2 + * [THRIFT-1090] - Document the generation of a file called "Constants.java" + * [THRIFT-1082] - Thrift::FramedTransport sometimes calls close() on an undefined value + * [THRIFT-956] - Python module's version meta-data should be updated + * [THRIFT-973] - Cocoa library won't compile using clang + * [THRIFT-1632] - ruby: data corruption in thrift_native implementation of MemoryBufferTransport + * [THRIFT-1665] - TBinaryProtocol: exceeded message length raises generic TException + * [THRIFT-1664] - Reference to non-existing variable in build script + * [THRIFT-1663] - Java Thrift server is not throwing exceptions + * [THRIFT-1662] - "removeObject:" should be "removeObserver:" in [-TSocketServer dealloc]? + * [THRIFT-1643] - Denial of Service attack in TBinaryProtocol.readString + * [THRIFT-1674] - Update Thrift D library to be compatible with 2.060 + * [THRIFT-1673] - Ruby compile flags for extension for multi arch builds (os x) + * [THRIFT-1655] - Configure still trying to use thrift_generators in output + * [THRIFT-1654] - c_glib thrift_socket_read() returns corrupted data + * [THRIFT-1653] - TThreadedSelectorServer leaks CLOSE_WAIT sockets + * [THRIFT-1658] - Java thrift server is not throwing TApplicationException + * [THRIFT-1656] - Setting proper headers in THttpServer.cpp so that "Cross-Origin Resource Sharing" on js client can work. + * [THRIFT-1652] - TSaslTransport does not log the error when kerberos auth fails + * [THRIFT-2272] - CLONE - Denial of Service attack in TBinaryProtocol.readString + * [THRIFT-2086] - Invalid generated code for Node.JS when using namespaces + * [THRIFT-1686] - t_php_generator.cc uses "and" instead of "&&", and causes compiler errors with Visual Studio + * [THRIFT-1693] - libthrift has dependency on two different versions of httpcore + * [THRIFT-1689] - don't exit(-1) in TNonblockingServer + * [THRIFT-1679] - NodeJS: protocol readString() should treat string as utf8, not binary + * [THRIFT-1721] - Dist broken due to 0.8.0 to 0.9.0 changes + * [THRIFT-1710] - Minor issues in test case code + * [THRIFT-1709] - Warning "Bitwise-or operator used on a sign-extended operand; consider casting to a smaller unsigned type first" in TBinaryProtocol.cs at ReadInt64() + * [THRIFT-1707] - [ruby] Adjust server_spec.rb for RSpec 2.11.x and Ruby 1.9.3 + * [THRIFT-1671] - Cocoa code generator does not put keywords into generated method calls + * [THRIFT-1670] - Incompatibilities between different versions of a Thrift interface + * [THRIFT-1669] - NameError: global name 'TApplicationException' is not defined + * [THRIFT-1668] - Compile error in contrib/fb303, thrift/TDispatchProcessor.h: No such file or directory + * [THRIFT-1845] - Fix compiler warning caused by implicit string conversion with Xcode 4.6 + * [THRIFT-304] - Building the Python library requires development headers + * [THRIFT-369] - sets and maps break equality + * [THRIFT-556] - Ruby compiler does not correctly referred to top-level modules when a submodule masks the top-level name + * [THRIFT-481] - indentation of ruby classes is off by a few + +## Improvement + * [THRIFT-1498] - Allow TThreadedPoolServer.Args to pass a ExecutorService + * [THRIFT-1444] - FunctionRunner - add syntactic sugar to create shared_ptrs + * [THRIFT-1443] - define a TProcessor helper class to implement process() + * [THRIFT-1441] - Generate constructor with parameters for exception class to let it update message property automatically. + * [THRIFT-1520] - Embed version number in erlang .app file + * [THRIFT-1480] - python: remove tabs, adjust whitespace and address PEP8 warnings + * [THRIFT-1485] - Performance: pass large and/or refcounted arguments as "const" + * [THRIFT-1484] - Introduce phpunit test suite + * [THRIFT-1532] - The type specifications in the generated Erlang code should include "undefined" where it's used as a default value + * [THRIFT-1534] - Required fields in the Delphi code generator. + * [THRIFT-1469] - Java isset space optimization + * [THRIFT-1465] - Visibility of methods in generated java code + * [THRIFT-1453] - Don't change types of arguments when serializing with thrift php extension + * [THRIFT-1452] - generate a swap() method for all generated structs + * [THRIFT-1451] - FramedTransport: Prevent infinite loop when writing + * [THRIFT-1521] - Two patches for more Performance + * [THRIFT-1555] - Delphi version of the tutorial code + * [THRIFT-1535] - Why thrift don't use wrapped class for optional fields ? + * [THRIFT-1204] - Ruby autogenerated files should require 'thrift' gem + * [THRIFT-1344] - Using the httpc module directly rather than the deprecated http layer + * [THRIFT-1343] - no_auto_import min/2 to avoid compile warning + * [THRIFT-1340] - Add support of ARC to Objective-C + * [THRIFT-1611] - Improved code generation for typedefs + * [THRIFT-1593] - Pass on errors like "connection closed" to the handler module + * [THRIFT-1615] - PHP Namespace + * [THRIFT-1567] - Thrift/cpp: Allow alternate classes to be used for + * [THRIFT-1072] - Missing - (id) initWithSharedProcessor in TSharedProcessorFactory.h + * [THRIFT-1650] - [ruby] Update clean items and svn:ignore entries for OS X artifacts + * [THRIFT-1661] - [PATCH] Add --with-qt4 configure option + * [THRIFT-1675] - Do we have any plan to support scala? + * [THRIFT-1645] - Replace Object#tee with more conventional Object#tap in specs + * [THRIFT-1644] - Upgrade RSpec to 2.10.x and refactor specs as needed + * [THRIFT-1672] - MonoTouch (and Mono for Android) compatibility + * [THRIFT-1702] - a thrift manual + * [THRIFT-1694] - Re-Enable serialization for WP7 Silverlight + * [THRIFT-1691] - Serializer/deserializer support for Delphi + * [THRIFT-1688] - Update IDL page markup + * [THRIFT-1725] - Tutorial web pages for Delphi and C# + * [THRIFT-1714] - [ruby] Explicitly add CWD to Ruby test_suites.rb + * [THRIFT-317] - Issues with Java struct validation + * [THRIFT-164] - Build web tutorial on Incubator web site + * [THRIFT-541] - Cocoa code generator doesn't put keywords before all arguments. + * [THRIFT-681] - The HTML generator does not handle JavaDoc style comments very well + +## New Feature + * [THRIFT-1500] - D programming language support + * [THRIFT-1510] - There should be an implementation of the JsonProtocol for ruby + * [THRIFT-1115] - python TBase class for dynamic (de)serialization, and __slots__ option for memory savings + * [THRIFT-1953] - support for asp.net mvc 3 + +## Question + * [THRIFT-1235] - How could I use THttpServerTransportFactory withTNonBlockingServer + * [THRIFT-1368] - TNonblockingServer usage + * [THRIFT-1061] - Read an invalid frame size of 0. Are you using TFramedTransport on the client side? + * [THRIFT-491] - Ripping raw pthreads out of TFileTransport and associated test issues + +## Sub-task + * [THRIFT-1596] - Delphi: Test clients should have a return codes that reflect whether they succeeded or not + * [THRIFT-982] - javame: add version Info to the library + * [THRIFT-1722] - C# WP7 Assembly addition beaks mono build + * [THRIFT-336] - Compact Protocol in C# + +## Test + * [THRIFT-1613] - Add code back into empty source file ToStringTest.java + * [THRIFT-1718] - Incorrect check in TFileTransportTest + +## Wish + * [THRIFT-1463] - Decouple Thrift IDL from generators + * [THRIFT-1466] - Proper Documentation for Thrift C Glib + * [THRIFT-1539] - Build and distribute the fb303 python libraries along with thrift + * [THRIFT-1685] - Please add "aereo.com" to "Powered by Apache Thrift" list in about page + * [THRIFT-330] - TProcessor - additional method to called when connection is broken + + + +Thrift 0.8 +-------------------------------------------------------------------------------- +## Bug + * [THRIFT-1436] - pip install thrift fails on Windows with "Unable to find vcvarsall.bat" + * [THRIFT-1432] - Javascript struct constants declared in the same file as their struct definition will cause an error + * [THRIFT-1428] - shared.thrft does not include namespace for php, so thrift compiler generate incorrect name + * [THRIFT-1426] - Dist package missing files for release 0.8 + * [THRIFT-1425] - The Node package is incompatible with latest node (0.6) & npm (1.0.27) + * [THRIFT-1416] - Python Unit test is broken on ci + * [THRIFT-1419] - AbstractNonBlockingServer does not catch errors when invoking the processor + * [THRIFT-1424] - Ruby specs fail when run with rake + * [THRIFT-1420] - Nonblocking and HsHa server should make sure to close all their socket connections when the selector exits + * [THRIFT-1413] - Generated code does not read MapEnd / ListEnd / SetEnd + * [THRIFT-1409] - Name conflict check does not work properly for exception object(Delphi). + * [THRIFT-1408] - Delphi Test Server: Exception test case fails due to naming conflict with e.message + * [THRIFT-1407] - Typo in Python socket server causes Thrift to fail when we enable a global socket timout + * [THRIFT-1397] - CI server fails during build due to unused parameters in delphi generator + * [THRIFT-1404] - Delphi compiler generates struct reader code with problem. + * [THRIFT-1400] - Ruby native extension aborts with __stack_chk_fail in OSX + * [THRIFT-1399] - One of the TServerImpl.Create CTORs lacks implementation + * [THRIFT-1390] - Debian packages build fix for Squeeze (build from the official 0.7.0 tarball) + * [THRIFT-1393] - TTransportException's thrown from THttpClient contain superfluous slashes in the Exception message + * [THRIFT-1392] - Enabling both namespaces and autoloading in generated PHP code won't work. + * [THRIFT-1406] - Build error after applying THRIFT-1395 + * [THRIFT-1405] - Delphi compiler does not generates container serializer properly. + * [THRIFT-1411] - java generator does not provide type parameter for TBaseProcessor + * [THRIFT-1473] - JSON context stack may be left in an incorrect state when an exception is thrown during read or write operations + * [THRIFT-1331] - Ruby library deserializes an empty map to nil + * [THRIFT-1330] - PHP Namespaces no longer generated + * [THRIFT-1328] - TBaseHelper.toString(...) appends ByteBuffer data outside of valid buffer range + * [THRIFT-1322] - OCaml lib fail to compile: Thrift.ml line 305, int vs int32 mismatch + * [THRIFT-1143] - Build doesn't detect correct architecture type on 64bit osx + * [THRIFT-1205] - port server unduly fragile with arbitrary input + * [THRIFT-1279] - type set is handled incorrectly when writing object + * [THRIFT-1298] - Standard scheme doesn't read or write metadata along with field values + * [THRIFT-1265] - C++ container deserialize + * [THRIFT-1263] - publish ruby client to rubygems + * [THRIFT-1384] - Java help menu missing newline near javame flag + * [THRIFT-1382] - Bundle install doesnot work because thrift crashes + * [THRIFT-1381] - Thrift C++ libs have incorrectly versioned names + * [THRIFT-1350] - Go library code does not build as of r60 (most recent release) + * [THRIFT-1365] - TupleProtocol#writeBitSet unintentionally writes a variable length byte array + * [THRIFT-1359] - --gen-cob cpp:cob_style does not compile anymore + * [THRIFT-1319] - Mismatch between how a union reads and writes a container + * [THRIFT-1309] - libfb303-0.7.0.jar missing in maven repository + * [THRIFT-1238] - Thrift JS client cannot read map of structures + * [THRIFT-1254] - Code can't be compiled against a regular JRE: Object.clone() override has a different return type + * [THRIFT-1367] - Mac OSX build fails with "no such file to load -- spec/rake/spectask" + * [THRIFT-1355] - Running make in lib/rb doesn't build the native extensions + * [THRIFT-1370] - Debian packaging should Build-Depend on libglib2.0-dev + * [THRIFT-1342] - Compilation problem on Windows of fastbinary.c + * [THRIFT-1341] - TProtocol.h endian detection wrong with boost + * [THRIFT-1583] - c_glib leaks memory + * [THRIFT-1582] - Bad includes of nested thrift files in c_glib + * [THRIFT-1578] - C_GLib generated code does not compile + * [THRIFT-1027] - 'make -j 16' fails with "unterminated #ifdef" error + * [THRIFT-1121] - Java server performance regression in 0.6 + * [THRIFT-857] - tests run by "make install" fail if generators are disabled + * [THRIFT-380] - Use setuptools for python build + +## Dependency upgrade + * [THRIFT-1257] - thrift's dependency scope on javax.servlet:servlet-api should be 'provided' + +## Improvement + * [THRIFT-1445] - minor C++ generator variable cleanup + * [THRIFT-1435] - make TException.Message property conformant to the usual expectations + * [THRIFT-1431] - Rename 'sys' module to 'util' + * [THRIFT-1396] - Dephi generator has dependacy on boost 1.42 later. + * [THRIFT-1395] - Patch to prevent warnings for integer types in some cases + * [THRIFT-1275] - thrift: always prefix namespaces with " ::" + * [THRIFT-1274] - thrift: fail compilation if an unexpected token is + * [THRIFT-1271] - thrift: fix missing namespace in generated local + * [THRIFT-1270] - thrift: add --allow-neg-keys argument to allow + * [THRIFT-1345] - Allow building without tests + * [THRIFT-1286] - Modernize the Thrift Ruby Library Dev Environment + * [THRIFT-1284] - thrift: fix processor inheritance + * [THRIFT-1283] - thrift: wrap t_cpp_generator::generate_process_function() to 80 + * [THRIFT-1282] - Upgrade httpclient to 4.1.2 (from 4.0.1) + * [THRIFT-1281] - add @generated to the docblock + * [THRIFT-1280] - Thrift: Improve Monitor exception-free interfaces + * [THRIFT-1278] - javadoc warnings - compilation + * [THRIFT-1227] - Erlang implementation of thrift JSON protocol + * [THRIFT-1295] - Duplicate include in TSocket.cpp + * [THRIFT-1294] - thrift: fix log message typos in TSimpleServer + * [THRIFT-1293] - thrift: improve handling of exceptions thrown by + * [THRIFT-1292] - thrift: silence log spew from TThreadedServer + * [THRIFT-1288] - Allow typedefed exceptions in throws clauses + * [THRIFT-1290] - thrift: TNonblockingServer: clean up state in the + * [THRIFT-1287] - thrift: start refactoring some of the C++ processor + * [THRIFT-1289] - thrift: implement TNonblockingServer::stop() + * [THRIFT-1305] - thrift: make TConnection a private inner class of + * [THRIFT-1304] - TNonblockingServer: pass in the connection context to + * [THRIFT-1302] - thrift: raise an exception if send() times out in + * [THRIFT-1301] - thrift: consolidate common code in TNonblockingServer + * [THRIFT-1377] - abort PHP deserialization on unknown field type + * [THRIFT-1379] - fix uninitialized enum values in thrift C++ objects + * [THRIFT-1376] - Make port specification option in thrift remote + * [THRIFT-1375] - fixed a hex char conversion bug in TJSONProtocol + * [THRIFT-1373] - Fix user-defined exception generation in thrift (python) + * [THRIFT-1361] - Optional replacement of pthread by boost::thread + * [THRIFT-1320] - Consistency of configure generated config.h + * [THRIFT-1317] - Remove copy constructibility from + * [THRIFT-1316] - thrift: update server classes to accept + * [THRIFT-1315] - thrift: generate server interface factory classes + * [THRIFT-1314] - thrift: add TProcessorFactory + * [THRIFT-1335] - Add accept timeout to TServerSocket + * [THRIFT-1334] - Add more info to IllegalStateException + * [THRIFT-1333] - Make RWGuard not copyable + * [THRIFT-1332] - TSSLTransportParameters class uses hard coded value keyManagerType: SunX509 + * [THRIFT-1251] - Generated java code should indicate which fields are required and which are optional + * [THRIFT-1387] - Build MSVC libraries with Boost Threads instead of Pthreads + * [THRIFT-1339] - Extend Tuple Protocol to TUnions + * [THRIFT-1031] - Patch to compile Thrift for vc++ 9.0 and 10.0 + * [THRIFT-1130] - Add the ability to specify symbolic default value for optional boolean + * [THRIFT-1123] - Patch to compile Thrift server and client for vc++ 9.0 and 10.0 + * [THRIFT-386] - Make it possible to build the Python library without the extension + +## New Feature + * [THRIFT-1401] - JSON-protocol for Delphi XE Libraries + * [THRIFT-1167] - Java nonblocking server with more than one thread for select and handling IO + * [THRIFT-1366] - Delphi generator, lirbrary and unit test. + * [THRIFT-1354] - Add rake task to build just the gem file + * [THRIFT-769] - Pluggable Serializers + +## Sub-task + * [THRIFT-1415] - delphi: add version Info to the library + * [THRIFT-1391] - Improved Delphi XE test cases + + + +Thrift 0.7 +-------------------------------------------------------------------------------- +## Bug + * [THRIFT-1140] - Framed Transport Client using C (Glib) Library hangs when connecting to Ruby Server + * [THRIFT-1154] - HttpClient does not specify the connection close parameter + * [THRIFT-1153] - HttpClient does not specify the connection close parameter + * [THRIFT-1149] - Nonblocking server fails when client connection is reset + * [THRIFT-1146] - Android Incompatibility : in Android < 2.3 java.io.IOException doesn't support for Throwable parameter in constructor + * [THRIFT-1133] - Java and JavaScript tutorial is broken since we have Java maven deployment + * [THRIFT-1132] - Deserialization error in TApplicationException C# + * [THRIFT-1131] - C# JSON Protocol is unable to decode escaped characters in string + * [THRIFT-1208] - python TCompactProtocol.py writeBool and readBool not follow the compact-proto-spec-2.txt spec for CONTAINER_WRITE, CONTAINER_READ + * [THRIFT-1200] - JS compiler generates code that clobbers existing namespaces + * [THRIFT-1183] - Pure-ruby CompactProtocol raises ArgumentError when deserializing under Ruby 1.9 + * [THRIFT-1182] - Native deserializer segfaults on incorrect list element type + * [THRIFT-1181] - AS3 compiler generates incorrect code for setting default values in constructor + * [THRIFT-1234] - thrift --help is missing doc on py:utf8strings + * [THRIFT-1180] - AS3 compiler generates uncompilable code for binary types. + * [THRIFT-1194] - Java lib does not install artifacts to local dir correctly + * [THRIFT-1193] - Potential infinite loop in nonblocking_server + * [THRIFT-1192] - Typo: TProtocol.h tests for HAVE_SYS_PARAM_H_ + * [THRIFT-1190] - readBufferBytesAllocated in TNonblockingServer.java should be AtomicLong to fix FD leakage and general server malfunction + * [THRIFT-1187] - nonblocking_server shutdown race under Ruby 1.9 + * [THRIFT-1178] - Java: TBase signature should be T extends TBase + * [THRIFT-1164] - Segmentation fault on NULL pointer in t_js_generator::generate_const + * [THRIFT-1171] - Perl write/readDouble assumes little-endian platform + * [THRIFT-1222] - Unhandled exception for TEvhttpServer request + * [THRIFT-1220] - TProcessor::process never returns false + * [THRIFT-1285] - Stable 0.7.0 Windows compiler exe available on the webside is not the good one + * [THRIFT-1218] - c_glib uses wrong name in pkg-config + * [THRIFT-1215] - Undefined property Thirft in lib/js/thrift.js + * [THRIFT-1211] - When using THttpClient, non 200 responses leave the connection open + * [THRIFT-1228] - The php accelerator module calls flush incorrectly + * [THRIFT-1308] - libfb303-0.7.0.jar missing in maven repository + * [THRIFT-1255] - Mismatch of method name between JavaME's lib and generated code (compareTo/compareObjects) + * [THRIFT-1253] - Code generated for maps is not compiling + * [THRIFT-1252] - Segfault in Ruby deserializer + * [THRIFT-1094] - bug in TCompactProto python readMessageEnd method and updated test cases + * [THRIFT-1093] - several bugs in python TCompactProtocol + * [THRIFT-1092] - generated validate() method has wrong indentation + * [THRIFT-1011] - Error generating package imports when using classes from other packages + * [THRIFT-1050] - Declaring an argument named "manager" to a service method produces code that fails compile due to name conflicts with protected ivars in TAsyncClient + * [THRIFT-1074] - .keystore and .truststore are missing from the 0.6.0 distribution + * [THRIFT-1067] - Tons of bugs in php implementation + * [THRIFT-1065] - Unexpected exceptions not proper handled on JS + * [THRIFT-1076] - Erlang Thrift socket server has a bug that causes java thrift client of framed binary client to throw "out of sequence" exception + * [THRIFT-1057] - casts in TBinaryProtocol.tcc causing "dereferencing type-punned pointer will break strict-aliasing rules" warnings from gcc + * [THRIFT-1055] - csharp TServerSocket and TSocket do not disable Nagle via Socket.NoDelay = true like cpp and java do + * [THRIFT-1054] - explicit call to PKG_PROG_PKG_CONFIG is missing and first use of PKG_CHECK_MODULES may not happen, causes mono detection to fail + * [THRIFT-1117] - JavaScript Unit Test does not work anymore because libthrift*.jar where moved by Maven Deployment + * [THRIFT-1111] - The HTML generator does not distinguish between string and binary types + * [THRIFT-1032] - "make dist" fails due to c_glib problem + * [THRIFT-1036] - Auto-generated C++ code fails to compile with "-Werror -Wextra -Wall" g++ compiler flags + * [THRIFT-1041] - TDeserializer holds onto a reference of the array it reads after it is done deserializing + * [THRIFT-1106] - C++ code TAsyncProtocolProcessor.h & TAsyncBufferProcessor.h dont have virtual functions but no virtual destructor. Causes warnings on -Wall + * [THRIFT-1105] - OCaml generator does not prefix methods of included structs with their type + * [THRIFT-1104] - INSTALLDIRS should be included in configure script + * [THRIFT-1102] - typo in configure.ac: "==" operator in 'test' (instead of"'=") + * [THRIFT-1101] - bytebuffer length calculation in TBinaryProtocol writeBinary + * [THRIFT-1098] - Undefined properties in TBinaryProtocolFactory + * [THRIFT-1081] - PHP tests broken and somewhat incomplete + * [THRIFT-1080] - erlang test's 'make' fails on Mac OSX + * [THRIFT-1078] - ThriftTest.thrift generates invalid PHP library + * [THRIFT-1120] - proto.WriteListEnd being called in the wrong place + * [THRIFT-1119] - TJSONProtocol fails to UTF8 decode strings + * [THRIFT-867] - PHP accelerator module's output transport is incompatible with TFramedTransport + * [THRIFT-826] - PHP TSocket Write Timeout + * [THRIFT-835] - Bad AS3 syntax in constructors that set default values + * [THRIFT-788] - thrift_protocol.so: multiget/multiget_slice does not handle more than 17 keys correctly + * [THRIFT-125] - OCaml libraries don't compile with 32-bit ocaml + * [THRIFT-342] - PHP: can't have sets of complex types + * [THRIFT-731] - configure doesn't check for ant >= 1.7 + * [THRIFT-690] - Update TApplicationException codes + * [THRIFT-638] - BufferedTransport + C extensions block until recv timeout is reached on last fread call + +## Dependency upgrade + * [THRIFT-1177] - Update thrift to reflect changes in Go's networking libraries + +## Improvement + * [THRIFT-1155] - Remove log4j dependency from java client + * [THRIFT-1151] - Produce more informative runtime error in case of schema and data mismatch during serialization + * [THRIFT-1207] - Support DESTDIR on "make install" of ruby libs + * [THRIFT-1199] - Union structs should have generated methods to test whether a specific field is currently set + * [THRIFT-1233] - Remove unused include in generated C++ code + * [THRIFT-1189] - Ruby deserializer speed improvements + * [THRIFT-1170] - Thrift Generated Code and Java 5 + * [THRIFT-1174] - Publish as3 client implementation via Maven for use by flex-mojos users + * [THRIFT-1225] - TCompactProtocol for PHP + * [THRIFT-1221] - Remove SimpleCallback.h + * [THRIFT-1217] - Use evutil_socketpair instead of pipe (Windows port) + * [THRIFT-1216] - build Java Library behind a proxy + * [THRIFT-1231] - Remove bogus include + * [THRIFT-1213] - Membuffer should provide a way to get back the buffer + * [THRIFT-1237] - Java fb303 missing some methods + * [THRIFT-1063] - Fix Erlang Tutorial Files + * [THRIFT-1053] - Make remote client's IP address available for all socket related transports + * [THRIFT-1109] - Deploy fb303 along side libthrift to maven repo + * [THRIFT-1107] - improvement for compiler-generated python for 'None' object comparisons + * [THRIFT-1069] - Add command line option to prevent thrift from inserting gen-* directories + * [THRIFT-1049] - Allow for TServerSocket python library to bind to a specific host + * [THRIFT-1126] - Extending struct_info for erlang bindings + * [THRIFT-1100] - python TSSLSocket improvements, including certificate validation + * [THRIFT-994] - Don't try to invoke phpize if we don't have it + * [THRIFT-993] - Some improvements in C++ stubs for oneway operations + * [THRIFT-997] - Using valueOf for base types in getFieldValue + * [THRIFT-418] - Don't do runtime sorting of struct fields + * [THRIFT-151] - TSSLServerSocket and TSSLSocket implementation + * [THRIFT-27] - Generated erlang types don't contain default values for records + * [THRIFT-113] - to-string methods should omit optional null fields from output + * [THRIFT-363] - Maven Deploy + * [THRIFT-447] - Make an abstract base Client class so we can generate less code + * [THRIFT-627] - should c++ have setters for optional fields? + +## New Feature + * [THRIFT-1236] - Erlang Reconnecting Thrift Client + * [THRIFT-1021] - Framed transport support for OCaml + * [THRIFT-1068] - Python SSL Socket Support + * [THRIFT-1103] - TZlibTransport for python, a zlib compressed transport + * [THRIFT-1083] - Preforking python process pool server + * [THRIFT-999] - Add TForkingServer + +## Sub-task + * [THRIFT-1152] - Attributes from private to protected + * [THRIFT-1038] - Generated Java code for structures containing binary fields (or collections thereof) are not serializable (in the Java sense) even though they implement java.io.Serializable + +## Task + * [THRIFT-892] - Refactor erlang build system with rebar + +## Wish + * [THRIFT-625] - Add support for 'Go' + + + +Thrift 0.6.1 +-------------------------------------------------------------------------------- +## Bug + * [THRIFT-1133] - Java and JavaScript tutorial is broken since we have Java maven deployment + * [THRIFT-1131] - C# JSON Protocol is unable to decode escaped characters in string + * [THRIFT-1074] - .keystore and .truststore are missing from the 0.6.0 distribution + +## Improvement + * [THRIFT-1109] - Deploy fb303 along side libthrift to maven repo + * [THRIFT-363] - Maven Deploy + +## Question + * [THRIFT-1206] - did the THRIFT 0.6.1 merge THRIFT-563 ? + +## Sub-task + * [THRIFT-1163] - How can i use multi service in one program? + +## Task + * [THRIFT-1112] - Apply THRIFT-363 to 0.6 branch + * [THRIFT-1113] - Apply THRIFT-1074 to 0.6 branch + + + +Thrift 0.6 +-------------------------------------------------------------------------------- +## Bug + * [THRIFT-1020] - OCaml compiler generates invalid OCaml + * [THRIFT-1015] - TUnion does not handle ByteBuffer in toString + * [THRIFT-1013] - generated java code may have name clashes with thrift library + * [THRIFT-1009] - TUnion does not correctly deep copy a ByteBuffer + * [THRIFT-1032] - "make dist" fails due to c_glib problem + * [THRIFT-868] - Referencing constant values doesn't work with with typedef types + * [THRIFT-971] - java module can't be compiled without ivy and network connection + * [THRIFT-970] - Under heavy load, THttpClient may fail with "too many open files" + * [THRIFT-969] - Java Tutorial broken, move CalculatorHandler to a separate file + * [THRIFT-807] - JavaScript: Initialization of Base Types with 0 instead of null + * [THRIFT-955] - Thrift compiler for Windows uses lowercase names and directories which is inconsistent with compiling on other platforms + * [THRIFT-992] - Naming convention in C# constructor is not consistent with other fields causes compile errors + * [THRIFT-1008] - byte[] accessors throw NPE on unset field + * [THRIFT-1006] - Impossible to correctly qualify an enum constant in an external thrift file + * [THRIFT-950] - Haskell bindings treat 'byte' as unsigned 8-bit int (Data.Word.Word8), java/cpp as signed (byte/int8_t). + * [THRIFT-975] - lib/c_glib/README is missing => breaks make dist + * [THRIFT-944] - Support all version-4s of base + * [THRIFT-939] - optional binary fields throw NPE on default byte[] getters + * [THRIFT-935] - PHP Extension aborts the build if php-config is not installed + * [THRIFT-933] - Haskell's Thrift.cabal has warnings + * [THRIFT-932] - Haskell tests need to be run through 'make check' (and probably 'cabal check') too + * [THRIFT-904] - C# TSocket should disable nagle and linger + * [THRIFT-941] - Make PHP C Extension use the defined Protocol writeMessageBegin function + * [THRIFT-940] - 'make check' fails if boost is not in the std include and link paths + * [THRIFT-924] - Fix generated php structure constants + * [THRIFT-979] - ruby bindings used to work on jruby + * [THRIFT-977] - Hex Conversion Bug in C++ TJSONProtocol + * [THRIFT-347] - PHP TSocket Timeout Issues + * [THRIFT-517] - TExceptions thrown by server result in cryptic error message on client - Tried to read 4 bytes, but only got 0 bytes + +## Improvement + * [THRIFT-1024] - Add Python Twisted example to the Tutorial + * [THRIFT-958] - Change accessmodifer on trans_ field in the FrameBuffer class to public. + * [THRIFT-957] - THsHaServer: Change access modifier of the invoker field. + * [THRIFT-1002] - CodeStyle: t_c_glib_generator.cc + * [THRIFT-1005] - Give unions byte[] signature methods to go along with their ByteBuffer counterparts + * [THRIFT-951] - Add a new isServing() method to TServer + * [THRIFT-943] - Silly readme typo fix. + * [THRIFT-961] - JavaScript TestSuite using ant/ivy and Java's ServerTestBase Handler + * [THRIFT-960] - add TestServer, TestNonblockingServer and TestClient again + * [THRIFT-949] - Modify the TEnum interface so it defines a method similar to findByValue + * [THRIFT-946] - Augment FieldValueMetaData so it differentiates 'string' and 'binary' fields. + * [THRIFT-903] - custom ThreadFactory in THsHaServer + * [THRIFT-913] - Test Case for Url encoded strings + simple enhancement to lib/js/test/RunTestServer.sh + * [THRIFT-926] - Miscellaneous C++ improvements + * [THRIFT-929] - Improvements to the C++ test suite + * [THRIFT-893] - add JavaScript to the tutorial examples + * [THRIFT-1003] - Polishing c_glib code + * [THRIFT-71] - Debian packaging for thrift + +## New Feature + * [THRIFT-1033] - Node.js language target + * [THRIFT-947] - Provide a helper method to determine the TProtocol used to serialize some data. + * [THRIFT-928] - Make more statistics available in C++ servers + * [THRIFT-922] - Templatized [de]serialization code for C++ + * [THRIFT-923] - Event-driven client and server support for C++ + * [THRIFT-925] - Provide name<->value map for enums in C++ + * [THRIFT-927] - Add option to modify the PHP include path + * [THRIFT-377] - TFileTransport port in Java + * [THRIFT-106] - TSSLServerSocket + * [THRIFT-582] - C implementation of Thrift + * [THRIFT-745] - Make it easier to instantiate servers + +## Sub-task + * [THRIFT-1038] - Generated Java code for structures containing binary fields (or collections thereof) are not serializable (in the Java sense) even though they implement java.io.Serializable + +## Task + * [THRIFT-862] - Async client issues / improvements + +## Test + * [THRIFT-581] - Add a testsuite for txThrift (Twisted) + + + +Thrift 0.5.0 - Incubating +-------------------------------------------------------------------------------- +THRIFT-505 Build Make configure give a summary of the enabled components (David Reiss) +THRIFT-506 Build Allow Thrift to be built without the C++ library (David Reiss) +THRIFT-844 Build Build Requirements state autoconf 2.59+ is required, but 2.60+ is needed (Harlan Lieberman-Berg) +THRIFT-850 Build Perl runtime requires Bit::Vector which may not be installed by default, but configure does not fail (Michael Lum) +THRIFT-854 Build Provide configure option and make rules to build/install php extension (Anthony Molinaro) +THRIFT-858 Build Have bootstrap.sh check for a suitable autoconf version before running (David Reiss) +THRIFT-871 Build Thrift compiler for WIndows (binary distribution) (David Reiss) +THRIFT-323 C# TJSONProtocol (Roger Meier) +THRIFT-634 C# C# Compiler Generates Incorrect Code For Fields which begin with an uppercase letter (Jon S Akhtar) +THRIFT-881 C# add csharp to the tutorial (Roger Meier) +THRIFT-856 C++ Building cpp library fails on OS X with malloc and free not being declared in scope (James Clarke) +THRIFT-865 C++ C++ compiler build depends on libfl even when flex/lex not detected (David Reiss) +THRIFT-900 C++ Unix domain socket (Roger Meier) +THRIFT-920 C++ C++ Test and Tutorial does not compile anymore due to the change within Enum handling (Roger Meier) +THRIFT-567 C++ Can't immediately stop a TSimpleServer thread that is idle (Rush Manbert) +THRIFT-756 C++ Exposing TSocket(int) constructor to public (Rajat Goel) +THRIFT-798 C++ TNonblockingServer leaks resources when destroyed (David Reiss) +THRIFT-812 C++, Python Demo of Thrift over ZeroMQ (David Reiss) +THRIFT-629 Cocoa Unused Field In TSocketServer Appears To Break iPhone Build (Jon S Akhtar) +THRIFT-838 Cocoa Generated Cocoa classes have useless @dynamic declarations (Kevin Ballard) +THRIFT-805 Cocoa Don't generate process_XXXX methods for oneway methods (Brad Taylor) +THRIFT-507 Compiler Remove the compiler's dependency on Boost (David Reiss) +THRIFT-895 Compiler (General) Thrift compiler does not allow two different enumerations to have the same key name for one of the enum values (David Reiss) +THRIFT-852 Compiler (General) Missing newline causes many compiler warnings (Anthony Molinaro) +THRIFT-877 Compiler (General) smalltalk namespace doesn't work (Bruce Lowekamp) +THRIFT-897 Compiler (General) Don't allow unqualified constant access to enum values (Bryan Duxbury) +THRIFT-9 Compiler (General) Add a default namespace declaration for all languages (David Reiss) +THRIFT-599 Erlang Don't use unnecessary processes in the Erlang transports and clients (David Reiss) +THRIFT-646 Erlang Erlang library is missing install target (David Reiss) +THRIFT-698 Erlang Generated module list should contain atoms, not strings (Anthony Molinaro) +THRIFT-866 Erlang term() in spec definitions seems to not work in erlang R12 (Anthony Molinaro) +THRIFT-886 Erlang Dialyzer warning (Anthony Molinaro) +THRIFT-785 Erlang Framed transport server problems (Anthony Molinaro) +THRIFT-884 HTML HTML Generator: add Key attribute to the Data Types Tables (Roger Meier) +THRIFT-652 Haskell Generated field name for strut is not capitalized correctly (Christian Lavoie) +THRIFT-743 Haskell compile error with GHC 6.12.1 (Christian Lavoie) +THRIFT-901 Haskell Allow the bindings to compile without -fglasgow-exts and with -Wall -Werror (Christian Lavoie) +THRIFT-905 Haskell Make haskell thrift bindings use automake to compile and install (Christian Lavoie) +THRIFT-906 Haskell Improve type mappings (Christian Lavoie) +THRIFT-914 Haskell Make haskell bindings 'easily' compilable (Christian Lavoie) +THRIFT-918 Haskell Make haskell tests run again (Christian Lavoie) +THRIFT-919 Haskell Update Haskell bindings README (Christian Lavoie) +THRIFT-787 Haskell Enums are not read correctly (Christian Lavoie) +THRIFT-250 Java ExecutorService as a constructor parameter for TServer (Ed Ceaser) +THRIFT-693 Java Thrift compiler generated java code that throws compiler warnings about deprecated methods. (Bryan Duxbury) +THRIFT-843 Java TNonblockingSocket connects without a timeout (Bryan Duxbury) +THRIFT-845 Java async client does not respect timeout (Ning Liang) +THRIFT-870 Java Java constants don't get Javadoc comments (Bryan Duxbury) +THRIFT-873 Java Java tests fail due to Too many open files (Todd Lipcon) +THRIFT-876 Java Add SASL support (Aaron T. Myers) +THRIFT-879 Java Remove @Override from TUnion.clear (Dave Engberg) +THRIFT-882 Java deep copy of binary fields does not copy ByteBuffer characteristics (arrayOffset, position) (Bryan Duxbury) +THRIFT-888 Java async client should also have nonblocking connect (Eric Jensen) +THRIFT-890 Java Java tutorial doesn't work (Todd Lipcon) +THRIFT-894 Java Make default accessors for binary fields return byte[]; provide new accessors to get ByteBuffer version (Bryan Duxbury) +THRIFT-896 Java TNonblockingSocket.isOpen() returns true even after close() (Eric Jensen) +THRIFT-907 Java libfb303 doesn't compile in 0.4.0 (Todd Lipcon) +THRIFT-912 Java Improvements and bug fixes to SASL implementation (Todd Lipcon) +THRIFT-917 Java THsHaServer should not accept an ExecutorService without catching RejectedExecutionException (Ed Ceaser) +THRIFT-931 Java Use log4j for Java tests (Todd Lipcon) +THRIFT-880 JavaME JavaME code generator and runtime library (Dave Engberg) +THRIFT-846 JavaScript JavaScript Test Framwork: extended Testcases (Roger Meier) +THRIFT-885 JavaScript Url encoded strings never get decoded? How do we fix this? (T Jake Luciani) +THRIFT-911 JavaScript (JavaScript compiler) Const structs, maps, sets, and lists generate a trailing comma (T Jake Luciani) +THRIFT-860 OCaml copy method and reset method (Lev Walkin) +THRIFT-682 PHP PHP extension doesn't compile on Mac OS X (Bryan Duxbury) +THRIFT-851 PHP php extension fails to compile on centos 5.x (Todd Lipcon) +THRIFT-840 Perl Perl protocol handler could be more robust against unrecognised types (Conrad Hughes) +THRIFT-758 Perl incorrect deference in exception handling (Yann Kerherve) +THRIFT-257 Python Support validation of required fields (Esteve Fernandez) +THRIFT-335 Python Compact Protocol for Python (David Reiss) +THRIFT-596 Python Make Python's TBufferedTransport use a configurable input buffer (David Reiss) +THRIFT-597 Python Python THttpServer performance improvements (David Reiss) +THRIFT-598 Python Allow Python's threading servers to use daemon threads (David Reiss) +THRIFT-666 Python Allow the handler to override HTTP responses in THttpServer (David Reiss) +THRIFT-673 Python Generated Python code has whitespace issues (Ian Eure) +THRIFT-721 Python THttpClient ignores url parameters (Thomas Kho) +THRIFT-824 Python TApplicationException.__str__() refers to class constants as globals (Peter Schuller) +THRIFT-855 Python Include optimized compiled python objects in install (Anthony Molinaro) +THRIFT-859 Python Allow py:twisted to be generated in different namespace than py (Bruce Lowekamp) +THRIFT-869 Python TSocket.py on Mac (and FreeBSD) doesn't handle ECONNRESET from recv() (Steven Knight) +THRIFT-875 Python Include python setup.cfg in dist (Anthony Molinaro) +THRIFT-610 Ruby binary_protocol.rb segfaults [line 86] (Unassigned) +THRIFT-899 Ruby Ruby read timeouts can sometimes be 2x what they should be (Ryan King) +THRIFT-909 Ruby allow block argument to struct constructor (Michael Stockton) +THRIFT-456 Test Suite Bad IP address string in test/cpp/src/main.cpp (Rush Manbert) + + +Thrift 0.4.0 - Incubating +-------------------------------------------------------------------------------- +THRIFT-650 Build Make Check fails on Centos/OSX with 0.2.0 tarball (Anthony Molinaro) +THRIFT-770 Build Get 'make dist' to work without first compiling source code (Anthony Molinaro) +THRIFT-160 C# Created THttpTransport for the C# library based on WebHttpRequest (Michael Greene) +THRIFT-834 C# THttpClient resends contents of message after transport errors (Anatoly Fayngelerin) +THRIFT-247 C++ THttpServer Transport (Unassigned) +THRIFT-676 C++ Change C++ code generator so that generated classes can be wrapped with SWIG (Unassigned) +THRIFT-570 Compiler Thrift compiler does not error when duplicate method names are present (Bruce Simpson) +THRIFT-808 Compiler Segfault when constant declaration references a struct field that doesn't exist (Bryan Duxbury) +THRIFT-646 Erlang Erlang library is missing install target (Anthony Molinaro) +THRIFT-544 General multiple enums with the same key generate invalid code (Ben Taitelbaum) +THRIFT-434 General ruby compiler should warn when a reserved word is used (Michael Stockton) +THRIFT-799 General Files missing proper Apache license header (Bryan Duxbury) +THRIFT-832 HTML HTML generator shows unspecified struct fields as 'required' (Bryan Duxbury) +THRIFT-226 Java Collections with binary keys or values break equals() (Bryan Duxbury) +THRIFT-484 Java Ability to use a slice of a buffer instead of a direct byte[] for binary fields (Bryan Duxbury) +THRIFT-714 Java maxWorkerThreads parameter to THsHaServer has no effect (Bryan Duxbury) +THRIFT-751 Java Add clear() method to TBase (Bryan Duxbury) +THRIFT-765 Java Improved string encoding and decoding performance (Bryan Duxbury) +THRIFT-768 Java Async client for Java (Bryan Duxbury) +THRIFT-774 Java TDeserializer should provide a partialDeserialize method for primitive types (Piotr Kozikowski) +THRIFT-783 Java .equals java method is broken on structs containing binary-type fields (Unassigned) +THRIFT-804 Java CompareTo is broken for unions set to map, set, or list (Bryan Duxbury) +THRIFT-814 Java Include a TServlet in the standard Thrift distribution (Mathias Herberts) +THRIFT-818 Java Async client doesn't send method args (Bryan Duxbury) +THRIFT-830 Java Switch binary field implementation from byte[] to ByteBuffer (Bryan Duxbury) +THRIFT-831 Java FramedTransport implementation that reuses its buffers (Bryan Duxbury) +THRIFT-833 Java build.xml in lib/java is missing a classpathref attribute for the javadoc task (Bryan Duxbury) +THRIFT-836 Java Race condition causes CancelledKeyException in TAsyncClientManager (Bryan Duxbury) +THRIFT-842 Java Upgrade to current version of commons-lang (2.5 instead of 2.4) and/or change dependency in ivy.xml to not be exact (Bryan Duxbury) +THRIFT-815 JavaScript Deserialization of lists is critically broken. (T Jake Luciani) +THRIFT-827 OCaml OCaml generator to take default values into account (Lev Walkin) +THRIFT-647 PHP PHP library is missing install target (Anthony Molinaro) +THRIFT-682 PHP PHP extension doesn't compile on Mac OS X (Bryan Duxbury) +THRIFT-718 PHP Thrift PHP library includes closing tags and extraneous whitespace (Nicholas Telford) +THRIFT-778 PHP PHP socket listening server (Nick Jones) +THRIFT-780 PHP PHP extension sometimes causes an abort with two exceptions at the same time (David Reiss) +THRIFT-837 PHP PHP accelerator bug for writes > 8k (Thomas Kho) +THRIFT-782 Perl Perl code for writing containers doesn't count length of write*Begin or write*End (Conrad Hughes) +THRIFT-395 Python Python library + compiler does not support unicode strings (Unassigned) +THRIFT-133 Ruby 'namespace ruby' should error out, or be an alias to 'namespace rb' (Bryan Duxbury) +THRIFT-664 Ruby Ruby extension fails to build with Ruby 1.9.1 (Rajesh Malepati) +THRIFT-699 Ruby Excise unused "native protocol method table" stuff from thrift_native (Bryan Duxbury) +THRIFT-767 Ruby ruby compiler does not keep comments for enum values (Bryan Duxbury) +THRIFT-811 Ruby http_client_transport.rb: allow custom http headers (Tony Kamenick) +THRIFT-459 Ruby Ruby installation always tries to write to /Library/Ruby/site (Matthieu Imbert) + + +Thrift 0.1.0 - Incubating (not released) +-------------------------------------------------------------------------------- +Compatibility Breaking Changes: + C++: + * It's quite possible that regenerating code and rebuilding will be + required. Make sure your headers match your libs! + + Java: + + Python: + + Ruby: + * Generated files now have underscored names [THRIFT-421] + * The library has been rearranged to be more Ruby-like [THRIFT-276] + + Erlang: + * Generated code will have to be regenerated, and the new code will + have to be deployed atomically with the new library code [THRIFT-136] + +New Features and Bug Fixes: + C++: + * Support for TCompactProtocol [THRIFT-333] + + Java: + * Support for TCompactProtocol [THRIFT-110] + + Python: + * Support for Twisted [THRIFT-148] + + Ruby: + * Support for TCompactProtocol [THRIFT-332] + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9f57a66 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,124 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +cmake_minimum_required(VERSION 3.1) + +# CMake 3.1 supports C++ standards selection with CMAKE_CXX_STANDARD +# If you need CMake 3.1+ for Ubuntu 14.04, try +# https://launchpad.net/~george-edison55/+archive/ubuntu/cmake-3.x +# If you need CMake 3.1+ for debian "jessie", get it from jessie-backports +# Otherwise +# http://cmake.org + +project("Apache Thrift") + +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake") + +# TODO: add `git rev-parse --short HEAD` +# Read the version information from the Autoconf file +file (STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/configure.ac" CONFIGURE_AC REGEX "AC_INIT\\(.*\\)" ) + +# The following variable is used in the version.h.in file +string(REGEX REPLACE "AC_INIT\\(\\[.*\\], \\[([0-9]+\\.[0-9]+\\.[0-9]+(-dev)?)\\]\\)" "\\1" PACKAGE_VERSION ${CONFIGURE_AC}) +message(STATUS "Parsed Thrift package version: ${PACKAGE_VERSION}") + +# These are internal to CMake +string(REGEX REPLACE "([0-9]+\\.[0-9]+\\.[0-9]+)(-dev)?" "\\1" thrift_VERSION ${PACKAGE_VERSION}) +string(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" thrift_VERSION_MAJOR ${thrift_VERSION}) +string(REGEX REPLACE "[0-9]+\\.([0-9])+\\.[0-9]+" "\\1" thrift_VERSION_MINOR ${thrift_VERSION}) +string(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" thrift_VERSION_PATCH ${thrift_VERSION}) +message(STATUS "Parsed Thrift version: ${thrift_VERSION} (${thrift_VERSION_MAJOR}.${thrift_VERSION_MINOR}.${thrift_VERSION_PATCH})") + +# Some default settings +include(DefineCMakeDefaults) + +# Build time options are defined here +include(DefineOptions) +include(DefineInstallationPaths) + +# Based on the options set some platform specifics +include(DefinePlatformSpecifc) + +# Generate the config.h file +include(ConfigureChecks) + +# Package it +include(CPackConfig) + + +find_package(Threads) + +include(CTest) +if(BUILD_TESTING) + message(STATUS "Building with unittests") + + enable_testing() + # Define "make check" as alias for "make test" + add_custom_target(check COMMAND ctest) +else () + message(STATUS "Building without tests") +endif () + +if(BUILD_COMPILER) + if(NOT EXISTS ${THRIFT_COMPILER}) + set(THRIFT_COMPILER $) + endif() + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/compiler/cpp) +elseif(EXISTS ${THRIFT_COMPILER}) + add_executable(thrift-compiler IMPORTED) + set_property(TARGET thrift-compiler PROPERTY IMPORTED_LOCATION ${THRIFT_COMPILER}) +endif() + +if(BUILD_CPP) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/cpp) + if(BUILD_TUTORIALS) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tutorial/cpp) + endif() + if(BUILD_TESTING) + if(WITH_LIBEVENT AND WITH_ZLIB AND WITH_OPENSSL) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test/cpp) + else() + message(WARNING "libevent and/or ZLIB and/or OpenSSL not found or disabled; will not build some tests") + endif() + endif() +endif() + +if(BUILD_C_GLIB) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/c_glib) +endif() + +if(BUILD_JAVA) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/java) +endif() + +if(BUILD_PYTHON) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/py) + if(BUILD_TESTING) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test/py) + endif() +endif() + +if(BUILD_HASKELL) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/hs) + if(BUILD_TESTING) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test/hs) + endif() +endif() + +PRINT_CONFIG_SUMMARY() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..0460359 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,99 @@ +# How to Contribute # + +Thank you for your interest in contributing to the Apache Thrift project! Information on why and how to contribute is available on the Apache Software Foundation (ASF) web site. In particular, we recommend the following to become acquainted with Apache Contributions: + + * [Contributors Tech Guide](http://www.apache.org/dev/contributors) + * [Get involved!](http://www.apache.org/foundation/getinvolved.html) + * [Legal aspects on Submission of Contributions (Patches)](http://www.apache.org/licenses/LICENSE-2.0.html#contributions) + +## If you want to build the project locally ## + +For Windows systems, see our detailed instructions on the [CMake README](/build/cmake/README.md). + +For Windows Native C++ builds, see our detailed instructions on the [WinCPP README](/build/wincpp/README.md). + +For unix systems, see our detailed instructions on the [Docker README](/build/docker/README.md). + +## If you want to review open issues... ## + + 1. Review the [GitHub Pull Request Backlog](https://github.com/apache/thrift/pulls). Code reviews are open to all. + 2. Review the [Jira issue tracker](http://issues.apache.org/jira/browse/THRIFT). You can search for tickets relating to languages you are interested in or currently using with thrift, for example a Jira search (Issues -> Search For Issues) query of ``project = THRIFT AND component in ("Erlang - Library") and status not in (resolved, closed)`` will locate all the open Erlang Library issues. + +## If you discovered a defect... ## + + 1. Check to see if the issue is already in the [Jira issue tracker](http://issues.apache.org/jira/browse/THRIFT). + 1. If not, create a ticket describing the change you're proposing in the Jira issue tracker. + 1. Contribute your code changes using the GitHub pull request method: + +## Contributing via GitHub pull requests ## + +This is the preferred method of submitting changes. When you submit a pull request through github, it activates the continuous integration (CI) build systems at Appveyor and Travis to build your changes on a variety of Windows and Linux configurations and run all the test suites. + + 1. Create a fork in your GitHub account of http://github.com/apache/thrift + 1. Clone the fork to your development system. + 1. Create a branch for your changes (best practice is issue as branch name, e.g. THRIFT-9999). + 1. Modify the source to include the improvement/bugfix, and: + + * Remember to provide *tests* for all submitted changes! + * Use test-driven development (TDD): add a test that will isolate the bug *before* applying a change that fixes it. + * Verify that you follow [Thrift Coding Standards](/docs/coding_standards) (you can run 'make style', which ensures proper format for some languages). + * [*optional*] Verify that your change works on other platforms by adding a GitHub service hook to [Travis CI](http://docs.travis-ci.com/user/getting-started/#Step-one%3A-Sign-in) and [AppVeyor](http://www.appveyor.com/docs). You can use this technique to run the Thrift CI jobs in your account to check your changes before they are made public. Every GitHub pull request into Thrift will run the full CI build and test suite on your changes. + + 1. Squash your changes to a single commit. This is very important as it makes the process of applying your commit upstream much easier. + 1. Commit and push changes to your branch (please use issue name and description as commit title, e.g. "THRIFT-9999: make it perfect"). + 1. Use GitHub to create a pull request going from your branch to apache:master. Ensure that the Jira ticket number is at the beginning of the title of your pull request, same as the commit title. + 1. Wait for other contributors or committers to review your new addition, and for a CI build to complete. + 1. Wait for a committer to commit your patch. You can nudge the committers if necessary by sending a message to the [Apache Thrift mailing list](https://thrift.apache.org/mailing). + +## Contributing via Patch ## + +Some changes do not require a build, for example in documentation. For changes that are not code or build related, you can submit a patch on Jira for review. To create a patch from changes in your local directory: + + git diff > ../THRIFT-NNNN.patch + +then wait for contributors or committers to review your changes, and then for a committer to apply your patch. + +## GitHub recipes for Pull Requests ## + +Sometimes commmitters may ask you to take actions in your pull requests. Here are some recipes that will help you accomplish those requests. These examples assume you are working on Jira issue THRIFT-9999. You should also be familiar with the [upstream](https://help.github.com/articles/syncing-a-fork/) repository concept. + +### Squash your changes ### + +If you have not submitted a pull request yet, or if you have not yet rebased your existing pull request, you can squash all your commits down to a single commit. This makes life easier for the committers. If your pull request on GitHub has more than one commit, you should do this. + +1. Use the command ``git log`` to identify how many commits you made since you began. +2. Use the command ``git rebase -i HEAD~N`` where N is the number of commits. +3. Leave "pull" in the first line. +4. Change all other lines from "pull" to "fixup". +5. All your changes are now in a single commit. + +If you already have a pull request outstanding, you will need to do a "force push" to overwrite it since you changed your commit history: + + git push -u origin THRIFT-9999 --force + +A more detailed walkthrough of a squash can be found at [Git Ready](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html). + +### Rebase your pull request ### + +If your pull request has a conflict with master, it needs to be rebased: + + git checkout THRIFT-9999 + git rebase upstream master + (resolve any conflicts, make sure it builds) + git push -u origin THRIFT-9999 --force + +### Fix a bad merge ### + +If your pull request contains commits that are not yours, then you should use the following technique to fix the bad merge in your branch: + + git checkout master + git pull upstream master + git checkout -b THRIFT-9999-take-2 + git cherry-pick ... + (pick only your commits from your original pull request in ascending chronological order) + squash your changes to a single commit if there is more than one (see above) + git push -u origin THRIFT-9999-take-2:THRIFT-9999 + +This procedure will apply only your commits in order to the current master, then you will squash them to a single commit, and then you force push your local THRIFT-9999-take-2 into remote THRIFT-9999 which represents your pull request, replacing all the commits with the new one. + + diff --git a/LANGUAGES.md b/LANGUAGES.md new file mode 100644 index 0000000..2f68a4e --- /dev/null +++ b/LANGUAGES.md @@ -0,0 +1,305 @@ +# Apache Thrift Language Support # + +Last Modified: 2017-10-05
+Version: 0.11.0+ + +Thrift supports many programming languages and has an impressive test suite that exercises most of the languages, protocols, and transports that represents a matrix of thousands of possible combinations. Each language typically has a minimum required version as well as support libraries - some mandatory and some optional. All of this information is provided below to help you assess whether you can use Apache Thrift with your project. Obviously this is a complex matrix to maintain and may not be correct in all cases - if you spot an error please inform the developers using the mailing list. + +Apache Thrift has a choice of two build systems. The `autoconf` build system is the most complete build and is used to build all supported languages. The `cmake` build system has been designated by the project to replace `autoconf` however this transition will take quite some time to complete. + +The Language/Library Levels indicate the minimum and maximum versions that are used in the [continuous integration environments](build/docker/README.md) (Appveyor, Travis) for Apache Thrift. Note that while a language may contain support for protocols, transports, and servers, the extent to which each is tested as part of the overall build process varies. The definitive integration test for the project is called the "cross" test which executes a test matrix with clients and servers communicating across languages. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LanguageBuild SystemsLang/Lib LevelsLow-Level TransportsTransport WrappersProtocolsServersOpen Issues
autoconfcmakeMinMaxDomain File Memory Pipe Socket TLS Framed http  zlib BinaryCompact JSON MultiplexForkingNonblockingSimpleThreadedThreadPool
ActionScriptActionScript 3YesYesYesActionScript
C (glib)YesYes2.40.22.54.0YesYesYesYesYesYesYesYesYesC (glib)
C++YesYesC++98, gcc YesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesC++
C#Yes.NET 3.5 / mono 3.2.8.0.NET 4.6.1 / mono 4.6.2.7YesYesYesYesYesYesYesYesYesYesYesYesYesC# (.NET)
CocoaunknownYesYesYesYesYesYesYesYesYesYesCocoa
DYes2.070.22.076.0YesYesYesYesYesYesYesYesYesYesYesYesYesYesYesD
DartYes1.20.11.24.2YesYesYesYesYesYesYesDart
Delphi2010unknownYesYesYesYesYesYesYesYesDelphi
.NET Core2.0.02.0.3YesYesYesYesYesYesYesYesYesYesYes.NET Core
ErlangYesR16B0320.0.4YesYesYesYesYesYesYesYesYesYesYesErlang
GoYes1.2.11.8.3YesYesYesYesYesYesYesYesYesYesYesGo
HaskellYesYes7.6.38.0.2YesYesYesYesYesYesYesYesYesYesYesHaskell
HaxeYes3.2.1YesYesYesYesYesYesYesYesYesHaxe
Java (SE)YesYes1.7.0_1511.8.0_144YesYesYesYesYesYesYesYesYesYesYesYesYesYesYesJava SE
Java (ME)unknownYesYesYesYesYesYesJava ME
JavascriptYesunknownYesYesYesYesYesJavascript
LuaYes5.1.55.2.4YesYesYesYesYesYesYesYesLua
node.jsYes4.2.68.9.1YesYesYesYesYesYesYesYesYesnode.js
OCaml4.02.34.04.0YesYesYesYesYesOCaml
PerlYes5.18.25.26.0YesYesYesYesYesYesYesYesYesYesYesPerl
PHPYes5.5.97.1.8YesYesYesYesYesYesYesYesYesYesYesPHP
PythonYesYes2.7.6, 3.4.32.7.14, 3.6.3YesYesYesYesYesYesYesYesYesYesYesPython
RubyYes1.9.3p4842.3.3p222YesYesYesYesYesYesYesYesYesYesYesYesYesYesRuby
RustYes1.15.11.18.0YesYesYesYesYesYesYesRust
SmalltalkunknownYesYesSmalltalk
LanguageautoconfcmakeMinMaxDomain File Memory Pipe Socket TLS Framed http  zlib BinaryCompact JSON MultiplexForkingNonblockingSimpleThreadedThreadPoolOpen Issues
Build SystemsLang/Lib LevelsLow-Level TransportsTransport WrappersProtocolsServers
diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3b6d7d7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,239 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +-------------------------------------------------- +SOFTWARE DISTRIBUTED WITH THRIFT: + +The Apache Thrift software includes a number of subcomponents with +separate copyright notices and license terms. Your use of the source +code for the these subcomponents is subject to the terms and +conditions of the following licenses. + +-------------------------------------------------- +Portions of the following files are licensed under the MIT License: + + lib/erl/src/Makefile.am + +Please see doc/otp-base-license.txt for the full terms of this license. + +-------------------------------------------------- +For the aclocal/ax_boost_base.m4 and contrib/fb303/aclocal/ax_boost_base.m4 components: + +# Copyright (c) 2007 Thomas Porschberg +# +# Copying and distribution of this file, with or without +# modification, are permitted in any medium without royalty provided +# the copyright notice and this notice are preserved. + +-------------------------------------------------- +For the lib/nodejs/lib/thrift/json_parse.js: + +/* + json_parse.js + 2015-05-02 + Public Domain. + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + +*/ +(By Douglas Crockford ) +-------------------------------------------------- diff --git a/Makefile.am b/Makefile.am new file mode 100755 index 0000000..3d71fd4 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,135 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +ACLOCAL_AMFLAGS = -I ./aclocal + +if WITH_PLUGIN +# To enable bootstrap, build order is lib/cpp -> compiler -> others +SUBDIRS = lib/cpp compiler/cpp lib +if WITH_TESTS +SUBDIRS += lib/cpp/test +endif +else +SUBDIRS = compiler/cpp lib +endif + +if WITH_TESTS +SUBDIRS += test +endif + +if WITH_TUTORIAL +SUBDIRS += tutorial +endif + +dist-hook: + find $(distdir) -type f \( -iname ".DS_Store" -or -iname "._*" -or -iname ".gitignore" \) | xargs rm -rf + find $(distdir) -type d \( -iname ".deps" -or -iname ".libs" \) | xargs rm -rf + find $(distdir) -type d \( -iname ".svn" -or -iname ".git" \) | xargs rm -rf + +print-version: + @echo $(PACKAGE_VERSION) + +.PHONY: precross cross +precross-%: all + $(MAKE) -C $* precross +precross: all precross-test precross-lib + +empty := +space := $(empty) $(empty) +comma := , + +CROSS_LANGS = @MAYBE_CPP@ @MAYBE_C_GLIB@ @MAYBE_D@ @MAYBE_JAVA@ @MAYBE_CSHARP@ @MAYBE_PYTHON@ @MAYBE_PY3@ @MAYBE_RUBY@ @MAYBE_HASKELL@ @MAYBE_PERL@ @MAYBE_PHP@ @MAYBE_GO@ @MAYBE_NODEJS@ @MAYBE_DART@ @MAYBE_ERLANG@ @MAYBE_LUA@ @MAYBE_RS@ @MAYBE_DOTNETCORE@ +CROSS_LANGS_COMMA_SEPARATED = $(subst $(space),$(comma),$(CROSS_LANGS)) + +if WITH_PY3 +CROSS_PY=$(PYTHON3) +else +CROSS_PY=$(PYTHON) +endif + +if WITH_PYTHON +crossfeature: precross + $(CROSS_PY) test/test.py --retry-count 3 --features .* --skip-known-failures --server $(CROSS_LANGS_COMMA_SEPARATED) +else +# feature test needs python build +crossfeature: +endif + +cross-%: precross crossfeature + $(CROSS_PY) test/test.py --retry-count 3 --skip-known-failures --server $(CROSS_LANGS_COMMA_SEPARATED) --client $(CROSS_LANGS_COMMA_SEPARATED) --regex "$*" + +cross: cross-.* + +TIMES = 1 2 3 +fail: precross + $(CROSS_PY) test/test.py || true + $(CROSS_PY) test/test.py --update-expected-failures=overwrite + $(foreach var,$(TIMES),test/test.py -s || true;test/test.py --update-expected-failures=merge;) + +codespell_skip_files = \ + *.jar \ + *.class \ + *.so \ + *.a \ + *.la \ + *.o \ + *.p12 \ + *OCamlMakefile \ + .keystore \ + .truststore \ + CHANGES \ + config.sub \ + configure \ + depcomp \ + libtool.m4 \ + output.* \ + rebar \ + thrift + +skipped_files = $(subst $(space),$(comma),$(codespell_skip_files)) + +style-local: + codespell --write-changes --skip=$(skipped_files) --disable-colors + +EXTRA_DIST = \ + .clang-format \ + .editorconfig \ + .travis.yml \ + .rustfmt.toml \ + .dockerignore \ + appveyor.yml \ + bower.json \ + build \ + bootstrap.sh \ + cleanup.sh \ + CMakeLists.txt \ + composer.json \ + contrib \ + CONTRIBUTING.md \ + debian \ + doc \ + doap.rdf \ + package.json \ + sonar-project.properties \ + LANGUAGES.md \ + LICENSE \ + CHANGES \ + NOTICE \ + README.md \ + Thrift.podspec diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..078a845 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,1114 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@WITH_PLUGIN_TRUE@@WITH_TESTS_TRUE@am__append_1 = lib/cpp/test +@WITH_TESTS_TRUE@am__append_2 = test +@WITH_TUTORIAL_TRUE@am__append_3 = tutorial +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(am__DIST_COMMON) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = compiler/cpp/src/thrift/version.h \ + compiler/cpp/test/plugin/t_cpp_generator.cc +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + cscope distdir dist dist-all distcheck +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ + $(LISP)config.hin config.hin config.hin +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +CSCOPE = cscope +DIST_SUBDIRS = compiler/cpp lib test tutorial lib/cpp lib/cpp/test +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.hin \ + $(top_srcdir)/compiler/cpp/src/thrift/generate/t_cpp_generator.cc \ + $(top_srcdir)/compiler/cpp/src/thrift/version.h.in compile \ + config.guess config.sub install-sh ltmain.sh missing +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_distdir) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +DIST_TARGETS = dist-gzip +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +ACLOCAL_AMFLAGS = -I ./aclocal +@WITH_PLUGIN_FALSE@SUBDIRS = compiler/cpp lib $(am__append_2) \ +@WITH_PLUGIN_FALSE@ $(am__append_3) + +# To enable bootstrap, build order is lib/cpp -> compiler -> others +@WITH_PLUGIN_TRUE@SUBDIRS = lib/cpp compiler/cpp lib $(am__append_1) \ +@WITH_PLUGIN_TRUE@ $(am__append_2) $(am__append_3) +empty := +space := $(empty) $(empty) +comma := , +CROSS_LANGS = @MAYBE_CPP@ @MAYBE_C_GLIB@ @MAYBE_D@ @MAYBE_JAVA@ @MAYBE_CSHARP@ @MAYBE_PYTHON@ @MAYBE_PY3@ @MAYBE_RUBY@ @MAYBE_HASKELL@ @MAYBE_PERL@ @MAYBE_PHP@ @MAYBE_GO@ @MAYBE_NODEJS@ @MAYBE_DART@ @MAYBE_ERLANG@ @MAYBE_LUA@ @MAYBE_RS@ @MAYBE_DOTNETCORE@ +CROSS_LANGS_COMMA_SEPARATED = $(subst $(space),$(comma),$(CROSS_LANGS)) +@WITH_PY3_FALSE@CROSS_PY = $(PYTHON) +@WITH_PY3_TRUE@CROSS_PY = $(PYTHON3) +TIMES = 1 2 3 +codespell_skip_files = \ + *.jar \ + *.class \ + *.so \ + *.a \ + *.la \ + *.o \ + *.p12 \ + *OCamlMakefile \ + .keystore \ + .truststore \ + CHANGES \ + config.sub \ + configure \ + depcomp \ + libtool.m4 \ + output.* \ + rebar \ + thrift + +skipped_files = $(subst $(space),$(comma),$(codespell_skip_files)) +EXTRA_DIST = \ + .clang-format \ + .editorconfig \ + .travis.yml \ + .rustfmt.toml \ + .dockerignore \ + appveyor.yml \ + bower.json \ + build \ + bootstrap.sh \ + cleanup.sh \ + CMakeLists.txt \ + composer.json \ + contrib \ + CONTRIBUTING.md \ + debian \ + doc \ + doap.rdf \ + package.json \ + sonar-project.properties \ + LANGUAGES.md \ + LICENSE \ + CHANGES \ + NOTICE \ + README.md \ + Thrift.podspec + +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @test -f $@ || rm -f stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + +stamp-h1: $(srcdir)/config.hin $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.hin: $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +lib/cpp/src/thrift/config.h: lib/cpp/src/thrift/stamp-h2 + @test -f $@ || rm -f lib/cpp/src/thrift/stamp-h2 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) lib/cpp/src/thrift/stamp-h2 + +lib/cpp/src/thrift/stamp-h2: $(srcdir)/config.hin $(top_builddir)/config.status + @rm -f lib/cpp/src/thrift/stamp-h2 + cd $(top_builddir) && $(SHELL) ./config.status lib/cpp/src/thrift/config.h + +lib/c_glib/src/thrift/config.h: lib/c_glib/src/thrift/stamp-h3 + @test -f $@ || rm -f lib/c_glib/src/thrift/stamp-h3 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) lib/c_glib/src/thrift/stamp-h3 + +lib/c_glib/src/thrift/stamp-h3: $(srcdir)/config.hin $(top_builddir)/config.status + @rm -f lib/c_glib/src/thrift/stamp-h3 + cd $(top_builddir) && $(SHELL) ./config.status lib/c_glib/src/thrift/config.h + +distclean-hdr: + -rm -f config.h stamp-h1 lib/cpp/src/thrift/config.h lib/cpp/src/thrift/stamp-h2 lib/c_glib/src/thrift/config.h lib/c_glib/src/thrift/stamp-h3 +compiler/cpp/src/thrift/version.h: $(top_builddir)/config.status $(top_srcdir)/compiler/cpp/src/thrift/version.h.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__post_remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=../.. --prefix="$$dc_install_base" \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__post_remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile config.h +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr \ + distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +style: style-recursive + +style-am: style-local + +uninstall-am: + +.MAKE: $(am__recursive_targets) all install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--refresh check check-am clean clean-cscope clean-generic \ + clean-libtool cscope cscopelist-am ctags ctags-am dist \ + dist-all dist-bzip2 dist-gzip dist-hook dist-lzip dist-shar \ + dist-tarZ dist-xz dist-zip distcheck distclean \ + distclean-generic distclean-hdr distclean-libtool \ + distclean-tags distcleancheck distdir distuninstallcheck dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +dist-hook: + find $(distdir) -type f \( -iname ".DS_Store" -or -iname "._*" -or -iname ".gitignore" \) | xargs rm -rf + find $(distdir) -type d \( -iname ".deps" -or -iname ".libs" \) | xargs rm -rf + find $(distdir) -type d \( -iname ".svn" -or -iname ".git" \) | xargs rm -rf + +print-version: + @echo $(PACKAGE_VERSION) + +.PHONY: precross cross +precross-%: all + $(MAKE) -C $* precross +precross: all precross-test precross-lib + +@WITH_PYTHON_TRUE@crossfeature: precross +@WITH_PYTHON_TRUE@ $(CROSS_PY) test/test.py --retry-count 3 --features .* --skip-known-failures --server $(CROSS_LANGS_COMMA_SEPARATED) +# feature test needs python build +@WITH_PYTHON_FALSE@crossfeature: + +cross-%: precross crossfeature + $(CROSS_PY) test/test.py --retry-count 3 --skip-known-failures --server $(CROSS_LANGS_COMMA_SEPARATED) --client $(CROSS_LANGS_COMMA_SEPARATED) --regex "$*" + +cross: cross-.* +fail: precross + $(CROSS_PY) test/test.py || true + $(CROSS_PY) test/test.py --update-expected-failures=overwrite + $(foreach var,$(TIMES),test/test.py -s || true;test/test.py --update-expected-failures=merge;) + +style-local: + codespell --write-changes --skip=$(skipped_files) --disable-colors + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..902dc8d --- /dev/null +++ b/NOTICE @@ -0,0 +1,5 @@ +Apache Thrift +Copyright 2006-2017 The Apache Software Foundation. + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). diff --git a/README.md b/README.md new file mode 100644 index 0000000..5435041 --- /dev/null +++ b/README.md @@ -0,0 +1,178 @@ +Apache Thrift +============= + +Last Modified: 2017-11-10 + +License +======= + +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + +Introduction +============ + +Thrift is a lightweight, language-independent software stack with an +associated code generation mechanism for RPC. Thrift provides clean +abstractions for data transport, data serialization, and application +level processing. The code generation system takes a simple definition +language as its input and generates code across programming languages that +uses the abstracted stack to build interoperable RPC clients and servers. + +![Apache Thrift Layered Architecture](doc/images/thrift-layers.png) + +Thrift makes it easy for programs written in different programming +languages to share data and call remote procedures. With support +for [over 20 programming languages](LANGUAGES.md), chances are Thrift +supports the ones that you currently use. + +Thrift is specifically designed to support non-atomic version changes +across client and server code. + +For more details on Thrift's design and implementation, take a gander at +the Thrift whitepaper included in this distribution or at the README.md file +in your particular subdirectory of interest. + +Project Hierarchy +================= + +thrift/ + + compiler/ + + Contains the Thrift compiler, implemented in C++. + + lib/ + + Contains the Thrift software library implementation, subdivided by + language of implementation. + + cpp/ + go/ + java/ + php/ + py/ + rb/ + ... + + test/ + + Contains sample Thrift files and test code across the target programming + languages. + + tutorial/ + + Contains a basic tutorial that will teach you how to develop software + using Thrift. + +Requirements +============ + +See http://thrift.apache.org/docs/install for an up-to-date list of build requirements. + +Resources +========= + +More information about Thrift can be obtained on the Thrift webpage at: + + http://thrift.apache.org + +Acknowledgments +=============== + +Thrift was inspired by pillar, a lightweight RPC tool written by Adam D'Angelo, +and also by Google's protocol buffers. + +Installation +============ + +If you are building from the first time out of the source repository, you will +need to generate the configure scripts. (This is not necessary if you +downloaded a tarball.) From the top directory, do: + + ./bootstrap.sh + +Once the configure scripts are generated, thrift can be configured. +From the top directory, do: + + ./configure + +You may need to specify the location of the boost files explicitly. +If you installed boost in /usr/local, you would run configure as follows: + + ./configure --with-boost=/usr/local + +Note that by default the thrift C++ library is typically built with debugging +symbols included. If you want to customize these options you should use the +CXXFLAGS option in configure, as such: + + ./configure CXXFLAGS='-g -O2' + ./configure CFLAGS='-g -O2' + ./configure CPPFLAGS='-DDEBUG_MY_FEATURE' + +To enable gcov required options -fprofile-arcs -ftest-coverage enable them: + + ./configure --enable-coverage + +Run ./configure --help to see other configuration options + +Please be aware that the Python library will ignore the --prefix option +and just install wherever Python's distutils puts it (usually along +the lines of /usr/lib/pythonX.Y/site-packages/). If you need to control +where the Python modules are installed, set the PY_PREFIX variable. +(DESTDIR is respected for Python and C++.) + +Make thrift: + + make + +From the top directory, become superuser and do: + + make install + +Note that some language packages must be installed manually using build tools +better suited to those languages (at the time of this writing, this applies +to Java, Ruby, PHP). + +Look for the README.md file in the lib// folder for more details on the +installation of each language library package. + +Testing +======= + +There are a large number of client library tests that can all be run +from the top-level directory. + + make -k check + +This will make all of the libraries (as necessary), and run through +the unit tests defined in each of the client libraries. If a single +language fails, the make check will continue on and provide a synopsis +at the end. + +To run the cross-language test suite, please run: + + make cross + +This will run a set of tests that use different language clients and +servers. + +Development +=========== + +To build the same way Travis CI builds the project you should use docker. +We have [comprehensive building instructions for docker](build/docker/README.md). diff --git a/Thrift.podspec b/Thrift.podspec new file mode 100644 index 0000000..6f8ebb7 --- /dev/null +++ b/Thrift.podspec @@ -0,0 +1,18 @@ +Pod::Spec.new do |s| + s.name = "Thrift" + s.version = "0.11.0" + s.summary = "Apache Thrift is a lightweight, language-independent software stack with an associated code generation mechanism for RPC." + s.description = <<-DESC +The Apache Thrift software framework, for scalable cross-language services development, combines a software stack with a code generation engine to build services that work efficiently and seamlessly between C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi and other languages. + DESC + s.homepage = "http://thrift.apache.org" + s.license = { :type => 'Apache License, Version 2.0', :url => 'https://raw.github.com/apache/thrift/thrift-0.9.0/LICENSE' } + s.author = { "The Apache Software Foundation" => "apache@apache.org" } + s.requires_arc = true + s.ios.deployment_target = '7.0' + s.osx.deployment_target = '10.8' + s.ios.framework = 'CFNetwork' + s.osx.framework = 'CoreServices' + s.source = { :git => "https://github.com/apache/thrift.git", :tag => "thrift-0.11.0" } + s.source_files = 'lib/cocoa/src/**/*.{h,m,swift}' +end \ No newline at end of file diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..c1eab2c --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1719 @@ +# generated automatically by aclocal 1.15 -*- Autoconf -*- + +# Copyright (C) 1996-2014 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +dnl serial 11 (pkg-config-0.29.1) +dnl +dnl Copyright © 2004 Scott James Remnant . +dnl Copyright © 2012-2015 Dan Nicholson +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a +dnl configuration script generated by Autoconf, you may include it under +dnl the same distribution terms that you use for the rest of that +dnl program. + +dnl PKG_PREREQ(MIN-VERSION) +dnl ----------------------- +dnl Since: 0.29 +dnl +dnl Verify that the version of the pkg-config macros are at least +dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's +dnl installed version of pkg-config, this checks the developer's version +dnl of pkg.m4 when generating configure. +dnl +dnl To ensure that this macro is defined, also add: +dnl m4_ifndef([PKG_PREREQ], +dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) +dnl +dnl See the "Since" comment for each macro you use to see what version +dnl of the macros you require. +m4_defun([PKG_PREREQ], +[m4_define([PKG_MACROS_VERSION], [0.29.1]) +m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, + [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) +])dnl PKG_PREREQ + +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) +dnl ---------------------------------- +dnl Since: 0.16 +dnl +dnl Search for the pkg-config tool and set the PKG_CONFIG variable to +dnl first found in the path. Checks that the version of pkg-config found +dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is +dnl used since that's the first version where most current features of +dnl pkg-config existed. +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])dnl PKG_PROG_PKG_CONFIG + +dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------------------------------- +dnl Since: 0.18 +dnl +dnl Check to see whether a particular set of modules exists. Similar to +dnl PKG_CHECK_MODULES(), but does not set variables or print errors. +dnl +dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +dnl only at the first occurence in configure.ac, so if the first place +dnl it's called might be skipped (such as if it is within an "if", you +dnl have to call PKG_CHECK_EXISTS manually +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +dnl --------------------------------------------- +dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting +dnl pkg_failed based on the result. +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])dnl _PKG_CONFIG + +dnl _PKG_SHORT_ERRORS_SUPPORTED +dnl --------------------------- +dnl Internal check to see if pkg-config supports short errors. +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])dnl _PKG_SHORT_ERRORS_SUPPORTED + + +dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl -------------------------------------------------------------- +dnl Since: 0.4.0 +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES might not happen, you should be sure to include an +dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])dnl PKG_CHECK_MODULES + + +dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------------------- +dnl Since: 0.29 +dnl +dnl Checks for existence of MODULES and gathers its build flags with +dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags +dnl and VARIABLE-PREFIX_LIBS from --libs. +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to +dnl include an explicit call to PKG_PROG_PKG_CONFIG in your +dnl configure.ac. +AC_DEFUN([PKG_CHECK_MODULES_STATIC], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +_save_PKG_CONFIG=$PKG_CONFIG +PKG_CONFIG="$PKG_CONFIG --static" +PKG_CHECK_MODULES($@) +PKG_CONFIG=$_save_PKG_CONFIG[]dnl +])dnl PKG_CHECK_MODULES_STATIC + + +dnl PKG_INSTALLDIR([DIRECTORY]) +dnl ------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable pkgconfigdir as the location where a module +dnl should install pkg-config .pc files. By default the directory is +dnl $libdir/pkgconfig, but the default can be changed by passing +dnl DIRECTORY. The user can override through the --with-pkgconfigdir +dnl parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_INSTALLDIR + + +dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) +dnl -------------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable noarch_pkgconfigdir as the location where a +dnl module should install arch-independent pkg-config .pc files. By +dnl default the directory is $datadir/pkgconfig, but the default can be +dnl changed by passing DIRECTORY. The user can override through the +dnl --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_NOARCH_INSTALLDIR + + +dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------- +dnl Since: 0.28 +dnl +dnl Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])dnl PKG_CHECK_VAR + +# Copyright (C) 2002-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.15' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.15], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.15])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each '.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# AM_EXTRA_RECURSIVE_TARGETS -*- Autoconf -*- + +# Copyright (C) 2012-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_EXTRA_RECURSIVE_TARGETS +# -------------------------- +# Define the list of user recursive targets. This macro exists only to +# be traced by Automake, which will ensure that a proper definition of +# user-defined recursive targets (and associated rules) is propagated +# into all the generated Makefiles. +# TODO: We should really reject non-literal arguments here... +AC_DEFUN([AM_EXTRA_RECURSIVE_TARGETS], []) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.65])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. +]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Copyright (C) 1998-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_LEX +# ----------- +# Autoconf leaves LEX=: if lex or flex can't be found. Change that to a +# "missing" invocation, for better error output. +AC_DEFUN([AM_PROG_LEX], +[AC_PREREQ([2.50])dnl +AC_REQUIRE([AM_MISSING_HAS_RUN])dnl +AC_REQUIRE([AC_PROG_LEX])dnl +if test "$LEX" = :; then + LEX=${am_missing_run}flex +fi]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it is modern enough. +# If it is, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i]) +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +AC_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# --------------------------------------------------------------------------- +# Adds support for distributing Python modules and packages. To +# install modules, copy them to $(pythondir), using the python_PYTHON +# automake variable. To install a package with the same name as the +# automake package, install to $(pkgpythondir), or use the +# pkgpython_PYTHON automake variable. +# +# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as +# locations to install python extension modules (shared libraries). +# Another macro is required to find the appropriate flags to compile +# extension modules. +# +# If your package is configured with a different prefix to python, +# users will have to add the install directory to the PYTHONPATH +# environment variable, or create a .pth file (see the python +# documentation for details). +# +# If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will +# cause an error if the version of python installed on the system +# doesn't meet the requirement. MINIMUM-VERSION should consist of +# numbers and dots only. +AC_DEFUN([AM_PATH_PYTHON], + [ + dnl Find a Python interpreter. Python versions prior to 2.0 are not + dnl supported. (2.0 was released on October 16, 2000). + m4_define_default([_AM_PYTHON_INTERPRETER_LIST], +[python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 dnl + python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0]) + + AC_ARG_VAR([PYTHON], [the Python interpreter]) + + m4_if([$1],[],[ + dnl No version check is needed. + # Find any Python interpreter. + if test -z "$PYTHON"; then + AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :) + fi + am_display_PYTHON=python + ], [ + dnl A version check is needed. + if test -n "$PYTHON"; then + # If the user set $PYTHON, use it and don't search something else. + AC_MSG_CHECKING([whether $PYTHON version is >= $1]) + AM_PYTHON_CHECK_VERSION([$PYTHON], [$1], + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no]) + AC_MSG_ERROR([Python interpreter is too old])]) + am_display_PYTHON=$PYTHON + else + # Otherwise, try each interpreter until we find one that satisfies + # VERSION. + AC_CACHE_CHECK([for a Python interpreter with version >= $1], + [am_cv_pathless_PYTHON],[ + for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do + test "$am_cv_pathless_PYTHON" = none && break + AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break]) + done]) + # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. + if test "$am_cv_pathless_PYTHON" = none; then + PYTHON=: + else + AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON]) + fi + am_display_PYTHON=$am_cv_pathless_PYTHON + fi + ]) + + if test "$PYTHON" = :; then + dnl Run any user-specified action, or abort. + m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) + else + + dnl Query Python for its version number. Getting [:3] seems to be + dnl the best way to do this; it's what "site.py" does in the standard + dnl library. + + AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], + [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`]) + AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) + + dnl Use the values of $prefix and $exec_prefix for the corresponding + dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made + dnl distinct variables so they can be overridden if need be. However, + dnl general consensus is that you shouldn't need this ability. + + AC_SUBST([PYTHON_PREFIX], ['${prefix}']) + AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}']) + + dnl At times (like when building shared libraries) you may want + dnl to know which OS platform Python thinks this is. + + AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], + [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`]) + AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) + + # Just factor out some code duplication. + am_python_setup_sysconfig="\ +import sys +# Prefer sysconfig over distutils.sysconfig, for better compatibility +# with python 3.x. See automake bug#10227. +try: + import sysconfig +except ImportError: + can_use_sysconfig = 0 +else: + can_use_sysconfig = 1 +# Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs: +# +try: + from platform import python_implementation + if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7': + can_use_sysconfig = 0 +except ImportError: + pass" + + dnl Set up 4 directories: + + dnl pythondir -- where to install python scripts. This is the + dnl site-packages directory, not the python standard library + dnl directory like in previous automake betas. This behavior + dnl is more consistent with lispdir.m4 for example. + dnl Query distutils for this directory. + AC_CACHE_CHECK([for $am_display_PYTHON script directory], + [am_cv_python_pythondir], + [if test "x$prefix" = xNONE + then + am_py_prefix=$ac_default_prefix + else + am_py_prefix=$prefix + fi + am_cv_python_pythondir=`$PYTHON -c " +$am_python_setup_sysconfig +if can_use_sysconfig: + sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) +else: + from distutils import sysconfig + sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') +sys.stdout.write(sitedir)"` + case $am_cv_python_pythondir in + $am_py_prefix*) + am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` + am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` + ;; + *) + case $am_py_prefix in + /usr|/System*) ;; + *) + am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages + ;; + esac + ;; + esac + ]) + AC_SUBST([pythondir], [$am_cv_python_pythondir]) + + dnl pkgpythondir -- $PACKAGE directory under pythondir. Was + dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is + dnl more consistent with the rest of automake. + + AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) + + dnl pyexecdir -- directory for installing python extension modules + dnl (shared libraries) + dnl Query distutils for this directory. + AC_CACHE_CHECK([for $am_display_PYTHON extension module directory], + [am_cv_python_pyexecdir], + [if test "x$exec_prefix" = xNONE + then + am_py_exec_prefix=$am_py_prefix + else + am_py_exec_prefix=$exec_prefix + fi + am_cv_python_pyexecdir=`$PYTHON -c " +$am_python_setup_sysconfig +if can_use_sysconfig: + sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'}) +else: + from distutils import sysconfig + sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix') +sys.stdout.write(sitedir)"` + case $am_cv_python_pyexecdir in + $am_py_exec_prefix*) + am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` + am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` + ;; + *) + case $am_py_exec_prefix in + /usr|/System*) ;; + *) + am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages + ;; + esac + ;; + esac + ]) + AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) + + dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) + + AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) + + dnl Run any user-specified action. + $2 + fi + +]) + + +# AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +# --------------------------------------------------------------------------- +# Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION. +# Run ACTION-IF-FALSE otherwise. +# This test uses sys.hexversion instead of the string equivalent (first +# word of sys.version), in order to cope with versions such as 2.2c1. +# This supports Python 2.0 or higher. (2.0 was released on October 16, 2000). +AC_DEFUN([AM_PYTHON_CHECK_VERSION], + [prog="import sys +# split strings by '.' and convert to numeric. Append some zeros +# because we need at least 4 digits for the hex conversion. +# map returns an iterator in Python 3.0 and a list in 2.x +minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]] +minverhex = 0 +# xrange is not present in Python 3.0 and range returns an iterator +for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] +sys.exit(sys.hexversion < minverhex)" + AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +# +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) + AC_MSG_RESULT([$am_cv_prog_tar_$1])]) + +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([aclocal/ac_prog_bison.m4]) +m4_include([aclocal/ax_boost_base.m4]) +m4_include([aclocal/ax_check_openssl.m4]) +m4_include([aclocal/ax_compare_version.m4]) +m4_include([aclocal/ax_cxx_compile_stdcxx.m4]) +m4_include([aclocal/ax_cxx_compile_stdcxx_11.m4]) +m4_include([aclocal/ax_dmd.m4]) +m4_include([aclocal/ax_javac_and_java.m4]) +m4_include([aclocal/ax_lib_event.m4]) +m4_include([aclocal/ax_lib_zlib.m4]) +m4_include([aclocal/ax_lua.m4]) +m4_include([aclocal/ax_prog_dotnetcore_version.m4]) +m4_include([aclocal/ax_prog_haxe_version.m4]) +m4_include([aclocal/ax_prog_perl_modules.m4]) +m4_include([aclocal/ax_signed_right_shift.m4]) +m4_include([aclocal/ax_thrift_internal.m4]) +m4_include([aclocal/libtool.m4]) +m4_include([aclocal/ltoptions.m4]) +m4_include([aclocal/ltsugar.m4]) +m4_include([aclocal/ltversion.m4]) +m4_include([aclocal/lt~obsolete.m4]) diff --git a/aclocal/ac_prog_bison.m4 b/aclocal/ac_prog_bison.m4 new file mode 100644 index 0000000..4d1198b --- /dev/null +++ b/aclocal/ac_prog_bison.m4 @@ -0,0 +1,54 @@ +dnl +dnl Check Bison version +dnl AC_PROG_BISON([MIN_VERSION=2.4]) +dnl +dnl Will define BISON_USE_PARSER_H_EXTENSION if Automake is < 1.11 +dnl for use with .h includes. +dnl + +AC_DEFUN([AC_PROG_BISON], [ +if test "x$1" = "x" ; then + bison_required_version="2.4" +else + bison_required_version="$1" +fi + +AC_CHECK_PROG(have_prog_bison, [bison], [yes],[no]) + +AC_DEFINE_UNQUOTED([BISON_VERSION], [0.0], [Bison version if bison is not available]) + +#Do not use *.h extension for parser header files, use newer *.hh +bison_use_parser_h_extension=false + +if test "$have_prog_bison" = "yes" ; then + AC_MSG_CHECKING([for bison version >= $bison_required_version]) + bison_version=`bison --version | head -n 1 | cut '-d ' -f 4` + AC_DEFINE_UNQUOTED([BISON_VERSION], [$bison_version], [Defines bison version]) + if test "$bison_version" \< "$bison_required_version" ; then + BISON=: + AC_MSG_RESULT([no]) + AC_MSG_ERROR([Bison version $bison_required_version or higher must be installed on the system!]) + else + AC_MSG_RESULT([yes]) + BISON=bison + AC_SUBST(BISON) + + #Verify automake version 1.11 headers for yy files are .h, > 1.12 uses .hh + automake_version=`automake --version | head -n 1 | cut '-d ' -f 4` + AC_DEFINE_UNQUOTED([AUTOMAKE_VERSION], [$automake_version], [Defines automake version]) + + if test "$automake_version" \< "1.12" ; then + #Use *.h extension for parser header file + bison_use_parser_h_extension=true + echo "Automake version < 1.12" + AC_DEFINE([BISON_USE_PARSER_H_EXTENSION], [1], [Use *.h extension for parser header file]) + fi + fi +else + BISON=: + AC_MSG_RESULT([NO]) +fi + +AM_CONDITIONAL([BISON_USE_PARSER_H_EXTENSION], [test x$bison_use_parser_h_extension = xtrue]) +AC_SUBST(BISON) +]) diff --git a/aclocal/ax_boost_base.m4 b/aclocal/ax_boost_base.m4 new file mode 100644 index 0000000..19c71b6 --- /dev/null +++ b/aclocal/ax_boost_base.m4 @@ -0,0 +1,301 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_boost_base.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# DESCRIPTION +# +# Test for the Boost C++ libraries of a particular version (or newer) +# +# If no path to the installed boost library is given the macro searchs +# under /usr, /usr/local, /opt and /opt/local and evaluates the +# $BOOST_ROOT environment variable. Further documentation is available at +# . +# +# This macro calls: +# +# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS) +# +# And sets: +# +# HAVE_BOOST +# +# LICENSE +# +# Copyright (c) 2008 Thomas Porschberg +# Copyright (c) 2009 Peter Adolphs +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 42 + +# example boost program (need to pass version) +m4_define([_AX_BOOST_BASE_PROGRAM], + [AC_LANG_PROGRAM([[ +#include +]],[[ +(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($1))])); +]])]) + +AC_DEFUN([AX_BOOST_BASE], +[ +AC_ARG_WITH([boost], + [AS_HELP_STRING([--with-boost@<:@=ARG@:>@], + [use Boost library from a standard location (ARG=yes), + from the specified location (ARG=), + or disable it (ARG=no) + @<:@ARG=yes@:>@ ])], + [ + AS_CASE([$withval], + [no],[want_boost="no";_AX_BOOST_BASE_boost_path=""], + [yes],[want_boost="yes";_AX_BOOST_BASE_boost_path=""], + [want_boost="yes";_AX_BOOST_BASE_boost_path="$withval"]) + ], + [want_boost="yes"]) + + +AC_ARG_WITH([boost-libdir], + [AS_HELP_STRING([--with-boost-libdir=LIB_DIR], + [Force given directory for boost libraries. + Note that this will override library path detection, + so use this parameter only if default library detection fails + and you know exactly where your boost libraries are located.])], + [ + AS_IF([test -d "$withval"], + [_AX_BOOST_BASE_boost_lib_path="$withval"], + [AC_MSG_ERROR([--with-boost-libdir expected directory name])]) + ], + [_AX_BOOST_BASE_boost_lib_path=""]) + +BOOST_LDFLAGS="" +BOOST_CPPFLAGS="" +AS_IF([test "x$want_boost" = "xyes"], + [_AX_BOOST_BASE_RUNDETECT([$1],[$2],[$3])]) +AC_SUBST(BOOST_CPPFLAGS) +AC_SUBST(BOOST_LDFLAGS) +]) + + +# convert a version string in $2 to numeric and affect to polymorphic var $1 +AC_DEFUN([_AX_BOOST_BASE_TONUMERICVERSION],[ + AS_IF([test "x$2" = "x"],[_AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0"],[_AX_BOOST_BASE_TONUMERICVERSION_req="$2"]) + _AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\.[[0-9]]*\)'` + _AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\)'` + AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_major" = "x"], + [AC_MSG_ERROR([You should at least specify libboost major version])]) + _AX_BOOST_BASE_TONUMERICVERSION_req_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.\([[0-9]]*\)'` + AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_minor" = "x"], + [_AX_BOOST_BASE_TONUMERICVERSION_req_minor="0"]) + _AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + AS_IF([test "X$_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor" = "X"], + [_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor="0"]) + _AX_BOOST_BASE_TONUMERICVERSION_RET=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req_major \* 100000 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_minor \* 100 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor` + AS_VAR_SET($1,$_AX_BOOST_BASE_TONUMERICVERSION_RET) +]) + +dnl Run the detection of boost should be run only if $want_boost +AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ + _AX_BOOST_BASE_TONUMERICVERSION(WANT_BOOST_VERSION,[$1]) + succeeded=no + + + AC_REQUIRE([AC_CANONICAL_HOST]) + dnl On 64-bit systems check for system libraries in both lib64 and lib. + dnl The former is specified by FHS, but e.g. Debian does not adhere to + dnl this (as it rises problems for generic multi-arch support). + dnl The last entry in the list is chosen by default when no libraries + dnl are found, e.g. when only header-only libraries are installed! + AS_CASE([${host_cpu}], + [x86_64],[libsubdirs="lib64 libx32 lib lib64"], + [ppc64|s390x|sparc64|aarch64|ppc64le],[libsubdirs="lib64 lib lib64"], + [libsubdirs="lib"], + ) + + dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give + dnl them priority over the other paths since, if libs are found there, they + dnl are almost assuredly the ones desired. + AS_CASE([${host_cpu}], + [i?86],[multiarch_libsubdir="lib/i386-${host_os}"], + [multiarch_libsubdir="lib/${host_cpu}-${host_os}"] + ) + + dnl first we check the system location for boost libraries + dnl this location ist chosen if boost libraries are installed with the --layout=system option + dnl or if you install boost with RPM + AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[ + AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"]) + AS_IF([test -d "$_AX_BOOST_BASE_boost_path/include" && test -r "$_AX_BOOST_BASE_boost_path/include"],[ + AC_MSG_RESULT([yes]) + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include" + for _AX_BOOST_BASE_boost_path_tmp in $multiarch_libsubdir $libsubdirs; do + AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) lib path in "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"]) + AS_IF([test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ],[ + AC_MSG_RESULT([yes]) + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"; + break; + ], + [AC_MSG_RESULT([no])]) + done],[ + AC_MSG_RESULT([no])]) + ],[ + if test X"$cross_compiling" = Xyes; then + search_libsubdirs=$multiarch_libsubdir + else + search_libsubdirs="$multiarch_libsubdir $libsubdirs" + fi + for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local ; do + if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then + for libsubdir in $search_libsubdirs ; do + if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path_tmp/$libsubdir" + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include" + break; + fi + done + ]) + + dnl overwrite ld flags if we have required special directory with + dnl --with-boost-libdir parameter + AS_IF([test "x$_AX_BOOST_BASE_boost_lib_path" != "x"], + [BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_lib_path"]) + + AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION)]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_REQUIRE([AC_PROG_CXX]) + AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[ + AC_MSG_RESULT(yes) + succeeded=yes + found_system=yes + ],[ + ]) + AC_LANG_POP([C++]) + + + + dnl if we found no boost with system layout we search for boost libraries + dnl built and installed without the --layout=system option or for a staged(not installed) version + if test "x$succeeded" != "xyes" ; then + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + BOOST_CPPFLAGS= + if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + BOOST_LDFLAGS= + fi + _version=0 + if test -n "$_AX_BOOST_BASE_boost_path" ; then + if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then + for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "x$V_CHECK" = "x1" ; then + _version=$_version_tmp + fi + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include/boost-$VERSION_UNDERSCORE" + done + dnl if nothing found search for layout used in Windows distributions + if test -z "$BOOST_CPPFLAGS"; then + if test -d "$_AX_BOOST_BASE_boost_path/boost" && test -r "$_AX_BOOST_BASE_boost_path/boost"; then + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path" + fi + fi + dnl if we found something and BOOST_LDFLAGS was unset before + dnl (because "$_AX_BOOST_BASE_boost_lib_path" = ""), set it here. + if test -n "$BOOST_CPPFLAGS" && test -z "$BOOST_LDFLAGS"; then + for libsubdir in $libsubdirs ; do + if ls "$_AX_BOOST_BASE_boost_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$libsubdir" + fi + fi + else + if test "x$cross_compiling" != "xyes" ; then + for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local ; do + if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then + for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "x$V_CHECK" = "x1" ; then + _version=$_version_tmp + best_path=$_AX_BOOST_BASE_boost_path + fi + done + fi + done + + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" + if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + for libsubdir in $libsubdirs ; do + if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$best_path/$libsubdir" + fi + fi + + if test -n "$BOOST_ROOT" ; then + for libsubdir in $libsubdirs ; do + if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then + version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'` + stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` + stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'` + V_CHECK=`expr $stage_version_shorten \>\= $_version` + if test "x$V_CHECK" = "x1" && test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) + BOOST_CPPFLAGS="-I$BOOST_ROOT" + BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir" + fi + fi + fi + fi + + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[ + AC_MSG_RESULT(yes) + succeeded=yes + found_system=yes + ],[ + ]) + AC_LANG_POP([C++]) + fi + + if test "x$succeeded" != "xyes" ; then + if test "x$_version" = "x0" ; then + AC_MSG_NOTICE([[We could not detect the boost libraries (version $1 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation.]]) + else + AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) + fi + # execute ACTION-IF-NOT-FOUND (if present): + ifelse([$3], , :, [$3]) + else + AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) + # execute ACTION-IF-FOUND (if present): + ifelse([$2], , :, [$2]) + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + +]) diff --git a/aclocal/ax_check_openssl.m4 b/aclocal/ax_check_openssl.m4 new file mode 100644 index 0000000..28e48cb --- /dev/null +++ b/aclocal/ax_check_openssl.m4 @@ -0,0 +1,124 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_openssl.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_OPENSSL([action-if-found[, action-if-not-found]]) +# +# DESCRIPTION +# +# Look for OpenSSL in a number of default spots, or in a user-selected +# spot (via --with-openssl). Sets +# +# OPENSSL_INCLUDES to the include directives required +# OPENSSL_LIBS to the -l directives required +# OPENSSL_LDFLAGS to the -L or -R flags required +# +# and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately +# +# This macro sets OPENSSL_INCLUDES such that source files should use the +# openssl/ directory in include directives: +# +# #include +# +# LICENSE +# +# Copyright (c) 2009,2010 Zmanda Inc. +# Copyright (c) 2009,2010 Dustin J. Mitchell +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 10 + +AU_ALIAS([CHECK_SSL], [AX_CHECK_OPENSSL]) +AC_DEFUN([AX_CHECK_OPENSSL], [ + found=false + AC_ARG_WITH([openssl], + [AS_HELP_STRING([--with-openssl=DIR], + [root of the OpenSSL directory])], + [ + case "$withval" in + "" | y | ye | yes | n | no) + AC_MSG_ERROR([Invalid --with-openssl value]) + ;; + *) ssldirs="$withval" + ;; + esac + ], [ + # if pkg-config is installed and openssl has installed a .pc file, + # then use that information and don't search ssldirs + AC_CHECK_TOOL([PKG_CONFIG], [pkg-config]) + if test x"$PKG_CONFIG" != x""; then + OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` + if test $? = 0; then + OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` + OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` + found=true + fi + fi + + # no such luck; use some default ssldirs + if ! $found; then + ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" + fi + ] + ) + + + # note that we #include , so the OpenSSL headers have to be in + # an 'openssl' subdirectory + + if ! $found; then + OPENSSL_INCLUDES= + for ssldir in $ssldirs; do + AC_MSG_CHECKING([for openssl/ssl.h in $ssldir]) + if test -f "$ssldir/include/openssl/ssl.h"; then + OPENSSL_INCLUDES="-I$ssldir/include" + OPENSSL_LDFLAGS="-L$ssldir/lib" + OPENSSL_LIBS="-lssl -lcrypto" + found=true + AC_MSG_RESULT([yes]) + break + else + AC_MSG_RESULT([no]) + fi + done + + # if the file wasn't found, well, go ahead and try the link anyway -- maybe + # it will just work! + fi + + # try the preprocessor and linker with our new flags, + # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS + + AC_MSG_CHECKING([whether compiling and linking against OpenSSL works]) + echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ + "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&AS_MESSAGE_LOG_FD + + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + save_CPPFLAGS="$CPPFLAGS" + LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" + LIBS="$OPENSSL_LIBS $LIBS" + CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([#include ], [SSL_new(NULL)])], + [ + AC_MSG_RESULT([yes]) + $1 + ], [ + AC_MSG_RESULT([no]) + $2 + ]) + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + + AC_SUBST([OPENSSL_INCLUDES]) + AC_SUBST([OPENSSL_LIBS]) + AC_SUBST([OPENSSL_LDFLAGS]) +]) diff --git a/aclocal/ax_compare_version.m4 b/aclocal/ax_compare_version.m4 new file mode 100644 index 0000000..9c8e208 --- /dev/null +++ b/aclocal/ax_compare_version.m4 @@ -0,0 +1,177 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_compare_version.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +# +# DESCRIPTION +# +# This macro compares two version strings. Due to the various number of +# minor-version numbers that can exist, and the fact that string +# comparisons are not compatible with numeric comparisons, this is not +# necessarily trivial to do in a autoconf script. This macro makes doing +# these comparisons easy. +# +# The six basic comparisons are available, as well as checking equality +# limited to a certain number of minor-version levels. +# +# The operator OP determines what type of comparison to do, and can be one +# of: +# +# eq - equal (test A == B) +# ne - not equal (test A != B) +# le - less than or equal (test A <= B) +# ge - greater than or equal (test A >= B) +# lt - less than (test A < B) +# gt - greater than (test A > B) +# +# Additionally, the eq and ne operator can have a number after it to limit +# the test to that number of minor versions. +# +# eq0 - equal up to the length of the shorter version +# ne0 - not equal up to the length of the shorter version +# eqN - equal up to N sub-version levels +# neN - not equal up to N sub-version levels +# +# When the condition is true, shell commands ACTION-IF-TRUE are run, +# otherwise shell commands ACTION-IF-FALSE are run. The environment +# variable 'ax_compare_version' is always set to either 'true' or 'false' +# as well. +# +# Examples: +# +# AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) +# AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) +# +# would both be true. +# +# AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) +# AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) +# +# would both be false. +# +# AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) +# +# would be true because it is only comparing two minor versions. +# +# AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) +# +# would be true because it is only comparing the lesser number of minor +# versions of the two values. +# +# Note: The characters that separate the version numbers do not matter. An +# empty string is the same as version 0. OP is evaluated by autoconf, not +# configure, so must be a string, not a variable. +# +# The author would like to acknowledge Guido Draheim whose advice about +# the m4_case and m4_ifvaln functions make this macro only include the +# portions necessary to perform the specific comparison specified by the +# OP argument in the final configure script. +# +# LICENSE +# +# Copyright (c) 2008 Tim Toolan +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 12 + +dnl ######################################################################### +AC_DEFUN([AX_COMPARE_VERSION], [ + AC_REQUIRE([AC_PROG_AWK]) + + # Used to indicate true or false condition + ax_compare_version=false + + # Convert the two version strings to be compared into a format that + # allows a simple string comparison. The end result is that a version + # string of the form 1.12.5-r617 will be converted to the form + # 0001001200050617. In other words, each number is zero padded to four + # digits, and non digits are removed. + AS_VAR_PUSHDEF([A],[ax_compare_version_A]) + A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + AS_VAR_PUSHDEF([B],[ax_compare_version_B]) + B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary + dnl # then the first line is used to determine if the condition is true. + dnl # The sed right after the echo is to remove any indented white space. + m4_case(m4_tolower($2), + [lt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [gt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [le],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ], + [ge],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ],[ + dnl Split the operator from the subversion count if present. + m4_bmatch(m4_substr($2,2), + [0],[ + # A count of zero means use the length of the shorter version. + # Determine the number of characters in A and B. + ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` + ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` + + # Set A to no more than B's length and B to no more than A's length. + A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` + B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` + ], + [[0-9]+],[ + # A count greater than zero means use only that many subversions + A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + ], + [.+],[ + AC_WARNING( + [illegal OP numeric parameter: $2]) + ],[]) + + # Pad zeros at end of numbers to make same length. + ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" + B="$B`echo $A | sed 's/./0/g'`" + A="$ax_compare_version_tmp_A" + + # Check for equality or inequality as necessary. + m4_case(m4_tolower(m4_substr($2,0,2)), + [eq],[ + test "x$A" = "x$B" && ax_compare_version=true + ], + [ne],[ + test "x$A" != "x$B" && ax_compare_version=true + ],[ + AC_WARNING([illegal OP parameter: $2]) + ]) + ]) + + AS_VAR_POPDEF([A])dnl + AS_VAR_POPDEF([B])dnl + + dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. + if test "$ax_compare_version" = "true" ; then + m4_ifvaln([$4],[$4],[:])dnl + m4_ifvaln([$5],[else $5])dnl + fi +]) dnl AX_COMPARE_VERSION diff --git a/aclocal/ax_cxx_compile_stdcxx.m4 b/aclocal/ax_cxx_compile_stdcxx.m4 new file mode 100644 index 0000000..5032bba --- /dev/null +++ b/aclocal/ax_cxx_compile_stdcxx.m4 @@ -0,0 +1,982 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the specified +# version of the C++ standard. If necessary, add switches to CXX and +# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) +# or '14' (for the C++14 standard). +# +# The second argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The third argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline support for the specified C++ standard is +# required and that the macro should error out if no mode with that +# support is found. If specified 'optional', then configuration proceeds +# regardless, after defining HAVE_CXX${VERSION} if and only if a +# supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# Copyright (c) 2016 Krzesimir Nowak +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 7 + +dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro +dnl (serial version number 13). + +AX_REQUIRE_DEFINED([AC_MSG_WARN]) +AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl + m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], + [$1], [14], [ax_cxx_compile_alternatives="14 1y"], + [$1], [17], [ax_cxx_compile_alternatives="17 1z"], + [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$2], [], [], + [$2], [ext], [], + [$2], [noext], [], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], + [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], + [$3], [optional], [ax_cxx_compile_cxx$1_required=false], + [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, + ax_cv_cxx_compile_cxx$1, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [ax_cv_cxx_compile_cxx$1=yes], + [ax_cv_cxx_compile_cxx$1=no])]) + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then + ac_success=yes + fi + + m4_if([$2], [noext], [], [dnl + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + switch="-std=gnu++${alternative}" + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + fi]) + + m4_if([$2], [ext], [], [dnl + if test x$ac_success = xno; then + dnl HP's aCC needs +std=c++11 according to: + dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf + dnl Cray's crayCC needs "-h std=c++11" + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx$1_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) + fi + fi + if test x$ac_success = xno; then + HAVE_CXX$1=0 + AC_MSG_NOTICE([No compiler with C++$1 support was found]) + else + HAVE_CXX$1=1 + AC_DEFINE(HAVE_CXX$1,1, + [define if the compiler supports basic C++$1 syntax]) + fi + AC_SUBST(HAVE_CXX$1) + m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])]) +]) + + +dnl Test body for checking C++11 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 +) + + +dnl Test body for checking C++14 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 +) + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 +) + +dnl Tests for new features in C++11 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + +]]) + + +dnl Tests for new features in C++14 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + +]]) + + +dnl Tests for new features in C++17 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus <= 201402L + +#error "This is not a C++17 compiler" + +#else + +#if defined(__clang__) + #define REALLY_CLANG +#else + #if defined(__GNUC__) + #define REALLY_GCC + #endif +#endif + +#include +#include +#include + +namespace cxx17 +{ + +#if !defined(REALLY_CLANG) + namespace test_constexpr_lambdas + { + + // TODO: test it with clang++ from git + + constexpr int foo = [](){return 42;}(); + + } +#endif // !defined(REALLY_CLANG) + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template + int multiply(Args... args) + { + return (args * ... * 1); + } + + template + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_auto_brace_init_list + { + + auto foo = {5}; + auto bar {5}; + + static_assert(std::is_same, decltype(foo)>::value); + static_assert(std::is_same::value); + } + + namespace test_typename_in_template_template_parameter + { + + template typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() + { + return 13; + } + + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } + + } + +#if !defined(REALLY_CLANG) + namespace test_template_argument_deduction_for_class_templates + { + + // TODO: test it with clang++ from git + + template + struct pair + { + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} + + T1 m1; + T2 m2; + }; + + void f() + { + [[maybe_unused]] auto p = pair{13, 42u}; + } + + } +#endif // !defined(REALLY_CLANG) + + namespace test_non_type_auto_template_parameters + { + + template + struct B + {}; + + B<5> b1; + B<'a'> b2; + + } + +#if !defined(REALLY_CLANG) + namespace test_structured_bindings + { + + // TODO: test it with clang++ from git + + int arr[2] = { 1, 2 }; + std::pair pr = { 1, 2 }; + + auto f1() -> int(&)[2] + { + return arr; + } + + auto f2() -> std::pair& + { + return pr; + } + + struct S + { + int x1 : 2; + volatile double y1; + }; + + S f3() + { + return {}; + } + + auto [ x1, y1 ] = f1(); + auto& [ xr1, yr1 ] = f1(); + auto [ x2, y2 ] = f2(); + auto& [ xr2, yr2 ] = f2(); + const auto [ x3, y3 ] = f3(); + + } +#endif // !defined(REALLY_CLANG) + +#if !defined(REALLY_CLANG) + namespace test_exception_spec_type_system + { + + // TODO: test it with clang++ from git + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template + Bad + f(T*, T*); + + template + Good + f(T1*, T2*); + + static_assert (std::is_same_v); + + } +#endif // !defined(REALLY_CLANG) + + namespace test_inline_variables + { + + template void f(T) + {} + + template inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // __cplusplus <= 201402L + +]]) diff --git a/aclocal/ax_cxx_compile_stdcxx_11.m4 b/aclocal/ax_cxx_compile_stdcxx_11.m4 new file mode 100644 index 0000000..1733fd8 --- /dev/null +++ b/aclocal/ax_cxx_compile_stdcxx_11.m4 @@ -0,0 +1,39 @@ +# ============================================================================= +# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# ============================================================================= +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++11 +# standard; if necessary, add switches to CXX and CXXCPP to enable +# support. +# +# This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX +# macro with the version set to C++11. The two optional arguments are +# forwarded literally as the second and third argument respectively. +# Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for +# more information. If you want to use this macro, you also need to +# download the ax_cxx_compile_stdcxx.m4 file. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 18 + +AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX]) +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])]) diff --git a/aclocal/ax_dmd.m4 b/aclocal/ax_dmd.m4 new file mode 100644 index 0000000..13b84b0 --- /dev/null +++ b/aclocal/ax_dmd.m4 @@ -0,0 +1,107 @@ +dnl @synopsis AX_DMD +dnl +dnl Test for the presence of a DMD-compatible D2 compiler, and (optionally) +dnl specified modules on the import path. +dnl +dnl If "DMD" is defined in the environment, that will be the only +dnl dmd command tested. Otherwise, a hard-coded list will be used. +dnl +dnl After AX_DMD runs, the shell variables "success" and "ax_dmd" are set to +dnl "yes" or "no", and "DMD" is set to the appropriate command. Furthermore, +dnl "dmd_optlink" will be set to "yes" or "no" depending on whether OPTLINK is +dnl used as the linker (DMD/Windows), and "dmd_of_dirsep" will be set to the +dnl directory separator to use when passing -of to DMD (OPTLINK requires a +dnl backslash). +dnl +dnl AX_CHECK_D_MODULE must be run after AX_DMD. It tests for the presence of a +dnl module in the import path of the chosen compiler, and sets the shell +dnl variable "success" to "yes" or "no". +dnl +dnl @category D +dnl @version 2011-05-31 +dnl @license AllPermissive +dnl +dnl Copyright (C) 2009 David Reiss +dnl Copyright (C) 2011 David Nadlinger +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. + + +AC_DEFUN([AX_DMD], + [ + dnl Hard-coded default commands to test. + DMD_PROGS="dmd,gdmd,ldmd" + + dnl Allow the user to specify an alternative. + if test -n "$DMD" ; then + DMD_PROGS="$DMD" + fi + + AC_MSG_CHECKING(for DMD) + + # std.algorithm as a quick way to check for D2/Phobos. + echo "import std.algorithm; void main() {}" > configtest_ax_dmd.d + success=no + oIFS="$IFS" + + IFS="," + for DMD in $DMD_PROGS ; do + IFS="$oIFS" + + echo "Running \"$DMD configtest_ax_dmd.d\"" >&AS_MESSAGE_LOG_FD + if $DMD configtest_ax_dmd.d >&AS_MESSAGE_LOG_FD 2>&1 ; then + success=yes + break + fi + done + + if test "$success" != "yes" ; then + AC_MSG_RESULT(no) + DMD="" + else + AC_MSG_RESULT(yes) + fi + + ax_dmd="$success" + + # Test whether OPTLINK is used by trying if DMD accepts -L/? without + # erroring out. + if test "$success" == "yes" ; then + AC_MSG_CHECKING(whether DMD uses OPTLINK) + echo "Running \”$DMD -L/? configtest_ax_dmd.d\"" >&AS_MESSAGE_LOG_FD + if $DMD -L/? configtest_ax_dmd.d >&AS_MESSAGE_LOG_FD 2>&1 ; then + AC_MSG_RESULT(yes) + dmd_optlink="yes" + + # This actually produces double slashes in the final configure + # output, but at least it works. + dmd_of_dirsep="\\\\" + else + AC_MSG_RESULT(no) + dmd_optlink="no" + dmd_of_dirsep="/" + fi + fi + + rm -f configtest_ax_dmd* + ]) + + +AC_DEFUN([AX_CHECK_D_MODULE], + [ + AC_MSG_CHECKING(for D module [$1]) + + echo "import $1; void main() {}" > configtest_ax_dmd.d + + echo "Running \"$DMD configtest_ax_dmd.d\"" >&AS_MESSAGE_LOG_FD + if $DMD -c configtest_ax_dmd.d >&AS_MESSAGE_LOG_FD 2>&1 ; then + AC_MSG_RESULT(yes) + success=yes + else + AC_MSG_RESULT(no) + success=no + fi + + rm -f configtest_ax_dmd* + ]) diff --git a/aclocal/ax_javac_and_java.m4 b/aclocal/ax_javac_and_java.m4 new file mode 100644 index 0000000..0203960 --- /dev/null +++ b/aclocal/ax_javac_and_java.m4 @@ -0,0 +1,129 @@ +dnl @synopsis AX_JAVAC_AND_JAVA +dnl @synopsis AX_CHECK_JAVA_CLASS(CLASSNAME) +dnl +dnl Test for the presence of a JDK, and (optionally) specific classes. +dnl +dnl If "JAVA" is defined in the environment, that will be the only +dnl java command tested. Otherwise, a hard-coded list will be used. +dnl Similarly for "JAVAC". +dnl +dnl AX_JAVAC_AND_JAVA does not currently support testing for a particular +dnl Java version, testing for only one of "java" and "javac", or +dnl compiling or running user-provided Java code. +dnl +dnl After AX_JAVAC_AND_JAVA runs, the shell variables "success" and +dnl "ax_javac_and_java" are set to "yes" or "no", and "JAVAC" and +dnl "JAVA" are set to the appropriate commands. +dnl +dnl AX_CHECK_JAVA_CLASS must be run after AX_JAVAC_AND_JAVA. +dnl It tests for the presence of a class based on a fully-qualified name. +dnl It sets the shell variable "success" to "yes" or "no". +dnl +dnl @category Java +dnl @version 2009-02-09 +dnl @license AllPermissive +dnl +dnl Copyright (C) 2009 David Reiss +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. + + +AC_DEFUN([AX_JAVAC_AND_JAVA], + [ + + dnl Hard-coded default commands to test. + JAVAC_PROGS="javac,jikes,gcj -C" + JAVA_PROGS="java,kaffe" + + dnl Allow the user to specify an alternative. + if test -n "$JAVAC" ; then + JAVAC_PROGS="$JAVAC" + fi + if test -n "$JAVA" ; then + JAVA_PROGS="$JAVA" + fi + + AC_MSG_CHECKING(for javac and java) + + echo "public class configtest_ax_javac_and_java { public static void main(String args@<:@@:>@) { } }" > configtest_ax_javac_and_java.java + success=no + oIFS="$IFS" + + IFS="," + for JAVAC in $JAVAC_PROGS ; do + IFS="$oIFS" + + echo "Running \"$JAVAC configtest_ax_javac_and_java.java\"" >&AS_MESSAGE_LOG_FD + if $JAVAC configtest_ax_javac_and_java.java >&AS_MESSAGE_LOG_FD 2>&1 ; then + + # prevent $JAVA VM issues with UTF-8 path names (THRIFT-3271) + oLC_ALL="$LC_ALL" + LC_ALL="" + + IFS="," + for JAVA in $JAVA_PROGS ; do + IFS="$oIFS" + + echo "Running \"$JAVA configtest_ax_javac_and_java\"" >&AS_MESSAGE_LOG_FD + if $JAVA configtest_ax_javac_and_java >&AS_MESSAGE_LOG_FD 2>&1 ; then + success=yes + break 2 + fi + + done + + # restore LC_ALL + LC_ALL="$oLC_ALL" + oLC_ALL="" + + fi + + done + + rm -f configtest_ax_javac_and_java.java configtest_ax_javac_and_java.class + + if test "$success" != "yes" ; then + AC_MSG_RESULT(no) + JAVAC="" + JAVA="" + else + AC_MSG_RESULT(yes) + fi + + ax_javac_and_java="$success" + + ]) + + +AC_DEFUN([AX_CHECK_JAVA_CLASS], + [ + AC_MSG_CHECKING(for Java class [$1]) + + echo "import $1; public class configtest_ax_javac_and_java { public static void main(String args@<:@@:>@) { } }" > configtest_ax_javac_and_java.java + + echo "Running \"$JAVAC configtest_ax_javac_and_java.java\"" >&AS_MESSAGE_LOG_FD + if $JAVAC configtest_ax_javac_and_java.java >&AS_MESSAGE_LOG_FD 2>&1 ; then + AC_MSG_RESULT(yes) + success=yes + else + AC_MSG_RESULT(no) + success=no + fi + + rm -f configtest_ax_javac_and_java.java configtest_ax_javac_and_java.class + ]) + + +AC_DEFUN([AX_CHECK_ANT_VERSION], + [ + AC_MSG_CHECKING(for ant version > $2) + ANT_VALID=`expr "x$(printf "$2\n$($1 -version 2>/dev/null | sed -n 's/.*version \(@<:@0-9\.@:>@*\).*/\1/p')" | sort -t '.' -k 1,1 -k 2,2 -k 3,3 -g | sed -n 1p)" = "x$2"` + if test "x$ANT_VALID" = "x1" ; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + ANT="" + fi + ]) + diff --git a/aclocal/ax_lib_event.m4 b/aclocal/ax_lib_event.m4 new file mode 100644 index 0000000..d4dcdc9 --- /dev/null +++ b/aclocal/ax_lib_event.m4 @@ -0,0 +1,194 @@ +dnl @synopsis AX_LIB_EVENT([MINIMUM-VERSION]) +dnl +dnl Test for the libevent library of a particular version (or newer). +dnl +dnl If no path to the installed libevent is given, the macro will first try +dnl using no -I or -L flags, then searches under /usr, /usr/local, /opt, +dnl and /opt/libevent. +dnl If these all fail, it will try the $LIBEVENT_ROOT environment variable. +dnl +dnl This macro requires that #include works and defines u_char. +dnl +dnl This macro calls: +dnl AC_SUBST(LIBEVENT_CPPFLAGS) +dnl AC_SUBST(LIBEVENT_LDFLAGS) +dnl AC_SUBST(LIBEVENT_LIBS) +dnl +dnl And (if libevent is found): +dnl AC_DEFINE(HAVE_LIBEVENT) +dnl +dnl It also leaves the shell variables "success" and "ax_have_libevent" +dnl set to "yes" or "no". +dnl +dnl NOTE: This macro does not currently work for cross-compiling, +dnl but it can be easily modified to allow it. (grep "cross"). +dnl +dnl @category InstalledPackages +dnl @category C +dnl @version 2007-09-12 +dnl @license AllPermissive +dnl +dnl Copyright (C) 2009 David Reiss +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. + +dnl Input: ax_libevent_path, WANT_LIBEVENT_VERSION +dnl Output: success=yes/no +AC_DEFUN([AX_LIB_EVENT_DO_CHECK], + [ + # Save our flags. + CPPFLAGS_SAVED="$CPPFLAGS" + LDFLAGS_SAVED="$LDFLAGS" + LIBS_SAVED="$LIBS" + LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH" + + # Set our flags if we are checking a specific directory. + if test -n "$ax_libevent_path" ; then + LIBEVENT_CPPFLAGS="-I$ax_libevent_path/include" + LIBEVENT_LDFLAGS="-L$ax_libevent_path/lib" + LD_LIBRARY_PATH="$ax_libevent_path/lib:$LD_LIBRARY_PATH" + else + LIBEVENT_CPPFLAGS="" + LIBEVENT_LDFLAGS="" + fi + + # Required flag for libevent. + LIBEVENT_LIBS="-levent" + + # Prepare the environment for compilation. + CPPFLAGS="$CPPFLAGS $LIBEVENT_CPPFLAGS" + LDFLAGS="$LDFLAGS $LIBEVENT_LDFLAGS" + LIBS="$LIBS $LIBEVENT_LIBS" + export CPPFLAGS + export LDFLAGS + export LIBS + export LD_LIBRARY_PATH + + success=no + + # Compile, link, and run the program. This checks: + # - event.h is available for including. + # - event_get_version() is available for linking. + # - The event version string is lexicographically greater + # than the required version. + AC_LANG_PUSH([C]) + dnl This can be changed to AC_LINK_IFELSE if you are cross-compiling, + dnl but then the version cannot be checked. + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + ]], [[ + const char* lib_version = event_get_version(); + const char* wnt_version = "$WANT_LIBEVENT_VERSION"; + int lib_digits; + int wnt_digits; + for (;;) { + /* If we reached the end of the want version. We have it. */ + if (*wnt_version == '\0' || *wnt_version == '-') { + return 0; + } + /* If the want version continues but the lib version does not, */ + /* we are missing a letter. We don't have it. */ + if (*lib_version == '\0' || *lib_version == '-') { + return 1; + } + /* In the 1.4 version numbering style, if there are more digits */ + /* in one version than the other, that one is higher. */ + for (lib_digits = 0; + lib_version[lib_digits] >= '0' && + lib_version[lib_digits] <= '9'; + lib_digits++) + ; + for (wnt_digits = 0; + wnt_version[wnt_digits] >= '0' && + wnt_version[wnt_digits] <= '9'; + wnt_digits++) + ; + if (lib_digits > wnt_digits) { + return 0; + } + if (lib_digits < wnt_digits) { + return 1; + } + /* If we have greater than what we want. We have it. */ + if (*lib_version > *wnt_version) { + return 0; + } + /* If we have less, we don't. */ + if (*lib_version < *wnt_version) { + return 1; + } + lib_version++; + wnt_version++; + } + return 0; + ]])], [ + success=yes + ]) + AC_LANG_POP([C]) + + # Restore flags. + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + LIBS="$LIBS_SAVED" + LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED" + ]) + + +AC_DEFUN([AX_LIB_EVENT], + [ + + dnl Allow search path to be overridden on the command line. + AC_ARG_WITH([libevent], + AS_HELP_STRING([--with-libevent@<:@=DIR@:>@], [use libevent [default=yes]. Optionally specify the root prefix dir where libevent is installed]), + [ + if test "x$withval" = "xno"; then + want_libevent="no" + elif test "x$withval" = "xyes"; then + want_libevent="yes" + ax_libevent_path="" + else + want_libevent="yes" + ax_libevent_path="$withval" + fi + ], + [ want_libevent="yes" ; ax_libevent_path="" ]) + + + if test "$want_libevent" = "yes"; then + WANT_LIBEVENT_VERSION=ifelse([$1], ,1.2,$1) + + AC_MSG_CHECKING(for libevent >= $WANT_LIBEVENT_VERSION) + + # Run tests. + if test -n "$ax_libevent_path"; then + AX_LIB_EVENT_DO_CHECK + else + for ax_libevent_path in "" $lt_sysroot/usr $lt_sysroot/usr/local $lt_sysroot/opt $lt_sysroot/opt/local $lt_sysroot/opt/libevent "$LIBEVENT_ROOT" ; do + AX_LIB_EVENT_DO_CHECK + if test "$success" = "yes"; then + break; + fi + done + fi + + if test "$success" != "yes" ; then + AC_MSG_RESULT(no) + LIBEVENT_CPPFLAGS="" + LIBEVENT_LDFLAGS="" + LIBEVENT_LIBS="" + else + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_LIBEVENT,,[define if libevent is available]) + ax_have_libevent_[]m4_translit([$1], [.], [_])="yes" + fi + + ax_have_libevent="$success" + + AC_SUBST(LIBEVENT_CPPFLAGS) + AC_SUBST(LIBEVENT_LDFLAGS) + AC_SUBST(LIBEVENT_LIBS) + fi + + ]) diff --git a/aclocal/ax_lib_zlib.m4 b/aclocal/ax_lib_zlib.m4 new file mode 100644 index 0000000..bdb9e11 --- /dev/null +++ b/aclocal/ax_lib_zlib.m4 @@ -0,0 +1,173 @@ +dnl @synopsis AX_LIB_ZLIB([MINIMUM-VERSION]) +dnl +dnl Test for the libz library of a particular version (or newer). +dnl +dnl If no path to the installed zlib is given, the macro will first try +dnl using no -I or -L flags, then searches under /usr, /usr/local, /opt, +dnl and /opt/zlib. +dnl If these all fail, it will try the $ZLIB_ROOT environment variable. +dnl +dnl This macro calls: +dnl AC_SUBST(ZLIB_CPPFLAGS) +dnl AC_SUBST(ZLIB_LDFLAGS) +dnl AC_SUBST(ZLIB_LIBS) +dnl +dnl And (if zlib is found): +dnl AC_DEFINE(HAVE_ZLIB) +dnl +dnl It also leaves the shell variables "success" and "ax_have_zlib" +dnl set to "yes" or "no". +dnl +dnl NOTE: This macro does not currently work for cross-compiling, +dnl but it can be easily modified to allow it. (grep "cross"). +dnl +dnl @category InstalledPackages +dnl @category C +dnl @version 2007-09-12 +dnl @license AllPermissive +dnl +dnl Copyright (C) 2009 David Reiss +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. + +dnl Input: ax_zlib_path, WANT_ZLIB_VERSION +dnl Output: success=yes/no +AC_DEFUN([AX_LIB_ZLIB_DO_CHECK], + [ + # Save our flags. + CPPFLAGS_SAVED="$CPPFLAGS" + LDFLAGS_SAVED="$LDFLAGS" + LIBS_SAVED="$LIBS" + LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH" + + # Set our flags if we are checking a specific directory. + if test -n "$ax_zlib_path" ; then + ZLIB_CPPFLAGS="-I$ax_zlib_path/include" + ZLIB_LDFLAGS="-L$ax_zlib_path/lib" + LD_LIBRARY_PATH="$ax_zlib_path/lib:$LD_LIBRARY_PATH" + else + ZLIB_CPPFLAGS="" + ZLIB_LDFLAGS="" + fi + + # Required flag for zlib. + ZLIB_LIBS="-lz" + + # Prepare the environment for compilation. + CPPFLAGS="$CPPFLAGS $ZLIB_CPPFLAGS" + LDFLAGS="$LDFLAGS $ZLIB_LDFLAGS" + LIBS="$LIBS $ZLIB_LIBS" + export CPPFLAGS + export LDFLAGS + export LIBS + export LD_LIBRARY_PATH + + success=no + + # Compile, link, and run the program. This checks: + # - zlib.h is available for including. + # - zlibVersion() is available for linking. + # - ZLIB_VERNUM is greater than or equal to the desired version. + # - ZLIB_VERSION (defined in zlib.h) matches zlibVersion() + # (defined in the library). + AC_LANG_PUSH([C]) + dnl This can be changed to AC_LINK_IFELSE if you are cross-compiling. + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + #if ZLIB_VERNUM >= 0x$WANT_ZLIB_VERSION + #else + # error zlib is too old + #endif + ]], [[ + const char* lib_version = zlibVersion(); + const char* hdr_version = ZLIB_VERSION; + for (;;) { + if (*lib_version != *hdr_version) { + /* If this happens, your zlib header doesn't match your zlib */ + /* library. That is really bad. */ + return 1; + } + if (*lib_version == '\0') { + break; + } + lib_version++; + hdr_version++; + } + return 0; + ]])], [ + success=yes + ]) + AC_LANG_POP([C]) + + # Restore flags. + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + LIBS="$LIBS_SAVED" + LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED" + ]) + + +AC_DEFUN([AX_LIB_ZLIB], + [ + + dnl Allow search path to be overridden on the command line. + AC_ARG_WITH([zlib], + AS_HELP_STRING([--with-zlib@<:@=DIR@:>@], [use zlib (default is yes) - it is possible to specify an alternate root directory for zlib]), + [ + if test "x$withval" = "xno"; then + want_zlib="no" + elif test "x$withval" = "xyes"; then + want_zlib="yes" + ax_zlib_path="" + else + want_zlib="yes" + ax_zlib_path="$withval" + fi + ], + [want_zlib="yes" ; ax_zlib_path="" ]) + + + if test "$want_zlib" = "yes"; then + # Parse out the version. + zlib_version_req=ifelse([$1], ,1.2.3,$1) + zlib_version_req_major=`expr $zlib_version_req : '\([[0-9]]*\)'` + zlib_version_req_minor=`expr $zlib_version_req : '[[0-9]]*\.\([[0-9]]*\)'` + zlib_version_req_patch=`expr $zlib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + if test -z "$zlib_version_req_patch" ; then + zlib_version_req_patch="0" + fi + WANT_ZLIB_VERSION=`expr $zlib_version_req_major \* 1000 \+ $zlib_version_req_minor \* 100 \+ $zlib_version_req_patch \* 10` + + AC_MSG_CHECKING(for zlib >= $zlib_version_req) + + # Run tests. + if test -n "$ax_zlib_path"; then + AX_LIB_ZLIB_DO_CHECK + else + for ax_zlib_path in "" /usr /usr/local /opt /opt/zlib "$ZLIB_ROOT" ; do + AX_LIB_ZLIB_DO_CHECK + if test "$success" = "yes"; then + break; + fi + done + fi + + if test "$success" != "yes" ; then + AC_MSG_RESULT(no) + ZLIB_CPPFLAGS="" + ZLIB_LDFLAGS="" + ZLIB_LIBS="" + else + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_ZLIB,,[define if zlib is available]) + fi + + ax_have_zlib="$success" + + AC_SUBST(ZLIB_CPPFLAGS) + AC_SUBST(ZLIB_LDFLAGS) + AC_SUBST(ZLIB_LIBS) + fi + + ]) diff --git a/aclocal/ax_lua.m4 b/aclocal/ax_lua.m4 new file mode 100644 index 0000000..5920167 --- /dev/null +++ b/aclocal/ax_lua.m4 @@ -0,0 +1,664 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_lua.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] +# AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] +# AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] +# AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] +# +# DESCRIPTION +# +# Detect a Lua interpreter, optionally specifying a minimum and maximum +# version number. Set up important Lua paths, such as the directories in +# which to install scripts and modules (shared libraries). +# +# Also detect Lua headers and libraries. The Lua version contained in the +# header is checked to match the Lua interpreter version exactly. When +# searching for Lua libraries, the version number is used as a suffix. +# This is done with the goal of supporting multiple Lua installs (5.1, +# 5.2, and 5.3 side-by-side). +# +# A note on compatibility with previous versions: This file has been +# mostly rewritten for serial 18. Most developers should be able to use +# these macros without needing to modify configure.ac. Care has been taken +# to preserve each macro's behavior, but there are some differences: +# +# 1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as +# AX_PROG_LUA with no arguments. +# +# 2) AX_LUA_HEADERS now checks that the version number defined in lua.h +# matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore +# unnecessary, so it is deprecated and does not expand to anything. +# +# 3) The configure flag --with-lua-suffix no longer exists; the user +# should instead specify the LUA precious variable on the command line. +# See the AX_PROG_LUA description for details. +# +# Please read the macro descriptions below for more information. +# +# This file was inspired by Andrew Dalke's and James Henstridge's +# python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4 +# (serial 17). Basically, this file is a mash-up of those two files. I +# like to think it combines the best of the two! +# +# AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua +# paths. Adds precious variable LUA, which may contain the path of the Lua +# interpreter. If LUA is blank, the user's path is searched for an +# suitable interpreter. +# +# If MINIMUM-VERSION is supplied, then only Lua interpreters with a +# version number greater or equal to MINIMUM-VERSION will be accepted. If +# TOO-BIG-VERSION is also supplied, then only Lua interpreters with a +# version number greater or equal to MINIMUM-VERSION and less than +# TOO-BIG-VERSION will be accepted. +# +# The Lua version number, LUA_VERSION, is found from the interpreter, and +# substituted. LUA_PLATFORM is also found, but not currently supported (no +# standard representation). +# +# Finally, the macro finds four paths: +# +# luadir Directory to install Lua scripts. +# pkgluadir $luadir/$PACKAGE +# luaexecdir Directory to install Lua modules. +# pkgluaexecdir $luaexecdir/$PACKAGE +# +# These paths are found based on $prefix, $exec_prefix, Lua's +# package.path, and package.cpath. The first path of package.path +# beginning with $prefix is selected as luadir. The first path of +# package.cpath beginning with $exec_prefix is used as luaexecdir. This +# should work on all reasonable Lua installations. If a path cannot be +# determined, a default path is used. Of course, the user can override +# these later when invoking make. +# +# luadir Default: $prefix/share/lua/$LUA_VERSION +# luaexecdir Default: $exec_prefix/lib/lua/$LUA_VERSION +# +# These directories can be used by Automake as install destinations. The +# variable name minus 'dir' needs to be used as a prefix to the +# appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES. +# +# If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is +# performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT- +# FOUND is blank, then it will default to printing an error. To prevent +# the default behavior, give ':' as an action. +# +# AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be +# expanded before this macro. Adds precious variable LUA_INCLUDE, which +# may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If +# LUA_INCLUDE is blank, then this macro will attempt to find suitable +# flags. +# +# LUA_INCLUDE can be used by Automake to compile Lua modules or +# executables with embedded interpreters. The *_CPPFLAGS variables should +# be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE). +# +# This macro searches for the header lua.h (and others). The search is +# performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE. +# If the search is unsuccessful, then some common directories are tried. +# If the headers are then found, then LUA_INCLUDE is set accordingly. +# +# The paths automatically searched are: +# +# * /usr/include/luaX.Y +# * /usr/include/lua/X.Y +# * /usr/include/luaXY +# * /usr/local/include/luaX.Y +# * /usr/local/include/lua-X.Y +# * /usr/local/include/lua/X.Y +# * /usr/local/include/luaXY +# +# (Where X.Y is the Lua version number, e.g. 5.1.) +# +# The Lua version number found in the headers is always checked to match +# the Lua interpreter's version number. Lua headers with mismatched +# version numbers are not accepted. +# +# If headers are found, then ACTION-IF-FOUND is performed, otherwise +# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then +# it will default to printing an error. To prevent the default behavior, +# set the action to ':'. +# +# AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be +# expanded before this macro. Adds precious variable LUA_LIB, which may +# contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank, +# then this macro will attempt to find suitable flags. +# +# LUA_LIB can be used by Automake to link Lua modules or executables with +# embedded interpreters. The *_LIBADD and *_LDADD variables should be used +# for this purpose, e.g. mymod_LIBADD = $(LUA_LIB). +# +# This macro searches for the Lua library. More technically, it searches +# for a library containing the function lua_load. The search is performed +# with a combination of LIBS, LIBRARY_PATH, and LUA_LIB. +# +# If the search determines that some linker flags are missing, then those +# flags will be added to LUA_LIB. +# +# If libraries are found, then ACTION-IF-FOUND is performed, otherwise +# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then +# it will default to printing an error. To prevent the default behavior, +# set the action to ':'. +# +# AX_LUA_READLINE: Search for readline headers and libraries. Requires the +# AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the +# Autoconf Archive. +# +# If a readline compatible library is found, then ACTION-IF-FOUND is +# performed, otherwise ACTION-IF-NOT-FOUND is performed. +# +# LICENSE +# +# Copyright (c) 2015 Reuben Thomas +# Copyright (c) 2014 Tim Perkins +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 40 + +dnl ========================================================================= +dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION], +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ========================================================================= +AC_DEFUN([AX_PROG_LUA], +[ + dnl Check for required tools. + AC_REQUIRE([AC_PROG_GREP]) + AC_REQUIRE([AC_PROG_SED]) + + dnl Make LUA a precious variable. + AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1]) + + dnl Find a Lua interpreter. + m4_define_default([_AX_LUA_INTERPRETER_LIST], + [lua lua5.3 lua53 lua5.2 lua52 lua5.1 lua51 lua50]) + + m4_if([$1], [], + [ dnl No version check is needed. Find any Lua interpreter. + AS_IF([test "x$LUA" = 'x'], + [AC_PATH_PROGS([LUA], [_AX_LUA_INTERPRETER_LIST], [:])]) + ax_display_LUA='lua' + + AS_IF([test "x$LUA" != 'x:'], + [ dnl At least check if this is a Lua interpreter. + AC_MSG_CHECKING([if $LUA is a Lua interpreter]) + _AX_LUA_CHK_IS_INTRP([$LUA], + [AC_MSG_RESULT([yes])], + [ AC_MSG_RESULT([no]) + AC_MSG_ERROR([not a Lua interpreter]) + ]) + ]) + ], + [ dnl A version check is needed. + AS_IF([test "x$LUA" != 'x'], + [ dnl Check if this is a Lua interpreter. + AC_MSG_CHECKING([if $LUA is a Lua interpreter]) + _AX_LUA_CHK_IS_INTRP([$LUA], + [AC_MSG_RESULT([yes])], + [ AC_MSG_RESULT([no]) + AC_MSG_ERROR([not a Lua interpreter]) + ]) + dnl Check the version. + m4_if([$2], [], + [_ax_check_text="whether $LUA version >= $1"], + [_ax_check_text="whether $LUA version >= $1, < $2"]) + AC_MSG_CHECKING([$_ax_check_text]) + _AX_LUA_CHK_VER([$LUA], [$1], [$2], + [AC_MSG_RESULT([yes])], + [ AC_MSG_RESULT([no]) + AC_MSG_ERROR([version is out of range for specified LUA])]) + ax_display_LUA=$LUA + ], + [ dnl Try each interpreter until we find one that satisfies VERSION. + m4_if([$2], [], + [_ax_check_text="for a Lua interpreter with version >= $1"], + [_ax_check_text="for a Lua interpreter with version >= $1, < $2"]) + AC_CACHE_CHECK([$_ax_check_text], + [ax_cv_pathless_LUA], + [ for ax_cv_pathless_LUA in _AX_LUA_INTERPRETER_LIST none; do + test "x$ax_cv_pathless_LUA" = 'xnone' && break + _AX_LUA_CHK_IS_INTRP([$ax_cv_pathless_LUA], [], [continue]) + _AX_LUA_CHK_VER([$ax_cv_pathless_LUA], [$1], [$2], [break]) + done + ]) + dnl Set $LUA to the absolute path of $ax_cv_pathless_LUA. + AS_IF([test "x$ax_cv_pathless_LUA" = 'xnone'], + [LUA=':'], + [AC_PATH_PROG([LUA], [$ax_cv_pathless_LUA])]) + ax_display_LUA=$ax_cv_pathless_LUA + ]) + ]) + + AS_IF([test "x$LUA" = 'x:'], + [ dnl Run any user-specified action, or abort. + m4_default([$4], [AC_MSG_ERROR([cannot find suitable Lua interpreter])]) + ], + [ dnl Query Lua for its version number. + AC_CACHE_CHECK([for $ax_display_LUA version], + [ax_cv_lua_version], + [ dnl Get the interpreter version in X.Y format. This should work for + dnl interpreters version 5.0 and beyond. + ax_cv_lua_version=[`$LUA -e ' + -- return a version number in X.Y format + local _, _, ver = string.find(_VERSION, "^Lua (%d+%.%d+)") + print(ver)'`] + ]) + AS_IF([test "x$ax_cv_lua_version" = 'x'], + [AC_MSG_ERROR([invalid Lua version number])]) + AC_SUBST([LUA_VERSION], [$ax_cv_lua_version]) + AC_SUBST([LUA_SHORT_VERSION], [`echo "$LUA_VERSION" | $SED 's|\.||'`]) + + dnl The following check is not supported: + dnl At times (like when building shared libraries) you may want to know + dnl which OS platform Lua thinks this is. + AC_CACHE_CHECK([for $ax_display_LUA platform], + [ax_cv_lua_platform], + [ax_cv_lua_platform=[`$LUA -e 'print("unknown")'`]]) + AC_SUBST([LUA_PLATFORM], [$ax_cv_lua_platform]) + + dnl Use the values of $prefix and $exec_prefix for the corresponding + dnl values of LUA_PREFIX and LUA_EXEC_PREFIX. These are made distinct + dnl variables so they can be overridden if need be. However, the general + dnl consensus is that you shouldn't need this ability. + AC_SUBST([LUA_PREFIX], ['${prefix}']) + AC_SUBST([LUA_EXEC_PREFIX], ['${exec_prefix}']) + + dnl Lua provides no way to query the script directory, and instead + dnl provides LUA_PATH. However, we should be able to make a safe educated + dnl guess. If the built-in search path contains a directory which is + dnl prefixed by $prefix, then we can store scripts there. The first + dnl matching path will be used. + AC_CACHE_CHECK([for $ax_display_LUA script directory], + [ax_cv_lua_luadir], + [ AS_IF([test "x$prefix" = 'xNONE'], + [ax_lua_prefix=$ac_default_prefix], + [ax_lua_prefix=$prefix]) + + dnl Initialize to the default path. + ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION" + + dnl Try to find a path with the prefix. + _AX_LUA_FND_PRFX_PTH([$LUA], [$ax_lua_prefix], [script]) + AS_IF([test "x$ax_lua_prefixed_path" != 'x'], + [ dnl Fix the prefix. + _ax_strip_prefix=`echo "$ax_lua_prefix" | $SED 's|.|.|g'` + ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \ + $SED "s|^$_ax_strip_prefix|$LUA_PREFIX|"` + ]) + ]) + AC_SUBST([luadir], [$ax_cv_lua_luadir]) + AC_SUBST([pkgluadir], [\${luadir}/$PACKAGE]) + + dnl Lua provides no way to query the module directory, and instead + dnl provides LUA_PATH. However, we should be able to make a safe educated + dnl guess. If the built-in search path contains a directory which is + dnl prefixed by $exec_prefix, then we can store modules there. The first + dnl matching path will be used. + AC_CACHE_CHECK([for $ax_display_LUA module directory], + [ax_cv_lua_luaexecdir], + [ AS_IF([test "x$exec_prefix" = 'xNONE'], + [ax_lua_exec_prefix=$ax_lua_prefix], + [ax_lua_exec_prefix=$exec_prefix]) + + dnl Initialize to the default path. + ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION" + + dnl Try to find a path with the prefix. + _AX_LUA_FND_PRFX_PTH([$LUA], + [$ax_lua_exec_prefix], [module]) + AS_IF([test "x$ax_lua_prefixed_path" != 'x'], + [ dnl Fix the prefix. + _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | $SED 's|.|.|g'` + ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \ + $SED "s|^$_ax_strip_prefix|$LUA_EXEC_PREFIX|"` + ]) + ]) + AC_SUBST([luaexecdir], [$ax_cv_lua_luaexecdir]) + AC_SUBST([pkgluaexecdir], [\${luaexecdir}/$PACKAGE]) + + dnl Run any user specified action. + $3 + ]) +]) + +dnl AX_WITH_LUA is now the same thing as AX_PROG_LUA. +AC_DEFUN([AX_WITH_LUA], +[ + AC_MSG_WARN([[$0 is deprecated, please use AX_PROG_LUA instead]]) + AX_PROG_LUA +]) + + +dnl ========================================================================= +dnl _AX_LUA_CHK_IS_INTRP(PROG, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +dnl ========================================================================= +AC_DEFUN([_AX_LUA_CHK_IS_INTRP], +[ + dnl A minimal Lua factorial to prove this is an interpreter. This should work + dnl for Lua interpreters version 5.0 and beyond. + _ax_lua_factorial=[`$1 2>/dev/null -e ' + -- a simple factorial + function fact (n) + if n == 0 then + return 1 + else + return n * fact(n-1) + end + end + print("fact(5) is " .. fact(5))'`] + AS_IF([test "$_ax_lua_factorial" = 'fact(5) is 120'], + [$2], [$3]) +]) + + +dnl ========================================================================= +dnl _AX_LUA_CHK_VER(PROG, MINIMUM-VERSION, [TOO-BIG-VERSION], +dnl [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +dnl ========================================================================= +AC_DEFUN([_AX_LUA_CHK_VER], +[ + dnl Check that the Lua version is within the bounds. Only the major and minor + dnl version numbers are considered. This should work for Lua interpreters + dnl version 5.0 and beyond. + _ax_lua_good_version=[`$1 -e ' + -- a script to compare versions + function verstr2num(verstr) + local _, _, majorver, minorver = string.find(verstr, "^(%d+)%.(%d+)") + if majorver and minorver then + return tonumber(majorver) * 100 + tonumber(minorver) + end + end + local minver = verstr2num("$2") + local _, _, trimver = string.find(_VERSION, "^Lua (.*)") + local ver = verstr2num(trimver) + local maxver = verstr2num("$3") or 1e9 + if minver <= ver and ver < maxver then + print("yes") + else + print("no") + end'`] + AS_IF([test "x$_ax_lua_good_version" = "xyes"], + [$4], [$5]) +]) + + +dnl ========================================================================= +dnl _AX_LUA_FND_PRFX_PTH(PROG, PREFIX, SCRIPT-OR-MODULE-DIR) +dnl ========================================================================= +AC_DEFUN([_AX_LUA_FND_PRFX_PTH], +[ + dnl Get the script or module directory by querying the Lua interpreter, + dnl filtering on the given prefix, and selecting the shallowest path. If no + dnl path is found matching the prefix, the result will be an empty string. + dnl The third argument determines the type of search, it can be 'script' or + dnl 'module'. Supplying 'script' will perform the search with package.path + dnl and LUA_PATH, and supplying 'module' will search with package.cpath and + dnl LUA_CPATH. This is done for compatibility with Lua 5.0. + + ax_lua_prefixed_path=[`$1 -e ' + -- get the path based on search type + local searchtype = "$3" + local paths = "" + if searchtype == "script" then + paths = (package and package.path) or LUA_PATH + elseif searchtype == "module" then + paths = (package and package.cpath) or LUA_CPATH + end + -- search for the prefix + local prefix = "'$2'" + local minpath = "" + local mindepth = 1e9 + string.gsub(paths, "(@<:@^;@:>@+)", + function (path) + path = string.gsub(path, "%?.*$", "") + path = string.gsub(path, "/@<:@^/@:>@*$", "") + if string.find(path, prefix) then + local depth = string.len(string.gsub(path, "@<:@^/@:>@", "")) + if depth < mindepth then + minpath = path + mindepth = depth + end + end + end) + print(minpath)'`] +]) + + +dnl ========================================================================= +dnl AX_LUA_HEADERS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ========================================================================= +AC_DEFUN([AX_LUA_HEADERS], +[ + dnl Check for LUA_VERSION. + AC_MSG_CHECKING([if LUA_VERSION is defined]) + AS_IF([test "x$LUA_VERSION" != 'x'], + [AC_MSG_RESULT([yes])], + [ AC_MSG_RESULT([no]) + AC_MSG_ERROR([cannot check Lua headers without knowing LUA_VERSION]) + ]) + + dnl Make LUA_INCLUDE a precious variable. + AC_ARG_VAR([LUA_INCLUDE], [The Lua includes, e.g. -I/usr/include/lua5.1]) + + dnl Some default directories to search. + LUA_SHORT_VERSION=`echo "$LUA_VERSION" | $SED 's|\.||'` + m4_define_default([_AX_LUA_INCLUDE_LIST], + [ /usr/include/lua$LUA_VERSION \ + /usr/include/lua-$LUA_VERSION \ + /usr/include/lua/$LUA_VERSION \ + /usr/include/lua$LUA_SHORT_VERSION \ + /usr/local/include/lua$LUA_VERSION \ + /usr/local/include/lua-$LUA_VERSION \ + /usr/local/include/lua/$LUA_VERSION \ + /usr/local/include/lua$LUA_SHORT_VERSION \ + ]) + + dnl Try to find the headers. + _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" + AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h]) + CPPFLAGS=$_ax_lua_saved_cppflags + + dnl Try some other directories if LUA_INCLUDE was not set. + AS_IF([test "x$LUA_INCLUDE" = 'x' && + test "x$ac_cv_header_lua_h" != 'xyes'], + [ dnl Try some common include paths. + for _ax_include_path in _AX_LUA_INCLUDE_LIST; do + test ! -d "$_ax_include_path" && continue + + AC_MSG_CHECKING([for Lua headers in]) + AC_MSG_RESULT([$_ax_include_path]) + + AS_UNSET([ac_cv_header_lua_h]) + AS_UNSET([ac_cv_header_lualib_h]) + AS_UNSET([ac_cv_header_lauxlib_h]) + AS_UNSET([ac_cv_header_luaconf_h]) + + _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS -I$_ax_include_path" + AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h]) + CPPFLAGS=$_ax_lua_saved_cppflags + + AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'], + [ LUA_INCLUDE="-I$_ax_include_path" + break + ]) + done + ]) + + AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'], + [ dnl Make a program to print LUA_VERSION defined in the header. + dnl TODO It would be really nice if we could do this without compiling a + dnl program, then it would work when cross compiling. But I'm not sure how + dnl to do this reliably. For now, assume versions match when cross compiling. + + AS_IF([test "x$cross_compiling" != 'xyes'], + [ AC_CACHE_CHECK([for Lua header version], + [ax_cv_lua_header_version], + [ _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" + AC_RUN_IFELSE( + [ AC_LANG_SOURCE([[ +#include +#include +#include +int main(int argc, char ** argv) +{ + if(argc > 1) printf("%s", LUA_VERSION); + exit(EXIT_SUCCESS); +} +]]) + ], + [ ax_cv_lua_header_version=`./conftest$EXEEXT p | \ + $SED -n "s|^Lua \(@<:@0-9@:>@\{1,\}\.@<:@0-9@:>@\{1,\}\).\{0,\}|\1|p"` + ], + [ax_cv_lua_header_version='unknown']) + CPPFLAGS=$_ax_lua_saved_cppflags + ]) + + dnl Compare this to the previously found LUA_VERSION. + AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION]) + AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"], + [ AC_MSG_RESULT([yes]) + ax_header_version_match='yes' + ], + [ AC_MSG_RESULT([no]) + ax_header_version_match='no' + ]) + ], + [ AC_MSG_WARN([cross compiling so assuming header version number matches]) + ax_header_version_match='yes' + ]) + ]) + + dnl Was LUA_INCLUDE specified? + AS_IF([test "x$ax_header_version_match" != 'xyes' && + test "x$LUA_INCLUDE" != 'x'], + [AC_MSG_ERROR([cannot find headers for specified LUA_INCLUDE])]) + + dnl Test the final result and run user code. + AS_IF([test "x$ax_header_version_match" = 'xyes'], [$1], + [m4_default([$2], [AC_MSG_ERROR([cannot find Lua includes])])]) +]) + +dnl AX_LUA_HEADERS_VERSION no longer exists, use AX_LUA_HEADERS. +AC_DEFUN([AX_LUA_HEADERS_VERSION], +[ + AC_MSG_WARN([[$0 is deprecated, please use AX_LUA_HEADERS instead]]) +]) + + +dnl ========================================================================= +dnl AX_LUA_LIBS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ========================================================================= +AC_DEFUN([AX_LUA_LIBS], +[ + dnl TODO Should this macro also check various -L flags? + + dnl Check for LUA_VERSION. + AC_MSG_CHECKING([if LUA_VERSION is defined]) + AS_IF([test "x$LUA_VERSION" != 'x'], + [AC_MSG_RESULT([yes])], + [ AC_MSG_RESULT([no]) + AC_MSG_ERROR([cannot check Lua libs without knowing LUA_VERSION]) + ]) + + dnl Make LUA_LIB a precious variable. + AC_ARG_VAR([LUA_LIB], [The Lua library, e.g. -llua5.1]) + + AS_IF([test "x$LUA_LIB" != 'x'], + [ dnl Check that LUA_LIBS works. + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + AC_SEARCH_LIBS([lua_load], [], + [_ax_found_lua_libs='yes'], + [_ax_found_lua_libs='no']) + LIBS=$_ax_lua_saved_libs + + dnl Check the result. + AS_IF([test "x$_ax_found_lua_libs" != 'xyes'], + [AC_MSG_ERROR([cannot find libs for specified LUA_LIB])]) + ], + [ dnl First search for extra libs. + _ax_lua_extra_libs='' + + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + AC_SEARCH_LIBS([exp], [m]) + AC_SEARCH_LIBS([dlopen], [dl]) + LIBS=$_ax_lua_saved_libs + + AS_IF([test "x$ac_cv_search_exp" != 'xno' && + test "x$ac_cv_search_exp" != 'xnone required'], + [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp"]) + + AS_IF([test "x$ac_cv_search_dlopen" != 'xno' && + test "x$ac_cv_search_dlopen" != 'xnone required'], + [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen"]) + + dnl Try to find the Lua libs. + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + AC_SEARCH_LIBS([lua_load], + [ lua$LUA_VERSION \ + lua$LUA_SHORT_VERSION \ + lua-$LUA_VERSION \ + lua-$LUA_SHORT_VERSION \ + lua \ + ], + [_ax_found_lua_libs='yes'], + [_ax_found_lua_libs='no'], + [$_ax_lua_extra_libs]) + LIBS=$_ax_lua_saved_libs + + AS_IF([test "x$ac_cv_search_lua_load" != 'xno' && + test "x$ac_cv_search_lua_load" != 'xnone required'], + [LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs"]) + ]) + + dnl Test the result and run user code. + AS_IF([test "x$_ax_found_lua_libs" = 'xyes'], [$1], + [m4_default([$2], [AC_MSG_ERROR([cannot find Lua libs])])]) +]) + + +dnl ========================================================================= +dnl AX_LUA_READLINE([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ========================================================================= +AC_DEFUN([AX_LUA_READLINE], +[ + AX_LIB_READLINE + AS_IF([test "x$ac_cv_header_readline_readline_h" != 'x' && + test "x$ac_cv_header_readline_history_h" != 'x'], + [ LUA_LIBS_CFLAGS="-DLUA_USE_READLINE $LUA_LIBS_CFLAGS" + $1 + ], + [$2]) +]) diff --git a/aclocal/ax_prog_dotnetcore_version.m4 b/aclocal/ax_prog_dotnetcore_version.m4 new file mode 100644 index 0000000..92c7495 --- /dev/null +++ b/aclocal/ax_prog_dotnetcore_version.m4 @@ -0,0 +1,61 @@ +# =============================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_prog_dotnetcore_version.html +# =============================================================================== +# +# SYNOPSIS +# +# AX_PROG_DOTNETCORE_VERSION([VERSION],[ACTION-IF-TRUE],[ACTION-IF-FALSE]) +# +# DESCRIPTION +# +# Makes sure that .NET Core supports the version indicated. If true the +# shell commands in ACTION-IF-TRUE are executed. If not the shell commands +# in ACTION-IF-FALSE are run. The $dotnetcore_version variable will be +# filled with the detected version. +# +# This macro uses the $DOTNETCORE variable to perform the check. If +# $DOTNETCORE is not set prior to calling this macro, the macro will fail. +# +# Example: +# +# AC_PATH_PROG([DOTNETCORE],[dotnet]) +# AC_PROG_DOTNETCORE_VERSION([1.0.2],[ ... ],[ ... ]) +# +# Searches for .NET Core, then checks if at least version 1.0.2 is +# present. +# +# LICENSE +# +# Copyright (c) 2016 Jens Geyer +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 2 + +AC_DEFUN([AX_PROG_DOTNETCORE_VERSION],[ + AC_REQUIRE([AC_PROG_SED]) + + AS_IF([test -n "$DOTNETCORE"],[ + ax_dotnetcore_version="$1" + + AC_MSG_CHECKING([for .NET Core version]) + dotnetcore_version=`$DOTNETCORE --version 2>&1 | $SED -e 's/\(@<:@0-9@:>@*\.@<:@0-9@:>@*\.@<:@0-9@:>@*\)\(.*\)/\1/'` + AC_MSG_RESULT($dotnetcore_version) + + AC_SUBST([DOTNETCORE_VERSION],[$dotnetcore_version]) + + AX_COMPARE_VERSION([$ax_dotnetcore_version],[le],[$dotnetcore_version],[ + : + $2 + ],[ + : + $3 + ]) + ],[ + AC_MSG_WARN([could not find .NET Core]) + $3 + ]) +]) diff --git a/aclocal/ax_prog_haxe_version.m4 b/aclocal/ax_prog_haxe_version.m4 new file mode 100644 index 0000000..fcacc67 --- /dev/null +++ b/aclocal/ax_prog_haxe_version.m4 @@ -0,0 +1,60 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_prog_haxe_version.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_HAXE_VERSION([VERSION],[ACTION-IF-TRUE],[ACTION-IF-FALSE]) +# +# DESCRIPTION +# +# Makes sure that haxe supports the version indicated. If true the shell +# commands in ACTION-IF-TRUE are executed. If not the shell commands in +# ACTION-IF-FALSE are run. The $HAXE_VERSION variable will be filled with +# the detected version. +# +# This macro uses the $HAXE variable to perform the check. If $HAXE is not +# set prior to calling this macro, the macro will fail. +# +# Example: +# +# AC_PATH_PROG([HAXE],[haxe]) +# AC_PROG_HAXE_VERSION([3.1.3],[ ... ],[ ... ]) +# +# Searches for Haxe, then checks if at least version 3.1.3 is present. +# +# LICENSE +# +# Copyright (c) 2015 Jens Geyer +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 2 + +AC_DEFUN([AX_PROG_HAXE_VERSION],[ + AC_REQUIRE([AC_PROG_SED]) + + AS_IF([test -n "$HAXE"],[ + ax_haxe_version="$1" + + AC_MSG_CHECKING([for haxe version]) + haxe_version=`$HAXE -version 2>&1 | $SED -e 's/^.* \( @<:@0-9@:>@*\.@<:@0-9@:>@*\.@<:@0-9@:>@*\) .*/\1/'` + AC_MSG_RESULT($haxe_version) + + AC_SUBST([HAXE_VERSION],[$haxe_version]) + + AX_COMPARE_VERSION([$ax_haxe_version],[le],[$haxe_version],[ + : + $2 + ],[ + : + $3 + ]) + ],[ + AC_MSG_WARN([could not find Haxe]) + $3 + ]) +]) diff --git a/aclocal/ax_prog_perl_modules.m4 b/aclocal/ax_prog_perl_modules.m4 new file mode 100644 index 0000000..70b3230 --- /dev/null +++ b/aclocal/ax_prog_perl_modules.m4 @@ -0,0 +1,77 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_prog_perl_modules.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_PERL_MODULES([MODULES], [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +# +# DESCRIPTION +# +# Checks to see if the given perl modules are available. If true the shell +# commands in ACTION-IF-TRUE are executed. If not the shell commands in +# ACTION-IF-FALSE are run. Note if $PERL is not set (for example by +# calling AC_CHECK_PROG, or AC_PATH_PROG), AC_CHECK_PROG(PERL, perl, perl) +# will be run. +# +# MODULES is a space separated list of module names. To check for a +# minimum version of a module, append the version number to the module +# name, separated by an equals sign. +# +# Example: +# +# AX_PROG_PERL_MODULES( Text::Wrap Net::LDAP=1.0.3, , +# AC_MSG_WARN(Need some Perl modules) +# +# LICENSE +# +# Copyright (c) 2009 Dean Povey +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AU_ALIAS([AC_PROG_PERL_MODULES], [AX_PROG_PERL_MODULES]) +AC_DEFUN([AX_PROG_PERL_MODULES],[dnl + +m4_define([ax_perl_modules]) +m4_foreach([ax_perl_module], m4_split(m4_normalize([$1])), + [ + m4_append([ax_perl_modules], + [']m4_bpatsubst(ax_perl_module,=,[ ])[' ]) + ]) + +# Make sure we have perl +if test -z "$PERL"; then +AC_CHECK_PROG(PERL,perl,perl) +fi + +if test "x$PERL" != x; then + ax_perl_modules_failed=0 + for ax_perl_module in ax_perl_modules; do + AC_MSG_CHECKING(for perl module $ax_perl_module) + + # Would be nice to log result here, but can't rely on autoconf internals + $PERL -e "use $ax_perl_module; exit" > /dev/null 2>&1 + if test $? -ne 0; then + AC_MSG_RESULT(no); + ax_perl_modules_failed=1 + else + AC_MSG_RESULT(ok); + fi + done + + # Run optional shell commands + if test "$ax_perl_modules_failed" = 0; then + : + $2 + else + : + $3 + fi +else + AC_MSG_WARN(could not find perl) +fi])dnl diff --git a/aclocal/ax_signed_right_shift.m4 b/aclocal/ax_signed_right_shift.m4 new file mode 100644 index 0000000..9c3ceb7 --- /dev/null +++ b/aclocal/ax_signed_right_shift.m4 @@ -0,0 +1,127 @@ +dnl @synopsis AX_SIGNED_RIGHT_SHIFT +dnl +dnl Tests the behavior of a right shift on a negative signed int. +dnl +dnl This macro calls: +dnl AC_DEFINE(SIGNED_RIGHT_SHIFT_IS) +dnl AC_DEFINE(ARITHMETIC_RIGHT_SHIFT) +dnl AC_DEFINE(LOGICAL_RIGHT_SHIFT) +dnl AC_DEFINE(UNKNOWN_RIGHT_SHIFT) +dnl +dnl SIGNED_RIGHT_SHIFT_IS will be equal to one of the other macros. +dnl It also leaves the shell variables "ax_signed_right_shift" +dnl set to "arithmetic", "logical", or "unknown". +dnl +dnl NOTE: This macro does not work for cross-compiling. +dnl +dnl @category C +dnl @version 2009-03-25 +dnl @license AllPermissive +dnl +dnl Copyright (C) 2009 David Reiss +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. + +AC_DEFUN([AX_SIGNED_RIGHT_SHIFT], + [ + + AC_MSG_CHECKING(the behavior of a signed right shift) + + success_arithmetic=no + AC_RUN_IFELSE([AC_LANG_PROGRAM([[]], [[ + return + /* 0xffffffff */ + -1 >> 1 != -1 || + -1 >> 2 != -1 || + -1 >> 3 != -1 || + -1 >> 4 != -1 || + -1 >> 8 != -1 || + -1 >> 16 != -1 || + -1 >> 24 != -1 || + -1 >> 31 != -1 || + /* 0x80000000 */ + (-2147483647 - 1) >> 1 != -1073741824 || + (-2147483647 - 1) >> 2 != -536870912 || + (-2147483647 - 1) >> 3 != -268435456 || + (-2147483647 - 1) >> 4 != -134217728 || + (-2147483647 - 1) >> 8 != -8388608 || + (-2147483647 - 1) >> 16 != -32768 || + (-2147483647 - 1) >> 24 != -128 || + (-2147483647 - 1) >> 31 != -1 || + /* 0x90800000 */ + -1870659584 >> 1 != -935329792 || + -1870659584 >> 2 != -467664896 || + -1870659584 >> 3 != -233832448 || + -1870659584 >> 4 != -116916224 || + -1870659584 >> 8 != -7307264 || + -1870659584 >> 16 != -28544 || + -1870659584 >> 24 != -112 || + -1870659584 >> 31 != -1 || + 0; + ]])], [ + success_arithmetic=yes + ]) + + + success_logical=no + AC_RUN_IFELSE([AC_LANG_PROGRAM([[]], [[ + return + /* 0xffffffff */ + -1 >> 1 != (signed)((unsigned)-1 >> 1) || + -1 >> 2 != (signed)((unsigned)-1 >> 2) || + -1 >> 3 != (signed)((unsigned)-1 >> 3) || + -1 >> 4 != (signed)((unsigned)-1 >> 4) || + -1 >> 8 != (signed)((unsigned)-1 >> 8) || + -1 >> 16 != (signed)((unsigned)-1 >> 16) || + -1 >> 24 != (signed)((unsigned)-1 >> 24) || + -1 >> 31 != (signed)((unsigned)-1 >> 31) || + /* 0x80000000 */ + (-2147483647 - 1) >> 1 != (signed)((unsigned)(-2147483647 - 1) >> 1) || + (-2147483647 - 1) >> 2 != (signed)((unsigned)(-2147483647 - 1) >> 2) || + (-2147483647 - 1) >> 3 != (signed)((unsigned)(-2147483647 - 1) >> 3) || + (-2147483647 - 1) >> 4 != (signed)((unsigned)(-2147483647 - 1) >> 4) || + (-2147483647 - 1) >> 8 != (signed)((unsigned)(-2147483647 - 1) >> 8) || + (-2147483647 - 1) >> 16 != (signed)((unsigned)(-2147483647 - 1) >> 16) || + (-2147483647 - 1) >> 24 != (signed)((unsigned)(-2147483647 - 1) >> 24) || + (-2147483647 - 1) >> 31 != (signed)((unsigned)(-2147483647 - 1) >> 31) || + /* 0x90800000 */ + -1870659584 >> 1 != (signed)((unsigned)-1870659584 >> 1) || + -1870659584 >> 2 != (signed)((unsigned)-1870659584 >> 2) || + -1870659584 >> 3 != (signed)((unsigned)-1870659584 >> 3) || + -1870659584 >> 4 != (signed)((unsigned)-1870659584 >> 4) || + -1870659584 >> 8 != (signed)((unsigned)-1870659584 >> 8) || + -1870659584 >> 16 != (signed)((unsigned)-1870659584 >> 16) || + -1870659584 >> 24 != (signed)((unsigned)-1870659584 >> 24) || + -1870659584 >> 31 != (signed)((unsigned)-1870659584 >> 31) || + 0; + ]])], [ + success_logical=yes + ]) + + + AC_DEFINE([ARITHMETIC_RIGHT_SHIFT], 1, [Possible value for SIGNED_RIGHT_SHIFT_IS]) + AC_DEFINE([LOGICAL_RIGHT_SHIFT], 2, [Possible value for SIGNED_RIGHT_SHIFT_IS]) + AC_DEFINE([UNKNOWN_RIGHT_SHIFT], 3, [Possible value for SIGNED_RIGHT_SHIFT_IS]) + + if test "$success_arithmetic" = "yes" && test "$success_logical" = "yes" ; then + AC_MSG_ERROR("Right shift appears to be both arithmetic and logical!") + elif test "$success_arithmetic" = "yes" ; then + ax_signed_right_shift=arithmetic + AC_DEFINE([SIGNED_RIGHT_SHIFT_IS], 1, + [Indicates the effect of the right shift operator + on negative signed integers]) + elif test "$success_logical" = "yes" ; then + ax_signed_right_shift=logical + AC_DEFINE([SIGNED_RIGHT_SHIFT_IS], 2, + [Indicates the effect of the right shift operator + on negative signed integers]) + else + ax_signed_right_shift=unknown + AC_DEFINE([SIGNED_RIGHT_SHIFT_IS], 3, + [Indicates the effect of the right shift operator + on negative signed integers]) + fi + + AC_MSG_RESULT($ax_signed_right_shift) + ]) diff --git a/aclocal/ax_thrift_internal.m4 b/aclocal/ax_thrift_internal.m4 new file mode 100644 index 0000000..8c0e3cb --- /dev/null +++ b/aclocal/ax_thrift_internal.m4 @@ -0,0 +1,28 @@ +dnl @synopsis AX_THRIFT_GEN(SHORT_LANGUAGE, LONG_LANGUAGE, DEFAULT) +dnl @synopsis AX_THRIFT_LIB(SHORT_LANGUAGE, LONG_LANGUAGE, DEFAULT) +dnl +dnl Allow a particular language generator to be disabled. +dnl Allow a particular language library to be disabled. +dnl +dnl These macros have poor error handling and are poorly documented. +dnl They are intended only for internal use by the Thrift compiler. +dnl +dnl @version 2008-02-20 +dnl @license AllPermissive +dnl +dnl Copyright (C) 2009 David Reiss +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. + +AC_DEFUN([AX_THRIFT_LIB], + [ + AC_ARG_WITH($1, + AC_HELP_STRING([--with-$1], [build the $2 library @<:@default=$3@:>@]), + [with_$1="$withval"], + [with_$1=$3] + ) + have_$1=no + dnl What we do here is going to vary from library to library, + dnl so we can't really generalize (yet!). + ]) diff --git a/aclocal/libtool.m4 b/aclocal/libtool.m4 new file mode 100644 index 0000000..10ab284 --- /dev/null +++ b/aclocal/libtool.m4 @@ -0,0 +1,8388 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 2014 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program or library that is built +# using GNU Libtool, you may include this file under the same +# distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +]) + +# serial 58 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS=$ltmain + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_PREPARE_CC_BASENAME +# ----------------------- +m4_defun([_LT_PREPARE_CC_BASENAME], [ +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in @S|@*""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} +])# _LT_PREPARE_CC_BASENAME + + +# _LT_CC_BASENAME(CC) +# ------------------- +# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, +# but that macro is also expanded into generated libtool script, which +# arranges for $SED and $ECHO to be set by different means. +m4_defun([_LT_CC_BASENAME], +[m4_require([_LT_PREPARE_CC_BASENAME])dnl +AC_REQUIRE([_LT_DECL_SED])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl +func_cc_basename $1 +cc_basename=$func_cc_basename_result +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl +m4_require([_LT_CMD_TRUNCATE])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options that allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a '.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld=$lt_cv_prog_gnu_ld + +old_CC=$CC +old_CFLAGS=$CFLAGS + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' +]) + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from 'configure', and 'config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# 'config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain=$ac_aux_dir/ltmain.sh +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the 'libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to 'config.status' so that its +# declaration there will have the same value as in 'configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags='_LT_TAGS'dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into 'config.status', and then the shell code to quote escape them in +# for loops in 'config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# '#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test 0 = "$lt_write_fail" && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +'$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2011 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test 0 != $[#] +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try '$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try '$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +lt_cl_success=: +test yes = "$silent" && + lt_config_lt_args="$lt_config_lt_args --quiet" +exec AS_MESSAGE_LOG_FD>/dev/null +$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false +exec AS_MESSAGE_LOG_FD>>config.log +$lt_cl_success || AS_EXIT(1) +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options that allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST + fi + + cfgfile=${ofile}T + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL +# Generated automatically by $as_me ($PACKAGE) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +_LT_COPYING +_LT_LIBTOOL_TAGS + +# Configured defaults for sys_lib_dlsearch_path munging. +: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + cat <<'_LT_EOF' >> "$cfgfile" + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +_LT_PREPARE_MUNGE_PATH_LIST +_LT_PREPARE_CC_BASENAME + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Go], [_LT_LANG(GO)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +m4_ifndef([AC_PROG_GO], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "$LT_MULTI_MODULE"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test 0 = "$_lt_result"; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS=$save_LDFLAGS + ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + 10.[[012]][[,.]]*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test yes = "$lt_cv_apple_cc_single_mod"; then + _lt_dar_single_mod='$single_module' + fi + if test yes = "$lt_cv_ld_exported_symbols_list"; then + _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' + fi + if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + if test yes = "$lt_cv_ld_force_load"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + m4_if([$1], [CXX], +[ if test yes != "$lt_cv_apple_cc_single_mod"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) +# ---------------------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script that will find a shell with a builtin +# printf (that we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case $ECHO in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], + [Search for dependent libraries within DIR (or the compiler's sysroot + if not specified).])], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case $with_sysroot in #( + yes) + if test yes = "$GCC"; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([$with_sysroot]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and where our libraries should be installed.])]) + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test no = "$enable_libtool_lock" || enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out what ABI is being produced by ac_compile, and set mode + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE=32 + ;; + *ELF-64*) + HPUX_IA64_MODE=64 + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test yes = "$lt_cv_prog_gnu_ld"; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +mips64*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + emul=elf + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + emul="${emul}32" + ;; + *64-bit*) + emul="${emul}64" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *MSB*) + emul="${emul}btsmip" + ;; + *LSB*) + emul="${emul}ltsmip" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *N32*) + emul="${emul}n32" + ;; + esac + LD="${LD-ld} -m $emul" + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. Note that the listed cases only cover the + # situations where additional linker options are needed (such as when + # doing 32-bit compilation for a host where ld defaults to 64-bit, or + # vice versa); the common cases where no linker options are needed do + # not appear in the list. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test yes != "$lt_cv_cc_needs_belf"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS=$SAVE_CFLAGS + fi + ;; +*-*solaris*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*|x86_64-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD=${LD-ld}_sol2 + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks=$enable_libtool_lock +])# _LT_ENABLE_LOCK + + +# _LT_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +: ${AR_FLAGS=cru} +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test 0 -eq "$ac_status"; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test 0 -ne "$ac_status"; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test no = "$lt_cv_ar_at_file"; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + bitrig* | openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +_LT_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test yes = "[$]$2"; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS +]) + +if test yes = "[$]$2"; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring=ABCD + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len" && \ + test undefined != "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test X`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test 17 != "$i" # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n "$lt_cv_sys_max_cmd_len"; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test yes = "$cross_compiling"; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test yes != "$enable_dlopen"; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen=load_add_on + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen=LoadLibrary + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ + lt_cv_dlopen=dyld + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + tpf*) + # Don't try to run any link tests for TPF. We know it's impossible + # because TPF is a cross-compiler, and we know how we open DSOs. + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + lt_cv_dlopen_self=no + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen=shl_load], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen=dlopen], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test no = "$lt_cv_dlopen"; then + enable_dlopen=no + else + enable_dlopen=yes + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS=$CPPFLAGS + test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS=$LDFLAGS + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS=$LIBS + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test yes = "$lt_cv_dlopen_self"; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS=$save_CPPFLAGS + LDFLAGS=$save_LDFLAGS + LIBS=$save_LIBS + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links=nottested +if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test no = "$hard_links"; then + AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", + [Define to the sub-directory where libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then + + # We can hardcode non-existent directories. + if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && + test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || + test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP"; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_PREPARE_MUNGE_PATH_LIST +# --------------------------- +# Make sure func_munge_path_list() is defined correctly. +m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], +[[# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x@S|@2 in + x) + ;; + *:) + eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" + ;; + x:*) + eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" + ;; + *) + eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" + ;; + esac +} +]])# _LT_PREPARE_PATH_LIST + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test yes = "$GCC"; then + case $host_os in + darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; + *) lt_awk_arg='/^libraries:/' ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; + *) lt_sed_strip_eq='s|=/|/|g' ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary... + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + # ...but if some path component already ends with the multilib dir we assume + # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). + case "$lt_multi_os_dir; $lt_search_path_spec " in + "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) + lt_multi_os_dir= + ;; + esac + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" + elif test -n "$lt_multi_os_dir"; then + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS = " "; FS = "/|\n";} { + lt_foo = ""; + lt_count = 0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo = "/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=.so +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +AC_ARG_VAR([LT_SYS_LIBRARY_PATH], +[User-defined run-time library search path.]) + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='$libname$release$shared_ext$major' + ;; + +aix[[4-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; then + # AIX 5 supports IA64 + library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line '#! .'. This would cause the generated library to + # depend on '.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a[(]lib.so.V[)]' + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='$libname$shared_ext' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' + soname_spec='$libname$release$major$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[23]].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + if test 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" + sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) to the search path. + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec; then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' + soname_spec='$libname$shared_ext.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=sco + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test yes = "$with_gnu_ld"; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], + [Detected run-time system search path for libraries]) +_LT_DECL([], [configure_time_lt_sys_library_path], [2], + [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program that can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$1"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD=$lt_cv_path_MAGIC_CMD + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac]) +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program that can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test no = "$withval" || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test yes = "$GCC"; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return, which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD=$ac_prog + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test yes = "$with_gnu_ld"; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD=$ac_dir/$ac_prog + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i +cat conftest.i conftest.i >conftest2.i +: ${lt_DD:=$DD} +AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], +[if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: +fi]) +rm -f conftest.i conftest2.i conftest.out]) +])# _LT_PATH_DD + + +# _LT_CMD_TRUNCATE +# ---------------- +# find command to truncate a binary pipe +m4_defun([_LT_CMD_TRUNCATE], +[m4_require([_LT_PATH_DD]) +AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], +[printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +lt_cv_truncate_bin= +if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" +fi +rm -f conftest.i conftest2.i conftest.out +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) +_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], + [Command to truncate a binary pipe]) +])# _LT_CMD_TRUNCATE + + +# _LT_CHECK_MAGIC_METHOD +# ---------------------- +# how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_MAGIC_METHOD], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +AC_CACHE_CHECK([how to recognize dependent libraries], +lt_cv_deplibs_check_method, +[lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# 'unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# that responds to the $file_magic_cmd with a given extended regex. +# If you have 'file' or equivalent on your system and you're not sure +# whether 'pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[[4-9]]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[[45]]*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd* | bitrig*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +os2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method = "file_magic"]) +_LT_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM=$NM +else + lt_nm_to_check=${ac_tool_prefix}nm + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/$lt_tmp_nm + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the 'sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty + case $build_os in + mingw*) lt_bad_file=conftest.nm/nofile ;; + *) lt_bad_file=/dev/null ;; + esac + case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in + *$lt_bad_file* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break 2 + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break 2 + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS=$lt_save_ifs + done + : ${lt_cv_path_NM=no} +fi]) +if test no != "$lt_cv_path_NM"; then + NM=$lt_cv_path_NM +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols -headers" + ;; + *) + DUMPBIN=: + ;; + esac + fi + AC_SUBST([DUMPBIN]) + if test : != "$DUMPBIN"; then + NM=$DUMPBIN + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + +# _LT_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh; + # decide which one to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd=$ECHO + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test yes != "$lt_cv_path_mainfest_tool"; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# _LT_DLL_DEF_P([FILE]) +# --------------------- +# True iff FILE is a Windows DLL '.def' file. +# Keep in sync with func_dll_def_p in the libtool script +AC_DEFUN([_LT_DLL_DEF_P], +[dnl + test DEF = "`$SED -n dnl + -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace + -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments + -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl + -e q dnl Only consider the first "real" line + $1`" dnl +])# _LT_DLL_DEF_P + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM=-lm) + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test yes = "$GCC"; then + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test ia64 = "$host_cpu"; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n"\ +$lt_cdecl_hook\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ +$lt_c_name_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ +$lt_c_name_lib_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function, + # D for any global variable and I for any imported variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ +" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ +" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ +" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT@&t@_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS=conftstm.$ac_objext + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test yes = "$pipe_works"; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], + [Transform the output of nm into a list of symbols to manually relocate]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +_LT_DECL([nm_interface], [lt_cv_nm_interface], [1], + [The name lister interface]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test yes = "$GXX"; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + if test ia64 != "$host_cpu"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64, which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test yes = "$GCC"; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + case $cc_basename in + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64, which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms that do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +AC_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ' (' and ')$', so one must not match beginning or + # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', + # as well as any symbol that contains 'd'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test yes != "$GCC"; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd* | bitrig*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test yes = "$with_gnu_ld"; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test yes = "$lt_use_gnu_ld_interface"; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='$wl' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test ia64 != "$host_cpu"; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test linux-dietlibc = "$host_os"; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test no = "$tmp_diet" + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + nagfor*) # NAGFOR 5.3 + tmp_sharedflag='-Wl,-shared' ;; + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + + if test yes = "$supports_anon_versioning"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + tcc*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' + ;; + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test yes = "$supports_anon_versioning"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then + aix_use_runtimelinking=yes + break + fi + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # traditional, no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + ;; + esac + + if test yes = "$GCC"; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag="$shared_flag "'$wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + ;; + + hpux10*) + if test yes,no = "$GCC,$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test yes,no = "$GCC,$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) + ;; + esac + fi + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS=$save_LDFLAGS]) + if test yes = "$lt_cv_irix_exported_symbol"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + linux*) + case $cc_basename in + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + _LT_TAGVAR(ld_shlibs, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + osf3*) + if test yes = "$GCC"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test yes = "$GCC"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test yes = "$GCC"; then + wlarc='$wl' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='$wl' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. GCC discards it without '$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test yes = "$GCC"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test sequent = "$host_vendor"; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test sni = "$host_vendor"; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test yes,yes = "$GCC,$enable_shared"; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting $shlibpath_var if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC=$CC +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report what library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC=$lt_save_CC +])# _LT_LANG_C_CONFIG + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test no != "$CXX" && + ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || + (test g++ != "$CXX"))); then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_caught_CXX_error"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test yes = "$GXX"; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test yes = "$GXX"; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test yes = "$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='$wl' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + ;; + esac + + if test yes = "$GXX"; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag=$shared_flag' $wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + # The "-G" linker flag allows undefined symbols. + _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared + # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + if test yes = "$supports_anon_versioning"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes,no = "$GXX,$with_gnu_ld"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test yes,no = "$GXX,$with_gnu_ld"; then + _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require '-G' NOT '-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no + + _LT_TAGVAR(GCC, $1)=$GXX + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test yes != "$_lt_caught_CXX_error" + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case @S|@2 in + .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; + *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $prev$p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test x-L = "$p" || + test x-R = "$p"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test no = "$pre_test_object_deps_done"; then + case $prev in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)=$prev$p + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test no = "$pre_test_object_deps_done"; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)=$p + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)=$p + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_LANG_PUSH(Fortran 77) +if test -z "$F77" || test no = "$F77"; then + _lt_disable_F77=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_disable_F77"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)=$G77 + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test yes != "$_lt_disable_F77" + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_LANG_PUSH(Fortran) + +if test -z "$FC" || test no = "$FC"; then + _lt_disable_FC=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_disable_FC"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test yes != "$_lt_disable_FC" + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)=$LD +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_SAVE + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)=$LD +_LT_CC_BASENAME([$compiler]) + +# Go did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code=$lt_simple_compile_test_code + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + +# _LT_DECL_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f "$lt_ac_sed" && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test 10 -lt "$lt_ac_count" && break + lt_ac_count=`expr $lt_ac_count + 1` + if test "$lt_ac_count" -gt "$lt_ac_max"; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine what file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS diff --git a/aclocal/ltoptions.m4 b/aclocal/ltoptions.m4 new file mode 100644 index 0000000..94b0829 --- /dev/null +++ b/aclocal/ltoptions.m4 @@ -0,0 +1,437 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software +# Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 8 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option '$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl 'shared' nor 'disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], + [_LT_WITH_AIX_SONAME([aix])]) + ]) +])# _LT_SET_OPTIONS + + +## --------------------------------- ## +## Macros to handle LT_INIT options. ## +## --------------------------------- ## + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the 'shared' and +# 'disable-shared' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the 'static' and +# 'disable-static' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the 'fast-install' +# and 'disable-fast-install' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the 'fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the 'disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_AIX_SONAME([DEFAULT]) +# ---------------------------------- +# implement the --with-aix-soname flag, and support the `aix-soname=aix' +# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT +# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. +m4_define([_LT_WITH_AIX_SONAME], +[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl +shared_archive_member_spec= +case $host,$enable_shared in +power*-*-aix[[5-9]]*,yes) + AC_MSG_CHECKING([which variant of shared library versioning to provide]) + AC_ARG_WITH([aix-soname], + [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], + [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], + [case $withval in + aix|svr4|both) + ;; + *) + AC_MSG_ERROR([Unknown argument to --with-aix-soname]) + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname], + [AC_CACHE_VAL([lt_cv_with_aix_soname], + [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) + with_aix_soname=$lt_cv_with_aix_soname]) + AC_MSG_RESULT([$with_aix_soname]) + if test aix != "$with_aix_soname"; then + # For the AIX way of multilib, we name the shared archive member + # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', + # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. + # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, + # the AIX toolchain works better with OBJECT_MODE set (default 32). + if test 64 = "${OBJECT_MODE-32}"; then + shared_archive_member_spec=shr_64 + else + shared_archive_member_spec=shr + fi + fi + ;; +*) + with_aix_soname=aix + ;; +esac + +_LT_DECL([], [shared_archive_member_spec], [0], + [Shared archive member basename, for filename based shared library versioning on AIX])dnl +])# _LT_WITH_AIX_SONAME + +LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) +LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) +LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the 'pic-only' and 'no-pic' +# LT_INIT options. +# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $withval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [pic_mode=m4_default([$1], [default])]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + +## ----------------- ## +## LTDL_INIT Options ## +## ----------------- ## + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) diff --git a/aclocal/ltsugar.m4 b/aclocal/ltsugar.m4 new file mode 100644 index 0000000..48bc934 --- /dev/null +++ b/aclocal/ltsugar.m4 @@ -0,0 +1,124 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software +# Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59, which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) diff --git a/aclocal/ltversion.m4 b/aclocal/ltversion.m4 new file mode 100644 index 0000000..fa04b52 --- /dev/null +++ b/aclocal/ltversion.m4 @@ -0,0 +1,23 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# @configure_input@ + +# serial 4179 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4.6]) +m4_define([LT_PACKAGE_REVISION], [2.4.6]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4.6' +macro_revision='2.4.6' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) diff --git a/aclocal/lt~obsolete.m4 b/aclocal/lt~obsolete.m4 new file mode 100644 index 0000000..c6b26f8 --- /dev/null +++ b/aclocal/lt~obsolete.m4 @@ -0,0 +1,99 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software +# Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 5 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) diff --git a/appveyor.yml b/appveyor.yml new file mode 100755 index 0000000..073ffd4 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,101 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# build Apache Thrift on AppVeyor - https://ci.appveyor.com + +version: '0.11.0.{build}' + +shallow_clone: true + +os: + - Visual Studio 2015 + +cache: + - C:\projects\thrift\buildcache -> build\appveyor\MSVC-appveyor-install.bat + - C:\ProgramData\chocolatey\lib -> build\appveyor\MSVC-appveyor-install.bat + - C:\msys64\var\cache\pacman -> build\appveyor\MSYS-appveyor-install.bat + +environment: + matrix: + - PROFILE: MSVC2010 + PLATFORM: x86 + CONFIGURATION: Debug + BOOST_VERSION: 1.54.0 + LIBEVENT_VERSION: 2.0.22 + QT_VERSION: 5.6 + ZLIB_VERSION: 1.2.8 + DISABLED_TESTS: StressTestNonBlocking + + - PROFILE: MSVC2015 + PLATFORM: x64 + CONFIGURATION: Release + BOOST_VERSION: 1.64.0 + LIBEVENT_VERSION: 2.0.22 + PYTHON_VERSION: 3.6 + QT_VERSION: 5.8 + ZLIB_VERSION: 1.2.11 + DISABLED_TESTS: StressTestNonBlocking + + - PROFILE: MINGW + PLATFORM: x64 + CONFIGURATION: Release + +matrix: + fast_finish: true + +install: + - cd %APPVEYOR_BUILD_FOLDER% + - call build\appveyor\%PROFILE:~0,4%-appveyor-install.bat + - refreshenv + +build_script: + - cd %APPVEYOR_BUILD_FOLDER% + - call build\appveyor\%PROFILE:~0,4%-appveyor-build.bat + +test_script: + - cd %APPVEYOR_BUILD_FOLDER% + - call build\appveyor\%PROFILE:~0,4%-appveyor-test.bat + + +# artifact capture disabled as it might increase service cost for little gain: +# +# artifacts: +# - path: local-thrift-inst +# name: cmake installed content +# type: zip +# +# - path: local-thrift-build\Testing +# name: ctest output +# type: zip + +# RDP support: use one or the other... +# +# enables RDP for each build job so you can inspect the environment at the beginning of the job: +# init: +# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) +# +# enables RDP at the end of the build job so you can login and re-run +# commands to see why something failed... +#on_finish: +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) +# +# also need: +# environment: +# APPVEYOR_RDP_PASSWORD: thr1FT2345$xyzZ + diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..c7e000c --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,57 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +./cleanup.sh +if test -d lib/php/src/ext/thrift_protocol ; then + if phpize -v >/dev/null 2>/dev/null ; then + (cd lib/php/src/ext/thrift_protocol && phpize) + fi +fi + +set -e + +# libtoolize is called "glibtoolize" on OSX. +if libtoolize --version 1 >/dev/null 2>/dev/null; then + LIBTOOLIZE=libtoolize +elif glibtoolize --version 1 >/dev/null 2>/dev/null; then + LIBTOOLIZE=glibtoolize +else + echo >&2 "Couldn't find libtoolize!" + exit 1 +fi + +# we require automake 1.13 or later +# check must happen externally due to use of newer macro +AUTOMAKE_VERSION=`automake --version | grep automake | egrep -o '([0-9]{1,}\.)+[0-9]{1,}'` +if [ "$AUTOMAKE_VERSION" \< "1.13" ]; then + echo >&2 "automake version $AUTOMAKE_VERSION is too old (need 1.13 or later)" + exit 1 +fi + +set -e +autoscan +$LIBTOOLIZE --copy --automake +aclocal -I ./aclocal +autoheader +sed '/undef VERSION/d' config.hin > config.hin2 +mv config.hin2 config.hin +autoconf +automake --copy --add-missing --foreign diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..1092c65 --- /dev/null +++ b/bower.json @@ -0,0 +1,15 @@ +{ + "name": "thrift", + "homepage": "https://git-wip-us.apache.org/repos/asf/thrift.git", + "authors": [ + "Apache Thrift " + ], + "description": "Apache Thrift", + "main": "lib/js/src/thrift.js", + "keywords": [ + "thrift" + ], + "license": "Apache v2", + "ignore": [ + ] +} diff --git a/build/appveyor/MING-appveyor-build.bat b/build/appveyor/MING-appveyor-build.bat new file mode 100644 index 0000000..838e428 --- /dev/null +++ b/build/appveyor/MING-appveyor-build.bat @@ -0,0 +1,36 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +@ECHO OFF +SETLOCAL EnableDelayedExpansion + +CD build\appveyor || EXIT /B +CALL cl_banner_build.bat || EXIT /B +CALL cl_setenv.bat || EXIT /B + +SET CMAKEARGS=^ + -G'%GENERATOR%' ^ + -DCMAKE_BUILD_TYPE=%CONFIGURATION% ^ + -DCMAKE_INSTALL_PREFIX=%INSTDIR_MSYS% ^ + -DCMAKE_MAKE_PROGRAM=/mingw64/bin/mingw32-make ^ + -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc.exe ^ + -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++.exe ^ + -DWITH_LIBEVENT=OFF ^ + -DWITH_PYTHON=OFF ^ + -DWITH_SHARED_LIB=OFF ^ + -DWITH_STATIC_LIB=ON + +@ECHO ON +%BASH% -lc "mkdir -p %BUILDDIR_MSYS% && cd %BUILDDIR_MSYS% && cmake.exe %SRCDIR_MSYS% %CMAKEARGS% && cmake --build . --config %CONFIGURATION% --target install" || EXIT /B +@ECHO OFF diff --git a/build/appveyor/MING-appveyor-install.bat b/build/appveyor/MING-appveyor-install.bat new file mode 100644 index 0000000..0d5f99e --- /dev/null +++ b/build/appveyor/MING-appveyor-install.bat @@ -0,0 +1,21 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Appveyor install script for MinGW +:: Installs (or builds) third party packages we need +:: + +:: Same as the MSYS installation requirements +CALL build\appveyor\MSYS-appveyor-install.bat diff --git a/build/appveyor/MING-appveyor-test.bat b/build/appveyor/MING-appveyor-test.bat new file mode 100644 index 0000000..c37c72a --- /dev/null +++ b/build/appveyor/MING-appveyor-test.bat @@ -0,0 +1,16 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: Same as MSYS2 +CALL build\appveyor\MSYS-appveyor-test.bat diff --git a/build/appveyor/MSVC-appveyor-build.bat b/build/appveyor/MSVC-appveyor-build.bat new file mode 100644 index 0000000..a4b92a2 --- /dev/null +++ b/build/appveyor/MSVC-appveyor-build.bat @@ -0,0 +1,47 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +@ECHO OFF +SETLOCAL EnableDelayedExpansion + +CD build\appveyor || EXIT /B +CALL cl_banner_build.bat || EXIT /B +CALL cl_setenv.bat || EXIT /B +MKDIR "%BUILDDIR%" || EXIT /B +CD "%BUILDDIR%" || EXIT /B + +@ECHO ON + cmake "%SRCDIR%" ^ + -G"%GENERATOR%" ^ + -DBISON_EXECUTABLE=C:\ProgramData\chocolatey\lib\winflexbison3\tools\win_bison.exe ^ + -DBOOST_ROOT="%BOOST_ROOT%" ^ + -DBOOST_LIBRARYDIR="%BOOST_LIBRARYDIR%" ^ + -DCMAKE_BUILD_TYPE="%CONFIGURATION%" ^ + -DCMAKE_INSTALL_PREFIX="%INSTDIR%" ^ + -DFLEX_EXECUTABLE=C:\ProgramData\chocolatey\lib\winflexbison3\tools\win_flex.exe ^ + -DINTTYPES_ROOT="%WIN3P%\msinttypes" ^ + -DLIBEVENT_ROOT="%WIN3P%\libevent-%LIBEVENT_VERSION%-stable" ^ + -DOPENSSL_ROOT_DIR="%OPENSSL_ROOT%" ^ + -DOPENSSL_USE_STATIC_LIBS=OFF ^ + -DZLIB_LIBRARY="%WIN3P%\zlib-inst\lib\zlib%ZLIB_LIB_SUFFIX%.lib" ^ + -DZLIB_ROOT="%WIN3P%\zlib-inst" ^ + -DWITH_PYTHON=%WITH_PYTHON% ^ + -DWITH_%THREADMODEL%THREADS=ON ^ + -DWITH_SHARED_LIB=OFF ^ + -DWITH_STATIC_LIB=ON || EXIT /B +@ECHO OFF + +cmake --build . ^ + --config "%CONFIGURATION%" ^ + --target INSTALL || EXIT /B diff --git a/build/appveyor/MSVC-appveyor-install.bat b/build/appveyor/MSVC-appveyor-install.bat new file mode 100644 index 0000000..573700e --- /dev/null +++ b/build/appveyor/MSVC-appveyor-install.bat @@ -0,0 +1,72 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Appveyor install script for MSVC +:: Installs (or builds) third party packages we need +:: + +@ECHO OFF +SETLOCAL EnableDelayedExpansion + +CD build\appveyor || EXIT /B +CALL cl_banner_install.bat || EXIT /B +CALL cl_setenv.bat || EXIT /B +CALL cl_showenv.bat || EXIT /B +MKDIR "%WIN3P%" || EXIT /B + +:: Install ant - this also installs the latest JDK as a dependency +:: The installation of JDK requires us to pick up PATH and JAVE_HOME from the registry +cinst -c "%BUILDCACHE%" -y ant || EXIT /B + +:: Install bison and flex +cinst -c "%BUILDCACHE%" -y winflexbison3 || EXIT /B + +:: zlib +CD "%APPVEYOR_SCRIPTS%" || EXIT /B +call build-zlib.bat || EXIT /B + +:: libevent +CD "%APPVEYOR_SCRIPTS%" || EXIT /B +call build-libevent.bat || EXIT /B + +:: python packages +pip install backports.ssl_match_hostname ^ + ipaddress ^ + tornado ^ + twisted || EXIT /B + +:: msinttypes - for MSVC2010 only +SET MSINTTYPESURL=https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/msinttypes/msinttypes-r26.zip +IF "%COMPILER%" == "vc100" ( + MKDIR "%WIN3P%\msinttypes" || EXIT /B + CD "%WIN3P%\msinttypes" || EXIT /B + appveyor DownloadFile "%MSINTTYPESURL%" || EXIT /B + 7z x "msinttypes-r26.zip" || EXIT /B +) + +:: appveyor build slaves do not have MSVC2010 Boost installed +IF "%COMPILER%" == "vc100" ( + SET BITS=64 + IF "%PLATFORM%" == "x86" ( + SET BITS=32 + ) + SET BOOSTEXEURL=https://downloads.sourceforge.net/project/boost/boost-binaries/%BOOST_VERSION%/boost_%BOOST_VERSION:.=_%-msvc-10.0-!BITS!.exe + SET BOOSTEXE=C:\projects\thrift\buildcache\boost_%BOOST_VERSION:.=_%-msvc-10.0-!BITS!.exe + appveyor DownloadFile "!BOOSTEXEURL!" -FileName "!BOOSTEXE!" || EXIT /B + "!BOOSTEXE!" /dir=C:\Libraries\boost_%BOOST_VERSION:.=_% /silent || EXIT /B +) + +:: Haskell (GHC) and cabal +cinst -c "%BUILDCACHE%" -y ghc || EXIT /B diff --git a/build/appveyor/MSVC-appveyor-test.bat b/build/appveyor/MSVC-appveyor-test.bat new file mode 100644 index 0000000..16ee207 --- /dev/null +++ b/build/appveyor/MSVC-appveyor-test.bat @@ -0,0 +1,25 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +@ECHO OFF +SETLOCAL EnableDelayedExpansion +CD build\appveyor || EXIT /B +CALL cl_banner_test.bat || EXIT /B +CALL cl_setenv.bat || EXIT /B +CD "%BUILDDIR%" || EXIT /B + +:: Add directories to the path to find DLLs of third party libraries so tests run +SET PATH=%BOOST_LIBRARYDIR%;%OPENSSL_ROOT%\bin;%WIN3P%\zlib-inst\bin;%PATH% + +ctest -C %CONFIGURATION% --timeout 300 -VV -E "(%DISABLED_TESTS%)" || EXIT /B diff --git a/build/appveyor/MSYS-appveyor-build.bat b/build/appveyor/MSYS-appveyor-build.bat new file mode 100644 index 0000000..b9d8955 --- /dev/null +++ b/build/appveyor/MSYS-appveyor-build.bat @@ -0,0 +1,47 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +@ECHO OFF +SETLOCAL EnableDelayedExpansion + +CD build\appveyor || EXIT /B +CALL cl_banner_build.bat || EXIT /B +CALL cl_setenv.bat || EXIT /B + +SET BASH=C:\msys64\usr\bin\bash +SET CMAKE=/c/msys64/mingw64/bin/cmake.exe + +@ECHO ON +SET CMAKEARGS=-G\"%GENERATOR%\" ^ + -DBoost_DEBUG=ON ^ + -DBoost_NAMESPACE=libboost ^ + -DBOOST_INCLUDEDIR=%BOOST_INCLUDEDIR% ^ + -DBOOST_LIBRARYDIR=%BOOST_LIBRARYDIR% ^ + -DCMAKE_BUILD_TYPE=%CONFIGURATION% ^ + -DCMAKE_C_COMPILER=gcc.exe ^ + -DCMAKE_CXX_COMPILER=g++.exe ^ + -DCMAKE_MAKE_PROGRAM=make.exe ^ + -DCMAKE_INSTALL_PREFIX=%INSTDIR_MSYS% ^ + -DOPENSSL_LIBRARIES=%OPENSSL_LIBRARIES% ^ + -DOPENSSL_ROOT_DIR=%OPENSSL_ROOT% ^ + -DOPENSSL_USE_STATIC_LIBS=ON ^ + -DWITH_BOOST_STATIC=ON ^ + -DWITH_JAVA=OFF ^ + -DWITH_LIBEVENT=OFF ^ + -DWITH_PYTHON=%WITH_PYTHON% ^ + -DWITH_SHARED_LIB=OFF ^ + -DWITH_STATIC_LIB=ON + +%BASH% -lc "mkdir %BUILDDIR_MSYS% && cd %BUILDDIR_MSYS% && %CMAKE% %SRCDIR_MSYS% %CMAKEARGS% && %CMAKE% --build . --config %CONFIGURATION% --target install" || EXIT /B +@ECHO OFF diff --git a/build/appveyor/MSYS-appveyor-install.bat b/build/appveyor/MSYS-appveyor-install.bat new file mode 100644 index 0000000..ff43cd3 --- /dev/null +++ b/build/appveyor/MSYS-appveyor-install.bat @@ -0,0 +1,41 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Appveyor install script for MSYS +:: Installs (or builds) third party packages we need +:: + +@ECHO OFF +SETLOCAL EnableDelayedExpansion + +CD build\appveyor || EXIT /B +CALL cl_banner_install.bat || EXIT /B +CALL cl_setenv.bat || EXIT /B +CALL cl_showenv.bat || EXIT /B + +SET PACKAGES=^ + --needed -S bison flex ^ + make ^ + mingw-w64-x86_64-boost ^ + mingw-w64-x86_64-cmake ^ + mingw-w64-x86_64-openssl ^ + mingw-w64-x86_64-toolchain ^ + mingw-w64-x86_64-zlib + +:: omitting libevent-devel for now it is version 2.1.4 and doesn't play nice with MinGW + +%BASH% -lc "pacman --noconfirm -Syu" || EXIT /B +%BASH% -lc "pacman --noconfirm -Su" || EXIT /B +%BASH% -lc "pacman --noconfirm %PACKAGES%" || EXIT /B diff --git a/build/appveyor/MSYS-appveyor-test.bat b/build/appveyor/MSYS-appveyor-test.bat new file mode 100644 index 0000000..0f37ec5 --- /dev/null +++ b/build/appveyor/MSYS-appveyor-test.bat @@ -0,0 +1,26 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +@ECHO OFF +SETLOCAL EnableDelayedExpansion + +CD build\appveyor || EXIT /B +CALL cl_banner_test.bat || EXIT /B +CALL cl_setenv.bat || EXIT /B +CD "%BUILDDIR%" || EXIT /B + +:: randomly fails on mingw; see Jira THRIFT-4106 +SET DISABLED_TESTS=concurrency_test + +%BASH% -lc "cd %BUILDDIR_MSYS% && ctest.exe -C %CONFIGURATION% --timeout 300 -VV -E '(%DISABLED_TESTS%)'" || EXIT /B diff --git a/build/appveyor/README.md b/build/appveyor/README.md new file mode 100644 index 0000000..1a2aa30 --- /dev/null +++ b/build/appveyor/README.md @@ -0,0 +1,34 @@ + + +# Appveyor Build + +Appveyor is capable of building MSVC 2010 through 2015 as well as +having the latest MSYS2/MinGW 64-bit environment. It has many versions +of boost and python installed as well. See what appveyor has +[installed on build workers](https://www.appveyor.com/docs/installed-software/). + +We run a matrix build on Appveyor and build the following combinations: + +* MinGW x64 (gcc 6.3.0) +* MSVC 2010 x86, an older boost, an older python +* MSVC 2015 x86/x64, the latest boost, the latest python +* MSYS2 x64 (gcc 6.3.0) - this is a work in progress + +The Appveyor script takes the first four letters from the PROFILE specified in +the environment stanza and runs these scripts in order: + +????-appveyor-install.bat will install third party libraries and set up the environment +????-appveyor-build.bat will build with cmake +????-appveyor-test.bat will run ctest diff --git a/build/appveyor/build-libevent.bat b/build/appveyor/build-libevent.bat new file mode 100644 index 0000000..13c74ee --- /dev/null +++ b/build/appveyor/build-libevent.bat @@ -0,0 +1,30 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +SETLOCAL EnableDelayedExpansion + +SET URLFILE=libevent-%LIBEVENT_VERSION%-stable.tar.gz +SET URL=https://github.com/libevent/libevent/releases/download/release-%LIBEVENT_VERSION%-stable/%URLFILE% + +CD %WIN3P% || EXIT /B +appveyor DownloadFile %URL% || EXIT /B +7z x %URLFILE% -so | 7z x -si -ttar > nul || EXIT /B +CD "libevent-%LIBEVENT_VERSION%-stable" || EXIT /B +nmake -f Makefile.nmake || EXIT /B +mkdir lib || EXIT /B +move *.lib lib\ || EXIT /B +move WIN32-Code\event2\* include\event2\ || EXIT /B +move *.h include\ || EXIT /B + +ENDLOCAL diff --git a/build/appveyor/build-zlib.bat b/build/appveyor/build-zlib.bat new file mode 100644 index 0000000..d8811a1 --- /dev/null +++ b/build/appveyor/build-zlib.bat @@ -0,0 +1,49 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +SETLOCAL EnableDelayedExpansion + +SET PACKAGE=zlib-%ZLIB_VERSION% +SET BUILDDIR=%WIN3P%\zlib-build +SET INSTDIR=%WIN3P%\zlib-inst +SET SRCDIR=%WIN3P%\%PACKAGE% +SET URLFILE=%PACKAGE%.tar.gz + +:: This allows us to tolerate when the current version is archived +SET URL=http://zlib.net/%URLFILE% +SET FURL=http://zlib.net/fossils/%URLFILE% + +:: Download +CD "%WIN3P%" || EXIT /B +appveyor DownloadFile "%URL%" +IF ERRORLEVEL 1 ( + appveyor DownloadFile "%FURL%" || EXIT /B +) +7z x "%URLFILE%" -so | 7z x -si -ttar > nul || EXIT /B + +:: Generate +MKDIR "%BUILDDIR%" || EXIT /B +CD "%BUILDDIR%" || EXIT /B +cmake "%SRCDIR%" ^ + -G"NMake Makefiles" ^ + -DCMAKE_INSTALL_PREFIX="%INSTDIR%" ^ + -DCMAKE_BUILD_TYPE="%CONFIGURATION%" || EXIT /B + +:: Build +nmake /fMakefile install || EXIT /B +IF "%CONFIGURATION%" == "Debug" ( + COPY "%BUILDDIR%\zlibd.pdb" "%INSTDIR%\bin\" || EXIT /B +) + +ENDLOCAL diff --git a/build/appveyor/cl_banner_apache_thrift.bat b/build/appveyor/cl_banner_apache_thrift.bat new file mode 100644 index 0000000..78f2a2a --- /dev/null +++ b/build/appveyor/cl_banner_apache_thrift.bat @@ -0,0 +1,24 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: A visual indicator in a large log helps you locate things when scanning +:: http://www.patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Apache%20Thrift + +ECHO/ +ECHO ___ __ ________ _ _____ +ECHO / _ | ___ ___ _____/ / ___ /_ __/ / ____(_) _/ /_ +ECHO / __ |/ _ \/ _ `/ __/ _ \/ -_) / / / _ \/ __/ / _/ __/ +ECHO /_/ |_/ .__/\_,_/\__/_//_/\__/ /_/ /_//_/_/ /_/_/ \__/ +ECHO /_/ +ECHO/ diff --git a/build/appveyor/cl_banner_build.bat b/build/appveyor/cl_banner_build.bat new file mode 100644 index 0000000..60272f3 --- /dev/null +++ b/build/appveyor/cl_banner_build.bat @@ -0,0 +1,23 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: A visual indicator in a large log helps you locate things when scanning +:: http://www.patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Build + +ECHO/ +ECHO ___ _ __ __ +ECHO / _ )__ __(_) /__/ / +ECHO / _ / // / / / _ / @@@ BUILD +ECHO /____/\_,_/_/_/\_,_/ +ECHO/ diff --git a/build/appveyor/cl_banner_install.bat b/build/appveyor/cl_banner_install.bat new file mode 100644 index 0000000..fde3da2 --- /dev/null +++ b/build/appveyor/cl_banner_install.bat @@ -0,0 +1,23 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: A visual indicator in a large log helps you locate things when scanning +:: http://www.patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Install + +ECHO/ +ECHO ____ __ ____ +ECHO / _/__ ___ / /____ _/ / / +ECHO _/ // _ \(_-^&1 | findstr /C:"Version %1%." > nul +EXIT /B diff --git a/build/appveyor/cl_setenv.bat b/build/appveyor/cl_setenv.bat new file mode 100644 index 0000000..e80d6b5 --- /dev/null +++ b/build/appveyor/cl_setenv.bat @@ -0,0 +1,92 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + + IF "%PROFILE%" == "MSVC2010" ( + CALL "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" %PLATFORM% +) ELSE IF "%PROFILE%" == "MSVC2012" ( + CALL "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" %PLATFORM% +) ELSE IF "%PROFILE%" == "MSVC2013" ( + CALL "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %PLATFORM% +) ELSE IF "%PROFILE%" == "MSVC2015" ( + CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %PLATFORM% +) ELSE IF "%PROFILE%" == "MSVC2017" ( + CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\VsDevCmd.bat" %PLATFORM% +) ELSE IF "%PROFILE%" == "MINGW" ( + SET MSYS2_PATH_TYPE=stock +) ELSE IF "%PROFILE%" == "MSYS" ( + SET MSYS2_PATH_TYPE=stock +) ELSE ( + ECHO Unsupported PROFILE=%PROFILE% or PLATFORM=%PLATFORM% + EXIT /B 1 +) + +CALL cl_setcompiler.bat || EXIT /B +CALL cl_setgenerator.bat || EXIT /B + +SET APPVEYOR_SCRIPTS=%APPVEYOR_BUILD_FOLDER%\build\appveyor +SET BUILDCACHE=%APPVEYOR_BUILD_FOLDER%\buildcache +SET BUILDDIR=%APPVEYOR_BUILD_FOLDER%\local-thrift-build +SET INSTDIR=%APPVEYOR_BUILD_FOLDER%\local-thrift-inst +SET SRCDIR=%APPVEYOR_BUILD_FOLDER% + +: PLATFORM is x64 or x86, but we want x86 to become "32" when we strip it down for paths: +SET NORM_PLATFORM=%PLATFORM:~-2,2% +IF "%NORM_PLATFORM%" == "86" (SET NORM_PLATFORM=32) + +:: FindBoost needs forward slashes so cmake doesn't see something as an escaped character +SET BOOST_ROOT=C:/Libraries/boost_%BOOST_VERSION:.=_% +SET BOOST_LIBRARYDIR=%BOOST_ROOT%/lib%NORM_PLATFORM%-msvc-%COMPILER:~-3,2%.0 +SET OPENSSL_ROOT=C:\OpenSSL-Win%NORM_PLATFORM% +SET WIN3P=%APPVEYOR_BUILD_FOLDER%\thirdparty + +:: MSVC2010 doesn't "do" std::thread +IF "%COMPILER%" == "vc100" ( + SET THREADMODEL=BOOST +) ELSE ( + SET THREADMODEL=STD +) + +IF "%PYTHON_VERSION%" == "" ( + SET WITH_PYTHON=OFF +) ELSE ( + SET WITH_PYTHON=ON + SET PATH=C:\Python%PYTHON_VERSION:.=%\scripts;C:\Python%PYTHON_VERSION:.=%;!PATH! +) +IF "%CONFIGURATION%" == "Debug" (SET ZLIB_LIB_SUFFIX=d) + +IF NOT "%QT_VERSION%" == "" ( + IF /i "%PLATFORM%" == "x64" SET QTEXT=_64 + SET PATH=C:\Qt\%QT_VERSION%\%PROFILE%!QTEXT!\bin;!PATH! +) + +IF NOT "%PROFILE:~0,4%" == "MSVC" ( + + SET BASH=C:\msys64\usr\bin\bash.exe + SET BOOST_ROOT= + SET BOOST_INCLUDEDIR=/mingw64/include + SET BOOST_LIBRARYDIR=/mingw64/lib + SET OPENSSL_LIBRARIES=/mingw64/lib + SET OPENSSL_ROOT=/mingw64 + SET WIN3P= + + !BASH! -lc "sed -i '/export PATH=\/mingw64\/bin/d' ~/.bash_profile && echo 'export PATH=/mingw64/bin:$PATH' >> ~/.bash_profile" || EXIT /B + +) + +SET BUILDDIR_MSYS=%BUILDDIR:\=/% +SET BUILDDIR_MSYS=/c%BUILDDIR_MSYS:~2% +SET INSTDIR_MSYS=%INSTDIR:\=/% +SET INSTDIR_MSYS=/c%INSTDIR_MSYS:~2% +SET SRCDIR_MSYS=%SRCDIR:\=/% +SET SRCDIR_MSYS=/c%SRCDIR_MSYS:~2% diff --git a/build/appveyor/cl_setgenerator.bat b/build/appveyor/cl_setgenerator.bat new file mode 100644 index 0000000..7ca9853 --- /dev/null +++ b/build/appveyor/cl_setgenerator.bat @@ -0,0 +1,74 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Detect the compiler edition we're building in and then +:: set the GENERATOR environment variable to one of: +:: +:: Visual Studio 15 2017 [arch] = Generates Visual Studio 2017 project files. +:: Optional [arch] can be "Win64" or "ARM". +:: Visual Studio 14 2015 [arch] = Generates Visual Studio 2015 project files. +:: Optional [arch] can be "Win64" or "ARM". +:: Visual Studio 12 2013 [arch] = Generates Visual Studio 2013 project files. +:: Optional [arch] can be "Win64" or "ARM". +:: Visual Studio 11 2012 [arch] = Generates Visual Studio 2012 project files. +:: Optional [arch] can be "Win64" or "ARM". +:: Visual Studio 10 2010 [arch] = Generates Visual Studio 2010 project files. +:: Optional [arch] can be "Win64" or "IA64". +:: MinGW Makefiles = Generates makefiles for MinGW +:: MSYS Makefiles = Generates makefiles for MSYS +:: +:: Honors any existing GENERATOR environment variable +:: setting instead of overwriting it, to allow it +:: to be forced if needed. +:: +:: Sets ERRORLEVEL to 0 if GENERATOR can be determined, +:: to 1 if it cannot. +:: + +IF DEFINED GENERATOR ( + ECHO [warn ] using existing environment variable GENERATOR + EXIT /B 0 +) + + +IF "%PROFILE:~0,4%" == "MING" ( + SET GENERATOR=MinGW Makefiles +) ELSE IF "%PROFILE:~0,4%" == "MSYS" ( + SET GENERATOR=MSYS Makefiles +) ELSE ( + IF /i "%PLATFORM%" == "x64" SET GENARCH= Win64 + CALL :CHECK 16 + IF !ERRORLEVEL! == 0 SET GENERATOR=Visual Studio 10 2010!GENARCH! + CALL :CHECK 17 + IF !ERRORLEVEL! == 0 SET GENERATOR=Visual Studio 11 2012!GENARCH! + CALL :CHECK 18 + IF !ERRORLEVEL! == 0 SET GENERATOR=Visual Studio 12 2013!GENARCH! + CALL :CHECK 19.00 + IF !ERRORLEVEL! == 0 SET GENERATOR=Visual Studio 14 2015!GENARCH! + CALL :CHECK 19.10 + IF !ERRORLEVEL! == 0 SET GENERATOR=Visual Studio 15 2017!GENARCH! +) + +IF NOT DEFINED GENERATOR ( + ECHO [error] unable to determine the CMake generator to use + EXIT /B 1 +) + +ECHO [info ] using CMake generator %GENERATOR% +EXIT /B 0 + +:CHECK +cl /? 2>&1 | findstr /C:"Version %1%." > nul +EXIT /B diff --git a/build/appveyor/cl_showenv.bat b/build/appveyor/cl_showenv.bat new file mode 100644 index 0000000..33dd660 --- /dev/null +++ b/build/appveyor/cl_showenv.bat @@ -0,0 +1,67 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +ECHO/ +ECHO =============================================================================== +IF "%PROFILE:~0,4%" == "MSVC" ( +ECHO Versions +ECHO ------------------------------------------------------------------------------- +ECHO boost = %BOOST_VERSION% +ECHO libevent = %LIBEVENT_VERSION% +ECHO python = %PYTHON_VERSION% +ECHO qt = %QT_VERSION% +ECHO zlib = %ZLIB_VERSION% +ECHO/ +) +ECHO Appveyor Variables +ECHO ------------------------------------------------------------------------------- +ECHO APPVEYOR_BUILD_FOLDER = %APPVEYOR_BUILD_FOLDER% +ECHO CONFIGURATION = %CONFIGURATION% +ECHO PLATFORM = %PLATFORM% +ECHO PROFILE = %PROFILE% +ECHO/ +ECHO Our Variables +ECHO ------------------------------------------------------------------------------- +ECHO APPVEYOR_SCRIPTS = %APPVEYOR_SCRIPTS% +ECHO BOOST_ROOT = %BOOST_ROOT% +ECHO BOOST_INCLUDEDIR = %BOOST_INCLUDEDIR% +ECHO BOOST_LIBRARYDIR = %BOOST_LIBRARYDIR% +ECHO BUILDCACHE = %BUILDCACHE% +ECHO BUILDDIR = %BUILDDIR% +ECHO COMPILER = %COMPILER% +ECHO GENERATOR = %GENERATOR% +ECHO INSTDIR = %INSTDIR% +ECHO JAVA_HOME = %JAVA_HOME% +ECHO OPENSSL_ROOT = %OPENSSL_ROOT% +ECHO SRCDIR = %SRCDIR% +ECHO WIN3P = %WIN3P% +ECHO WITH_PYTHON = %WITH_PYTHON% +ECHO ZLIB_STATIC_SUFFIX = %ZLIB_STATIC_SUFFIX% +IF NOT "%PROFILE:~0,4%" == "MSVC" ( +ECHO/ +ECHO MSYS2/MinGW +ECHO ------------------------------------------------------------------------------- +ECHO BUILDDIR_MSYS = %BUILDDIR_MSYS% +ECHO INSTDIR_MSYS = %INSTDIR_MSYS% +ECHO MSYS2_PATH_TYPE = %MSYS2_PATH_TYPE% +ECHO SRCDIR_MSYS = %SRCDIR_MSYS% +ECHO PATH = +C:\msys64\usr\bin\bash -lc "echo $PATH" +) +ECHO/ +ECHO Windows PATH +ECHO ------------------------------------------------------------------------------- +ECHO %PATH% +ECHO =============================================================================== +ECHO/ diff --git a/build/appveyor/simulate-appveyor.bat b/build/appveyor/simulate-appveyor.bat new file mode 100644 index 0000000..b32c0da --- /dev/null +++ b/build/appveyor/simulate-appveyor.bat @@ -0,0 +1,35 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Helps build thrift by pretending to be appveyor +:: Usage: +:: cd build\appveyor +:: simulate-appveyor.bat [Debug|Release] [x86|x64] [MINGW|MSVC2015] +:: + +@ECHO OFF +SETLOCAL EnableDelayedExpansion + +SET APPVEYOR_BUILD_FOLDER=%~dp0..\.. +SET CONFIGURATION=%1 +SET PLATFORM=%2 +SET PROFILE=%3 + +CD %APPVEYOR_BUILD_FOLDER% +CALL build\appveyor\%PROFILE:~0,4%-appveyor-install.bat || EXIT /B +CD %APPVEYOR_BUILD_FOLDER% +CALL build\appveyor\%PROFILE:~0,4%-appveyor-build.bat || EXIT /B +CD %APPVEYOR_BUILD_FOLDER% +CALL build\appveyor\%PROFILE:~0,4%-appveyor-test.bat diff --git a/build/cmake/CPackConfig.cmake b/build/cmake/CPackConfig.cmake new file mode 100644 index 0000000..fdc1b4e --- /dev/null +++ b/build/cmake/CPackConfig.cmake @@ -0,0 +1,68 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +#TODO: Should we bundle system libraries for DLLs? +#include(InstallRequiredSystemLibraries) + +# For help take a look at: +# http://www.cmake.org/Wiki/CMake:CPackConfiguration + +### general settings +set(CPACK_PACKAGE_NAME "thrift") +set(CPACK_PACKAGE_VERSION "${PACKAGE_VERSION}") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Apache Thrift") +set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") +set(CPACK_PACKAGE_VENDOR "Apache Software Foundation") +set(CPACK_PACKAGE_CONTACT "dev@thrift.apache.org") +set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") +set(CPACK_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}") + +### versions +set(CPACK_PACKAGE_VERSION_MAJOR ${thrift_VERSION_MAJOR}) +set(CPACK_PACKAGE_VERSION_MINOR ${thrift_VERSION_MINOR}) +set(CPACK_PACKAGE_VERSION_PATCH ${thrift_VERSION_PATCH}) + +### source generator +set(CPACK_SOURCE_GENERATOR "TGZ") +set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;tags;cscope.*") +set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") + +### zip generator +set(CPACK_GENERATOR "ZIP") +set(CPACK_PACKAGE_INSTALL_DIRECTORY "thrift") + + +if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(CPACK_GENERATOR "NSIS") + set(CPACK_NSIS_HELP_LINK "http://thrift.apache.org") + set(CPACK_NSIS_MENU_LINKS + "http://thrift.apache.org" "Apache Thrift - Web Site" + "https://issues.apache.org/jira/browse/THRIFT" "Apache Thrift - Issues") + set(CPACK_NSIS_CONTACT ${CPACK_PACKAGE_CONTACT}) + set(CPACK_NSIS_MODIFY_PATH "ON") + set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") +else() + set(CPACK_GENERATOR "DEB" ) + set(CPACK_DEBIAN_PACKAGE_MAINTAINER ${CPACK_PACKAGE_CONTACT}) +endif() + + +include(CPack) diff --git a/build/cmake/ConfigureChecks.cmake b/build/cmake/ConfigureChecks.cmake new file mode 100644 index 0000000..12a50df --- /dev/null +++ b/build/cmake/ConfigureChecks.cmake @@ -0,0 +1,76 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckIncludeFiles) +include(CheckSymbolExists) + +if (Inttypes_FOUND) + # This allows the inttypes.h and stdint.h checks to succeed on platforms that + # do not natively provide there. + set (CMAKE_REQUIRED_INCLUDES ${INTTYPES_INCLUDE_DIRS}) +endif () + +check_include_file(arpa/inet.h HAVE_ARPA_INET_H) +check_include_file(fcntl.h HAVE_FCNTL_H) +check_include_file(getopt.h HAVE_GETOPT_H) +check_include_file(inttypes.h HAVE_INTTYPES_H) +check_include_file(netdb.h HAVE_NETDB_H) +check_include_file(netinet/in.h HAVE_NETINET_IN_H) +check_include_file(stdint.h HAVE_STDINT_H) +check_include_file(unistd.h HAVE_UNISTD_H) +check_include_file(pthread.h HAVE_PTHREAD_H) +check_include_file(sys/time.h HAVE_SYS_TIME_H) +check_include_file(sys/param.h HAVE_SYS_PARAM_H) +check_include_file(sys/resource.h HAVE_SYS_RESOURCE_H) +check_include_file(sys/socket.h HAVE_SYS_SOCKET_H) +check_include_file(sys/stat.h HAVE_SYS_STAT_H) +check_include_file(sys/un.h HAVE_SYS_UN_H) +check_include_file(sys/poll.h HAVE_SYS_POLL_H) +check_include_file(sys/select.h HAVE_SYS_SELECT_H) +check_include_file(sched.h HAVE_SCHED_H) +check_include_file(string.h HAVE_STRING_H) +check_include_file(strings.h HAVE_STRINGS_H) + +check_function_exists(gethostbyname HAVE_GETHOSTBYNAME) +check_function_exists(gethostbyname_r HAVE_GETHOSTBYNAME_R) +check_function_exists(strerror_r HAVE_STRERROR_R) +check_function_exists(sched_get_priority_max HAVE_SCHED_GET_PRIORITY_MAX) +check_function_exists(sched_get_priority_min HAVE_SCHED_GET_PRIORITY_MIN) + +include(CheckCSourceCompiles) +include(CheckCXXSourceCompiles) + +check_cxx_source_compiles( + " + #include + int main(){char b;char *a = strerror_r(0, &b, 0); return(0);} + " + STRERROR_R_CHAR_P) + + +set(PACKAGE ${PACKAGE_NAME}) +set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") +set(VERSION ${thrift_VERSION}) + +# generate a config.h file +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/thrift/config.h") + +include_directories("${CMAKE_CURRENT_BINARY_DIR}") diff --git a/build/cmake/DefineCMakeDefaults.cmake b/build/cmake/DefineCMakeDefaults.cmake new file mode 100644 index 0000000..bb32399 --- /dev/null +++ b/build/cmake/DefineCMakeDefaults.cmake @@ -0,0 +1,93 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +# Always include srcdir and builddir in include path +# This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY} in +# about every subdir +# since cmake 2.4.0 +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +# Put the include dirs which are in the source or build tree +# before all other include dirs, so the headers in the sources +# are preferred over the already installed ones +# since cmake 2.4.1 +set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON) + +# Use colored output +# since cmake 2.4.0 +set(CMAKE_COLOR_MAKEFILE ON) + +# Define the generic version of the libraries here +set(GENERIC_LIB_VERSION "0.11.0") +set(GENERIC_LIB_SOVERSION "0") + +# Set the default build type to release with debug info +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RelWithDebInfo + CACHE STRING + "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." + ) +endif (NOT CMAKE_BUILD_TYPE) + +# Create the compile command database for clang by default +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Put the libraries and binaries that get built into directories at the +# top of the build tree rather than in hard-to-find leaf +# directories. This simplifies manual testing and the use of the build +# tree rather than installed thrift libraries. +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +# +# "rpath" support. +# See http://www.itk.org/Wiki/index.php?title=CMake_RPATH_handling +# +# On MacOSX, for shared libraries, enable rpath support. +set(CMAKE_MACOSX_RPATH TRUE) +# +# On any OS, for executables, allow linking with shared libraries in non-system +# locations and running the executables without LD_PRELOAD or similar. +# This requires the library to be built with rpath support. +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +# +# C++ Language Level Defaults - this depends on the compiler capabilities +# +if (NOT DEFINED CMAKE_CXX_STANDARD) + if (MSVC AND MSVC_VERSION LESS 1800) + # MSVC 2012 and earlier don't support template aliases so you have to use C++98 + set(CMAKE_CXX_STANDARD 98) + message(STATUS "Setting C++98 as the default language level (for an older MSVC compiler).") + else() + set(CMAKE_CXX_STANDARD 11) # C++11 + message(STATUS "Setting C++11 as the default language level.") + endif() + message(STATUS "To specify a different C++ language level, set CMAKE_CXX_STANDARD") +endif() + +if (NOT DEFINED CMAKE_CXX_STANDARD_REQUIRED) + set(CMAKE_CXX_STANDARD_REQUIRED OFF) # can degrade to C++98 if compiler does not support C++11 +endif() + +if (NOT DEFINED CMAKE_CXX_EXTENSIONS) + set(CMAKE_CXX_EXTENSIONS OFF) # use standards compliant language level for portability +endif() diff --git a/build/cmake/DefineInstallationPaths.cmake b/build/cmake/DefineInstallationPaths.cmake new file mode 100644 index 0000000..122f0f6 --- /dev/null +++ b/build/cmake/DefineInstallationPaths.cmake @@ -0,0 +1,26 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +# Define the default install paths +set(BIN_INSTALL_DIR "bin" CACHE PATH "The binary install dir (default: bin)") +set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "The library install dir (default: lib${LIB_SUFFIX})") +set(INCLUDE_INSTALL_DIR "include" CACHE PATH "The library install dir (default: include)") +set(CMAKE_INSTALL_DIR "cmake" CACHE PATH "The subdirectory to install cmake config files (default: cmake)") +set(DOC_INSTALL_DIR "share/doc" CACHE PATH "The subdirectory to install documentation files (default: share/doc)") diff --git a/build/cmake/DefineOptions.cmake b/build/cmake/DefineOptions.cmake new file mode 100644 index 0000000..f1ea7bb --- /dev/null +++ b/build/cmake/DefineOptions.cmake @@ -0,0 +1,219 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +include(CMakeDependentOption) + +set(THRIFT_COMPILER "" CACHE FILEPATH "External Thrift compiler to use during build") + +# Additional components +option(BUILD_COMPILER "Build Thrift compiler" ON) + +if(BUILD_COMPILER OR EXISTS ${THRIFT_COMPILER}) + set(HAVE_COMPILER ON) +endif() +CMAKE_DEPENDENT_OPTION(BUILD_TESTING "Build with unit tests" ON "HAVE_COMPILER" OFF) +CMAKE_DEPENDENT_OPTION(BUILD_EXAMPLES "Build examples" ON "HAVE_COMPILER" OFF) +CMAKE_DEPENDENT_OPTION(BUILD_TUTORIALS "Build Thrift tutorials" ON "HAVE_COMPILER" OFF) +option(BUILD_LIBRARIES "Build Thrift libraries" ON) + +# Libraries to build + +# Each language library can be enabled or disabled using the WITH_ flag. +# By default CMake checks if the required dependencies for a language are present +# and enables the library if all are found. This means the default is to build as +# much as possible but leaving out libraries if their dependencies are not met. + +option(WITH_BOOST_FUNCTIONAL "Use boost/tr1/functional.hpp even under C++11 or later" OFF) +if (WITH_BOOST_FUNCTIONAL) + add_definitions(-DFORCE_BOOST_FUNCTIONAL) +endif() + +option(WITH_BOOST_SMART_PTR "Use boost/smart_ptr.hpp even under C++11 or later" OFF) +if (WITH_BOOST_SMART_PTR) + add_definitions(-DFORCE_BOOST_SMART_PTR) +endif() + +option(WITH_BOOST_STATIC "Build with Boost static link library" OFF) +set(Boost_USE_STATIC_LIBS ${WITH_BOOST_STATIC}) +if (NOT WITH_BOOST_STATIC) + add_definitions(-DBOOST_ALL_DYN_LINK) + add_definitions(-DBOOST_TEST_DYN_LINK) +endif() + +# C++ +option(WITH_CPP "Build C++ Thrift library" ON) +if(WITH_CPP) + find_package(Boost 1.53 QUIET) + # NOTE: Currently the following options are C++ specific, + # but in future other libraries might reuse them. + # So they are not dependent on WITH_CPP but setting them without WITH_CPP currently + # has no effect. + if(ZLIB_LIBRARY) + # FindZLIB.cmake does not normalize path so we need to do it ourselves. + file(TO_CMAKE_PATH ${ZLIB_LIBRARY} ZLIB_LIBRARY) + endif() + find_package(ZLIB QUIET) + CMAKE_DEPENDENT_OPTION(WITH_ZLIB "Build with ZLIB support" ON + "ZLIB_FOUND" OFF) + find_package(Libevent QUIET) + CMAKE_DEPENDENT_OPTION(WITH_LIBEVENT "Build with libevent support" ON + "Libevent_FOUND" OFF) + find_package(Qt4 QUIET COMPONENTS QtCore QtNetwork) + CMAKE_DEPENDENT_OPTION(WITH_QT4 "Build with Qt4 support" ON + "QT4_FOUND" OFF) + find_package(Qt5 QUIET COMPONENTS Core Network) + CMAKE_DEPENDENT_OPTION(WITH_QT5 "Build with Qt5 support" ON + "Qt5_FOUND" OFF) + if(${WITH_QT4} AND ${WITH_QT5} AND ${CMAKE_MAJOR_VERSION} LESS 3) + # cmake < 3.0.0 causes conflict when building both Qt4 and Qt5 + set(WITH_QT4 OFF) + endif() + find_package(OpenSSL QUIET) + CMAKE_DEPENDENT_OPTION(WITH_OPENSSL "Build with OpenSSL support" ON + "OPENSSL_FOUND" OFF) + option(WITH_STDTHREADS "Build with C++ std::thread support" OFF) + CMAKE_DEPENDENT_OPTION(WITH_BOOSTTHREADS "Build with Boost threads support" OFF + "NOT WITH_STDTHREADS;Boost_FOUND" OFF) +endif() +CMAKE_DEPENDENT_OPTION(BUILD_CPP "Build C++ library" ON + "BUILD_LIBRARIES;WITH_CPP;Boost_FOUND" OFF) +CMAKE_DEPENDENT_OPTION(WITH_PLUGIN "Build compiler plugin support" OFF + "BUILD_COMPILER;BUILD_CPP" OFF) + +# C GLib +option(WITH_C_GLIB "Build C (GLib) Thrift library" ON) +if(WITH_C_GLIB) + find_package(GLIB QUIET COMPONENTS gobject) +endif() +CMAKE_DEPENDENT_OPTION(BUILD_C_GLIB "Build C (GLib) library" ON + "BUILD_LIBRARIES;WITH_C_GLIB;GLIB_FOUND" OFF) + +if(BUILD_CPP) + set(boost_components) + if(WITH_BOOSTTHREADS OR BUILD_TESTING) + list(APPEND boost_components system thread) + endif() + if(BUILD_TESTING) + list(APPEND boost_components unit_test_framework filesystem chrono program_options) + endif() + if(boost_components) + find_package(Boost 1.53 REQUIRED COMPONENTS ${boost_components}) + endif() +elseif(BUILD_C_GLIB AND BUILD_TESTING) + find_package(Boost 1.53 REQUIRED) +endif() + +# Java +option(WITH_JAVA "Build Java Thrift library" ON) +if(ANDROID) + find_package(Gradle QUIET) + CMAKE_DEPENDENT_OPTION(BUILD_JAVA "Build Java library" ON + "BUILD_LIBRARIES;WITH_JAVA;GRADLE_FOUND" OFF) +else() + find_package(Java QUIET) + find_package(Ant QUIET) + CMAKE_DEPENDENT_OPTION(BUILD_JAVA "Build Java library" ON + "BUILD_LIBRARIES;WITH_JAVA;JAVA_FOUND;ANT_FOUND" OFF) +endif() + +# Python +option(WITH_PYTHON "Build Python Thrift library" ON) +find_package(PythonInterp QUIET) # for Python executable +find_package(PythonLibs QUIET) # for Python.h +CMAKE_DEPENDENT_OPTION(BUILD_PYTHON "Build Python library" ON + "BUILD_LIBRARIES;WITH_PYTHON;PYTHONLIBS_FOUND" OFF) + +# Haskell +option(WITH_HASKELL "Build Haskell Thrift library" ON) +find_package(GHC QUIET) +find_package(Cabal QUIET) +CMAKE_DEPENDENT_OPTION(BUILD_HASKELL "Build GHC library" ON + "BUILD_LIBRARIES;WITH_HASKELL;GHC_FOUND;CABAL_FOUND" OFF) + +# Common library options +option(WITH_SHARED_LIB "Build shared libraries" ON) +option(WITH_STATIC_LIB "Build static libraries" ON) +if (NOT WITH_SHARED_LIB AND NOT WITH_STATIC_LIB) + message(FATAL_ERROR "Cannot build with both shared and static outputs disabled!") +endif() + +#NOTE: C++ compiler options are defined in the lib/cpp/CMakeLists.txt + +# Visual Studio only options +if(MSVC) +option(WITH_MT "Build using MT instead of MD (MSVC only)" OFF) +endif(MSVC) + +macro(MESSAGE_DEP flag summary) +if(NOT ${flag}) + message(STATUS " - ${summary}") +endif() +endmacro(MESSAGE_DEP flag summary) + +macro(PRINT_CONFIG_SUMMARY) +message(STATUS "----------------------------------------------------------") +message(STATUS "Thrift version: ${thrift_VERSION} (${thrift_VERSION_MAJOR}.${thrift_VERSION_MINOR}.${thrift_VERSION_PATCH})") +message(STATUS "Thrift package version: ${PACKAGE_VERSION}") +message(STATUS "Build configuration Summary") +message(STATUS " Build Thrift compiler: ${BUILD_COMPILER}") +message(STATUS " Build compiler plugin support: ${WITH_PLUGIN}") +message(STATUS " Build with unit tests: ${BUILD_TESTING}") +MESSAGE_DEP(HAVE_COMPILER "Disabled because BUILD_THRIFT=OFF and no valid THRIFT_COMPILER is given") +message(STATUS " Build examples: ${BUILD_EXAMPLES}") +MESSAGE_DEP(HAVE_COMPILER "Disabled because BUILD_THRIFT=OFF and no valid THRIFT_COMPILER is given") +message(STATUS " Build Thrift libraries: ${BUILD_LIBRARIES}") +message(STATUS " Language libraries:") +message(STATUS " Build C++ library: ${BUILD_CPP}") +MESSAGE_DEP(WITH_CPP "Disabled by WITH_CPP=OFF") +MESSAGE_DEP(Boost_FOUND "Boost headers missing") +message(STATUS " C++ Language Level: ${CXX_LANGUAGE_LEVEL}") +message(STATUS " Build C (GLib) library: ${BUILD_C_GLIB}") +MESSAGE_DEP(WITH_C_GLIB "Disabled by WITH_C_GLIB=OFF") +MESSAGE_DEP(GLIB_FOUND "GLib missing") +message(STATUS " Build Java library: ${BUILD_JAVA}") +MESSAGE_DEP(WITH_JAVA "Disabled by WITH_JAVA=OFF") +if(ANDROID) + MESSAGE_DEP(GRADLE_FOUND "Gradle missing") +else() + MESSAGE_DEP(JAVA_FOUND "Java Runtime missing") + MESSAGE_DEP(ANT_FOUND "Ant missing") +endif() +message(STATUS " Build Python library: ${BUILD_PYTHON}") +MESSAGE_DEP(WITH_PYTHON "Disabled by WITH_PYTHON=OFF") +MESSAGE_DEP(PYTHONLIBS_FOUND "Python libraries missing") +message(STATUS " Build Haskell library: ${BUILD_HASKELL}") +MESSAGE_DEP(WITH_HASKELL "Disabled by WITH_HASKELL=OFF") +MESSAGE_DEP(GHC_FOUND "GHC missing") +MESSAGE_DEP(CABAL_FOUND "Cabal missing") +message(STATUS " Library features:") +message(STATUS " Build shared libraries: ${WITH_SHARED_LIB}") +message(STATUS " Build static libraries: ${WITH_STATIC_LIB}") +message(STATUS " Build with Boost static link library: ${WITH_BOOST_STATIC}") +message(STATUS " Build with Boost thread support: ${WITH_BOOSTTHREADS}") +message(STATUS " Build with boost/tr1/functional (forced) ${WITH_BOOST_FUNCTIONAL}") +message(STATUS " Build with boost/smart_ptr (forced) ${WITH_BOOST_SMART_PTR}") +message(STATUS " Build with C++ std::thread support: ${WITH_STDTHREADS}") +message(STATUS " Build with libevent support: ${WITH_LIBEVENT}") +message(STATUS " Build with OpenSSL support: ${WITH_OPENSSL}") +message(STATUS " Build with Qt4 support: ${WITH_QT4}") +message(STATUS " Build with Qt5 support: ${WITH_QT5}") +message(STATUS " Build with ZLIB support: ${WITH_ZLIB}") +message(STATUS "----------------------------------------------------------") +endmacro(PRINT_CONFIG_SUMMARY) diff --git a/build/cmake/DefinePlatformSpecifc.cmake b/build/cmake/DefinePlatformSpecifc.cmake new file mode 100644 index 0000000..f443489 --- /dev/null +++ b/build/cmake/DefinePlatformSpecifc.cmake @@ -0,0 +1,131 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Uncomment this to show some basic cmake variables about platforms +# include (NewPlatformDebug) + +# Visual Studio specific options +if(MSVC) + #For visual studio the library naming is as following: + # Dynamic libraries: + # - thrift.dll for release library + # - thriftd.dll for debug library + # + # Static libraries: + # - thriftmd.lib for /MD release build + # - thriftmt.lib for /MT release build + # + # - thriftmdd.lib for /MD debug build + # - thriftmtd.lib for /MT debug build + # + # the same holds for other libraries like libthriftz etc. + + # For Debug build types, append a "d" to the library names. + set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Set debug library postfix" FORCE) + set(CMAKE_RELEASE_POSTFIX "" CACHE STRING "Set release library postfix" FORCE) + set(CMAKE_RELWITHDEBINFO_POSTFIX "" CACHE STRING "Set release library postfix" FORCE) + + # Build using /MT option instead of /MD if the WITH_MT options is set + if(WITH_MT) + set(CompilerFlags + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_C_FLAGS + CMAKE_C_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_RELWITHDEBINFO + ) + foreach(CompilerFlag ${CompilerFlags}) + string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}") + endforeach() + set(STATIC_POSTFIX "mt" CACHE STRING "Set static library postfix" FORCE) + else(WITH_MT) + set(STATIC_POSTFIX "md" CACHE STRING "Set static library postfix" FORCE) + endif(WITH_MT) + + # Disable Windows.h definition of macros for min and max + add_definitions("-DNOMINMAX") + + # Disable boost auto linking pragmas - cmake includes the right files + add_definitions("-DBOOST_ALL_NO_LIB") + + # Windows build does not know how to make a shared library yet + # as there are no __declspec(dllexport) or exports files in the project. + if (WITH_SHARED_LIB) + message (FATAL_ERROR "Windows build does not support shared library output yet, please set -DWITH_SHARED_LIB=off") + endif() + + add_definitions("/MP") # parallel build + add_definitions("/W3") # warning level 3 + + # VS2010 does not provide inttypes which we need for "PRId64" used in many places + find_package(Inttypes) + if (Inttypes_FOUND) + include_directories(${INTTYPES_INCLUDE_DIRS}) + # OpenSSL conflicts with the definition of PRId64 unless it is defined first + add_definitions("/FIinttypes.h") + endif () +elseif(UNIX) + find_program( MEMORYCHECK_COMMAND valgrind ) + set( MEMORYCHECK_COMMAND_OPTIONS "--gen-suppressions=all --leak-check=full" ) + set( MEMORYCHECK_SUPPRESSIONS_FILE "${PROJECT_SOURCE_DIR}/test/valgrind.suppress" ) +endif() + +add_definitions("-D__STDC_FORMAT_MACROS") + +# WITH_*THREADS selects which threading library to use +if(WITH_BOOSTTHREADS) + add_definitions("-DUSE_BOOST_THREAD=1") +elseif(WITH_STDTHREADS) + add_definitions("-DUSE_STD_THREAD=1") +endif() + +# C++ Language Level +set(CXX_LANGUAGE_LEVEL "C++${CMAKE_CXX_STANDARD}") +if (CMAKE_CXX_STANDARD_REQUIRED) + string(CONCAT CXX_LANGUAGE_LEVEL "${CXX_LANGUAGE_LEVEL} [compiler must support it]") +else() + string(CONCAT CXX_LANGUAGE_LEVEL "${CXX_LANGUAGE_LEVEL} [fallback to earlier if compiler does not support it]") +endif() +if (CMAKE_CXX_EXTENSIONS) + string(CONCAT CXX_LANGUAGE_LEVEL "${CXX_LANGUAGE_LEVEL} [with compiler-specific extensions]") +else() + if ((CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") AND NOT MINGW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-variadic-macros -Wno-long-long") + endif() + if ((CMAKE_CXX_COMPILER_ID MATCHES "Clang") AND NOT MINGW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++11-long-long") + endif() +endif() + +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-register") +endif() + +# Building WITH_PLUGIN requires boost memory operations, for now, and gcc >= 4.8 +if (WITH_PLUGIN) + if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8") + message(SEND_ERROR "Thrift compiler plug-in support is not possible with older gcc ( < 4.8 ) compiler") + endif() + message(STATUS "Forcing use of boost::smart_ptr to build WITH_PLUGIN") + add_definitions("-DFORCE_BOOST_SMART_PTR=1") +endif() + diff --git a/build/cmake/FindAnt.cmake b/build/cmake/FindAnt.cmake new file mode 100644 index 0000000..8b0371d --- /dev/null +++ b/build/cmake/FindAnt.cmake @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +# ANT_FOUND - system has Ant +# Ant_EXECUTABLE - the Ant executable +# +# It will search the environment variable ANT_HOME if it is set + +include(FindPackageHandleStandardArgs) + +find_program(Ant_EXECUTABLE NAMES ant PATHS $ENV{ANT_HOME}/bin) +find_package_handle_standard_args(Ant DEFAULT_MSG Ant_EXECUTABLE) +mark_as_advanced(Ant_EXECUTABLE) diff --git a/build/cmake/FindCabal.cmake b/build/cmake/FindCabal.cmake new file mode 100644 index 0000000..fed337b --- /dev/null +++ b/build/cmake/FindCabal.cmake @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +# Cabal_FOUND - system has Cabal +# Cabal - the Cabal executable +# +# It will search the environment variable CABAL_HOME if it is set + +include(FindPackageHandleStandardArgs) + +find_program(CABAL NAMES cabal PATHS $ENV{HOME}/.cabal/bin $ENV{CABAL_HOME}/bin) +find_package_handle_standard_args(CABAL DEFAULT_MSG CABAL) +mark_as_advanced(CABAL) diff --git a/build/cmake/FindGHC.cmake b/build/cmake/FindGHC.cmake new file mode 100644 index 0000000..4873847 --- /dev/null +++ b/build/cmake/FindGHC.cmake @@ -0,0 +1,36 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +# GHC_FOUND - system has GHC +# GHC - the GHC executable +# RUN_HASKELL_FOUND - system has runhaskell +# RUN_HASKELL - the runhaskell executable +# +# It will search the environment variable GHC_HOME if it is set + +include(FindPackageHandleStandardArgs) + +find_program(GHC NAMES ghc PATHS $ENV{GHC_HOME}/bin) +find_package_handle_standard_args(GHC DEFAULT_MSG GHC) +mark_as_advanced(GHC) + +find_program(RUN_HASKELL NAMES runhaskell PATHS $ENV{GHC_HOME}/bin) +find_package_handle_standard_args(RUN_HASKELL DEFAULT_MSG RUN_HASKELL) +mark_as_advanced(RUN_HASKELL) diff --git a/build/cmake/FindGLIB.cmake b/build/cmake/FindGLIB.cmake new file mode 100644 index 0000000..acbe433 --- /dev/null +++ b/build/cmake/FindGLIB.cmake @@ -0,0 +1,122 @@ +# - Try to find Glib and its components (gio, gobject etc) +# Once done, this will define +# +# GLIB_FOUND - system has Glib +# GLIB_INCLUDE_DIRS - the Glib include directories +# GLIB_LIBRARIES - link these to use Glib +# +# Optionally, the COMPONENTS keyword can be passed to find_package() +# and Glib components can be looked for. Currently, the following +# components can be used, and they define the following variables if +# found: +# +# gio: GLIB_GIO_LIBRARIES +# gobject: GLIB_GOBJECT_LIBRARIES +# gmodule: GLIB_GMODULE_LIBRARIES +# gthread: GLIB_GTHREAD_LIBRARIES +# +# Note that the respective _INCLUDE_DIR variables are not set, since +# all headers are in the same directory as GLIB_INCLUDE_DIRS. +# +# Copyright (C) 2012 Raphael Kubo da Costa +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS +# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +find_package(PkgConfig) +pkg_check_modules(PC_GLIB QUIET glib-2.0) + +find_library(GLIB_LIBRARIES + NAMES glib-2.0 + HINTS ${PC_GLIB_LIBDIR} + ${PC_GLIB_LIBRARY_DIRS} +) + +# Files in glib's main include path may include glibconfig.h, which, +# for some odd reason, is normally in $LIBDIR/glib-2.0/include. +get_filename_component(_GLIB_LIBRARY_DIR ${GLIB_LIBRARIES} PATH) +find_path(GLIBCONFIG_INCLUDE_DIR + NAMES glibconfig.h + HINTS ${PC_LIBDIR} ${PC_LIBRARY_DIRS} ${_GLIB_LIBRARY_DIR} + ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} + PATH_SUFFIXES glib-2.0/include +) + +find_path(GLIB_INCLUDE_DIR + NAMES glib.h + HINTS ${PC_GLIB_INCLUDEDIR} + ${PC_GLIB_INCLUDE_DIRS} + PATH_SUFFIXES glib-2.0 +) + +set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIBCONFIG_INCLUDE_DIR}) + +if(GLIBCONFIG_INCLUDE_DIR) + # Version detection + file(READ "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h" GLIBCONFIG_H_CONTENTS) + string(REGEX MATCH "#define GLIB_MAJOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") + set(GLIB_VERSION_MAJOR "${CMAKE_MATCH_1}") + string(REGEX MATCH "#define GLIB_MINOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") + set(GLIB_VERSION_MINOR "${CMAKE_MATCH_1}") + string(REGEX MATCH "#define GLIB_MICRO_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") + set(GLIB_VERSION_MICRO "${CMAKE_MATCH_1}") + set(GLIB_VERSION "${GLIB_VERSION_MAJOR}.${GLIB_VERSION_MINOR}.${GLIB_VERSION_MICRO}") +endif() + +# Additional Glib components. We only look for libraries, as not all of them +# have corresponding headers and all headers are installed alongside the main +# glib ones. +foreach (_component ${GLIB_FIND_COMPONENTS}) + if (${_component} STREQUAL "gio") + find_library(GLIB_GIO_LIBRARIES NAMES gio-2.0 HINTS ${_GLIB_LIBRARY_DIR}) + set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GIO_LIBRARIES) + elseif (${_component} STREQUAL "gobject") + find_library(GLIB_GOBJECT_LIBRARIES NAMES gobject-2.0 HINTS ${_GLIB_LIBRARY_DIR}) + set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GOBJECT_LIBRARIES) + elseif (${_component} STREQUAL "gmodule") + find_library(GLIB_GMODULE_LIBRARIES NAMES gmodule-2.0 HINTS ${_GLIB_LIBRARY_DIR}) + set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GMODULE_LIBRARIES) + elseif (${_component} STREQUAL "gthread") + find_library(GLIB_GTHREAD_LIBRARIES NAMES gthread-2.0 HINTS ${_GLIB_LIBRARY_DIR}) + set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GTHREAD_LIBRARIES) + elseif (${_component} STREQUAL "gio-unix") + # gio-unix is compiled as part of the gio library, but the include paths + # are separate from the shared glib ones. Since this is currently only used + # by WebKitGTK+ we don't go to extraordinary measures beyond pkg-config. + pkg_check_modules(GIO_UNIX QUIET gio-unix-2.0) + endif () +endforeach () + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLIB REQUIRED_VARS GLIB_INCLUDE_DIRS GLIB_LIBRARIES ${ADDITIONAL_REQUIRED_VARS} + VERSION_VAR GLIB_VERSION) + +mark_as_advanced( + GLIBCONFIG_INCLUDE_DIR + GLIB_GIO_LIBRARIES + GLIB_GIO_UNIX_LIBRARIES + GLIB_GMODULE_LIBRARIES + GLIB_GOBJECT_LIBRARIES + GLIB_GTHREAD_LIBRARIES + GLIB_INCLUDE_DIR + GLIB_INCLUDE_DIRS + GLIB_LIBRARIES +) diff --git a/build/cmake/FindGradle.cmake b/build/cmake/FindGradle.cmake new file mode 100644 index 0000000..8845d69 --- /dev/null +++ b/build/cmake/FindGradle.cmake @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +# GRADLE_FOUND - system has Gradle +# GRADLE_EXECUTABLE - the Gradle executable +# +# It will search the environment variable ANT_HOME if it is set + +include(FindPackageHandleStandardArgs) + +find_program(GRADLE_EXECUTABLE NAMES gradle PATHS $ENV{GRADLE_HOME}/bin NO_CMAKE_FIND_ROOT_PATH) +find_package_handle_standard_args(Gradle DEFAULT_MSG GRADLE_EXECUTABLE) +mark_as_advanced(GRADLE_EXECUTABLE) diff --git a/build/cmake/FindInttypes.cmake b/build/cmake/FindInttypes.cmake new file mode 100644 index 0000000..e661f78 --- /dev/null +++ b/build/cmake/FindInttypes.cmake @@ -0,0 +1,41 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# find msinttypes on compilers that don't provide it, for example +# VS2010 + +# Usage: +# Provide INTTYPES_ROOT if you need it +# Result: INTTYPES_INCLUDE_DIRS, where to find inttypes.h +# Result: Inttypes_FOUND, If false, inttypes.h was not found + +find_path(INTTYPES_INCLUDE_DIRS inttypes.h HINTS ${INTTYPES_ROOT}) +if (INTTYPES_INCLUDE_DIRS) + set(Inttypes_FOUND TRUE) +else () + set(Inttypes_FOUND FALSE) + if (Inttypes_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find inttypes.h") + endif () + message(STATUS "inttypes.h NOT found") +endif () + +mark_as_advanced( + INTTYPES_INCLUDE_DIRS +) diff --git a/build/cmake/FindLibevent.cmake b/build/cmake/FindLibevent.cmake new file mode 100644 index 0000000..ac6a078 --- /dev/null +++ b/build/cmake/FindLibevent.cmake @@ -0,0 +1,45 @@ +# find LibEvent +# an event notification library (http://libevent.org/) +# +# Usage: +# LIBEVENT_INCLUDE_DIRS, where to find LibEvent headers +# LIBEVENT_LIBRARIES, LibEvent libraries +# Libevent_FOUND, If false, do not try to use libevent + +set(LIBEVENT_ROOT CACHE PATH "Root directory of libevent installation") +set(LibEvent_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}" ${LIBEVENT_ROOT}) +foreach(prefix ${LibEvent_EXTRA_PREFIXES}) + list(APPEND LibEvent_INCLUDE_PATHS "${prefix}/include") + list(APPEND LibEvent_LIBRARIES_PATHS "${prefix}/lib") +endforeach() + +# Looking for "event.h" will find the Platform SDK include dir on windows +# so we also look for a peer header like evhttp.h to get the right path +find_path(LIBEVENT_INCLUDE_DIRS evhttp.h event.h PATHS ${LibEvent_INCLUDE_PATHS}) + +# "lib" prefix is needed on Windows in some cases +# newer versions of libevent use three libraries +find_library(LIBEVENT_LIBRARIES NAMES event event_core event_extra libevent PATHS ${LibEvent_LIBRARIES_PATHS}) + +if (LIBEVENT_LIBRARIES AND LIBEVENT_INCLUDE_DIRS) + set(Libevent_FOUND TRUE) + set(LIBEVENT_LIBRARIES ${LIBEVENT_LIBRARIES}) +else () + set(Libevent_FOUND FALSE) +endif () + +if (Libevent_FOUND) + if (NOT Libevent_FIND_QUIETLY) + message(STATUS "Found libevent: ${LIBEVENT_LIBRARIES}") + endif () +else () + if (LibEvent_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find libevent.") + endif () + message(STATUS "libevent NOT found.") +endif () + +mark_as_advanced( + LIBEVENT_LIBRARIES + LIBEVENT_INCLUDE_DIRS + ) diff --git a/build/cmake/NewPlatformDebug.cmake b/build/cmake/NewPlatformDebug.cmake new file mode 100644 index 0000000..aa4d302 --- /dev/null +++ b/build/cmake/NewPlatformDebug.cmake @@ -0,0 +1,44 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# +# For debugging new platforms, just to see what some environment flags are... +# +macro(SHOWFLAG flag) + message(STATUS "${flag} = ${${flag}}") +endmacro(SHOWFLAG) + +set(NEWPLATFORMDEBUG ON) + +if(NEWPLATFORMDEBUG) + SHOWFLAG("APPLE") + SHOWFLAG("BORLAND") + SHOWFLAG("CMAKE_C_COMPILER_ID") + SHOWFLAG("CMAKE_CXX_COMPILER_ID") + SHOWFLAG("CMAKE_COMPILER_IS_GNUCC") + SHOWFLAG("CMAKE_COMPILER_IS_GNUCXX") + SHOWFLAG("CYGWIN") + SHOWFLAG("MINGW") + SHOWFLAG("MSVC") + SHOWFLAG("MSVC_VERSION") + SHOWFLAG("MSYS") + SHOWFLAG("UNIX") + SHOWFLAG("WATCOM") + SHOWFLAG("WIN32") +endif(NEWPLATFORMDEBUG) diff --git a/build/cmake/README-MSYS2.md b/build/cmake/README-MSYS2.md new file mode 100644 index 0000000..02679e6 --- /dev/null +++ b/build/cmake/README-MSYS2.md @@ -0,0 +1,63 @@ + + +# Building thrift on Windows (MinGW64/MSYS2) + +Thrift uses cmake to make it easier to build the project on multiple platforms, however to build a fully functional and production ready thrift on Windows requires a number of third party libraries to be obtained. Once third party libraries are ready, the right combination of options must be passed to cmake in order to generate the correct environment. + +> Note: libevent and libevent-devel do not work with this toolchain as they do not properly detect mingw64 and expect some headers to exist that do not, so the non-blocking server is not currently built into this solution. + +## MSYS2 + +Download and fully upgrade msys2 following the instructions at: + + https://msys2.github.io/ + +Install the necessary toolchain items for C++: + + $ pacman --needed -S bison flex make mingw-w64-x86_64-openssl \ + mingw-w64-x86_64-boost mingw-w64-x86_64-cmake \ + mingw-w64-x86_64-toolchain mingw-w64-x86_64-zlib + +Update your msys2 bash path to include /mingw64/bin by adding a line to your ~/.bash_profiles using this command: + + echo "export PATH=/mingw64/bin:\$PATH" >> ~/.bash_profile + +After that, close your shell and open a new one. + +Use cmake to create a MinGW makefile, out of tree (assumes you are in the top level of the thrift source tree): + + mkdir ../thrift-build + cd ../thrift-build + cmake -G"MinGW Makefiles" -DCMAKE_MAKE_PROGRAM=/mingw64/bin/mingw32-make \ + -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc.exe \ + -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++.exe \ + -DWITH_BOOSTTHREADS=ON -DWITH_LIBEVENT=OFF \ + -DWITH_SHARED_LIB=OFF -DWITH_STATIC_LIB=ON \ + -DWITH_JAVA=OFF -DWITH_PYTHON=OFF -DWITH_PERL=OFF \ + ../thrift + +Build thrift (inside thrift-build): + + cmake --build . + +Run the tests (inside thrift-build): + + ctest + +> If you run into issues, check Apache Jira THRIFT-4046 for patches relating to MinGW64/MSYS2 builds. + +## Tested With + +msys2 64-bit 2016-10-26 distribution diff --git a/build/cmake/README.md b/build/cmake/README.md new file mode 100644 index 0000000..ebc4f7d --- /dev/null +++ b/build/cmake/README.md @@ -0,0 +1,60 @@ +# Apache Thrift - CMake build + +## Goal +Extend Apache Thrift's *make cross* approach to the build system. + +Due to growing the field of operating system support, a proper executable +and library detection mechanism running on as much platforms as possible +becomes required. The other aspect to simplify the release process and +package generation process. + +As nice side benefit of CMake is the generation of development environment +specific soultion files. => No solution files within source tree. + + +## Usage +just do this: + + mkdir cmake-build && cd cmake-build + cmake .. + +if you use a specific toolchain pass it to cmake, the same for options: + + cmake -DCMAKE_TOOLCHAIN_FILE=../build/cmake/mingw32-toolchain.cmake .. + cmake -DCMAKE_C_COMPILER=clang-3.5 -DCMAKE_CXX_COMPILER=clang++-3.5 .. + cmake -DTHRIFT_COMPILER_HS=OFF .. + cmake -DWITH_ZLIB=ON .. + +or on Windows + + cmake -G "Visual Studio 12 2013 Win64" \ + -DBOOST_ROOT=C:/3rdparty/boost_1_58_0 \ + -DZLIB_ROOT=C:/3rdparty/zlib128-dll \ + -DWITH_SHARED_LIB=off -DWITH_BOOSTTHREADS=ON .. + +and open the development environment you like with the solution or do this: + + make + make check + make cross + make dist + +to generate an installer and distribution package do this: + + cpack + +## TODO +* git hash or tag based versioning depending on source state +* build tutorial +* build test +* with/without language lib// +* enable/disable +* make cross +* make dist (create an alias to make package_source) +* make doc +* cpack (C++ and make dist only ?) + * thrift-compiler + * libthrift + * tutorial + * test +* merge into /README.md diff --git a/build/cmake/ThriftMacros.cmake b/build/cmake/ThriftMacros.cmake new file mode 100644 index 0000000..f837f94 --- /dev/null +++ b/build/cmake/ThriftMacros.cmake @@ -0,0 +1,105 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Set debug library postfix" FORCE) + + +macro(ADD_LIBRARY_THRIFT name) + +if(WITH_SHARED_LIB) + add_library(${name} SHARED ${ARGN}) + set_target_properties(${name} PROPERTIES + OUTPUT_NAME ${name} + VERSION ${thrift_VERSION} + SOVERSION ${thrift_VERSION} ) + #set_target_properties(${name} PROPERTIES PUBLIC_HEADER "${thriftcpp_HEADERS}") + install(TARGETS ${name} + RUNTIME DESTINATION "${BIN_INSTALL_DIR}" + LIBRARY DESTINATION "${LIB_INSTALL_DIR}" + ARCHIVE DESTINATION "${LIB_INSTALL_DIR}" + PUBLIC_HEADER DESTINATION "${INCLUDE_INSTALL_DIR}") +endif() + +if(WITH_STATIC_LIB) + add_library(${name}_static STATIC ${ARGN}) + set_target_properties(${name}_static PROPERTIES + OUTPUT_NAME ${name}${STATIC_POSTFIX} + VERSION ${thrift_VERSION} + SOVERSION ${thrift_VERSION} ) + install(TARGETS ${name}_static + RUNTIME DESTINATION "${BIN_INSTALL_DIR}" + LIBRARY DESTINATION "${LIB_INSTALL_DIR}" + ARCHIVE DESTINATION "${LIB_INSTALL_DIR}" + PUBLIC_HEADER DESTINATION "${INCLUDE_INSTALL_DIR}") +endif() + +endmacro(ADD_LIBRARY_THRIFT) + + +macro(TARGET_INCLUDE_DIRECTORIES_THRIFT name) + +if(WITH_SHARED_LIB) + target_include_directories(${name} ${ARGN}) +endif() + +if(WITH_STATIC_LIB) + target_include_directories(${name}_static ${ARGN}) +endif() + +endmacro(TARGET_INCLUDE_DIRECTORIES_THRIFT) + + +macro(TARGET_LINK_LIBRARIES_THRIFT name) + +if(WITH_SHARED_LIB) + target_link_libraries(${name} ${ARGN}) +endif() + +if(WITH_STATIC_LIB) + target_link_libraries(${name}_static ${ARGN}) +endif() + +endmacro(TARGET_LINK_LIBRARIES_THRIFT) + + +macro(LINK_AGAINST_THRIFT_LIBRARY target libname) + +if (WITH_SHARED_LIB) + target_link_libraries(${target} ${libname}) +elseif (WITH_STATIC_LIB) + target_link_libraries(${target} ${libname}_static) +else() + message(FATAL "Not linking with shared or static libraries?") +endif() + +endmacro(LINK_AGAINST_THRIFT_LIBRARY) + + +macro(TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY target libname) + +if(WITH_SHARED_LIB) + target_link_libraries(${target} ${ARGN} ${libname}) +endif() + +if(WITH_STATIC_LIB) + target_link_libraries(${target}_static ${ARGN} ${libname}_static) +endif() + +endmacro(TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY) diff --git a/build/cmake/android-toolchain.cmake b/build/cmake/android-toolchain.cmake new file mode 100644 index 0000000..15f3d00 --- /dev/null +++ b/build/cmake/android-toolchain.cmake @@ -0,0 +1,26 @@ +set(ANDROID_NDK "/opt/android-ndk" CACHE) +set(ANDROID_PLATFORM "android-15" CACHE) +set(ANDROID_ARCH "arch-arm" CACHE) +set(ANDROID_TOOL_ARCH "android-arm" CACHE) +set(ANDROID_CPU "armeabi-v7a" CACHE) +set(ANDROID_GCC_VERSION 4.9 CACHE) +set(HOST_ARCH linux-x86_64 CACHE) + +set(CMAKE_SYSTEM_NAME Android) +set(ANDROID_SYSROOT "${ANDROID_NDK}/platforms/${ANDROID_PLATFORM}/${ANDROID_ARCH}") +set(ANDROID_TRIPLET arm-linux-androideabi) +set(ANDROID_STL "${ANDROID_NDK}/sources/cxx-stl/gnu-libstd++/${ANDROID_GCC_VERSION}") + +set(_COMPILER_ROOT ${ANDROID_NDK}/prebuilt/${ANDROID_TRIPLET}-${ANDROID_GCC_VERSION}/prebuilt/${HOST_ARCH}) +set(CMAKE_C_COMPILER ${_COMPILER_ROOT}/bin/${ANDROID_TRIPLET}-gcc) +set(CMAKE_CXCX_COMPILER ${_COMPILER_ROOT}/bin/${ANDROID_TRIPLET}-g++) + +include_directories( + ${ANDROID_STL}/include + ${ANDROID_STL}/libs/${ANDROID_CPU}/include) + +set(CMAKE_FIND_ROOT_PATH ${ANDROID_SYSROOT}) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/build/cmake/config.h.in b/build/cmake/config.h.in new file mode 100644 index 0000000..083bc55 --- /dev/null +++ b/build/cmake/config.h.in @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* config.h generated by CMake from config.h.in */ + +#ifndef CONFIG_H +#define CONFIG_H + + +/* Name of package */ +#cmakedefine PACKAGE "${PACKAGE}" + +/* Define to the address where bug reports for this package should be sent. */ +#cmakedefine PACKAGE_BUGREPORT "${PACKAGE_BUGREPORT}" + +/* Define to the full name of this package. */ +#cmakedefine PACKAGE_NAME "${PACKAGE_NAME}" + +/* Define to the one symbol short name of this package. */ +#cmakedefine PACKAGE_TARNAME "${PACKAGE_TARNAME}" + +/* Define to the home page for this package. */ +#cmakedefine PACKAGE_URL "${PACKAGE_URL}" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "${PACKAGE_VERSION}" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "${PACKAGE_STRING}" + +/************************** DEFINES *************************/ + +/* Define if the AI_ADDRCONFIG symbol is unavailable */ +#cmakedefine AI_ADDRCONFIG 0 + +/* Possible value for SIGNED_RIGHT_SHIFT_IS */ +/* TODO: This is just set to 1 for the moment + port the macro aclocal/ax_signed_right_shift.m4 to CMake to make this work */ +#define ARITHMETIC_RIGHT_SHIFT 1 + +/* Indicates the effect of the right shift operator on negative signed + integers */ +/* TODO: This is just set to 1 for the moment */ +#define SIGNED_RIGHT_SHIFT_IS 1 + +/* Use *.h extension for parser header file */ +/* TODO: This might now be necessary anymore as it is set only for automake < 1.11 + see: aclocal/ac_prog_bison.m4 */ +#cmakedefine BISON_USE_PARSER_H_EXTENSION 1 + +/* replaces POSIX pthread by boost::thread */ +#cmakedefine USE_BOOST_THREAD 1 + +/* replaces POSIX pthread by std::thread */ +#cmakedefine USE_STD_THREAD 1 + +/* Define to 1 if strerror_r returns char *. */ +#cmakedefine STRERROR_R_CHAR_P 1 + + +/************************** HEADER FILES *************************/ + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_FCNTL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_PTHREAD_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_UN_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_POLL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SCHED_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/*************************** FUNCTIONS ***************************/ + +/* Define to 1 if you have the `gethostbyname' function. */ +#cmakedefine HAVE_GETHOSTBYNAME 1 + +/* Define to 1 if you have the `gethostbyname_r' function. */ +#cmakedefine HAVE_GETHOSTBYNAME_R 1 + +/* Define to 1 if you have the `strerror_r' function. */ +#cmakedefine HAVE_STRERROR_R 1 + +/* Define to 1 if you have the `sched_get_priority_max' function. */ +#cmakedefine HAVE_SCHED_GET_PRIORITY_MAX 1 + +/* Define to 1 if you have the `sched_get_priority_min' function. */ +#cmakedefine HAVE_SCHED_GET_PRIORITY_MIN 1 + + +/* Define to 1 if strerror_r returns char *. */ +#cmakedefine STRERROR_R_CHAR_P 1 + +#endif diff --git a/build/cmake/mingw32-toolchain.cmake b/build/cmake/mingw32-toolchain.cmake new file mode 100644 index 0000000..864c0eb --- /dev/null +++ b/build/cmake/mingw32-toolchain.cmake @@ -0,0 +1,24 @@ +# CMake mingw32 cross compile toolchain file + +# the name of the target operating system +SET(CMAKE_SYSTEM_NAME Windows) + +# which compilers to use for C and C++ +SET(CMAKE_C_COMPILER i586-mingw32msvc-gcc) +SET(CMAKE_CXX_COMPILER i586-mingw32msvc-g++) +SET(CMAKE_RC_COMPILER i586-mingw32msvc-windres) + +# here is the target environment located +SET(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc) + +# adjust the default behaviour of the FIND_XXX() commands: +# search headers and libraries in the target environment, search +# programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +set(BUILD_SHARED_LIBS OFF) +SET(CMAKE_EXE_LINKER_FLAGS "-static") +set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-static-libgcc") +set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-static-libstdc++") diff --git a/build/docker/README.md b/build/docker/README.md new file mode 100644 index 0000000..a8d9501 --- /dev/null +++ b/build/docker/README.md @@ -0,0 +1,168 @@ +# Docker Integration # + +Due to the large number of language requirements to build Apache Thrift, docker containers are used to build and test the project on a variety of platforms to provide maximum test coverage. + +## Travis CI Integration ## + +The Travis CI scripts use the following environment variables and logic to determine their behavior. + +### Environment Variables ### + +| Variable | Default | Usage | +| -------- | ----- | ------- | +| `DISTRO` | `ubuntu-xenial` | Set by various build jobs in `.travis.yml` to run builds in different containers. Not intended to be set externally.| +| `DOCKER_REPO` | `thrift/thrift-build` | The name of the Docker Hub repository to obtain and store docker images. | +| `DOCKER_USER` | `` | The Docker Hub account name containing the repository. | +| `DOCKER_PASS` | `` | The Docker Hub account password to use when pushing new tags. | + +For example, the default docker image that is used in builds if no overrides are specified would be: `thrift/thrift-build:ubuntu-xenial` + +### Forks ### + +If you have forked the Apache Thrift repository and you would like to use your own Docker Hub account to store thrift build images, you can use the Travis CI web interface to set the `DOCKER_USER`, `DOCKER_PASS`, and `DOCKER_REPO` variables in a secure manner. Your fork builds will then pull, push, and tag the docker images in your account. + +### Logic ### + +The Travis CI build runs in two phases - first the docker images are rebuilt for each of the three supported containers if they do not match the Dockerfile that was used to build the most recent tag. If a `DOCKER_PASS` environment variable is specified, the docker stage builds will attempt to log into Docker Hub and push the resulting tags. + +## Supported Containers ## + +The Travis CI (continuous integration) builds use the Ubuntu Trusty, Xenial, and Artful images to maximize language level coverage. + +### Ubuntu ### + +* trusty (legacy) +* xenial (stable) +* artful (latest) + +## Unsupported Containers ## + +These containers may be in various states, and may not build everything. + +### CentOS ### +* 7.3 + * make check in lib/py may hang in test_sslsocket - root cause unknown + +### Debian ### + +* jessie +* stretch + * make check in lib/cpp fails due to https://svn.boost.org/trac10/ticket/12507 + +## Building like Travis CI does, locally ## + +We recommend you build locally the same way Travis CI does, so that when you submit your pull request you will run into fewer surprises. To make it a little easier, put the following into your `~/.bash_aliases` file: + + # Kill all running containers. + alias dockerkillall='docker kill $(docker ps -q)' + + # Delete all stopped containers. + alias dockercleanc='printf "\n>>> Deleting stopped containers\n\n" && docker rm $(docker ps -a -q)' + + # Delete all untagged images. + alias dockercleani='printf "\n>>> Deleting untagged images\n\n" && docker rmi $(docker images -q -f dangling=true)' + + # Delete all stopped containers and untagged images. + alias dockerclean='dockercleanc || true && dockercleani' + + # Build a thrift docker image (run from top level of git repo): argument #1 is image type (ubuntu, centos, etc). + function dockerbuild + { + docker build -t $1 build/docker/$1 + } + + # Run a thrift docker image: argument #1 is image type (ubuntu, centos, etc). + function dockerrun + { + docker run -v $(pwd):/thrift/src -it $1 /bin/bash + } + +To pull down the current image being used to build (the same way Travis CI does it) - if it is out of date in any way it will build a new one for you: + + thrift$ DOCKER_REPO=thrift/thrift-build DISTRO=ubuntu-xenial build/docker/refresh.sh + +To run all unit tests (just like Travis CI): + + thrift$ dockerrun ubuntu-xenial + root@8caf56b0ce7b:/thrift/src# build/docker/scripts/autotools.sh + +To run the cross tests (just like Travis CI): + + thrift$ dockerrun ubuntu-xenial + root@8caf56b0ce7b:/thrift/src# build/docker/scripts/cross-test.sh + +When you are done, you want to clean up occasionally so that docker isn't using lots of extra disk space: + + thrift$ dockerclean + +You need to run the docker commands from the root of the git repository for them to work. + +When you are done in the root docker shell you can `exit` to go back to your user host shell. Once the unit tests and cross test passes locally, then submit he changes, and squash the pull request to one commit to make it easier to merge. Thanks. I am going to update the docker README.md with this information so others can leverage it too. Now you are building like Travis CI does! + +## Raw Commands for Building with Docker ## + +If you do not want to use the same scripts Travis CI does, you can do it manually: + +Build the image: + + thrift$ docker build -t thrift build/docker/ubuntu-xenial + +Open a command prompt in the image: + + thrift$ docker run -v $(pwd):/thrift/src -it thrift /bin/bash + +## Core Tool Versions per Dockerfile ## + +Last updated: October 1, 2017 + +| Tool | ubuntu-trusty | ubuntu-xenial | ubuntu-artful | Notes | +| :-------- | :------------ | :------------ | :------------ | :---- | +| ant | 1.9.3 | 1.9.6 | 1.9.9 | | +| autoconf | 2.69 | 2.69 | 2.69 | | +| automake | 1.14.1 | 1.15 | 1.15 | | +| bison | 3.0.2 | 3.0.4 | 3.0.4 | | +| boost | 1.54.0 | 1.58.0 | 1.63.0 | artful: stock boost 1.62.0 has problems running unit tests | +| cmake | 3.2.2 | 3.5.1 | 3.9.1 | | +| cppcheck | 1.61 | 1.72 | 1.80 | | +| flex | 2.5.35 | 2.6.0 | 2.6.1 | | +| glibc | 2.19 | 2.23 | 2.26 | | +| libevent | 2.0.21 | 2.0.21 | 2.1 | | +| libstdc++ | 4.8.4 | 5.4.0 | 7.2.0 | | +| make | 3.81 | 4.1 | 4.1 | | +| openssl | 1.0.1f | 1.0.2g | 1.0.2g | | +| qt5 | 5.2.1 | 5.5.1 | 5.9.1 | | + +## Compiler/Language Versions per Dockerfile ## + +Last updated: October 1, 2017 + +| Language | ubuntu-trusty | ubuntu-xenial | ubuntu-artful | Notes | +| :-------- | :------------ | :------------ | :------------ | :---- | +| as3 | | | | Not in CI | +| C++ gcc | 4.8.4 | 5.4.0 | 7.2.0 | | +| C++ clang | 3.4 | 3.8 | 4.0 | | +| C# (mono) | 3.2.8.0 | 4.2.1 | 4.6.2.7 | | +| c_glib | 2.40.2 | 2.48.2 | 2.54.0 | | +| cocoa | | | | Not in CI | +| d | 2.070.2 | 2.073.2 | 2.076.0 | | +| dart | 1.20.1 | 1.24.2 | 1.24.2 | | +| delphi | | | | Not in CI | +| dotnet | | 2.0.3 | 2.0.3 | | +| erlang | R16B03 | 18.3 | 20.0.4 | | +| go | 1.2.1 | 1.6.2 | 1.8.3 | | +| haskell | 7.6.3 | 7.10.3 | 8.0.2 | | +| haxe | | 3.2.1 | 3.4.2 | disabled in trusty builds - cores on install v3.0.0, disabled in artful builds - see THRIFT-4352 | +| java | 1.7.0_151 | 1.8.0_131 | 1.8.0_151 | | +| js | | | | Unsure how to look for version info? | +| lua | 5.1.5 | 5.2.4 | 5.2.4 | Lua 5.3: see THRIFT-4386 | +| nodejs | | 4.2.6 | 8.9.1 | trusty has node.js 0.10.0 which is too old | +| ocaml | | 4.02.3 | 4.04.0 | | +| perl | 5.18.2 | 5.22.1 | 5.26.0 | | +| php | 5.5.9 | 7.0.22 | 7.1.8 | | +| python | 2.7.6 | 2.7.12 | 2.7.14 | | +| python3 | 3.4.3 | 3.5.2 | 3.6.3 | | +| ruby | 1.9.3p484 | 2.3.1p112 | 2.3.3p222 | | +| rust | 1.15.1 | 1.15.1 | 1.18.0 | | +| smalltalk | | | | Not in CI | +| swift | | | | Not in CI | + diff --git a/build/docker/Vagrantfile b/build/docker/Vagrantfile new file mode 100644 index 0000000..5eac6e6 --- /dev/null +++ b/build/docker/Vagrantfile @@ -0,0 +1,59 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Base system bootstrap script +$bootstrap_script = <<__BOOTSTRAP__ +echo "Provisioning defaults" + +sudo apt-get update -y +sudo apt-get upgrade -y + +# Install default packages +sudo apt-get install -y build-essential curl git + +# Install latest Docker version +sudo curl -sSL https://get.docker.io/gpg | sudo apt-key add - +sudo echo "deb http://get.docker.io/ubuntu docker main" > /etc/apt/sources.list.d/docker.list +sudo apt-get update -y +sudo apt-get install -y linux-image-extra-`uname -r` aufs-tools +sudo apt-get install -y lxc-docker + +echo "Finished provisioning defaults" +__BOOTSTRAP__ + +Vagrant.configure("2") do |config| + config.vm.box = "trusty64" + config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box" + config.ssh.forward_agent = true + + config.vm.provider :virtualbox do |vbox| + vbox.customize ["modifyvm", :id, "--memory", "1024"] + vbox.customize ["modifyvm", :id, "--cpus", "2"] + end + + # Setup the default bootstrap script for our ubuntu base box image + config.vm.provision "shell", inline: $bootstrap_script + + # Setup the custom docker image from our Ubuntu Dockerfile + config.vm.provision "docker" do |d| + d.build_image "/vagrant/ubuntu", args: "-t thrift" + end + + # Setup the custom docker image from our Centos Dockerfile + #config.vm.provision "docker" do |d| + # d.build_image "/vagrant/centos", args: "-t thrift-centos" + #end + +end diff --git a/build/docker/centos-7.3/Dockerfile b/build/docker/centos-7.3/Dockerfile new file mode 100644 index 0000000..096bbaa --- /dev/null +++ b/build/docker/centos-7.3/Dockerfile @@ -0,0 +1,199 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Apache Thrift Docker build environment for CentOS +# +# Known missing client libraries: +# - dotnet (will update to 2.0.0 separately) +# - haxe (not in centos) + +FROM centos:7.3.1611 +MAINTAINER Apache Thrift + +RUN yum install -y epel-release + +# General dependencies +RUN yum install -y \ + autoconf \ + bison \ + bison-devel \ + clang \ + clang-analyzer \ + cmake3 \ + curl \ + flex \ + gcc \ + gcc-c++ \ + gdb \ + git \ + libtool \ + m4 \ + make \ + tar \ + unzip \ + valgrind \ + wget && \ + ln -s /usr/bin/cmake3 /usr/bin/cmake && \ + ln -s /usr/bin/cpack3 /usr/bin/cpack && \ + ln -s /usr/bin/ctest3 /usr/bin/ctest + +# C++ dependencies +RUN yum install -y \ + boost-devel-static \ + zlib-devel \ + openssl-devel \ + libevent-devel && \ + cd /usr/lib64 && \ + ln -s libboost_thread-mt.a libboost_thread.a + +# C# Dependencies +RUN yum install -y \ + mono-core \ + mono-devel \ + mono-web-devel \ + mono-extras + +# D Dependencies +RUN yum install -y http://downloads.dlang.org/releases/2.x/2.076.0/dmd-2.076.0-0.fedora.x86_64.rpm xdg-utils +RUN curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \ + curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \ + mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ + mv libevent-master/deimos/* openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ + mv libevent-master/C/* openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \ + rm -rf libevent-master openssl-master + +# Dart +RUN cd /usr/local && \ + wget -q https://storage.googleapis.com/dart-archive/channels/stable/release/1.24.2/sdk/dartsdk-linux-x64-release.zip && \ + unzip -q dartsdk-linux-x64-release.zip && \ + rm dartsdk-linux-x64-release.zip +ENV PATH /usr/local/dart-sdk/bin:$PATH + +# Erlang Dependencies +RUN curl -sSL http://packages.erlang-solutions.com/rpm/centos/erlang_solutions.repo -o /etc/yum.repos.d/erlang_solutions.repo && \ + yum install -y \ + erlang-kernel \ + erlang-erts \ + erlang-stdlib \ + erlang-eunit \ + erlang-rebar \ + erlang-tools + +# GLibC Dependencies +RUN yum install -y glib2-devel + +# Go Dependencies +RUN curl -sSL https://storage.googleapis.com/golang/go1.9.linux-amd64.tar.gz | tar -C /usr/local/ -xz +ENV PATH /usr/local/go/bin:$PATH + +# Haskell Dependencies +RUN yum -y install haskell-platform + +# Haxe Dependencies +# Not in debian/stretch + +# Java Dependencies +RUN yum install -y \ + ant \ + junit \ + ant-junit \ + java-1.8.0-openjdk-devel + +# Lua Dependencies +# Lua in epel is too old (5.1.4, need 5.2) so we get the latest +RUN yum install -y readline-devel && \ + wget -q http://www.lua.org/ftp/lua-5.3.4.tar.gz && \ + tar xzf lua-5.3.4.tar.gz && \ + cd lua-5.3.4 && \ + sed -i 's/CFLAGS= /CFLAGS= -fPIC /g' src/Makefile && \ + make linux && \ + make install && \ + cd .. && \ + rm -rf lua-5* + +# MinGW Dependencies +RUN yum install -y \ + mingw32-binutils \ + mingw32-crt \ + mingw32-nsis + +# Node.js Dependencies +# Work around epel issue where they removed http-parser that nodejs depends on! +RUN yum -y install https://opensource.enda.eu/packages/http-parser-2.7.1-3.el7.x86_64.rpm +RUN yum install -y \ + nodejs \ + npm + +# Ocaml Dependencies +RUN yum install -y \ + ocaml \ + ocaml-ocamldoc && \ + wget -q https://raw.github.com/ocaml/opam/master/shell/opam_installer.sh -O - | sh -s /usr/local/bin && \ + opam init --yes && \ + opam install --yes oasis && \ + echo '. /root/.opam/opam-init/init.sh > /dev/null 2> /dev/null || true' >> ~/.bashrc + +# Perl Dependencies +RUN yum install -y \ + perl \ + perl-version \ + perl-Bit-Vector \ + perl-Class-Accessor \ + perl-ExtUtils-MakeMaker \ + perl-Test-Simple \ + perl-IO-Socket-SSL \ + perl-Net-SSLeay \ + perl-Crypt-SSLeay + +# PHP Dependencies +RUN yum install -y \ + php \ + php-devel \ + php-pear \ + re2c \ + php-phpunit-PHPUnit \ + bzip2 + +# Python Dependencies +RUN yum install -y \ + python \ + python-devel \ + python-pip \ + python-setuptools \ + python34 \ + python34-devel \ + python34-pip \ + python34-setuptools +RUN pip2 install --upgrade pip +RUN pip2 install --upgrade backports.ssl_match_hostname ipaddress setuptools six tornado tornado-testing twisted virtualenv zope-interface +RUN pip3 install --upgrade pip +RUN pip3 install --upgrade backports.ssl_match_hostname ipaddress setuptools six tornado tornado-testing twisted virtualenv zope-interface + +# Ruby Dependencies +RUN yum install -y \ + ruby \ + ruby-devel \ + rubygems && \ + gem install bundler rake + +# Rust +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.17.0 +ENV PATH /root/.cargo/bin:$PATH + +# Clean up +RUN rm -rf /tmp/* && \ + yum clean all + +ENV THRIFT_ROOT /thrift +RUN mkdir -p $THRIFT_ROOT/src +COPY Dockerfile $THRIFT_ROOT/ +WORKDIR $THRIFT_ROOT/src diff --git a/build/docker/debian-jessie/Dockerfile b/build/docker/debian-jessie/Dockerfile new file mode 100644 index 0000000..7bc74fc --- /dev/null +++ b/build/docker/debian-jessie/Dockerfile @@ -0,0 +1,204 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Apache Thrift Docker build environment for Debian +# +# Known missing client libraries: +# - dotnetcore +# - rust + +FROM buildpack-deps:jessie-scm +MAINTAINER Apache Thrift + +ENV DEBIAN_FRONTEND noninteractive + +# Add apt sources +# jessie-backports for cmake and some ruby bits +RUN echo "deb http://ftp.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/jessie-backports.list + +# Dart +RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ + curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list && \ + sed -i /etc/apt/sources.list.d/dart_stable.list -e 's/https:/http:/g' + +RUN apt-get update && apt-get install -y --no-install-recommends \ +`# General dependencies` \ + bison \ + build-essential \ + clang \ + debhelper \ + flex \ + pkg-config && \ + apt-get -t jessie-backports install -y --no-install-recommends cmake + +RUN apt-get install -y --no-install-recommends \ +`# C++ dependencies` \ + libboost-dev \ + libboost-filesystem-dev \ + libboost-program-options-dev \ + libboost-system-dev \ + libboost-test-dev \ + libboost-thread-dev \ + libevent-dev \ + libssl-dev \ + qt5-default \ + qtbase5-dev \ + qtbase5-dev-tools + +RUN apt-get install -y --no-install-recommends \ +`# Java dependencies` \ + ant \ + ant-optional \ + openjdk-7-jdk \ + maven + +RUN apt-get install -y --no-install-recommends \ +`# Python dependencies` \ + python-all \ + python-all-dbg \ + python-all-dev \ + python-pip \ + python-setuptools \ + python-twisted \ + python-zope.interface \ + python3-all \ + python3-all-dbg \ + python3-all-dev \ + python3-setuptools \ + python3-pip + +RUN apt-get install -y --no-install-recommends \ +`# Ruby dependencies` \ + ruby \ + ruby-dev \ +`# Perl dependencies` \ + libbit-vector-perl \ + libclass-accessor-class-perl \ + libcrypt-ssleay-perl \ + libio-socket-ssl-perl \ + libnet-ssleay-perl + +RUN apt-get -t jessie-backports install -y ruby-bundler +RUN apt-get install -y --no-install-recommends \ +`# Php dependencies` \ + php5 \ + php5-dev \ + php5-cli \ + php-pear \ + re2c \ + phpunit \ +`# GlibC dependencies` \ + libglib2.0-dev + +RUN apt-get update && apt-get install -y --no-install-recommends \ +`# Erlang dependencies` \ + erlang-base \ + erlang-eunit \ + erlang-dev \ + erlang-tools \ + rebar + +RUN apt-get update && apt-get install -y --no-install-recommends \ +`# Haskell dependencies` \ + ghc \ + cabal-install \ +`# Haxe dependencies` \ + neko \ + neko-dev \ + libneko0 + +RUN apt-get update && apt-get install -y --no-install-recommends \ +`# Node.js dependencies` \ + nodejs \ + nodejs-dev \ + nodejs-legacy \ + npm + +RUN apt-get update && apt-get install -y --no-install-recommends \ +`# CSharp dependencies` \ + libmono-system-web2.0-cil \ + mono-devel + +RUN apt-get update && apt-get install -y --no-install-recommends \ +`# D dependencies` \ + xdg-utils \ +`# Dart dependencies` \ + dart \ +`# Lua dependencies` \ + lua5.2 \ + lua5.2-dev \ +`# MinGW dependencies` \ + mingw32 \ + mingw32-binutils \ +`# mingw32-runtime` \ + nsis \ +`# Clean up` \ + && rm -rf /var/cache/apt/* && \ + rm -rf /var/lib/apt/lists/* && \ + rm -rf /tmp/* && \ + rm -rf /var/tmp/* + +# Ruby +RUN gem install bundler --no-ri --no-rdoc + +# Python optional dependencies +RUN pip2 install -U ipaddress backports.ssl_match_hostname tornado +RUN pip3 install -U backports.ssl_match_hostname tornado + +# Go +RUN curl -sSL https://storage.googleapis.com/golang/go1.4.3.linux-amd64.tar.gz | tar -C /usr/local/ -xz +ENV PATH /usr/local/go/bin:$PATH + +# Haxe +RUN mkdir -p /usr/lib/haxe && \ + wget -O - https://github.com/HaxeFoundation/haxe/releases/download/3.2.1/haxe-3.2.1-linux64.tar.gz | \ + tar -C /usr/lib/haxe --strip-components=1 -xz && \ + ln -s /usr/lib/haxe/haxe /usr/bin/haxe && \ + ln -s /usr/lib/haxe/haxelib /usr/bin/haxelib && \ + mkdir -p /usr/lib/haxe/lib && \ + chmod -R 777 /usr/lib/haxe/lib && \ + haxelib setup /usr/lib/haxe/lib && \ + haxelib install hxcpp + +# D +RUN curl -sSL http://downloads.dlang.org/releases/2.x/2.070.0/dmd_2.070.0-0_amd64.deb -o /tmp/dmd_2.070.0-0_amd64.deb && \ + dpkg -i /tmp/dmd_2.070.0-0_amd64.deb && \ + rm /tmp/dmd_2.070.0-0_amd64.deb && \ + curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \ + curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \ + mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ + mv libevent-master/deimos/* openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ + mv libevent-master/C/* openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \ + rm -rf libevent-master openssl-master && \ + echo 'gcc -Wl,--no-as-needed $*' > /usr/local/bin/gcc-dmd && \ + chmod 755 /usr/local/bin/gcc-dmd && \ + echo 'CC=/usr/local/bin/gcc-dmd' >> /etc/dmd.conf + +# Dart +ENV PATH /usr/lib/dart/bin:$PATH + +# OCaml +RUN echo 'deb http://ppa.launchpad.net/avsm/ppa/ubuntu trusty main' > /etc/apt/sources.list.d/avsm-official-ocaml.list && \ + gpg --keyserver keyserver.ubuntu.com --recv 61707B09 && \ + gpg --export --armor 61707B09 | apt-key add - && \ + apt-get update && \ + apt-get install -y ocaml opam && \ + opam init && \ + opam install oasis + +# Force utf8 locale to successfully build Haskell tf-random +ENV LC_ALL C.UTF-8 + +ENV THRIFT_ROOT /thrift +RUN mkdir -p $THRIFT_ROOT/src +COPY Dockerfile $THRIFT_ROOT/ +WORKDIR $THRIFT_ROOT/src diff --git a/build/docker/debian-stretch/Dockerfile b/build/docker/debian-stretch/Dockerfile new file mode 100644 index 0000000..503eecd --- /dev/null +++ b/build/docker/debian-stretch/Dockerfile @@ -0,0 +1,231 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Apache Thrift Docker build environment for Debian Stretch +# +# Known issues: +# - d: deimos for libevent and openssl disabled - build errors +# - dotnetcore, because netcore is for 1.0.0-preview and 2.0.0 is out +# - rust: cargo not in debian repo - perhaps not needed? + +FROM buildpack-deps:stretch-scm +MAINTAINER Apache Thrift + +ENV DEBIAN_FRONTEND noninteractive + +### Add apt repos + +RUN apt-get update && apt-get install -y --no-install-recommends apt apt-transport-https curl wget apt-utils + +# D +RUN wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list && \ + apt-get update && apt-get -y --allow-unauthenticated install --reinstall d-apt-keyring + +# Dart +RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ + curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list && \ + sed -i /etc/apt/sources.list.d/dart_stable.list -e 's/https:/http:/g' + +# dotnet (core) 2.0.0 - project isn't ready for this yet: +# RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \ +# echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > /etc/apt/sources.list.d/dotnetdev.list + +# node.js (this step runs apt-get update internally) +RUN curl -sL https://deb.nodesource.com/setup_8.x | bash + + +### install general dependencies +RUN apt-get install -y --no-install-recommends \ +`# General dependencies` \ + bash-completion \ + bison \ + build-essential \ + clang \ + cmake \ + debhelper \ + flex \ + gdb \ + ninja-build \ + pkg-config \ + valgrind \ + vim + + +### languages + +RUN apt-get install -y --no-install-recommends \ +`# C++ dependencies` \ + libboost-dev \ + libboost-filesystem-dev \ + libboost-program-options-dev \ + libboost-system-dev \ + libboost-test-dev \ + libboost-thread-dev \ + libevent-dev \ + libssl-dev \ + qt5-default \ + qtbase5-dev \ + qtbase5-dev-tools + +RUN apt-get install -y --no-install-recommends \ +`# csharp (mono) dependencies` \ + mono-devel + +RUN apt-get install -y --no-install-recommends \ +`# D dependencies` \ + dmd-bin \ + libevent-dev \ + libssl-dev \ + xdg-utils +# libevent deimos disabled - build errors +# RUN mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ +# curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \ +# mv libevent-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ +# mv libevent-master/C/* /usr/include/dmd/druntime/import/C/ && \ +# rm -rf libevent-master +# openssl deimos doesn't work with openssl-1.1.0 - disabling it for now: +# RUN curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \ +# mv openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ +# mv openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \ +# rm -rf openssl-master + +RUN apt-get install -y --no-install-recommends \ +`# Dart dependencies` \ + dart +ENV PATH /usr/lib/dart/bin:$PATH + +# project isn't ready for this quite yet: +# RUN apt-get install -y --no-install-recommends \ +# `# dotnet core dependencies` \ +# dotnet-sdk-2.0.0 + +RUN apt-get install -y --no-install-recommends \ +`# Erlang dependencies` \ + erlang-base \ + erlang-eunit \ + erlang-dev \ + erlang-tools \ + rebar + +RUN apt-get install -y --no-install-recommends \ +`# GlibC dependencies` \ + libglib2.0-dev + +RUN apt-get install -y --no-install-recommends \ +`# golang (go) dependencies` \ + golang-go + +RUN apt-get install -y --no-install-recommends \ +`# Haskell dependencies` \ + ghc \ + cabal-install + +RUN apt-get install -y --no-install-recommends \ +`# Haxe dependencies` \ + haxe \ + neko \ + neko-dev +RUN haxelib setup --always /usr/share/haxe/lib && \ + haxelib install --always hxcpp + +RUN apt-get install -y --no-install-recommends \ +`# Java dependencies` \ + ant \ + ant-optional \ + openjdk-8-jdk \ + maven + +RUN apt-get install -y --no-install-recommends \ +`# Lua dependencies` \ + lua5.2 \ + lua5.2-dev +# https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212 +# same for debian stretch +# lua5.3 does not install alternatives so stick with 5.2 here + +RUN apt-get install -y --no-install-recommends \ +`# Node.js dependencies` \ + nodejs + +RUN apt-get install -y --no-install-recommends \ +`# OCaml dependencies` \ + ocaml \ + opam && \ + opam init --yes && \ + opam install --yes oasis + +RUN apt-get install -y --no-install-recommends \ +`# Perl dependencies` \ + libbit-vector-perl \ + libclass-accessor-class-perl \ + libcrypt-ssleay-perl \ + libio-socket-ssl-perl \ + libnet-ssleay-perl + +RUN apt-get install -y --no-install-recommends \ +`# Php dependencies` \ + php7.0 \ + php7.0-cli \ + php7.0-dev \ + php-pear \ + re2c \ + phpunit + +RUN apt-get install -y --no-install-recommends \ +`# Python dependencies` \ + python-all \ + python-all-dbg \ + python-all-dev \ + python-backports.ssl-match-hostname \ + python-ipaddress \ + python-pip \ + python-setuptools \ + python-six \ + python-tornado \ + python-twisted \ + python-wheel \ + python-zope.interface \ + python3-all \ + python3-all-dbg \ + python3-all-dev \ + python3-setuptools \ + python3-six \ + python3-tornado \ + python3-twisted \ + python3-wheel \ + python3-zope.interface && \ + pip install --upgrade backports.ssl_match_hostname + +RUN apt-get install -y --no-install-recommends \ +`# Ruby dependencies` \ + ruby \ + ruby-dev \ + ruby-bundler +RUN gem install bundler --no-ri --no-rdoc + +RUN apt-get install -y --no-install-recommends \ +`# Rust dependencies` \ + rustc + +# Update anything else left hanging +RUN apt-get dist-upgrade -y + +# Clean up +RUN rm -rf /var/cache/apt/* && \ + rm -rf /var/lib/apt/lists/* && \ + rm -rf /tmp/* && \ + rm -rf /var/tmp/* + +ENV THRIFT_ROOT /thrift +RUN mkdir -p $THRIFT_ROOT/src +COPY Dockerfile $THRIFT_ROOT/ +WORKDIR $THRIFT_ROOT/src diff --git a/build/docker/refresh.sh b/build/docker/refresh.sh new file mode 100755 index 0000000..08cbc91 --- /dev/null +++ b/build/docker/refresh.sh @@ -0,0 +1,82 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# +# The build has two stages: "docker" and "test" +# The "docker" stage is meant to rebuild the docker images +# if needed. If we cannot push that result however then +# there is no reason to do anything. +# The "test" stage is an actual test job. Even if the docker +# image doesn't match what's in the repo, we still build +# the image so the build job can run properly. +# + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DOCKER_TAG=$DOCKER_REPO:$DISTRO + +function dockerfile_changed { + # image may not exist yet, so we have to let it fail silently: + docker pull $DOCKER_TAG || true + docker run $DOCKER_TAG bash -c 'cd .. && sha512sum Dockerfile' > .Dockerfile.sha512 + sha512sum -c .Dockerfile.sha512 +} + +# +# If this build has no DOCKER_PASS and it is in the docker stage +# then there's no reason to do any processing because we cannot +# push the result if the Dockerfile changed. +# + +if [[ "$TRAVIS_BUILD_STAGE" == "docker" ]] && [[ -z "$DOCKER_PASS" ]]; then + echo Detected docker stage build and no defined DOCKER_PASS, this build job will be skipped. + echo Subsequent jobs in the test stage may each rebuild the docker image. + exit 0 +fi + + +pushd ${SCRIPT_DIR}/$DISTRO +if dockerfile_changed; then + echo Dockerfile has not changed. No need to rebuild. + exit 0 +else + echo Dockerfile has changed. +fi +popd + +# +# Dockerfile has changed - rebuild it for the current build job. +# If it is a "docker" stage build then we want to push it back +# to the DOCKER_REPO. If it is a "test" stage build then we do +# not. If nobody defined a DOCKER_PASS then it doesn't matter. +# + +echo Rebuilding docker image $DISTRO +docker build --tag $DOCKER_TAG build/docker/$DISTRO + +if [[ "$TRAVIS_BUILD_STAGE" == "docker" ]] && [[ ! -z "$DOCKER_USER" ]] && [[ ! -z "$DOCKER_PASS" ]]; then + echo Pushing docker image $DOCKER_TAG + docker login -u $DOCKER_USER -p $DOCKER_PASS + docker push $DOCKER_TAG +else + echo Not pushing docker image: either not a docker stage build job, or one of DOCKER_USER or DOCKER_PASS is undefined. +fi + diff --git a/build/docker/run.sh b/build/docker/run.sh new file mode 100755 index 0000000..1fe19d5 --- /dev/null +++ b/build/docker/run.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DOCKER_TAG=$DOCKER_REPO:$DISTRO + +printenv | sort + +docker run --net=host -e BUILD_LIBS="$BUILD_LIBS" $BUILD_ENV -v $(pwd):/thrift/src \ + -it $DOCKER_TAG build/docker/scripts/$SCRIPT $BUILD_ARG + diff --git a/build/docker/scripts/autotools.sh b/build/docker/scripts/autotools.sh new file mode 100755 index 0000000..8388f72 --- /dev/null +++ b/build/docker/scripts/autotools.sh @@ -0,0 +1,6 @@ +#!/bin/sh +set -ev + +./bootstrap.sh +./configure $* +make check -j3 diff --git a/build/docker/scripts/cmake.sh b/build/docker/scripts/cmake.sh new file mode 100755 index 0000000..ccc311e --- /dev/null +++ b/build/docker/scripts/cmake.sh @@ -0,0 +1,23 @@ +#!/bin/sh +set -ev + +CMAKE_FLAGS=$* +MAKEPROG=make + +if ninja --version >/dev/null 2>&1; then + MAKEPROG=ninja + CMAKE_FLAGS="-GNinja $CMAKE_FLAGS" +fi + +mkdir -p cmake_build && cd cmake_build +cmake $CMAKE_FLAGS .. +for LIB in $BUILD_LIBS; do + if ! grep "^BUILD_${LIB}:BOOL=ON$" CMakeCache.txt ; then + echo "failed to configure $LIB" + exit 1 + fi +done +$MAKEPROG -j3 +cpack +ctest -VV -E "(python_test)" +# disabled cmake python_test for now since it fails in travis under centos diff --git a/build/docker/scripts/cross-test.sh b/build/docker/scripts/cross-test.sh new file mode 100755 index 0000000..43581a5 --- /dev/null +++ b/build/docker/scripts/cross-test.sh @@ -0,0 +1,16 @@ +#!/bin/sh +set -ev + +./bootstrap.sh +./configure --enable-tutorial=no +make -j3 precross + +set +e +make cross$1 + +RET=$? +if [ $RET -ne 0 ]; then + cat test/log/unexpected_failures.log +fi + +exit $RET diff --git a/build/docker/scripts/dpkg.sh b/build/docker/scripts/dpkg.sh new file mode 100755 index 0000000..3ba0cd4 --- /dev/null +++ b/build/docker/scripts/dpkg.sh @@ -0,0 +1,5 @@ +#!/bin/sh +set -ev + +dpkg-buildpackage -tc -us -uc +ls -al .. diff --git a/build/docker/scripts/make-dist.sh b/build/docker/scripts/make-dist.sh new file mode 100755 index 0000000..5a3681e --- /dev/null +++ b/build/docker/scripts/make-dist.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -ev + +./bootstrap.sh +./configure $* +make dist +tar xvf thrift-*.tar.gz +cd thrift-* +./build/docker/scripts/cmake.sh diff --git a/build/docker/scripts/sca.sh b/build/docker/scripts/sca.sh new file mode 100755 index 0000000..38803d4 --- /dev/null +++ b/build/docker/scripts/sca.sh @@ -0,0 +1,62 @@ +#!/bin/sh +set -ev + +# +# Generate thrift files so the static code analysis includes an analysis +# of the files the thrift compiler spits out. If running interactively +# set the NOBUILD environment variable to skip the boot/config/make phase. +# + +if [[ -z "$NOBUILD" ]]; then + ./bootstrap.sh + ./configure --enable-tutorial=no + make -j3 precross +fi + +# +# C/C++ static code analysis with cppcheck +# add --error-exitcode=1 to --enable=all as soon as everything is fixed +# +# Python code style check with flake8 +# +# search for TODO etc within source tree +# some statistics about the code base +# some info about the build machine + +# Compiler cppcheck (All) +cppcheck --force --quiet --inline-suppr --enable=all -j2 compiler/cpp/src + +# C++ cppcheck (All) +cppcheck --force --quiet --inline-suppr --enable=all -j2 lib/cpp/src lib/cpp/test test/cpp tutorial/cpp + +# C Glib cppcheck (All) +cppcheck --force --quiet --inline-suppr --enable=all -j2 lib/c_glib/src lib/c_glib/test test/c_glib/src tutorial/c_glib + +# Silent error checks +# See THRIFT-4371 : flex generated code triggers "possible null pointer dereference" in yy_init_buffer +cppcheck --force --quiet --inline-suppr --suppress="*:thrift/thriftl.cc" --error-exitcode=1 -j2 compiler/cpp/src +cppcheck --force --quiet --inline-suppr --error-exitcode=1 -j2 lib/cpp/src lib/cpp/test test/cpp tutorial/cpp +cppcheck --force --quiet --inline-suppr --error-exitcode=1 -j2 lib/c_glib/src lib/c_glib/test test/c_glib/src tutorial/c_glib + +# Python code style +flake8 --ignore=E501 lib/py +flake8 tutorial/py +# THRIFT-4371 : generated files are excluded because they haven't been scrubbed yet +flake8 --ignore=E501 --exclude="*/gen-py*/*" test/py +flake8 test/py.twisted +flake8 test/py.tornado +flake8 --ignore=E501 test/test.py +flake8 --ignore=E501,E722 test/crossrunner +flake8 test/features + +# TODO etc +echo FIXMEs: `grep -r FIXME * | wc -l` +echo HACKs: `grep -r HACK * | wc -l` +echo TODOs: `grep -r TODO * | wc -l` + +# LoC +sloccount . + +# System Info +dpkg -l +uname -a diff --git a/build/docker/scripts/ubsan.sh b/build/docker/scripts/ubsan.sh new file mode 100755 index 0000000..650dba0 --- /dev/null +++ b/build/docker/scripts/ubsan.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +set -e + +# Wraps autotools.sh, but each binary crashes if it exhibits undefined behavior. +# Set the undefined behavior flags. This crashes on all undefined behavior except for +# undefined casting, aka "vptr". +# TODO: fix undefined vptr behavior and turn this option back on. + +export CFLAGS="-fsanitize=undefined -fno-sanitize-recover=undefined -O0 -ggdb3 -fno-omit-frame-pointer" +export CXXFLAGS="${CFLAGS}" +export LDFLAGS="-lubsan" +export UBSAN_OPTIONS=print_stacktrace=1 + +# +# work around https://svn.boost.org/trac10/ticket/11632 if present +# + +sed -i 's/, stream_t(rdbuf()) /, stream_t(pbase_type::member.get())/g' /usr/include/boost/format/alt_sstream.hpp + +# llvm-symbolizer must be on PATH to get a stack trace on error + +CLANG_PATH="$(mktemp -d)" +trap "rm -rf ${CLANG_PATH}" EXIT +ln -s "$(whereis llvm-symbolizer-4.0 | rev | cut -d ' ' -f 1 | rev)" \ + "${CLANG_PATH}/llvm-symbolizer" +export PATH="${CLANG_PATH}:${PATH}" +llvm-symbolizer -version + +build/docker/scripts/autotools.sh $* diff --git a/build/docker/ubuntu-artful/Dockerfile b/build/docker/ubuntu-artful/Dockerfile new file mode 100644 index 0000000..cba2902 --- /dev/null +++ b/build/docker/ubuntu-artful/Dockerfile @@ -0,0 +1,254 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Apache Thrift Docker build environment for Ubuntu Artful +# Using all stock Ubuntu Artful packaging except for: +# - cpp: stock boost 1.62 in artful has a nasty bug so we use stock boost 1.63 +# - d: does not come with Ubuntu so we're installing the latest +# - d: deimos for libevent and openssl omitted - not compatible / build errors +# - haxe: see THRIFT-4352, but test/haxe cores during testing +# and hxcpp 3.4.64 is not compatible with artful +# + +FROM buildpack-deps:artful-scm +MAINTAINER Apache Thrift +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update && \ + apt-get dist-upgrade -y && \ + apt-get install -y --no-install-recommends \ + apt \ + apt-transport-https \ + apt-utils \ + curl \ + dirmngr \ + software-properties-common \ + wget + +# csharp (mono) - if we ever want a later version +# RUN echo "deb http://download.mono-project.com/repo/debian xenial main" | tee /etc/apt/sources.list.d/mono.list && \ +# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A6A19B38D3D831EF + +# dotnet (core) +RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \ + echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-artful-prod artful main" > /etc/apt/sources.list.d/dotnetdev.list + +# node.js (this step runs apt-get update internally) - if we ever want a later version +RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - + +### install general dependencies +RUN apt-get install -y --no-install-recommends \ +`# General dependencies` \ + bash-completion \ + bison \ + build-essential \ + clang \ + cmake \ + debhelper \ + flex \ + gdb \ + llvm \ + ninja-build \ + pkg-config \ + valgrind \ + vim +ENV PATH /usr/lib/llvm-3.8/bin:$PATH + +# boost-1.62 has a terrible bug in boost::test, see https://svn.boost.org/trac10/ticket/12507 +RUN apt-get install -y --no-install-recommends \ +`# C++ dependencies` \ + libboost1.63-all-dev \ + libevent-dev \ + libssl-dev \ + qt5-default \ + qtbase5-dev \ + qtbase5-dev-tools + +RUN apt-get install -y --no-install-recommends \ +`# csharp (mono) dependencies` \ + mono-devel + +RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EBCF975E5BA24D5E && \ + wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list && \ + wget -qO - https://dlang.org/d-keyring.gpg | apt-key add - && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + `# D dependencies` \ + dmd-bin \ + libphobos2-dev \ + dub \ + dfmt \ + dscanner \ + libevent-dev \ + libssl-dev \ + xdg-utils +# libevent deimos doesn't seem to work so not enabling it: +# RUN mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ +# curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \ +# mv libevent-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ +# mv libevent-master/C/* /usr/include/dmd/druntime/import/C/ && \ +# rm -rf libevent-master +# openssl deimos doesn't work with openssl-1.0.2 so not enabling it: +# RUN curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \ +# mv openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ +# mv openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \ +# rm -rf openssl-master + +# dart cannot be downloaded by aptitude because of +# https://github.com/dart-lang/sdk/issues/30512 +# RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ +# curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list && \ +# apt-get update && \ +# apt-get install -y --no-install-recommends \ +# `# Dart dependencies` \ +# dart +# so instead we do: +RUN wget https://storage.googleapis.com/dart-archive/channels/stable/release/latest/linux_packages/dart_1.24.2-1_amd64.deb && \ + dpkg -i dart_1.24.2-1_amd64.deb && \ + rm dart_1.24.2-1_amd64.deb +ENV PATH /usr/lib/dart/bin:$PATH + +RUN apt-get install -y --no-install-recommends \ +`# dotnet core dependencies` \ + dotnet-sdk-2.0.3 + +RUN apt-get install -y --no-install-recommends \ +`# Erlang dependencies` \ + erlang-base \ + erlang-eunit \ + erlang-dev \ + erlang-tools \ + rebar + +RUN apt-get install -y --no-install-recommends \ +`# GlibC dependencies` \ + libglib2.0-dev + +RUN apt-get install -y --no-install-recommends \ +`# golang (go) dependencies` \ + golang-go \ + golang-race-detector-runtime + +RUN apt-get install -y --no-install-recommends \ +`# Haskell dependencies` \ + ghc \ + cabal-install + +# see THRIFT-4352, test/haxe cores on artful +# RUN apt-get install -y --no-install-recommends \ +# `# Haxe dependencies` \ +# haxe \ +# neko \ +# neko-dev +# RUN haxelib setup --always /usr/share/haxe/lib && \ +# haxelib install --always hxcpp + +RUN apt-get install -y --no-install-recommends \ +`# Java dependencies` \ + ant \ + ant-optional \ + openjdk-8-jdk \ + maven + +RUN apt-get install -y --no-install-recommends \ +`# Lua dependencies` \ + lua5.2 \ + lua5.2-dev +# https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212 +# lua5.3 does not install alternatives! +# need to update our luasocket code, lua doesn't have luaL_openlib any more + +RUN apt-get install -y --no-install-recommends \ +`# Node.js dependencies` \ + nodejs + +RUN apt-get install -y --no-install-recommends \ +`# OCaml dependencies` \ + ocaml \ + opam && \ + opam init --yes && \ + opam install --yes oasis + +RUN apt-get install -y --no-install-recommends \ +`# Perl dependencies` \ + libbit-vector-perl \ + libclass-accessor-class-perl \ + libcrypt-ssleay-perl \ + libio-socket-ssl-perl \ + libnet-ssleay-perl + +RUN apt-get install -y --no-install-recommends \ +`# Php dependencies` \ + php \ + php-cli \ + php-dev \ + php-pear \ + re2c \ + phpunit + +RUN apt-get install -y --no-install-recommends \ +`# Python dependencies` \ + python-all \ + python-all-dbg \ + python-all-dev \ + python-ipaddress \ + python-pip \ + python-setuptools \ + python-six \ + python-tornado \ + python-twisted \ + python-wheel \ + python-zope.interface && \ + pip install --upgrade backports.ssl_match_hostname + +RUN apt-get install -y --no-install-recommends \ +`# Python3 dependencies` \ + python3-all \ + python3-all-dbg \ + python3-all-dev \ + python3-pip \ + python3-setuptools \ + python3-six \ + python3-tornado \ + python3-twisted \ + python3-wheel \ + python3-zope.interface + +RUN apt-get install -y --no-install-recommends \ +`# Ruby dependencies` \ + ruby \ + ruby-dev \ + ruby-bundler +RUN gem install bundler --no-ri --no-rdoc + +RUN apt-get install -y --no-install-recommends \ +`# Rust dependencies` \ + cargo \ + rustc + +RUN apt-get install -y --no-install-recommends \ +`# Static Code Analysis dependencies` \ + cppcheck \ + sloccount && \ + pip install flake8 + +# Clean up +RUN rm -rf /var/cache/apt/* && \ + rm -rf /var/lib/apt/lists/* && \ + rm -rf /tmp/* && \ + rm -rf /var/tmp/* + +ENV THRIFT_ROOT /thrift +RUN mkdir -p $THRIFT_ROOT/src +COPY Dockerfile $THRIFT_ROOT/ +WORKDIR $THRIFT_ROOT/src diff --git a/build/docker/ubuntu-trusty/Dockerfile b/build/docker/ubuntu-trusty/Dockerfile new file mode 100644 index 0000000..db2041a --- /dev/null +++ b/build/docker/ubuntu-trusty/Dockerfile @@ -0,0 +1,223 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Apache Thrift Docker build environment for Ubuntu Trusty +# Using all stock Ubuntu Trusty packaging except for: +# - d: does not come with Ubuntu so we're installing 2.070.0 +# - dart: does not come with Ubuntu so we're installing 1.20.1 +# - dotnetcore, disabled because netcore is for 1.0.0-preview and 2.0.0 is out +# - haxe, disabled because the distro comes with 3.0.0 and it cores while installing +# - node.js, disabled because it is at 0.10.0 in the distro which is too old (need 4+) +# - ocaml, disabled because it fails to install properly +# + +FROM buildpack-deps:trusty-scm +MAINTAINER Apache Thrift +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update && \ + apt-get dist-upgrade -y && \ + apt-get install -y --no-install-recommends \ + apt \ + apt-transport-https \ + apt-utils \ + curl \ + dirmngr \ + software-properties-common \ + wget + +RUN apt-get update && apt-get install -y --no-install-recommends \ +`# General dependencies` \ + bash-completion \ + bison \ + build-essential \ + clang \ + cmake \ + debhelper \ + flex \ + gdb \ + llvm \ + ninja-build \ + pkg-config \ + valgrind \ + vim +ENV PATH /usr/lib/llvm-3.8/bin:$PATH + +RUN apt-get install -y --no-install-recommends \ +`# C++ dependencies` \ + libboost-all-dev \ + libevent-dev \ + libssl-dev \ + qt5-default \ + qtbase5-dev \ + qtbase5-dev-tools + +RUN apt-get install -y --no-install-recommends \ +`# csharp (mono) dependencies` \ + mono-devel + +RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EBCF975E5BA24D5E && \ + wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list && \ + wget -qO - https://dlang.org/d-keyring.gpg | apt-key add - && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ +`# D dependencies` \ + dmd-bin=2.070.2-0 \ + libphobos2-dev=2.070.2-0 \ + dub \ + dfmt \ + dscanner \ + xdg-utils +# RUN mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ +# curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \ +# mv libevent-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ +# mv libevent-master/C/* /usr/include/dmd/druntime/import/C/ && \ +# rm -rf libevent-master +# RUN curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \ +# mv openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ +# mv openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \ +# rm -rf openssl-master + +RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ + curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ +`# Dart dependencies` \ + dart=1.20.1-1 +ENV PATH /usr/lib/dart/bin:$PATH + +RUN apt-get install -y --no-install-recommends \ +`# Erlang dependencies` \ + erlang-base \ + erlang-eunit \ + erlang-dev \ + erlang-tools \ + rebar + +RUN apt-get install -y --no-install-recommends \ +`# GlibC dependencies` \ + libglib2.0-dev + +RUN apt-get install -y --no-install-recommends \ +`# golang (go) dependencies` \ + golang-go + +RUN apt-get install -y --no-install-recommends \ +`# Haskell dependencies` \ + ghc \ + cabal-install + +# disabled because it cores while installing +# RUN apt-get install -y --no-install-recommends \ +# `# Haxe dependencies` \ +# haxe \ +# neko \ +# neko-dev && \ +# haxelib setup /usr/share/haxe/lib && \ +# haxelib install hxcpp 3.2.102 + +RUN apt-get install -y --no-install-recommends \ +`# Java dependencies` \ + ant \ + ant-optional \ + openjdk-7-jdk \ + maven + +RUN apt-get install -y --no-install-recommends \ +`# Lua dependencies` \ + lua5.1 \ + lua5.1-dev + +# disabled because it is too old +# RUN apt-get install -y --no-install-recommends \ +# `# Node.js dependencies` \ +# nodejs \ +# npm + +# disabled because it fails to install properly +# RUN apt-get install -y --no-install-recommends \ +# `# OCaml dependencies` \ +# ocaml \ +# opam && \ +# opam init --yes && \ +# opam install --yes oasis + +RUN apt-get install -y --no-install-recommends \ +`# Perl dependencies` \ + libbit-vector-perl \ + libclass-accessor-class-perl \ + libcrypt-ssleay-perl \ + libio-socket-ssl-perl \ + libnet-ssleay-perl + +RUN apt-get install -y --no-install-recommends \ +`# Php dependencies` \ + php5 \ + php5-cli \ + php5-dev \ + php-pear \ + re2c \ + phpunit + +RUN apt-get install -y --no-install-recommends \ +`# Python dependencies` \ + python-all \ + python-all-dbg \ + python-all-dev \ + python-pip \ + python-setuptools \ + python-six \ + python-twisted \ + python-wheel \ + python-zope.interface \ + python3-all \ + python3-all-dbg \ + python3-all-dev \ + python3-pip \ + python3-setuptools \ + python3-six \ + python3-wheel \ + python3-zope.interface && \ + pip install -U ipaddress backports.ssl_match_hostname tornado && \ + pip3 install -U backports.ssl_match_hostname tornado +# installing tornado by pip/pip3 instead of debian package +# if we install the debian package, the build fails in py2 + +RUN apt-get install -y --no-install-recommends \ +`# Ruby dependencies` \ + ruby \ + ruby-dev \ + ruby-bundler +RUN gem install bundler --no-ri --no-rdoc + +RUN apt-get install -y --no-install-recommends \ +`# Rust dependencies` \ + cargo \ + rustc + +RUN apt-get install -y --no-install-recommends \ +`# Static Code Analysis dependencies` \ + cppcheck \ + sloccount && \ + pip install flake8 + +# Clean up +RUN rm -rf /var/cache/apt/* && \ + rm -rf /var/lib/apt/lists/* && \ + rm -rf /tmp/* && \ + rm -rf /var/tmp/* + +ENV THRIFT_ROOT /thrift +RUN mkdir -p $THRIFT_ROOT/src +COPY Dockerfile $THRIFT_ROOT/ +WORKDIR $THRIFT_ROOT/src diff --git a/build/docker/ubuntu-trusty/Dockerfile.orig b/build/docker/ubuntu-trusty/Dockerfile.orig new file mode 100644 index 0000000..857384b --- /dev/null +++ b/build/docker/ubuntu-trusty/Dockerfile.orig @@ -0,0 +1,231 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Apache Thrift Docker build environment for Ubuntu +# +# Known missing client libraries: +# - dotnetcore + +FROM buildpack-deps:trusty-scm +MAINTAINER Apache Thrift + +ENV DEBIAN_FRONTEND noninteractive + +# Add apt sources +# CMAKE +RUN apt-get update && \ + apt-get install -y --no-install-recommends software-properties-common && \ + add-apt-repository -y ppa:george-edison55/cmake-3.x + +# Erlang +RUN echo 'deb http://packages.erlang-solutions.com/debian trusty contrib' > /etc/apt/sources.list.d/erlang_solutions.list && \ + curl -sSL https://packages.erlang-solutions.com/debian/erlang_solutions.asc | apt-key add - + +# Dart +RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ + curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list && \ + sed -i /etc/apt/sources.list.d/dart_stable.list -e 's/https:/http:/g' + +# Consider using mirror nearby when building locally +# TODO: Provide option via --build-arg=... +# RUN sed -i /etc/apt/sources.list -e 's!http://archive.ubuntu.com/ubuntu/!http://your/mirror/!g' + +RUN apt-get update && apt-get install -y --no-install-recommends \ +`# General dependencies` \ + bison \ + build-essential \ + clang \ + cmake \ + debhelper \ + flex \ + ninja-build \ + pkg-config \ +`# Included in buildpack-deps` \ +`# autoconf` \ +`# automake` \ +`# g++` \ +`# git` \ +`# libtool` \ +`# make` + +RUN apt-get install -y --no-install-recommends \ +`# C++ dependencies` \ +`# libevent and OpenSSL are needed by D too` \ + libboost-dev \ + libboost-filesystem-dev \ + libboost-program-options-dev \ + libboost-system-dev \ + libboost-test-dev \ + libboost-thread-dev \ + libevent-dev \ + libssl-dev \ + qt5-default \ + qtbase5-dev \ + qtbase5-dev-tools + +RUN apt-get install -y --no-install-recommends \ +`# Java dependencies` \ + ant \ + ant-optional \ + openjdk-7-jdk \ + maven + +RUN apt-get install -y --no-install-recommends \ +`# Python dependencies` \ +`# TODO:` \ +`# Install twisted and zope.interface via pip. we need twisted at ./configure time, otherwise` \ +`# py.twisted tests are skipped.` \ + python-all \ + python-all-dbg \ + python-all-dev \ + python-pip \ + python-setuptools \ + python-twisted \ + python-zope.interface \ + python3-all \ + python3-all-dbg \ + python3-all-dev \ + python3-setuptools \ + python3-pip + +RUN apt-get install -y --no-install-recommends \ +`# Ruby dependencies` \ + ruby \ + ruby-dev \ + ruby-bundler \ +`# Perl dependencies` \ + libbit-vector-perl \ + libclass-accessor-class-perl \ + libcrypt-ssleay-perl \ + libio-socket-ssl-perl \ + libnet-ssleay-perl + +RUN apt-get install -y --no-install-recommends \ +`# Php dependencies` \ + php5 \ + php5-dev \ + php5-cli \ + php-pear \ + re2c \ + phpunit \ +`# GlibC dependencies` \ + libglib2.0-dev + +RUN apt-get update && apt-get install -y --no-install-recommends \ +`# Erlang dependencies` \ + erlang-base \ + erlang-eunit \ + erlang-dev \ + erlang-tools \ + rebar + +RUN apt-get install -y --no-install-recommends \ +`# Haskell dependencies` \ + ghc \ + cabal-install \ +`# Haxe dependencies` \ + neko \ + neko-dev \ + libneko0 + +# Newer release of nodejs +RUN curl -sL https://deb.nodesource.com/setup_4.x | bash +RUN apt-get install -y --no-install-recommends \ +`# Node.js dependencies` \ + nodejs + +# Add mono package repository url to get latest version of mono +RUN echo "deb http://download.mono-project.com/repo/debian trusty main" | tee /etc/apt/sources.list.d/mono.list +RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A6A19B38D3D831EF +RUN apt-get update && apt-get install -y --no-install-recommends \ +`# CSharp dependencies` \ + mono-devel + +RUN apt-get install -y --no-install-recommends \ +`# D dependencies` \ + xdg-utils \ +`# Dart dependencies` \ + dart \ +`# Lua dependencies` \ + lua5.2 \ + lua5.2-dev \ +`# MinGW dependencies` \ + mingw32 \ + mingw32-binutils \ + mingw32-runtime \ + nsis \ +`# Clean up` \ + && rm -rf /var/cache/apt/* && \ + rm -rf /var/lib/apt/lists/* && \ + rm -rf /tmp/* && \ + rm -rf /var/tmp/* + +# Ruby +RUN gem install bundler --no-ri --no-rdoc + +# Python optional dependencies +RUN pip2 install -U ipaddress backports.ssl_match_hostname tornado +RUN pip3 install -U backports.ssl_match_hostname tornado + +# Go +RUN curl -sSL https://storage.googleapis.com/golang/go1.4.3.linux-amd64.tar.gz | tar -C /usr/local/ -xz +ENV PATH /usr/local/go/bin:$PATH + +# Haxe +RUN mkdir -p /usr/lib/haxe && \ + wget -O - https://github.com/HaxeFoundation/haxe/releases/download/3.2.1/haxe-3.2.1-linux64.tar.gz | \ + tar -C /usr/lib/haxe --strip-components=1 -xz && \ + ln -s /usr/lib/haxe/haxe /usr/bin/haxe && \ + ln -s /usr/lib/haxe/haxelib /usr/bin/haxelib && \ + mkdir -p /usr/lib/haxe/lib && \ + chmod -R 777 /usr/lib/haxe/lib && \ + haxelib setup --always /usr/lib/haxe/lib && \ + haxelib install --always hxcpp 3.4.64 + +# Node.js +# temporarily removed since this breaks the build (and is not needed to test C# code) +# RUN curl -sSL https://www.npmjs.com/install.sh | sh + +# D +RUN curl -sSL http://downloads.dlang.org/releases/2.x/2.070.0/dmd_2.070.0-0_amd64.deb -o /tmp/dmd_2.070.0-0_amd64.deb && \ + dpkg -i /tmp/dmd_2.070.0-0_amd64.deb && \ + rm /tmp/dmd_2.070.0-0_amd64.deb && \ + curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \ + curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \ + mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ + mv libevent-master/deimos/* openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ + mv libevent-master/C/* openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \ + rm -rf libevent-master openssl-master && \ + echo 'gcc -Wl,--no-as-needed $*' > /usr/local/bin/gcc-dmd && \ + chmod 755 /usr/local/bin/gcc-dmd && \ + echo 'CC=/usr/local/bin/gcc-dmd' >> /etc/dmd.conf + +# Dart +ENV PATH /usr/lib/dart/bin:$PATH + +# OCaml +RUN echo 'deb http://ppa.launchpad.net/avsm/ppa/ubuntu trusty main' > /etc/apt/sources.list.d/avsm-official-ocaml.list && \ + gpg --keyserver keyserver.ubuntu.com --recv 61707B09 && \ + gpg --export --armor 61707B09 | apt-key add - && \ + apt-get update && \ + apt-get install -y ocaml opam && \ + opam init && \ + opam install oasis + +# Rust +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.17.0 +ENV PATH /root/.cargo/bin:$PATH + +ENV THRIFT_ROOT /thrift +RUN mkdir -p $THRIFT_ROOT/src +COPY Dockerfile $THRIFT_ROOT/ +WORKDIR $THRIFT_ROOT/src diff --git a/build/docker/ubuntu-xenial/Dockerfile b/build/docker/ubuntu-xenial/Dockerfile new file mode 100644 index 0000000..c640bd9 --- /dev/null +++ b/build/docker/ubuntu-xenial/Dockerfile @@ -0,0 +1,249 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Apache Thrift Docker build environment for Ubuntu Xenial +# Using all stock Ubuntu Xenial packaging except for: +# - d: does not come with Ubuntu so we're installing 2.073.2 for coverage +# - dart: does not come with Ubuntu so we're installing 1.22.1 for coverage +# + +# +# Known missing or disabled libraries: +# - d: deimos for libevent and openssl omitted - not compatible / build errors + +FROM buildpack-deps:xenial-scm +MAINTAINER Apache Thrift +ENV DEBIAN_FRONTEND noninteractive + +### Add apt repos + +RUN apt-get update && apt-get dist-upgrade -y && apt-get install -y --no-install-recommends apt apt-transport-https curl wget apt-utils + +# csharp (mono) +# RUN echo "deb http://download.mono-project.com/repo/debian xenial main" | tee /etc/apt/sources.list.d/mono.list && \ +# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A6A19B38D3D831EF + +# D +RUN wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list && \ + wget -qO - https://dlang.org/d-keyring.gpg | apt-key add - +ENV D_VERSION 2.073.2-0 + +# Dart +RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ + curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list && \ + sed -i /etc/apt/sources.list.d/dart_stable.list -e 's/https:/http:/g' +# since ubuntu-artful can't run dart, we'll run 1.240 on xenial for now +ENV DART_VERSION 1.24.2-1 + +# dotnet (core) +RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \ + echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > /etc/apt/sources.list.d/dotnetdev.list + +# node.js (this step runs apt-get update internally) +# note: node 8.5 introduced some issues with directory handling / jsdoc / something... using 7.x for now +# RUN curl -sL https://deb.nodesource.com/setup_7.x | bash + + +### install general dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ +`# General dependencies` \ + bash-completion \ + bison \ + build-essential \ + clang \ + cmake \ + debhelper \ + flex \ + gdb \ + llvm \ + ninja-build \ + pkg-config \ + valgrind \ + vim +ENV PATH /usr/lib/llvm-3.8/bin:$PATH + +### languages + +RUN apt-get install -y --no-install-recommends \ +`# C++ dependencies` \ + libboost-dev \ + libboost-filesystem-dev \ + libboost-program-options-dev \ + libboost-system-dev \ + libboost-test-dev \ + libboost-thread-dev \ + libevent-dev \ + libssl-dev \ + qt5-default \ + qtbase5-dev \ + qtbase5-dev-tools + +RUN apt-get install -y --no-install-recommends \ +`# csharp (mono) dependencies` \ + mono-devel + +RUN apt-get install -y --allow-unauthenticated --no-install-recommends \ +`# D dependencies` \ + dmd-bin=$D_VERSION \ + libphobos2-dev=$D_VERSION \ + dub \ + dfmt \ + dscanner \ + libevent-dev \ + libssl-dev \ + xdg-utils +# libevent deimos doesn't seem to work so not enabling it: +# RUN mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ +# curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \ +# mv libevent-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ +# mv libevent-master/C/* /usr/include/dmd/druntime/import/C/ && \ +# rm -rf libevent-master +# openssl deimos doesn't work with openssl-1.0.2 so not enabling it: +# RUN curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \ +# mv openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ +# mv openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \ +# rm -rf openssl-master + +RUN apt-get install -y --no-install-recommends \ +`# Dart dependencies` \ + dart=$DART_VERSION +ENV PATH /usr/lib/dart/bin:$PATH + +RUN apt-get install -y --no-install-recommends \ +`# dotnet core dependencies` \ + dotnet-sdk-2.0.3 + +RUN apt-get install -y --no-install-recommends \ +`# Erlang dependencies` \ + erlang-base \ + erlang-eunit \ + erlang-dev \ + erlang-tools \ + rebar + +RUN apt-get install -y --no-install-recommends \ +`# GlibC dependencies` \ + libglib2.0-dev + +RUN apt-get install -y --no-install-recommends \ +`# golang (go) dependencies` \ + golang-go \ + golang-race-detector-runtime + +RUN apt-get install -y --no-install-recommends \ +`# Haskell dependencies` \ + ghc \ + cabal-install + +RUN apt-get install -y --no-install-recommends \ +`# Haxe dependencies` \ + haxe \ + neko \ + neko-dev \ + libneko0 +RUN haxelib setup --always /usr/share/haxe/lib && \ + haxelib install --always hxcpp 3.4.64 +# note: hxcpp 3.4.185 (latest) no longer ships static libraries, and caused a build failure + +RUN apt-get install -y --no-install-recommends \ +`# Java dependencies` \ + ant \ + ant-optional \ + openjdk-8-jdk \ + maven + +RUN apt-get install -y --no-install-recommends \ +`# Lua dependencies` \ + lua5.2 \ + lua5.2-dev +# https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212 +# lua5.3 does not install alternatives so stick with 5.2 here + +RUN apt-get install -y --no-install-recommends \ +`# Node.js dependencies` \ + nodejs \ + npm && \ + ln -s /usr/bin/nodejs /usr/bin/node + +RUN apt-get install -y --no-install-recommends \ +`# OCaml dependencies` \ + ocaml \ + opam && \ + opam init --yes && \ + opam install --yes oasis + +RUN apt-get install -y --no-install-recommends \ +`# Perl dependencies` \ + libbit-vector-perl \ + libclass-accessor-class-perl \ + libcrypt-ssleay-perl \ + libio-socket-ssl-perl \ + libnet-ssleay-perl + +RUN apt-get install -y --no-install-recommends \ +`# Php dependencies` \ + php7.0 \ + php7.0-cli \ + php7.0-dev \ + php-pear \ + re2c \ + phpunit + +RUN apt-get install -y --no-install-recommends \ +`# Python dependencies` \ + python-all \ + python-all-dbg \ + python-all-dev \ + python-backports.ssl-match-hostname \ + python-ipaddress \ + python-pip \ + python-setuptools \ + python-six \ + python-tornado \ + python-twisted \ + python-wheel \ + python-zope.interface \ + python3-all \ + python3-all-dbg \ + python3-all-dev \ + python3-setuptools \ + python3-six \ + python3-tornado \ + python3-twisted \ + python3-wheel \ + python3-zope.interface && \ + pip install --upgrade backports.ssl_match_hostname + +RUN apt-get install -y --no-install-recommends \ +`# Ruby dependencies` \ + ruby \ + ruby-dev \ + ruby-bundler +RUN gem install bundler --no-ri --no-rdoc + +RUN apt-get install -y --no-install-recommends \ +`# Rust dependencies` \ + cargo \ + rustc + +# Clean up +RUN rm -rf /var/cache/apt/* && \ + rm -rf /var/lib/apt/lists/* && \ + rm -rf /tmp/* && \ + rm -rf /var/tmp/* + +ENV DOTNET_CLI_TELEMETRY_OPTOUT 1 +ENV THRIFT_ROOT /thrift +RUN mkdir -p $THRIFT_ROOT/src +COPY Dockerfile $THRIFT_ROOT/ +WORKDIR $THRIFT_ROOT/src diff --git a/build/travis/installCXXDependencies.sh b/build/travis/installCXXDependencies.sh new file mode 100755 index 0000000..ac3edf3 --- /dev/null +++ b/build/travis/installCXXDependencies.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +# Mainly aiming Travis CI's Ubuntu machines for now +# see what we need: http://thrift.apache.org/docs/install/ubuntu + +# General dependencies +sudo apt-add-repository "deb http://archive.ubuntu.com/ubuntu/ trusty main restricted" -y +sudo apt-get update -qq + +sudo apt-get install -qq libpango-1.0-0 libqt4-dev qtbase5-dev qtbase5-dev-tools qt5-default libboost-dev libboost-test-dev libboost-program-options-dev libboost-system-dev libboost-filesystem-dev libboost-thread-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev make cmake git debhelper bc nsis ninja-build +dpkg -S /usr/include/boost/version.hpp diff --git a/build/travis/installDependencies.sh b/build/travis/installDependencies.sh new file mode 100755 index 0000000..eab8c6b --- /dev/null +++ b/build/travis/installDependencies.sh @@ -0,0 +1,66 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +SCRIPTPATH=$( cd $(dirname $0) ; pwd -P ) + +# Mainly aiming Travis CI's Ubuntu machines for now +# see what we need: http://thrift.apache.org/docs/install/ubuntu + +# Java dependencies +sudo apt-get install -qq ant openjdk-7-jdk +sudo update-java-alternatives -s java-1.7.0-openjdk-amd64 + +# Python dependencies +sudo apt-get install -qq python-all python-all-dev python-all-dbg python-setuptools python-support python-twisted python-six python3-six + +# Ruby dependencies +sudo apt-get install -qq ruby ruby-dev +sudo gem install bundler rake + +# Perl dependencies +sudo apt-get install -qq libbit-vector-perl libclass-accessor-class-perl libio-socket-ssl-perl libnet-ssleay-perl libcrypt-ssleay-perl + +# Php dependencies +sudo apt-get install -qq php5 php5-dev php5-cli php-pear re2c + +# GlibC dependencies +sudo apt-get install -qq libglib2.0-dev + +# Erlang dependencies +sudo apt-get install -qq erlang-base erlang-eunit erlang-dev erlang-tools rebar + +# GO dependencies +echo "golang-go golang-go/dashboard boolean false" | debconf-set-selections +sudo apt-get -y install -qq golang golang-go + +# Haskell dependencies +sudo add-apt-repository -y ppa:hvr/ghc +sudo apt-get update +sudo apt-get install cabal-install-1.20 ghc-$GHCVER + +# Lua dependencies +sudo apt-get install -qq lua5.2 lua5.2-dev + +# Node.js dependencies +sudo apt-get install -qq nodejs nodejs-dev npm +sudo update-alternatives --install /usr/bin/node node /usr/bin/nodejs 10 + +# CSharp +sudo apt-get install -qq mono-gmcs mono-devel libmono-system-web2.0-cil +sudo apt-get install -qq mingw32 mingw32-binutils mingw32-runtime nsis diff --git a/build/wincpp/README.md b/build/wincpp/README.md new file mode 100644 index 0000000..a231780 --- /dev/null +++ b/build/wincpp/README.md @@ -0,0 +1,219 @@ + + +# Building thrift on Windows (Native) + +Thrift uses cmake to make it easier to build the project on multiple platforms, however to build a fully functional and production ready thrift on Windows requires a number of third party libraries to be obtained or built. Once third party libraries are ready, the right combination of options must be passed to cmake in order to generate the correct environment. + +## Summary + +These instructions will help you build thrift for windows using Visual +Studio 2010 or later. The contributed batch files will help you build +the third party libraries needed for complete thrift functionality as +well as thrift itself. + +These instructions follow a directory layout that looks like the following: + + workspace\ + build\ - this is where the out-of-tree thrift cmake builds are generated + dist\ - this is where the thrift build results end up + thirdparty\ - this is where all third party binaries and libraries live + build\ - this is where all third party out-of-tree builds are generated + (except for openssl, which only builds in-tree) + dist\ - this is where all third party distributions end up + src\ - this is where all third party source projects live + scripts\ - batch files used to set environment variables for builds + thrift\ - this is where the thrift source project lives + +Create a "workspace" directory somewhere on your system and then copy the contents of this +directory to there, then clone or unpack thrift into `workspace\thrift`. + +## Third Party Libraries + +Batch scripts are provided to build some third party libraries. You must download them and place them into the directory noted for each. You can use different versions if you prefer; these instructions were made with the versions listed. + +> TIP: To modify the versions used in the batch scripts, look in scripts\tpversions.bat. + +Build them in the order listed to satisfy their dependencies. + +### winflexbison + + source: web site + location: https://sourceforge.net/projects/winflexbison/files/win_flex_bison-latest.zip/download + version: "latest" + directory: workspace\thirdparty\dist\winflexbison + +This package is required to build the compiler. This third party package does not need to be built as it is a binary distribution of the "bison" and "flex" tools normally found on Unix boxes. + +> TIP: If you are only interested in building the compiler, you can skip the remaining third party libraries. + +### zlib + + source: web site + location: http://zlib.net/ + version: 1.2.9 + directory: workspace\thirdparty\src\zlib-1.2.9 + +To build, open the appropriate Visual Studio command prompt and then run +the build-zlib.bat script in thirdparty\src. + +### openssl + + source: web site + location: https://www.openssl.org/ + version: 1.1.0c + directory: workspace\thirdparty\src\openssl-1.1.0c + depends-on: zlib + +If you are using openssl-1.1.0 or later, they changed static builds to use Microsoft Static RTL for release builds. zlib by default uses a dynamic runtime, as does libevent. Edit the file Configurations/10-main.conf and replace the section contents for "VC-noCE-common" with what appears below to make openssl build with dynamic runtime instead: + + "VC-noCE-common" => { + inherit_from => [ "VC-common" ], + template => 1, + cflags => add(picker(default => "-DUNICODE -D_UNICODE", + debug => "/MDd /Od -DDEBUG -D_DEBUG", + release => "/MD /O2" + )), + bin_cflags => add(picker(debug => "/MDd", + release => "/MD", + )), + bin_lflags => add("/subsystem:console /opt:ref"), + ex_libs => add(sub { + my @ex_libs = (); + push @ex_libs, 'ws2_32.lib' unless $disabled{sock}; + push @ex_libs, 'gdi32.lib advapi32.lib crypt32.lib user32.lib'; + return join(" ", @ex_libs); + }), + }, + +To build, open the appropriate Visual Studio command prompt and then run +the build-openssl.bat script in thirdparty\src. + +### libevent + + source: git + location: https://github.com/nmathewson/Libevent.git + use: commit 3821cca1a637f4da4099c9343e7326da00f6981c or later + date: Fri Dec 23 16:19:35 2016 +0800 or later + version: corresponds to 2.1.7rc + patches + directory: workspace\thirdparty\src\libevent-2.1.7rc2 + depends-on: openssl, zlib + +To build, open the appropriate Visual Studio command prompt and then run +the build-libevent.bat script in thirdparty\src. + +### msinttypes + + source: web site + location: https://code.google.com/archive/p/msinttypes/downloads + version: 26 + directory: workspace\thirdparty\dist\msinttypes + +> TIP: This is only necessary for Visual Studio 2010, which did not include an header. + +This third party package does not need to be built as it is a distribution of header files. + +### boost + + source: web site + location: http://boost.teeks99.com/ + version: 1_62_0 + directory: workspace\thirdparty\dist\boost_1_62_0 + +The pre-built binary versions of boost come in self-unpacking executables. Run each of the ones you are interested in and point them at the same thirdparty dist directory. + +## Building a Production thrift Compiler + +### Prerequisites + +* CMake-2.8.12.2 or later +* Visual Studio 2010 or later +* thrift source placed into workspace\thrift +* winflexbison placed into workspace\thirdparty\dist + +### Instructions + +By following these instructions you will end up with a release mode thrift compiler that is suitable for distribution as it has no external dependencies. + +1. Open the appropriate Visual Studio Command Prompt. +2. `cd workspace` +3. `build-thrift-compiler.bat` + +The batch file uses CMake to generate an out-of-tree build directory in `workspace\build` and then builds the compiler. The resulting `thrift.exe` program is placed into `workspace\dist` in a path that depends on your compiler version and platform. For example, if you use a Visual Studio 2010 x64 Command Prompt, the compiler will be placed into `workspace\dist\thrift-compiler-dev\vc100\x64\Release\thrift.exe` + +#### Details + +This section is for those who are curious about the CMake options used in the build process. + +CMake takes the source tree as the first argument and uses the remaining arguments for configuration. The batch file `build-thrift-compiler` essentially performs the following commands: + + C:\> CD workspace\build + C:\workspace\build> "C:\Program Files\CMake\bin\cmake.exe" ..\thrift + -DBISON_EXECUTABLE=..\thirdparty\dist\winflexbison\win_bison.exe + -DCMAKE_BUILD_TYPE=Release + -DFLEX_EXECUTABLE=..\thirdparty\dist\winflexbison\win_flex.exe + -DWITH_MT=ON + -DWITH_SHARED_LIB=OFF + -G"NMake Makefiles" + C:\workspace\build> NMAKE /FMakefile thrift-compiler + +WITH_MT controls the dynamic or static runtime library selection. To build a production compiler, the thrift project recommends using the static runtime library to make the executable portable. The batch file sets this. + +You can build a Visual Studio project file by following the example but substituting a different generator for the "-G" option. Run `cmake.exe --help` for a list of generators. Typically, this is one of the following on Windows (omit "Win64" to build 32-bit instead): + +* "Visual Studio 10 2010 Win64" +* "Visual Studio 11 2012 Win64" +* "Visual Studio 12 2013 Win64" +* "Visual Studio 14 2015 Win64" +* "Visual Studio 15 2017 Win64" + +For example you can build using a Visual Studio solution file on the command line by doing: + + C:\> CD workspace\build + C:\workspace\build> "C:\Program Files\CMake\bin\cmake.exe" ..\thrift + -DBISON_EXECUTABLE=..\thirdparty\dist\winflexbison\win_bison.exe + -DCMAKE_BUILD_TYPE=Release + -DFLEX_EXECUTABLE=..\thirdparty\dist\winflexbison\win_flex.exe + -DWITH_MT=ON + -DWITH_SHARED_LIB=OFF + -G"Visual Studio 14 2015 Win64" + C:\workspace\build> MSBUILD "Apache Thrift.sln" /p:Configuration=Release /p:Platform=x64 /t:thrift-compiler + +You can also double-click on the solution file to bring it up in Visual Studio and build or debug interactively from there. + +## Building the thrift C++ Run-Time Library + +These instructions are similar to the compiler build however there are additional dependencies on third party libraries to build a feature-complete runtime. The resulting static link library for thrift uses a dynamic Microsoft runtime. + +1. Open the desired Visual Studio Command Prompt. +2. `cd workspace` +3. `build-thrift.bat` + +Thrift depends on boost, libevent, openssl, and zlib in order to build with all server and transport types. To use later versions of boost like 1.62 you will need a recent version of cmake (at least 3.7). + +The build-thrift script has options to build debug or release and to optionally disable any of the generation (cmake), build, or test phases. By default, the batch file will generate an out-of-tree build directory inside `workspace\build`, then perform a release build, then run the unit tests. The batch file accepts some option flags to control its behavior: + + :: Flags you can use to change this behavior: + :: + :: /DEBUG - if building, perform a debug build instead + :: /NOGENERATE - skip cmake generation - useful if you + :: have already generated a solution and just + :: want to build + :: /NOBUILD - skip cmake build - useful if you just + :: want to generate a solution + :: /NOTEST - skip ctest execution + +For example if you want to generate the cmake environment without building or running tests: + + C:\workspace> build-thrift.bat /NOBUILD /NOTEST diff --git a/build/wincpp/build-thrift-compiler.bat b/build/wincpp/build-thrift-compiler.bat new file mode 100644 index 0000000..b6b42a8 --- /dev/null +++ b/build/wincpp/build-thrift-compiler.bat @@ -0,0 +1,79 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Produces a production thrift compiler suitable for redistribution. +:: The compiler is linked to runtime statically for maximum portability. +:: Assumes the thirdparty files for "winflexbison" have been placed +:: according to the README.md instructions. +:: +:: Open a Visual Studio Command Prompt of your choosing and then +:: run this script. + +@ECHO OFF +SETLOCAL EnableDelayedExpansion + +IF NOT DEFINED PACKAGE_NAME SET PACKAGE_NAME=thrift +IF NOT DEFINED PACKAGE_VERSION SET PACKAGE_VERSION=dev +IF NOT DEFINED SOURCE_DIR SET SOURCEDIR=%~dp0%PACKAGE_NAME% +IF NOT DEFINED WIN3P_ROOT SET WIN3P_ROOT=%~dp0thirdparty + +:: Set COMPILER to (vc100 - vc140) depending on the current environment +CALL scripts\cl_setcompiler.bat || EXIT /B + +:: Set ARCH to either win32 or x64 depending on the current environment +CALL scripts\cl_setarch.bat || EXIT /B + +:: Set GENERATOR for CMake depending on the current environment +CALL scripts\cl_setgenerator.bat || EXIT /B + +IF NOT DEFINED BUILDTYPE ( + SET BUILDTYPE=Release +) + + SET BUILDDIR=%~dp0build\%PACKAGE_NAME%-compiler\%PACKAGE_VERSION%\%COMPILER%\ + SET OUTDIR=%~dp0dist\%PACKAGE_NAME%-compiler-%PACKAGE_VERSION%\%COMPILER%\%ARCH%\%BUILDTYPE%\ + SET BOOST_LIBDIR=lib%ARCH:~-2,2%-msvc-%COMPILER:~-3,2%.0 + IF "%BUILDTYPE%" == "Debug" (SET ZLIB_STATIC_SUFFIX=d) + + ECHO/ + ECHO ========================================================================= + ECHO Configuration: %PACKAGE_NAME% %PACKAGE_VERSION% %COMPILER%:%ARCH%:%BUILDTYPE% "%GENERATOR%" +IF DEFINED COMPILERONLY ( + ECHO COMPILER ONLY +) + ECHO Build Directory: %BUILDDIR% + ECHO Install Directory: %OUTDIR% + ECHO Source Directory: %SOURCEDIR% + ECHO ========================================================================= + ECHO/ + + MKDIR "%BUILDDIR%" + CD "%BUILDDIR%" || EXIT /B + + CMAKE.EXE %~dp0thrift ^ + -G"%GENERATOR%" ^ + -DBISON_EXECUTABLE=%WIN3P_ROOT%\dist\winflexbison\win_bison.exe ^ + -DCMAKE_BUILD_TYPE=%BUILDTYPE% ^ + -DFLEX_EXECUTABLE=%WIN3P_ROOT%\dist\winflexbison\win_flex.exe ^ + -DWITH_MT=ON ^ + -DWITH_SHARED_LIB=OFF || EXIT /B + + CD %BUILDDIR% + + CMAKE.EXE --build . --config %BUILDTYPE% --target thrift-compiler || EXIT /B + XCOPY /F /Y %BUILDDIR%\bin\%BUILDTYPE%\thrift.exe %OUTDIR% + +ENDLOCAL +EXIT /B diff --git a/build/wincpp/build-thrift.bat b/build/wincpp/build-thrift.bat new file mode 100644 index 0000000..ba3e476 --- /dev/null +++ b/build/wincpp/build-thrift.bat @@ -0,0 +1,164 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Generates a Visual Studio solution for thrift and then builds it. +:: Assumes third party libraries have been built or placed already. +:: +:: Open a Visual Studio Command Prompt of your choosing and then +:: run this script. +:: +:: Normally the script will run cmake to generate a solution, then +:: perform a build, then run tests on the complete thrift library +:: in release mode. +:: +:: Flags you can use to change this behavior: +:: +:: /DEBUG - debug instead of release +:: /IDE - launch Visual Studio with a path set +:: up correctly to run tests instead of +:: performing any other actions, i.e. +:: implies setting the next three flags +:: /NOGENERATE - skip cmake generation - useful if you +:: have already generated a solution and just +:: want to build +:: /NOBUILD - skip cmake build - useful if you just +:: want to generate a solution +:: /NOTEST - skip ctest execution +:: + +@ECHO OFF +SETLOCAL EnableDelayedExpansion + +:: Sets variables for third party versions used in build +CALL scripts\tpversions.bat || EXIT /B + +IF NOT DEFINED PACKAGE_NAME SET PACKAGE_NAME=thrift +IF NOT DEFINED PACKAGE_VERSION SET PACKAGE_VERSION=dev +IF NOT DEFINED SOURCE_DIR SET SOURCEDIR=%~dp0%PACKAGE_NAME% +IF NOT DEFINED WIN3P_ROOT SET WIN3P_ROOT=%~dp0thirdparty + +:: Set COMPILER to (vc100 - vc140) depending on the current environment +CALL scripts\cl_setcompiler.bat || EXIT /B + +:: Set ARCH to either win32 or x64 depending on the current environment +CALL scripts\cl_setarch.bat || EXIT /B + +:: Set GENERATOR for CMake depending on the current environment +CALL scripts\cl_setgenerator.bat || EXIT /B + +:: Defaults + +IF NOT DEFINED BUILDTYPE SET BUILDTYPE=Release +SET OPT_IDE=0 +SET OPT_BUILD=1 +SET OPT_GENERATE=1 +SET OPT_TEST=1 + +:: Apply Flags + +IF /I "%1" == "/DEBUG" SET BUILDTYPE=Debug +IF /I "%2" == "/DEBUG" SET BUILDTYPE=Debug +IF /I "%3" == "/DEBUG" SET BUILDTYPE=Debug +IF /I "%1" == "/IDE" SET OPT_IDE=1 +IF /I "%2" == "/IDE" SET OPT_IDE=1 +IF /I "%3" == "/IDE" SET OPT_IDE=1 +IF /I "%1" == "/NOBUILD" SET OPT_BUILD=0 +IF /I "%2" == "/NOBUILD" SET OPT_BUILD=0 +IF /I "%3" == "/NOBUILD" SET OPT_BUILD=0 +IF /I "%1" == "/NOGENERATE" SET OPT_GENERATE=0 +IF /I "%2" == "/NOGENERATE" SET OPT_GENERATE=0 +IF /I "%3" == "/NOGENERATE" SET OPT_GENERATE=0 +IF /I "%1" == "/NOTEST" SET OPT_TEST=0 +IF /I "%2" == "/NOTEST" SET OPT_TEST=0 +IF /I "%3" == "/NOTEST" SET OPT_TEST=0 + +IF %OPT_IDE% == 1 ( + SET OPT_GENERATE=0 + SET OPT_BUILD=0 + SET OPT_TEST=0 +) + + SET BUILDDIR=%~dp0build\%PACKAGE_NAME%\%PACKAGE_VERSION%\%COMPILER%\%ARCH%\ + SET OUTDIR=%~dp0dist\%PACKAGE_NAME%-%PACKAGE_VERSION%\%COMPILER%\%ARCH%\%BUILDTYPE%\ + SET BOOST_LIBDIR=lib%ARCH:~-2,2%-msvc-%COMPILER:~-3,2%.0 + IF "%BUILDTYPE%" == "Debug" (SET ZLIB_STATIC_SUFFIX=d) + + ECHO/ + ECHO ========================================================================= + ECHO Configuration: %PACKAGE_NAME% %PACKAGE_VERSION% %COMPILER%:%ARCH%:%BUILDTYPE% "%GENERATOR%" +IF DEFINED COMPILERONLY ( + ECHO COMPILER ONLY +) + ECHO Build Directory: %BUILDDIR% + ECHO Install Directory: %OUTDIR% + ECHO Source Directory: %SOURCEDIR% + ECHO ========================================================================= + ECHO/ + +IF %OPT_IDE% == 1 ( + + CALL :SETRUNPATH || EXIT /B + CALL DEVENV "!BUILDDIR!Apache Thrift.sln" || EXIT /B + EXIT /B + +) + + MKDIR "%BUILDDIR%" + CD "%BUILDDIR%" || EXIT /B + +IF %OPT_GENERATE% == 1 ( + + CMAKE.EXE %~dp0thrift ^ + -G"%GENERATOR%" ^ + -DBISON_EXECUTABLE=%WIN3P_ROOT%\dist\winflexbison\win_bison.exe ^ + -DBOOST_ROOT=%WIN3P_ROOT%\dist\boost_%TP_BOOST_VERSION% ^ + -DBOOST_LIBRARYDIR=%WIN3P_ROOT%\dist\boost_%TP_BOOST_VERSION%\%BOOST_LIBDIR% ^ + -DCMAKE_INSTALL_PREFIX=%OUTDIR% ^ + -DCMAKE_BUILD_TYPE=%BUILDTYPE% ^ + -DFLEX_EXECUTABLE=%WIN3P_ROOT%\dist\winflexbison\win_flex.exe ^ + -DINTTYPES_ROOT=%WIN3P_ROOT%\dist\msinttypes ^ + -DLIBEVENT_ROOT=%WIN3P_ROOT%\dist\libevent-%TP_LIBEVENT_VERSION%\%COMPILER%\%ARCH%\%BUILDTYPE% ^ + -DOPENSSL_ROOT_DIR=%WIN3P_ROOT%\dist\openssl-%TP_OPENSSL_VERSION%\%COMPILER%\%ARCH%\%BUILDTYPE%\dynamic ^ + -DOPENSSL_USE_STATIC_LIBS=OFF ^ + -DZLIB_LIBRARY=%WIN3P_ROOT%\dist\zlib-%TP_ZLIB_VERSION%\%COMPILER%\%ARCH%\lib\zlib%ZLIB_LIB_SUFFIX%.lib ^ + -DZLIB_ROOT=%WIN3P_ROOT%\dist\zlib-%TP_ZLIB_VERSION%\%COMPILER%\%ARCH% ^ + -DWITH_BOOSTTHREADS=ON ^ + -DWITH_SHARED_LIB=OFF ^ + -DWITH_STATIC_LIB=ON || EXIT /B + +) + +IF %OPT_BUILD% == 1 ( + + CD %BUILDDIR% + CMAKE.EXE --build . --config %BUILDTYPE% --target INSTALL || EXIT /B + +) + +IF %OPT_TEST% == 1 ( + + CALL :SETRUNPATH || EXIT /B + CMAKE.EXE --build . --config %BUILDTYPE% --target RUN_TESTS || EXIT /B + +) + +:SETRUNPATH + SET PATH=!PATH!;%WIN3P_ROOT%\dist\boost_%TP_BOOST_VERSION%\%BOOST_LIBDIR% + SET PATH=!PATH!;%WIN3P_ROOT%\dist\openssl-%TP_OPENSSL_VERSION%\%COMPILER%\%ARCH%\%BUILDTYPE%\dynamic\bin + SET PATH=!PATH!;%WIN3P_ROOT%\dist\zlib-%TP_ZLIB_VERSION%\%COMPILER%\%ARCH%\bin + EXIT /B + +ENDLOCAL +EXIT /B diff --git a/build/wincpp/scripts/cl_setarch.bat b/build/wincpp/scripts/cl_setarch.bat new file mode 100644 index 0000000..9570a1e --- /dev/null +++ b/build/wincpp/scripts/cl_setarch.bat @@ -0,0 +1,47 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Detect the architecture we're building for. +:: Set the ARCH environment variable to one of: +:: win32 +:: x64 +:: +:: Honors any existing ARCH environment variable +:: setting instead of overwriting it, to allow it +:: to be forced if needed. +:: +:: Sets ERRORLEVEL to 0 if ARCH can be determined, +:: to 1 if it cannot. +:: + +IF DEFINED ARCH ( + ECHO [warn ] using existing environment variable ARCH + EXIT /B 0 +) + +CALL :CHECK x64 +IF %ERRORLEVEL% == 0 (SET ARCH=x64) ELSE (SET ARCH=win32) + +IF NOT DEFINED ARCH ( + ECHO [error] unable to determine the target architecture + EXIT /B 1 +) + +ECHO [info ] detected target architecture %ARCH% +EXIT /B 0 + +:CHECK +cl /? 2>&1 | findstr /C:" for %1%" > nul +EXIT /B %ERRORLEVEL% diff --git a/build/wincpp/scripts/cl_setcompiler.bat b/build/wincpp/scripts/cl_setcompiler.bat new file mode 100644 index 0000000..8405d76 --- /dev/null +++ b/build/wincpp/scripts/cl_setcompiler.bat @@ -0,0 +1,58 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Detect the compiler edition we're building in. +:: Set the COMPILER environment variable to one of: +:: vc100 = Visual Studio 2010 +:: vc110 = Visual Studio 2012 +:: vc120 = Visual Studio 2013 +:: vc140 = Visual Studio 2015 +:: vc150 = Visual Studio 2017 +:: +:: Honors any existing COMPILER environment variable +:: setting instead of overwriting it, to allow it +:: to be forced if needed. +:: +:: Sets ERRORLEVEL to 0 if COMPILER can be determined, +:: to 1 if it cannot. +:: + +IF DEFINED COMPILER ( + ECHO [warn ] using existing environment variable COMPILER + EXIT /B 0 +) + +CALL :CHECK 16 +IF %ERRORLEVEL% == 0 (IF NOT DEFINED COMPILER SET COMPILER=vc100) +CALL :CHECK 17 +IF %ERRORLEVEL% == 0 (IF NOT DEFINED COMPILER SET COMPILER=vc110) +CALL :CHECK 18 +IF %ERRORLEVEL% == 0 (IF NOT DEFINED COMPILER SET COMPILER=vc120) +CALL :CHECK 19.00 +IF %ERRORLEVEL% == 0 (IF NOT DEFINED COMPILER SET COMPILER=vc140) +CALL :CHECK 19.10 +IF %ERRORLEVEL% == 0 (IF NOT DEFINED COMPILER SET COMPILER=vc150) + +IF NOT DEFINED COMPILER ( + ECHO [error] unable to determine the compiler edition + EXIT /B 1 +) + +ECHO [info ] detected compiler edition %COMPILER% +EXIT /B 0 + +:CHECK +cl /? 2>&1 | findstr /C:"Version %1%." > nul +EXIT /B %ERRORLEVEL% diff --git a/build/wincpp/scripts/cl_setgenerator.bat b/build/wincpp/scripts/cl_setgenerator.bat new file mode 100644 index 0000000..bae2742 --- /dev/null +++ b/build/wincpp/scripts/cl_setgenerator.bat @@ -0,0 +1,69 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Detect the compiler edition we're building in and then +:: set the GENERATOR environment variable to one of: +:: +:: Visual Studio 15 2017 [arch] = Generates Visual Studio 2017 project files. +:: Optional [arch] can be "Win64" or "ARM". +:: Visual Studio 14 2015 [arch] = Generates Visual Studio 2015 project files. +:: Optional [arch] can be "Win64" or "ARM". +:: Visual Studio 12 2013 [arch] = Generates Visual Studio 2013 project files. +:: Optional [arch] can be "Win64" or "ARM". +:: Visual Studio 11 2012 [arch] = Generates Visual Studio 2012 project files. +:: Optional [arch] can be "Win64" or "ARM". +:: Visual Studio 10 2010 [arch] = Generates Visual Studio 2010 project files. +:: Optional [arch] can be "Win64" or "IA64". +:: +:: Honors any existing GENERATOR environment variable +:: setting instead of overwriting it, to allow it +:: to be forced if needed. +:: +:: Sets ERRORLEVEL to 0 if GENERATOR can be determined, +:: to 1 if it cannot. +:: +:: Requires cl_setarch.bat to have been executed or the ARCH environment +:: variable to be set. +:: + +IF "%ARCH%" == "x64" (SET GENARCH= Win64) + +IF DEFINED GENERATOR ( + ECHO [warn ] using existing environment variable GENERATOR + EXIT /B 0 +) + +CALL :CHECK 16 +IF %ERRORLEVEL% == 0 (IF NOT DEFINED GENERATOR SET GENERATOR=Visual Studio 10 2010%GENARCH%) +CALL :CHECK 17 +IF %ERRORLEVEL% == 0 (IF NOT DEFINED GENERATOR SET GENERATOR=Visual Studio 11 2012%GENARCH%) +CALL :CHECK 18 +IF %ERRORLEVEL% == 0 (IF NOT DEFINED GENERATOR SET GENERATOR=Visual Studio 12 2013%GENARCH%) +CALL :CHECK 19.00 +IF %ERRORLEVEL% == 0 (IF NOT DEFINED GENERATOR SET GENERATOR=Visual Studio 14 2015%GENARCH%) +CALL :CHECK 19.10 +IF %ERRORLEVEL% == 0 (IF NOT DEFINED GENERATOR SET GENERATOR=Visual Studio 15 2017%GENARCH%) + +IF NOT DEFINED GENERATOR ( + ECHO [error] unable to determine the CMake generator to use + EXIT /B 1 +) + +ECHO [info ] using CMake generator %GENERATOR% +EXIT /B 0 + +:CHECK +cl /? 2>&1 | findstr /C:"Version %1%." > nul +EXIT /B %ERRORLEVEL% diff --git a/build/wincpp/scripts/tpversions.bat b/build/wincpp/scripts/tpversions.bat new file mode 100644 index 0000000..d80c868 --- /dev/null +++ b/build/wincpp/scripts/tpversions.bat @@ -0,0 +1,24 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Set the versions of third party libraries to use. +:: + +IF NOT DEFINED TP_BOOST_VERSION SET TP_BOOST_VERSION=1_62_0 +IF NOT DEFINED TP_LIBEVENT_VERSION SET TP_LIBEVENT_VERSION=2.1.7rc2 +IF NOT DEFINED TP_OPENSSL_VERSION SET TP_OPENSSL_VERSION=1.1.0c +IF NOT DEFINED TP_ZLIB_VERSION SET TP_ZLIB_VERSION=1.2.9 + +EXIT /B 0 diff --git a/build/wincpp/thirdparty/src/build-libevent.bat b/build/wincpp/thirdparty/src/build-libevent.bat new file mode 100644 index 0000000..4af505c --- /dev/null +++ b/build/wincpp/thirdparty/src/build-libevent.bat @@ -0,0 +1,86 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Build script for libevent on windows +:: Use libevent master from github which has cmake integration +:: Uses the environment set up by a Visual Studio Command Prompt shortcut +:: to target a specific architecture and compiler +:: +:: Creates a static link library. +:: Links against OpenSSL and zlib statically. +:: + +@ECHO OFF +SETLOCAL EnableDelayedExpansion + +:: Sets variables for third party versions used in build +CALL ..\..\scripts\tpversions.bat || EXIT /B + +:: use "build-libevent.bat /yes" to skip the question part +IF /I "%1" == "/YES" SET NOASK=1 + +:: Set COMPILER to (vc100 - vc140) depending on the current environment +CALL ..\..\scripts\cl_setcompiler.bat || EXIT /B + +:: Set ARCH to either win32 or x64 depending on the current environment +CALL ..\..\scripts\cl_setarch.bat || EXIT /B + +IF NOT DEFINED GENERATOR SET GENERATOR=NMake Makefiles +IF NOT DEFINED PACKAGE_NAME SET PACKAGE_NAME=libevent +IF NOT DEFINED PACKAGE_VERSION SET PACKAGE_VERSION=%TP_LIBEVENT_VERSION% +IF NOT DEFINED SOURCEDIR SET SOURCEDIR=%~dp0%PACKAGE_NAME%-%PACKAGE_VERSION% +IF NOT DEFINED WIN3P_ROOT SET WIN3P_ROOT=%~dp0.. + +FOR %%X IN ( + Debug + Release +) DO ( + SET BUILDTYPE=%%X + SET BUILDDIR=%WIN3P_ROOT%\build\%PACKAGE_NAME%\%PACKAGE_VERSION%\%COMPILER%\%ARCH%\!BUILDTYPE! + SET OUTDIR=%WIN3P_ROOT%\dist\%PACKAGE_NAME%-%PACKAGE_VERSION%\%COMPILER%\%ARCH%\!BUILDTYPE! + + IF "!BUILDTYPE!" == "Debug" (SET ZLIB_LIB_SUFFIX=d) + + SET CMAKE_DEFS=^ + -DEVENT__DISABLE_SAMPLES=ON ^ + -DEVENT__DISABLE_TESTS=ON ^ + -DOPENSSL_USE_STATIC_LIBS=OFF ^ + -DOPENSSL_ROOT_DIR=%WIN3P_ROOT%\dist\openssl-%TP_OPENSSL_VERSION%\%COMPILER%\%ARCH%\!BUILDTYPE!\dynamic ^ + -DZLIB_LIBRARY=%WIN3P_ROOT%\dist\zlib-%TP_ZLIB_VERSION%\%COMPILER%\%ARCH%\lib\zlib!ZLIB_LIB_SUFFIX!.lib ^ + -DZLIB_ROOT=%WIN3P_ROOT%\dist\zlib-%TP_ZLIB_VERSION%\%COMPILER%\%ARCH% + + ECHO/ + ECHO ========================================================================= + ECHO Building: %PACKAGE_NAME% v%PACKAGE_VERSION% %COMPILER%:%ARCH%:!BUILDTYPE! "%GENERATOR%" + ECHO CMake Definitions: !CMAKE_DEFS! + ECHO Build Directory: !BUILDDIR! + ECHO Install Directory: !OUTDIR! + ECHO Source Directory: %SOURCEDIR% + ECHO ========================================================================= + ECHO/ + + IF NOT DEFINED NOASK ( + CHOICE /M "Do you want to build this configuration? " /c YN + IF !ERRORLEVEL! NEQ 1 (EXIT /B !ERRORLEVEL!) + ) + + MKDIR "!BUILDDIR!" + CD "!BUILDDIR!" || EXIT /B + + CMAKE.EXE -G"%GENERATOR%" -DCMAKE_INSTALL_PREFIX=!OUTDIR! -DCMAKE_BUILD_TYPE=!BUILDTYPE! !CMAKE_DEFS! "%SOURCEDIR%" || EXIT /B + NMAKE /fMakefile install || EXIT /B +) + +ENDLOCAL diff --git a/build/wincpp/thirdparty/src/build-openssl.bat b/build/wincpp/thirdparty/src/build-openssl.bat new file mode 100644 index 0000000..cf270f0 --- /dev/null +++ b/build/wincpp/thirdparty/src/build-openssl.bat @@ -0,0 +1,106 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Build script for openssl on windows +:: openssl uses an in-tree build so you have to clean between each one +:: +:: Uses the environment set up by a Visual Studio Command Prompt shortcut +:: to target a specific architecture and compiler +:: +:: If you use Lavasoft Ad-Aware, disable it for this build. It blocks the creation +:: of any file named "clienthellotest.exe" for whatever reason, which breaks the build. +:: + +@ECHO OFF +SETLOCAL EnableDelayedExpansion + +:: Sets variables for third party versions used in build +CALL ..\..\scripts\tpversions.bat || EXIT /B + +:: use "build-openssl.bat /yes" to skip the question part +IF /I "%1" == "/YES" SET NOASK=1 + +IF NOT DEFINED PACKAGE_NAME SET PACKAGE_NAME=openssl +IF NOT DEFINED PACKAGE_VERSION SET PACKAGE_VERSION=%TP_OPENSSL_VERSION% +IF NOT DEFINED SOURCEDIR SET SOURCEDIR=%~dp0%PACKAGE_NAME%-%PACKAGE_VERSION% +IF NOT DEFINED WIN3P_ROOT SET WIN3P_ROOT=%~dp0.. + +:: Set COMPILER to (vc100 - vc140) depending on the current environment +CALL ..\..\scripts\cl_setcompiler.bat || EXIT /B + +:: Set ARCH to either win32 or x64 depending on the current environment +CALL ..\..\scripts\cl_setarch.bat || EXIT /B + +IF "%ARCH%" == "x64" ( + SET TODO=debug-VC-WIN64A VC-WIN64A +) ELSE ( + SET TODO=debug-VC-WIN32 VC-WIN32 +) + +FOR %%X IN ( !TODO! ) DO ( + SET BUILDTYPE=%%X + FOR %%Y IN ( + nt + ntdll + ) DO ( + SET LIBTYPE=%%Y + + IF "!BUILDTYPE:~0,6!" == "debug-" ( + SET OUTBUILDTYPE=debug + SET ZLIBLIBSUFFIX=d + ) ELSE ( + SET OUTBUILDTYPE=release + SET ZLIBLIBSUFFIX= + ) + + IF "!LIBTYPE!" == "ntdll" ( + SET BUILD_OPTIONS=shared + SET OUTLIBTYPE=dynamic + SET ZLIBLIB=zlib!ZLIBLIBSUFFIX! + SET ZLIBOPT=zlib-dynamic + ) ELSE ( + SET BUILD_OPTIONS=no-shared + SET OUTLIBTYPE=static + SET ZLIBLIB=zlibstatic!ZLIBLIBSUFFIX!.lib + SET ZLIBOPT=zlib + ) + + SET LIB=%~dp0..\dist\zlib-%TP_ZLIB_VERSION%\!COMPILER!\!ARCH!\lib;!LIB! + SET BUILD_OPTIONS=!BUILD_OPTIONS! no-asm no-unit-test !ZLIBOPT! --openssldir=ssl --with-zlib-include=%~dp0..\dist\zlib-%TP_ZLIB_VERSION%\!COMPILER!\!ARCH!\include --with-zlib-lib=!ZLIBLIB! + SET OUTDIR=%WIN3P_ROOT%\dist\%PACKAGE_NAME%-%PACKAGE_VERSION%\%COMPILER%\%ARCH%\!OUTBUILDTYPE!\!OUTLIBTYPE! + + ECHO/ + ECHO ========================================================================= + ECHO Building: %PACKAGE_NAME% %PACKAGE_VERSION% %COMPILER%:%ARCH%:!OUTBUILDTYPE!:!OUTLIBTYPE! [!BUILDTYPE!] + ECHO Configure Options: !BUILD_OPTIONS! + ECHO Install Directory: !OUTDIR! + ECHO Source Directory: %SOURCEDIR% + ECHO ========================================================================= + ECHO/ + + IF NOT DEFINED NOASK ( + CHOICE /M "Do you want to build this configuration? " /c YN + IF !ERRORLEVEL! NEQ 1 (EXIT /B !ERRORLEVEL!) + ) + + CD %SOURCEDIR% || EXIT /B + perl Configure !BUILDTYPE! --prefix="!OUTDIR!" !BUILD_OPTIONS! || EXIT /B + NMAKE /FMakefile install_sw || EXIT /B + NMAKE /FMakefile clean || EXIT /B + ) +) + +ENDLOCAL +EXIT /B diff --git a/build/wincpp/thirdparty/src/build-zlib.bat b/build/wincpp/thirdparty/src/build-zlib.bat new file mode 100644 index 0000000..2427230 --- /dev/null +++ b/build/wincpp/thirdparty/src/build-zlib.bat @@ -0,0 +1,75 @@ +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: + +:: +:: Build script for zlib on windows. +:: Uses the environment set up by a Visual Studio Command Prompt shortcut +:: to target a specific architecture and compiler. +:: + +@ECHO OFF +SETLOCAL EnableDelayedExpansion + +:: Sets variables for third party versions used in build +CALL ..\..\scripts\tpversions.bat || EXIT /B + +:: use "build-zlib.bat /yes" to skip the question part +IF /I "%1" == "/YES" SET NOASK=1 + +IF NOT DEFINED GENERATOR SET GENERATOR=NMake Makefiles +IF NOT DEFINED PACKAGE_NAME SET PACKAGE_NAME=zlib +IF NOT DEFINED PACKAGE_VERSION SET PACKAGE_VERSION=%TP_ZLIB_VERSION% +IF NOT DEFINED SOURCE_DIR SET SOURCEDIR=%~dp0%PACKAGE_NAME%-%PACKAGE_VERSION% +IF NOT DEFINED WIN3P_ROOT SET WIN3P_ROOT=%~dp0.. + +:: Set COMPILER to (vc100 - vc140) depending on the current environment +CALL ..\..\scripts\cl_setcompiler.bat || EXIT /B + +:: Set ARCH to either win32 or x64 depending on the current environment +CALL ..\..\scripts\cl_setarch.bat || EXIT /B + +FOR %%X IN ( + Debug + Release +) DO ( + SET BUILDTYPE=%%X + SET BUILDDIR=%WIN3P_ROOT%\build\%PACKAGE_NAME%\%PACKAGE_VERSION%\%COMPILER%\%ARCH%\!BUILDTYPE! + SET OUTDIR=%WIN3P_ROOT%\dist\%PACKAGE_NAME%-%PACKAGE_VERSION%\%COMPILER%\%ARCH% + + ECHO/ + ECHO ========================================================================= + ECHO Building: %PACKAGE_NAME% v%PACKAGE_VERSION% %COMPILER%:%ARCH%:!BUILDTYPE! "%GENERATOR%" + ECHO Build Directory: !BUILDDIR! + ECHO Install Directory: !OUTDIR! + ECHO Source Directory: %SOURCEDIR% + ECHO ========================================================================= + ECHO/ + + IF NOT DEFINED NOASK ( + CHOICE /M "Do you want to build this configuration? " /c YN + IF !ERRORLEVEL! NEQ 1 (EXIT /B !ERRORLEVEL!) + ) + + MKDIR "!BUILDDIR!" + CD "!BUILDDIR!" || EXIT /B + + CMAKE.EXE -G"%GENERATOR%" -DCMAKE_INSTALL_PREFIX=!OUTDIR! -DCMAKE_BUILD_TYPE=!BUILDTYPE! "%SOURCEDIR%" || EXIT /B + NMAKE /fMakefile install || EXIT /B + + IF "!BUILDTYPE!" == "Debug" ( + COPY "!BUILDDIR!\zlibd.pdb" "!OUTDIR!\bin\" || EXIT /B + ) +) + +ENDLOCAL diff --git a/cleanup.sh b/cleanup.sh new file mode 100755 index 0000000..f110721 --- /dev/null +++ b/cleanup.sh @@ -0,0 +1,89 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +topsrcdir="`dirname $0`" +cd "$topsrcdir" + +make -k clean >/dev/null 2>&1 +make -k distclean >/dev/null 2>&1 +find . -name Makefile.in -exec rm -f {} \; +rm -rf \ +AUTHORS \ +ChangeLog \ +INSTALL \ +Makefile \ +Makefile.in \ +Makefile.orig \ +aclocal/libtool.m4 \ +aclocal/ltoptions.m4 \ +aclocal/ltsugar.m4 \ +aclocal/ltversion.m4 \ +aclocal/lt~obsolete.m4 \ +aclocal.m4 \ +autom4te.cache \ +autoscan.log \ +config.guess \ +config.h \ +config.hin \ +config.hin~ \ +config.log \ +config.status \ +config.status.lineno \ +config.sub \ +configure \ +configure.lineno \ +configure.scan \ +depcomp \ +.deps \ +install-sh \ +.libs \ +libtool \ +ltmain.sh \ +missing \ +ylwrap \ +if/gen-* \ +test/gen-* \ +lib/php/src/ext/thrift_protocol/.deps \ +lib/php/src/ext/thrift_protocol/Makefile \ +lib/php/src/ext/thrift_protocol/Makefile.fragments \ +lib/php/src/ext/thrift_protocol/Makefile.global \ +lib/php/src/ext/thrift_protocol/Makefile.objects \ +lib/php/src/ext/thrift_protocol/acinclude.m4 \ +lib/php/src/ext/thrift_protocol/aclocal.m4 \ +lib/php/src/ext/thrift_protocol/autom4te.cache \ +lib/php/src/ext/thrift_protocol/build \ +lib/php/src/ext/thrift_protocol/config.guess \ +lib/php/src/ext/thrift_protocol/config.h \ +lib/php/src/ext/thrift_protocol/config.h.in \ +lib/php/src/ext/thrift_protocol/config.log \ +lib/php/src/ext/thrift_protocol/config.nice \ +lib/php/src/ext/thrift_protocol/config.status \ +lib/php/src/ext/thrift_protocol/config.sub \ +lib/php/src/ext/thrift_protocol/configure \ +lib/php/src/ext/thrift_protocol/configure.in \ +lib/php/src/ext/thrift_protocol/include \ +lib/php/src/ext/thrift_protocol/install-sh \ +lib/php/src/ext/thrift_protocol/libtool \ +lib/php/src/ext/thrift_protocol/ltmain.sh \ +lib/php/src/ext/thrift_protocol/missing \ +lib/php/src/ext/thrift_protocol/mkinstalldirs \ +lib/php/src/ext/thrift_protocol/modules \ +lib/php/src/ext/thrift_protocol/run-tests.php diff --git a/compile b/compile new file mode 100755 index 0000000..a85b723 --- /dev/null +++ b/compile @@ -0,0 +1,347 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2012-10-14.11; # UTC + +# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + if test -f "$dir/lib$lib.a"; then + found=yes + lib=$dir/lib$lib.a + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + for arg + do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand '-c -o'. +Remove '-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file 'INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + # So we strip '-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no '-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # '.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use '[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/compiler/cpp/CMakeLists.txt b/compiler/cpp/CMakeLists.txt new file mode 100644 index 0000000..5da28aa --- /dev/null +++ b/compiler/cpp/CMakeLists.txt @@ -0,0 +1,217 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +cmake_minimum_required(VERSION 2.8.12) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/thrift/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/thrift/version.h) +if(MSVC) + # The winflexbison generator outputs some macros that conflict with the Visual Studio 2010 copy of stdint.h + # This might be fixed in later versions of Visual Studio, but an easy solution is to include stdint.h first + if(HAVE_STDINT_H) + add_definitions(-D__STDC_FORMAT_MACROS) + add_definitions(-D__STDC_LIMIT_MACROS) + add_definitions(/FI"stdint.h") + endif(HAVE_STDINT_H) +endif() + +find_package(FLEX REQUIRED) +find_package(BISON REQUIRED) + +# create directory for thrifty and thriftl +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/thrift/) + +# Create flex and bison files and build the lib parse static library +BISON_TARGET(thrifty ${CMAKE_CURRENT_SOURCE_DIR}/src/thrift/thrifty.yy ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.cc) +FLEX_TARGET(thriftl ${CMAKE_CURRENT_SOURCE_DIR}/src/thrift/thriftl.ll ${CMAKE_CURRENT_BINARY_DIR}/thrift/thriftl.cc) +ADD_FLEX_BISON_DEPENDENCY(thriftl thrifty) + +set(parse_SOURCES + ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.cc + ${CMAKE_CURRENT_BINARY_DIR}/thrift/thriftl.cc + ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.hh +) + +add_library(parse STATIC ${parse_SOURCES}) + +# Create the thrift compiler +set(compiler_core + src/thrift/common.cc + src/thrift/generate/t_generator.cc + src/thrift/parse/t_typedef.cc + src/thrift/parse/parse.cc + ${CMAKE_CURRENT_BINARY_DIR}/thrift/version.h +) + +set(thrift-compiler_SOURCES + src/thrift/main.cc + src/thrift/audit/t_audit.cpp +) + +# This macro adds an option THRIFT_COMPILER_${NAME} +# that allows enabling or disabling certain languages +macro(THRIFT_ADD_COMPILER name description initial) + string(TOUPPER "THRIFT_COMPILER_${name}" enabler) + set(src "src/thrift/generate/t_${name}_generator.cc") + option(${enabler} ${description} ${initial}) + if(${enabler}) + list(APPEND thrift-compiler_SOURCES ${src}) + endif() +endmacro() + +# The following compiler can be enabled or disabled +THRIFT_ADD_COMPILER(c_glib "Enable compiler for C with Glib" ON) +THRIFT_ADD_COMPILER(cpp "Enable compiler for C++" ON) +THRIFT_ADD_COMPILER(java "Enable compiler for Java" ON) +THRIFT_ADD_COMPILER(as3 "Enable compiler for ActionScript 3" ON) +THRIFT_ADD_COMPILER(dart "Enable compiler for Dart" ON) +THRIFT_ADD_COMPILER(haxe "Enable compiler for Haxe" ON) +THRIFT_ADD_COMPILER(csharp "Enable compiler for C#" ON) +THRIFT_ADD_COMPILER(netcore "Enable compiler for .NET Core" ON) +THRIFT_ADD_COMPILER(py "Enable compiler for Python 2.0" ON) +THRIFT_ADD_COMPILER(rb "Enable compiler for Ruby" ON) +THRIFT_ADD_COMPILER(perl "Enable compiler for Perl" ON) +THRIFT_ADD_COMPILER(php "Enable compiler for PHP" ON) +THRIFT_ADD_COMPILER(erl "Enable compiler for Erlang" ON) +THRIFT_ADD_COMPILER(cocoa "Enable compiler for Cocoa Objective-C" ON) +THRIFT_ADD_COMPILER(swift "Enable compiler for Cocoa Swift" ON) +THRIFT_ADD_COMPILER(st "Enable compiler for Smalltalk" ON) +THRIFT_ADD_COMPILER(ocaml "Enable compiler for OCaml" ON) +THRIFT_ADD_COMPILER(hs "Enable compiler for Haskell" ON) +THRIFT_ADD_COMPILER(xsd "Enable compiler for XSD" ON) +THRIFT_ADD_COMPILER(html "Enable compiler for HTML Documentation" ON) +THRIFT_ADD_COMPILER(js "Enable compiler for JavaScript" ON) +THRIFT_ADD_COMPILER(json "Enable compiler for JSON" ON) +THRIFT_ADD_COMPILER(javame "Enable compiler for Java ME" ON) +THRIFT_ADD_COMPILER(delphi "Enable compiler for Delphi" ON) +THRIFT_ADD_COMPILER(go "Enable compiler for Go" ON) +THRIFT_ADD_COMPILER(d "Enable compiler for D" ON) +THRIFT_ADD_COMPILER(lua "Enable compiler for Lua" ON) +THRIFT_ADD_COMPILER(gv "Enable compiler for GraphViz" ON) +THRIFT_ADD_COMPILER(rs "Enable compiler for Rust" ON) +THRIFT_ADD_COMPILER(xml "Enable compiler for XML" ON) + +# Thrift is looking for include files in the src directory +# we also add the current binary directory for generated files +include_directories(${CMAKE_CURRENT_BINARY_DIR} src) + +if(NOT ${WITH_PLUGIN}) + list(APPEND thrift-compiler_SOURCES ${compiler_core}) +endif() + +add_executable(thrift-compiler ${thrift-compiler_SOURCES}) + +if(${WITH_PLUGIN}) + add_executable(thrift-bootstrap ${compiler_core} + src/thrift/main.cc + src/thrift/audit/t_audit.cpp + src/thrift/generate/t_cpp_generator.cc + ) + target_link_libraries(thrift-bootstrap parse) + + set(PLUGIN_GEN_SOURCES + ${CMAKE_CURRENT_BINARY_DIR}/thrift/plugin/plugin_types.h + ${CMAKE_CURRENT_BINARY_DIR}/thrift/plugin/plugin_types.cpp + ${CMAKE_CURRENT_BINARY_DIR}/thrift/plugin/plugin_constants.h + ${CMAKE_CURRENT_BINARY_DIR}/thrift/plugin/plugin_constants.cpp + ) + + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/thrift/plugin) + add_custom_command(OUTPUT ${PLUGIN_GEN_SOURCES} + DEPENDS thrift-bootstrap src/thrift/plugin/plugin.thrift + COMMAND thrift-bootstrap -gen cpp + -out ${CMAKE_CURRENT_BINARY_DIR}/thrift/plugin + ${CMAKE_CURRENT_SOURCE_DIR}/src/thrift/plugin/plugin.thrift + ) + + include_directories(../../lib/cpp/src) + + include(ThriftMacros) + ADD_LIBRARY_THRIFT(thriftc + ${compiler_core} + ${PLUGIN_GEN_SOURCES} + src/thrift/logging.cc + src/thrift/plugin/plugin_output.cc + src/thrift/plugin/plugin.cc + ) + TARGET_INCLUDE_DIRECTORIES_THRIFT(thriftc PUBLIC ${Boost_INCLUDE_DIRS}) + TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY(thriftc thrift PUBLIC) + target_compile_definitions(thrift-compiler PUBLIC THRIFT_ENABLE_PLUGIN) + LINK_AGAINST_THRIFT_LIBRARY(thrift-compiler thriftc) +endif() + +set_target_properties(thrift-compiler PROPERTIES RUNTIME_OUTPUT_DIRECTORY bin/) +set_target_properties(thrift-compiler PROPERTIES OUTPUT_NAME thrift) + +target_link_libraries(thrift-compiler parse) + +install(TARGETS thrift-compiler DESTINATION bin) + +if(${WITH_PLUGIN}) + # Install the headers + install(FILES + "src/thrift/common.h" + "src/thrift/globals.h" + "src/thrift/logging.h" + "src/thrift/main.h" + "src/thrift/platform.h" + "${CMAKE_BINARY_DIR}/compiler/cpp/thrift/version.h" + DESTINATION "${INCLUDE_INSTALL_DIR}/thrift") + install(FILES + "src/thrift/audit/t_audit.h" + DESTINATION "${INCLUDE_INSTALL_DIR}/thrift/audit") + install(FILES + "src/thrift/generate/t_generator.h" + "src/thrift/generate/t_generator_registry.h" + "src/thrift/generate/t_html_generator.h" + "src/thrift/generate/t_oop_generator.h" + DESTINATION "${INCLUDE_INSTALL_DIR}/thrift/generate") + install(FILES + "src/thrift/parse/t_base_type.h" + "src/thrift/parse/t_const.h" + "src/thrift/parse/t_const_value.h" + "src/thrift/parse/t_container.h" + "src/thrift/parse/t_doc.h" + "src/thrift/parse/t_enum.h" + "src/thrift/parse/t_enum_value.h" + "src/thrift/parse/t_field.h" + "src/thrift/parse/t_function.h" + "src/thrift/parse/t_list.h" + "src/thrift/parse/t_map.h" + "src/thrift/parse/t_program.h" + "src/thrift/parse/t_scope.h" + "src/thrift/parse/t_service.h" + "src/thrift/parse/t_set.h" + "src/thrift/parse/t_struct.h" + "src/thrift/parse/t_typedef.h" + "src/thrift/parse/t_type.h" + DESTINATION "${INCLUDE_INSTALL_DIR}/thrift/parse") + install(FILES + "src/thrift/plugin/plugin.h" + "src/thrift/plugin/plugin_output.h" + "src/thrift/plugin/type_util.h" + DESTINATION "${INCLUDE_INSTALL_DIR}/thrift/plugin") +if(MSVC) + install(FILES + "src/thrift/windows/config.h" + DESTINATION "${INCLUDE_INSTALL_DIR}/thrift/windows") +endif() +endif() + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/compiler/cpp/Makefile.am b/compiler/cpp/Makefile.am new file mode 100644 index 0000000..482a89a --- /dev/null +++ b/compiler/cpp/Makefile.am @@ -0,0 +1,205 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# +# Contains some contributions under the Thrift Software License. +# Please see doc/old-thrift-license.txt in the Thrift distribution for +# details. + +AUTOMAKE_OPTIONS = subdir-objects + +# Note on why we have src/thrift and src/thrift/plugin directories: +# Since Automake supports only one set of BUILT_SOURCES per file and does not allow +# SUBDIRS built before BUILT_SOURCES, we end up separate Makefile.am for each source +# code generation, i.e. lex-yacc and Thrift, to achieve stable parallel make. + +SUBDIRS = src src/thrift/plugin . +if WITH_TESTS +SUBDIRS += test +endif + +bin_PROGRAMS = thrift + +thrift_OBJDIR = obj + +plugin_gen = src/thrift/plugin/plugin_types.h \ + src/thrift/plugin/plugin_types.cpp \ + src/thrift/plugin/plugin_constants.h \ + src/thrift/plugin/plugin_constants.cpp + +compiler_core = src/thrift/common.h \ + src/thrift/common.cc \ + src/thrift/generate/t_generator.cc \ + src/thrift/generate/t_generator_registry.h \ + src/thrift/globals.h \ + src/thrift/platform.h \ + src/thrift/logging.h \ + src/thrift/parse/t_doc.h \ + src/thrift/parse/t_type.h \ + src/thrift/parse/t_base_type.h \ + src/thrift/parse/t_enum.h \ + src/thrift/parse/t_enum_value.h \ + src/thrift/parse/t_typedef.h \ + src/thrift/parse/t_typedef.cc \ + src/thrift/parse/t_container.h \ + src/thrift/parse/t_list.h \ + src/thrift/parse/t_set.h \ + src/thrift/parse/t_map.h \ + src/thrift/parse/t_struct.h \ + src/thrift/parse/t_field.h \ + src/thrift/parse/t_service.h \ + src/thrift/parse/t_function.h \ + src/thrift/parse/t_program.h \ + src/thrift/parse/t_scope.h \ + src/thrift/parse/t_const.h \ + src/thrift/parse/t_const_value.h \ + src/thrift/parse/parse.cc \ + src/thrift/generate/t_generator.h \ + src/thrift/generate/t_oop_generator.h \ + src/thrift/generate/t_html_generator.h + +thrift_SOURCES = src/thrift/main.h \ + src/thrift/main.cc \ + src/thrift/audit/t_audit.cpp \ + src/thrift/audit/t_audit.h + +# Specific client generator source +thrift_SOURCES += src/thrift/generate/t_c_glib_generator.cc \ + src/thrift/generate/t_cpp_generator.cc \ + src/thrift/generate/t_java_generator.cc \ + src/thrift/generate/t_json_generator.cc \ + src/thrift/generate/t_as3_generator.cc \ + src/thrift/generate/t_dart_generator.cc \ + src/thrift/generate/t_haxe_generator.cc \ + src/thrift/generate/t_csharp_generator.cc \ + src/thrift/generate/t_netcore_generator.cc \ + src/thrift/generate/t_py_generator.cc \ + src/thrift/generate/t_rb_generator.cc \ + src/thrift/generate/t_perl_generator.cc \ + src/thrift/generate/t_php_generator.cc \ + src/thrift/generate/t_erl_generator.cc \ + src/thrift/generate/t_cocoa_generator.cc \ + src/thrift/generate/t_swift_generator.cc \ + src/thrift/generate/t_st_generator.cc \ + src/thrift/generate/t_ocaml_generator.cc \ + src/thrift/generate/t_hs_generator.cc \ + src/thrift/generate/t_xsd_generator.cc \ + src/thrift/generate/t_xml_generator.cc \ + src/thrift/generate/t_html_generator.cc \ + src/thrift/generate/t_js_generator.cc \ + src/thrift/generate/t_javame_generator.cc \ + src/thrift/generate/t_delphi_generator.cc \ + src/thrift/generate/t_go_generator.cc \ + src/thrift/generate/t_gv_generator.cc \ + src/thrift/generate/t_d_generator.cc \ + src/thrift/generate/t_lua_generator.cc \ + src/thrift/generate/t_rs_generator.cc + +thrift_CPPFLAGS = -I$(srcdir)/src +thrift_CXXFLAGS = -Wall -Wextra -pedantic -Werror +thrift_LDADD = @LEXLIB@ src/thrift/libparse.a + +if !WITH_PLUGIN +thrift_SOURCES += $(compiler_core) +else + +lib_LTLIBRARIES = libthriftc.la + +thrift_CPPFLAGS += -DTHRIFT_ENABLE_PLUGIN=1 +thrift_LDADD += libthriftc.la + +nodist_libthriftc_la_SOURCES = $(plugin_gen) +libthriftc_la_SOURCES = $(compiler_core) \ + src/thrift/plugin/type_util.h \ + src/thrift/plugin/plugin.h \ + src/thrift/plugin/plugin.cc \ + src/thrift/plugin/plugin_output.h \ + src/thrift/plugin/plugin_output.cc \ + src/thrift/plugin/plugin.thrift \ + src/thrift/logging.cc + + +libthriftc_la_CPPFLAGS = -I$(srcdir)/src -Isrc -I$(top_builddir)/lib/cpp/src -DTHRIFT_ENABLE_PLUGIN=1 +libthriftc_la_CXXFLAGS = -Wall -Wextra -pedantic +libthriftc_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la + +include_thriftdir = $(includedir)/thrift +include_thrift_HEADERS = src/thrift/common.h \ + src/thrift/globals.h \ + src/thrift/logging.h \ + src/thrift/main.h \ + src/thrift/platform.h \ + src/thrift/version.h + +include_auditdir = $(include_thriftdir)/windows +include_audit_HEADERS = src/thrift/audit/t_audit.h + +include_generatedir = $(include_thriftdir)/generate +include_generate_HEADERS = src/thrift/generate/t_generator.h \ + src/thrift/generate/t_generator_registry.h \ + src/thrift/generate/t_oop_generator.h \ + src/thrift/generate/t_html_generator.h + +include_parsedir = $(include_thriftdir)/parse +include_parse_HEADERS = src/thrift/parse/t_service.h \ + src/thrift/parse/t_program.h \ + src/thrift/parse/t_field.h \ + src/thrift/parse/t_scope.h \ + src/thrift/parse/t_typedef.h \ + src/thrift/parse/t_set.h \ + src/thrift/parse/t_const_value.h \ + src/thrift/parse/t_enum_value.h \ + src/thrift/parse/t_const.h \ + src/thrift/parse/t_list.h \ + src/thrift/parse/t_map.h \ + src/thrift/parse/t_container.h \ + src/thrift/parse/t_base_type.h \ + src/thrift/parse/t_enum.h \ + src/thrift/parse/t_function.h \ + src/thrift/parse/t_type.h \ + src/thrift/parse/t_doc.h \ + src/thrift/parse/t_struct.h + +include_plugindir = $(include_thriftdir)/plugin +include_plugin_HEADERS = src/thrift/plugin/plugin.h \ + src/thrift/plugin/type_util.h \ + src/thrift/plugin/plugin_output.h + +include_windowsdir = $(include_thriftdir)/windows +include_windows_HEADERS = src/thrift/windows/config.h +endif + +WINDOWS_DIST = \ + compiler.sln \ + compiler.vcxproj \ + compiler.vcxproj.filters + +EXTRA_DIST = \ + coding_standards.md \ + README.md \ + CMakeLists.txt \ + test \ + $(WINDOWS_DIST) + +clean-local: + $(RM) version.h $(plugin_gen) + +src/thrift/main.cc: src/thrift/version.h + +style-local: + $(CPPSTYLE_CMD) diff --git a/compiler/cpp/Makefile.in b/compiler/cpp/Makefile.in new file mode 100644 index 0000000..d83d398 --- /dev/null +++ b/compiler/cpp/Makefile.in @@ -0,0 +1,2314 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# +# Contains some contributions under the Thrift Software License. +# Please see doc/old-thrift-license.txt in the Thrift distribution for +# details. + + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@WITH_TESTS_TRUE@am__append_1 = test +bin_PROGRAMS = thrift$(EXEEXT) +@WITH_PLUGIN_FALSE@am__append_2 = $(compiler_core) +@WITH_PLUGIN_TRUE@am__append_3 = -DTHRIFT_ENABLE_PLUGIN=1 +@WITH_PLUGIN_TRUE@am__append_4 = libthriftc.la +subdir = compiler/cpp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__include_audit_HEADERS_DIST) \ + $(am__include_generate_HEADERS_DIST) \ + $(am__include_parse_HEADERS_DIST) \ + $(am__include_plugin_HEADERS_DIST) \ + $(am__include_thrift_HEADERS_DIST) \ + $(am__include_windows_HEADERS_DIST) $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(include_auditdir)" \ + "$(DESTDIR)$(include_generatedir)" \ + "$(DESTDIR)$(include_parsedir)" \ + "$(DESTDIR)$(include_plugindir)" \ + "$(DESTDIR)$(include_thriftdir)" \ + "$(DESTDIR)$(include_windowsdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +@WITH_PLUGIN_TRUE@libthriftc_la_DEPENDENCIES = \ +@WITH_PLUGIN_TRUE@ $(top_builddir)/lib/cpp/libthrift.la +am__libthriftc_la_SOURCES_DIST = src/thrift/common.h \ + src/thrift/common.cc src/thrift/generate/t_generator.cc \ + src/thrift/generate/t_generator_registry.h \ + src/thrift/globals.h src/thrift/platform.h \ + src/thrift/logging.h src/thrift/parse/t_doc.h \ + src/thrift/parse/t_type.h src/thrift/parse/t_base_type.h \ + src/thrift/parse/t_enum.h src/thrift/parse/t_enum_value.h \ + src/thrift/parse/t_typedef.h src/thrift/parse/t_typedef.cc \ + src/thrift/parse/t_container.h src/thrift/parse/t_list.h \ + src/thrift/parse/t_set.h src/thrift/parse/t_map.h \ + src/thrift/parse/t_struct.h src/thrift/parse/t_field.h \ + src/thrift/parse/t_service.h src/thrift/parse/t_function.h \ + src/thrift/parse/t_program.h src/thrift/parse/t_scope.h \ + src/thrift/parse/t_const.h src/thrift/parse/t_const_value.h \ + src/thrift/parse/parse.cc src/thrift/generate/t_generator.h \ + src/thrift/generate/t_oop_generator.h \ + src/thrift/generate/t_html_generator.h \ + src/thrift/plugin/type_util.h src/thrift/plugin/plugin.h \ + src/thrift/plugin/plugin.cc src/thrift/plugin/plugin_output.h \ + src/thrift/plugin/plugin_output.cc \ + src/thrift/plugin/plugin.thrift src/thrift/logging.cc +am__dirstamp = $(am__leading_dot)dirstamp +am__objects_1 = src/thrift/libthriftc_la-common.lo \ + src/thrift/generate/libthriftc_la-t_generator.lo \ + src/thrift/parse/libthriftc_la-t_typedef.lo \ + src/thrift/parse/libthriftc_la-parse.lo +@WITH_PLUGIN_TRUE@am_libthriftc_la_OBJECTS = $(am__objects_1) \ +@WITH_PLUGIN_TRUE@ src/thrift/plugin/libthriftc_la-plugin.lo \ +@WITH_PLUGIN_TRUE@ src/thrift/plugin/libthriftc_la-plugin_output.lo \ +@WITH_PLUGIN_TRUE@ src/thrift/libthriftc_la-logging.lo +am__objects_2 = src/thrift/plugin/libthriftc_la-plugin_types.lo \ + src/thrift/plugin/libthriftc_la-plugin_constants.lo +@WITH_PLUGIN_TRUE@nodist_libthriftc_la_OBJECTS = $(am__objects_2) +libthriftc_la_OBJECTS = $(am_libthriftc_la_OBJECTS) \ + $(nodist_libthriftc_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libthriftc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +@WITH_PLUGIN_TRUE@am_libthriftc_la_rpath = -rpath $(libdir) +PROGRAMS = $(bin_PROGRAMS) +am__thrift_SOURCES_DIST = src/thrift/main.h src/thrift/main.cc \ + src/thrift/audit/t_audit.cpp src/thrift/audit/t_audit.h \ + src/thrift/generate/t_c_glib_generator.cc \ + src/thrift/generate/t_cpp_generator.cc \ + src/thrift/generate/t_java_generator.cc \ + src/thrift/generate/t_json_generator.cc \ + src/thrift/generate/t_as3_generator.cc \ + src/thrift/generate/t_dart_generator.cc \ + src/thrift/generate/t_haxe_generator.cc \ + src/thrift/generate/t_csharp_generator.cc \ + src/thrift/generate/t_netcore_generator.cc \ + src/thrift/generate/t_py_generator.cc \ + src/thrift/generate/t_rb_generator.cc \ + src/thrift/generate/t_perl_generator.cc \ + src/thrift/generate/t_php_generator.cc \ + src/thrift/generate/t_erl_generator.cc \ + src/thrift/generate/t_cocoa_generator.cc \ + src/thrift/generate/t_swift_generator.cc \ + src/thrift/generate/t_st_generator.cc \ + src/thrift/generate/t_ocaml_generator.cc \ + src/thrift/generate/t_hs_generator.cc \ + src/thrift/generate/t_xsd_generator.cc \ + src/thrift/generate/t_xml_generator.cc \ + src/thrift/generate/t_html_generator.cc \ + src/thrift/generate/t_js_generator.cc \ + src/thrift/generate/t_javame_generator.cc \ + src/thrift/generate/t_delphi_generator.cc \ + src/thrift/generate/t_go_generator.cc \ + src/thrift/generate/t_gv_generator.cc \ + src/thrift/generate/t_d_generator.cc \ + src/thrift/generate/t_lua_generator.cc \ + src/thrift/generate/t_rs_generator.cc src/thrift/common.h \ + src/thrift/common.cc src/thrift/generate/t_generator.cc \ + src/thrift/generate/t_generator_registry.h \ + src/thrift/globals.h src/thrift/platform.h \ + src/thrift/logging.h src/thrift/parse/t_doc.h \ + src/thrift/parse/t_type.h src/thrift/parse/t_base_type.h \ + src/thrift/parse/t_enum.h src/thrift/parse/t_enum_value.h \ + src/thrift/parse/t_typedef.h src/thrift/parse/t_typedef.cc \ + src/thrift/parse/t_container.h src/thrift/parse/t_list.h \ + src/thrift/parse/t_set.h src/thrift/parse/t_map.h \ + src/thrift/parse/t_struct.h src/thrift/parse/t_field.h \ + src/thrift/parse/t_service.h src/thrift/parse/t_function.h \ + src/thrift/parse/t_program.h src/thrift/parse/t_scope.h \ + src/thrift/parse/t_const.h src/thrift/parse/t_const_value.h \ + src/thrift/parse/parse.cc src/thrift/generate/t_generator.h \ + src/thrift/generate/t_oop_generator.h \ + src/thrift/generate/t_html_generator.h +am__objects_3 = src/thrift/thrift-common.$(OBJEXT) \ + src/thrift/generate/thrift-t_generator.$(OBJEXT) \ + src/thrift/parse/thrift-t_typedef.$(OBJEXT) \ + src/thrift/parse/thrift-parse.$(OBJEXT) +@WITH_PLUGIN_FALSE@am__objects_4 = $(am__objects_3) +am_thrift_OBJECTS = src/thrift/thrift-main.$(OBJEXT) \ + src/thrift/audit/thrift-t_audit.$(OBJEXT) \ + src/thrift/generate/thrift-t_c_glib_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_cpp_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_java_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_json_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_as3_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_dart_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_haxe_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_csharp_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_netcore_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_py_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_rb_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_perl_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_php_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_erl_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_cocoa_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_swift_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_st_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_ocaml_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_hs_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_xsd_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_xml_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_html_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_js_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_javame_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_delphi_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_go_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_gv_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_d_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_lua_generator.$(OBJEXT) \ + src/thrift/generate/thrift-t_rs_generator.$(OBJEXT) \ + $(am__objects_4) +thrift_OBJECTS = $(am_thrift_OBJECTS) +thrift_DEPENDENCIES = src/thrift/libparse.a $(am__append_4) +thrift_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(thrift_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/lib/cpp/src/thrift -I$(top_builddir)/lib/c_glib/src/thrift +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libthriftc_la_SOURCES) $(nodist_libthriftc_la_SOURCES) \ + $(thrift_SOURCES) +DIST_SOURCES = $(am__libthriftc_la_SOURCES_DIST) \ + $(am__thrift_SOURCES_DIST) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__include_audit_HEADERS_DIST = src/thrift/audit/t_audit.h +am__include_generate_HEADERS_DIST = src/thrift/generate/t_generator.h \ + src/thrift/generate/t_generator_registry.h \ + src/thrift/generate/t_oop_generator.h \ + src/thrift/generate/t_html_generator.h +am__include_parse_HEADERS_DIST = src/thrift/parse/t_service.h \ + src/thrift/parse/t_program.h src/thrift/parse/t_field.h \ + src/thrift/parse/t_scope.h src/thrift/parse/t_typedef.h \ + src/thrift/parse/t_set.h src/thrift/parse/t_const_value.h \ + src/thrift/parse/t_enum_value.h src/thrift/parse/t_const.h \ + src/thrift/parse/t_list.h src/thrift/parse/t_map.h \ + src/thrift/parse/t_container.h src/thrift/parse/t_base_type.h \ + src/thrift/parse/t_enum.h src/thrift/parse/t_function.h \ + src/thrift/parse/t_type.h src/thrift/parse/t_doc.h \ + src/thrift/parse/t_struct.h +am__include_plugin_HEADERS_DIST = src/thrift/plugin/plugin.h \ + src/thrift/plugin/type_util.h \ + src/thrift/plugin/plugin_output.h +am__include_thrift_HEADERS_DIST = src/thrift/common.h \ + src/thrift/globals.h src/thrift/logging.h src/thrift/main.h \ + src/thrift/platform.h src/thrift/version.h +am__include_windows_HEADERS_DIST = src/thrift/windows/config.h +HEADERS = $(include_audit_HEADERS) $(include_generate_HEADERS) \ + $(include_parse_HEADERS) $(include_plugin_HEADERS) \ + $(include_thrift_HEADERS) $(include_windows_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = src src/thrift/plugin . test +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = subdir-objects + +# Note on why we have src/thrift and src/thrift/plugin directories: +# Since Automake supports only one set of BUILT_SOURCES per file and does not allow +# SUBDIRS built before BUILT_SOURCES, we end up separate Makefile.am for each source +# code generation, i.e. lex-yacc and Thrift, to achieve stable parallel make. +SUBDIRS = src src/thrift/plugin . $(am__append_1) +thrift_OBJDIR = obj +plugin_gen = src/thrift/plugin/plugin_types.h \ + src/thrift/plugin/plugin_types.cpp \ + src/thrift/plugin/plugin_constants.h \ + src/thrift/plugin/plugin_constants.cpp + +compiler_core = src/thrift/common.h \ + src/thrift/common.cc \ + src/thrift/generate/t_generator.cc \ + src/thrift/generate/t_generator_registry.h \ + src/thrift/globals.h \ + src/thrift/platform.h \ + src/thrift/logging.h \ + src/thrift/parse/t_doc.h \ + src/thrift/parse/t_type.h \ + src/thrift/parse/t_base_type.h \ + src/thrift/parse/t_enum.h \ + src/thrift/parse/t_enum_value.h \ + src/thrift/parse/t_typedef.h \ + src/thrift/parse/t_typedef.cc \ + src/thrift/parse/t_container.h \ + src/thrift/parse/t_list.h \ + src/thrift/parse/t_set.h \ + src/thrift/parse/t_map.h \ + src/thrift/parse/t_struct.h \ + src/thrift/parse/t_field.h \ + src/thrift/parse/t_service.h \ + src/thrift/parse/t_function.h \ + src/thrift/parse/t_program.h \ + src/thrift/parse/t_scope.h \ + src/thrift/parse/t_const.h \ + src/thrift/parse/t_const_value.h \ + src/thrift/parse/parse.cc \ + src/thrift/generate/t_generator.h \ + src/thrift/generate/t_oop_generator.h \ + src/thrift/generate/t_html_generator.h + + +# Specific client generator source +thrift_SOURCES = src/thrift/main.h src/thrift/main.cc \ + src/thrift/audit/t_audit.cpp src/thrift/audit/t_audit.h \ + src/thrift/generate/t_c_glib_generator.cc \ + src/thrift/generate/t_cpp_generator.cc \ + src/thrift/generate/t_java_generator.cc \ + src/thrift/generate/t_json_generator.cc \ + src/thrift/generate/t_as3_generator.cc \ + src/thrift/generate/t_dart_generator.cc \ + src/thrift/generate/t_haxe_generator.cc \ + src/thrift/generate/t_csharp_generator.cc \ + src/thrift/generate/t_netcore_generator.cc \ + src/thrift/generate/t_py_generator.cc \ + src/thrift/generate/t_rb_generator.cc \ + src/thrift/generate/t_perl_generator.cc \ + src/thrift/generate/t_php_generator.cc \ + src/thrift/generate/t_erl_generator.cc \ + src/thrift/generate/t_cocoa_generator.cc \ + src/thrift/generate/t_swift_generator.cc \ + src/thrift/generate/t_st_generator.cc \ + src/thrift/generate/t_ocaml_generator.cc \ + src/thrift/generate/t_hs_generator.cc \ + src/thrift/generate/t_xsd_generator.cc \ + src/thrift/generate/t_xml_generator.cc \ + src/thrift/generate/t_html_generator.cc \ + src/thrift/generate/t_js_generator.cc \ + src/thrift/generate/t_javame_generator.cc \ + src/thrift/generate/t_delphi_generator.cc \ + src/thrift/generate/t_go_generator.cc \ + src/thrift/generate/t_gv_generator.cc \ + src/thrift/generate/t_d_generator.cc \ + src/thrift/generate/t_lua_generator.cc \ + src/thrift/generate/t_rs_generator.cc $(am__append_2) +thrift_CPPFLAGS = -I$(srcdir)/src $(am__append_3) +thrift_CXXFLAGS = -Wall -Wextra -pedantic -Werror +thrift_LDADD = @LEXLIB@ src/thrift/libparse.a $(am__append_4) +@WITH_PLUGIN_TRUE@lib_LTLIBRARIES = libthriftc.la +@WITH_PLUGIN_TRUE@nodist_libthriftc_la_SOURCES = $(plugin_gen) +@WITH_PLUGIN_TRUE@libthriftc_la_SOURCES = $(compiler_core) \ +@WITH_PLUGIN_TRUE@ src/thrift/plugin/type_util.h \ +@WITH_PLUGIN_TRUE@ src/thrift/plugin/plugin.h \ +@WITH_PLUGIN_TRUE@ src/thrift/plugin/plugin.cc \ +@WITH_PLUGIN_TRUE@ src/thrift/plugin/plugin_output.h \ +@WITH_PLUGIN_TRUE@ src/thrift/plugin/plugin_output.cc \ +@WITH_PLUGIN_TRUE@ src/thrift/plugin/plugin.thrift \ +@WITH_PLUGIN_TRUE@ src/thrift/logging.cc + +@WITH_PLUGIN_TRUE@libthriftc_la_CPPFLAGS = -I$(srcdir)/src -Isrc -I$(top_builddir)/lib/cpp/src -DTHRIFT_ENABLE_PLUGIN=1 +@WITH_PLUGIN_TRUE@libthriftc_la_CXXFLAGS = -Wall -Wextra -pedantic +@WITH_PLUGIN_TRUE@libthriftc_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la +@WITH_PLUGIN_TRUE@include_thriftdir = $(includedir)/thrift +@WITH_PLUGIN_TRUE@include_thrift_HEADERS = src/thrift/common.h \ +@WITH_PLUGIN_TRUE@ src/thrift/globals.h \ +@WITH_PLUGIN_TRUE@ src/thrift/logging.h \ +@WITH_PLUGIN_TRUE@ src/thrift/main.h \ +@WITH_PLUGIN_TRUE@ src/thrift/platform.h \ +@WITH_PLUGIN_TRUE@ src/thrift/version.h + +@WITH_PLUGIN_TRUE@include_auditdir = $(include_thriftdir)/windows +@WITH_PLUGIN_TRUE@include_audit_HEADERS = src/thrift/audit/t_audit.h +@WITH_PLUGIN_TRUE@include_generatedir = $(include_thriftdir)/generate +@WITH_PLUGIN_TRUE@include_generate_HEADERS = src/thrift/generate/t_generator.h \ +@WITH_PLUGIN_TRUE@ src/thrift/generate/t_generator_registry.h \ +@WITH_PLUGIN_TRUE@ src/thrift/generate/t_oop_generator.h \ +@WITH_PLUGIN_TRUE@ src/thrift/generate/t_html_generator.h + +@WITH_PLUGIN_TRUE@include_parsedir = $(include_thriftdir)/parse +@WITH_PLUGIN_TRUE@include_parse_HEADERS = src/thrift/parse/t_service.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_program.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_field.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_scope.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_typedef.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_set.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_const_value.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_enum_value.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_const.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_list.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_map.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_container.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_base_type.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_enum.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_function.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_type.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_doc.h \ +@WITH_PLUGIN_TRUE@ src/thrift/parse/t_struct.h + +@WITH_PLUGIN_TRUE@include_plugindir = $(include_thriftdir)/plugin +@WITH_PLUGIN_TRUE@include_plugin_HEADERS = src/thrift/plugin/plugin.h \ +@WITH_PLUGIN_TRUE@ src/thrift/plugin/type_util.h \ +@WITH_PLUGIN_TRUE@ src/thrift/plugin/plugin_output.h + +@WITH_PLUGIN_TRUE@include_windowsdir = $(include_thriftdir)/windows +@WITH_PLUGIN_TRUE@include_windows_HEADERS = src/thrift/windows/config.h +WINDOWS_DIST = \ + compiler.sln \ + compiler.vcxproj \ + compiler.vcxproj.filters + +EXTRA_DIST = \ + coding_standards.md \ + README.md \ + CMakeLists.txt \ + test \ + $(WINDOWS_DIST) + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .cc .cpp .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign compiler/cpp/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign compiler/cpp/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } +src/thrift/$(am__dirstamp): + @$(MKDIR_P) src/thrift + @: > src/thrift/$(am__dirstamp) +src/thrift/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/thrift/$(DEPDIR) + @: > src/thrift/$(DEPDIR)/$(am__dirstamp) +src/thrift/libthriftc_la-common.lo: src/thrift/$(am__dirstamp) \ + src/thrift/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/$(am__dirstamp): + @$(MKDIR_P) src/thrift/generate + @: > src/thrift/generate/$(am__dirstamp) +src/thrift/generate/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/thrift/generate/$(DEPDIR) + @: > src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/libthriftc_la-t_generator.lo: \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/parse/$(am__dirstamp): + @$(MKDIR_P) src/thrift/parse + @: > src/thrift/parse/$(am__dirstamp) +src/thrift/parse/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/thrift/parse/$(DEPDIR) + @: > src/thrift/parse/$(DEPDIR)/$(am__dirstamp) +src/thrift/parse/libthriftc_la-t_typedef.lo: \ + src/thrift/parse/$(am__dirstamp) \ + src/thrift/parse/$(DEPDIR)/$(am__dirstamp) +src/thrift/parse/libthriftc_la-parse.lo: \ + src/thrift/parse/$(am__dirstamp) \ + src/thrift/parse/$(DEPDIR)/$(am__dirstamp) +src/thrift/plugin/$(am__dirstamp): + @$(MKDIR_P) src/thrift/plugin + @: > src/thrift/plugin/$(am__dirstamp) +src/thrift/plugin/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/thrift/plugin/$(DEPDIR) + @: > src/thrift/plugin/$(DEPDIR)/$(am__dirstamp) +src/thrift/plugin/libthriftc_la-plugin.lo: \ + src/thrift/plugin/$(am__dirstamp) \ + src/thrift/plugin/$(DEPDIR)/$(am__dirstamp) +src/thrift/plugin/libthriftc_la-plugin_output.lo: \ + src/thrift/plugin/$(am__dirstamp) \ + src/thrift/plugin/$(DEPDIR)/$(am__dirstamp) +src/thrift/libthriftc_la-logging.lo: src/thrift/$(am__dirstamp) \ + src/thrift/$(DEPDIR)/$(am__dirstamp) +src/thrift/plugin/libthriftc_la-plugin_types.lo: \ + src/thrift/plugin/$(am__dirstamp) \ + src/thrift/plugin/$(DEPDIR)/$(am__dirstamp) +src/thrift/plugin/libthriftc_la-plugin_constants.lo: \ + src/thrift/plugin/$(am__dirstamp) \ + src/thrift/plugin/$(DEPDIR)/$(am__dirstamp) + +libthriftc.la: $(libthriftc_la_OBJECTS) $(libthriftc_la_DEPENDENCIES) $(EXTRA_libthriftc_la_DEPENDENCIES) + $(AM_V_CXXLD)$(libthriftc_la_LINK) $(am_libthriftc_la_rpath) $(libthriftc_la_OBJECTS) $(libthriftc_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +src/thrift/thrift-main.$(OBJEXT): src/thrift/$(am__dirstamp) \ + src/thrift/$(DEPDIR)/$(am__dirstamp) +src/thrift/audit/$(am__dirstamp): + @$(MKDIR_P) src/thrift/audit + @: > src/thrift/audit/$(am__dirstamp) +src/thrift/audit/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/thrift/audit/$(DEPDIR) + @: > src/thrift/audit/$(DEPDIR)/$(am__dirstamp) +src/thrift/audit/thrift-t_audit.$(OBJEXT): \ + src/thrift/audit/$(am__dirstamp) \ + src/thrift/audit/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_c_glib_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_cpp_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_java_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_json_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_as3_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_dart_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_haxe_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_csharp_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_netcore_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_py_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_rb_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_perl_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_php_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_erl_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_cocoa_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_swift_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_st_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_ocaml_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_hs_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_xsd_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_xml_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_html_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_js_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_javame_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_delphi_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_go_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_gv_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_d_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_lua_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_rs_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/thrift-common.$(OBJEXT): src/thrift/$(am__dirstamp) \ + src/thrift/$(DEPDIR)/$(am__dirstamp) +src/thrift/generate/thrift-t_generator.$(OBJEXT): \ + src/thrift/generate/$(am__dirstamp) \ + src/thrift/generate/$(DEPDIR)/$(am__dirstamp) +src/thrift/parse/thrift-t_typedef.$(OBJEXT): \ + src/thrift/parse/$(am__dirstamp) \ + src/thrift/parse/$(DEPDIR)/$(am__dirstamp) +src/thrift/parse/thrift-parse.$(OBJEXT): \ + src/thrift/parse/$(am__dirstamp) \ + src/thrift/parse/$(DEPDIR)/$(am__dirstamp) + +thrift$(EXEEXT): $(thrift_OBJECTS) $(thrift_DEPENDENCIES) $(EXTRA_thrift_DEPENDENCIES) + @rm -f thrift$(EXEEXT) + $(AM_V_CXXLD)$(thrift_LINK) $(thrift_OBJECTS) $(thrift_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f src/thrift/*.$(OBJEXT) + -rm -f src/thrift/*.lo + -rm -f src/thrift/audit/*.$(OBJEXT) + -rm -f src/thrift/generate/*.$(OBJEXT) + -rm -f src/thrift/generate/*.lo + -rm -f src/thrift/parse/*.$(OBJEXT) + -rm -f src/thrift/parse/*.lo + -rm -f src/thrift/plugin/*.$(OBJEXT) + -rm -f src/thrift/plugin/*.lo + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/$(DEPDIR)/libthriftc_la-common.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/$(DEPDIR)/libthriftc_la-logging.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/$(DEPDIR)/thrift-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/$(DEPDIR)/thrift-main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/audit/$(DEPDIR)/thrift-t_audit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/libthriftc_la-t_generator.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_as3_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_c_glib_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_cocoa_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_cpp_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_csharp_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_d_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_dart_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_delphi_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_erl_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_go_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_gv_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_haxe_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_hs_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_html_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_java_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_javame_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_js_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_json_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_lua_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_netcore_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_ocaml_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_perl_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_php_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_py_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_rb_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_rs_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_st_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_swift_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_xml_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/generate/$(DEPDIR)/thrift-t_xsd_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/parse/$(DEPDIR)/libthriftc_la-parse.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/parse/$(DEPDIR)/libthriftc_la-t_typedef.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/parse/$(DEPDIR)/thrift-parse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/parse/$(DEPDIR)/thrift-t_typedef.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin_constants.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin_output.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin_types.Plo@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +src/thrift/libthriftc_la-common.lo: src/thrift/common.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/libthriftc_la-common.lo -MD -MP -MF src/thrift/$(DEPDIR)/libthriftc_la-common.Tpo -c -o src/thrift/libthriftc_la-common.lo `test -f 'src/thrift/common.cc' || echo '$(srcdir)/'`src/thrift/common.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/$(DEPDIR)/libthriftc_la-common.Tpo src/thrift/$(DEPDIR)/libthriftc_la-common.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/common.cc' object='src/thrift/libthriftc_la-common.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/libthriftc_la-common.lo `test -f 'src/thrift/common.cc' || echo '$(srcdir)/'`src/thrift/common.cc + +src/thrift/generate/libthriftc_la-t_generator.lo: src/thrift/generate/t_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/libthriftc_la-t_generator.lo -MD -MP -MF src/thrift/generate/$(DEPDIR)/libthriftc_la-t_generator.Tpo -c -o src/thrift/generate/libthriftc_la-t_generator.lo `test -f 'src/thrift/generate/t_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/libthriftc_la-t_generator.Tpo src/thrift/generate/$(DEPDIR)/libthriftc_la-t_generator.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_generator.cc' object='src/thrift/generate/libthriftc_la-t_generator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/libthriftc_la-t_generator.lo `test -f 'src/thrift/generate/t_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_generator.cc + +src/thrift/parse/libthriftc_la-t_typedef.lo: src/thrift/parse/t_typedef.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/parse/libthriftc_la-t_typedef.lo -MD -MP -MF src/thrift/parse/$(DEPDIR)/libthriftc_la-t_typedef.Tpo -c -o src/thrift/parse/libthriftc_la-t_typedef.lo `test -f 'src/thrift/parse/t_typedef.cc' || echo '$(srcdir)/'`src/thrift/parse/t_typedef.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/parse/$(DEPDIR)/libthriftc_la-t_typedef.Tpo src/thrift/parse/$(DEPDIR)/libthriftc_la-t_typedef.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/parse/t_typedef.cc' object='src/thrift/parse/libthriftc_la-t_typedef.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/parse/libthriftc_la-t_typedef.lo `test -f 'src/thrift/parse/t_typedef.cc' || echo '$(srcdir)/'`src/thrift/parse/t_typedef.cc + +src/thrift/parse/libthriftc_la-parse.lo: src/thrift/parse/parse.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/parse/libthriftc_la-parse.lo -MD -MP -MF src/thrift/parse/$(DEPDIR)/libthriftc_la-parse.Tpo -c -o src/thrift/parse/libthriftc_la-parse.lo `test -f 'src/thrift/parse/parse.cc' || echo '$(srcdir)/'`src/thrift/parse/parse.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/parse/$(DEPDIR)/libthriftc_la-parse.Tpo src/thrift/parse/$(DEPDIR)/libthriftc_la-parse.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/parse/parse.cc' object='src/thrift/parse/libthriftc_la-parse.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/parse/libthriftc_la-parse.lo `test -f 'src/thrift/parse/parse.cc' || echo '$(srcdir)/'`src/thrift/parse/parse.cc + +src/thrift/plugin/libthriftc_la-plugin.lo: src/thrift/plugin/plugin.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/plugin/libthriftc_la-plugin.lo -MD -MP -MF src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin.Tpo -c -o src/thrift/plugin/libthriftc_la-plugin.lo `test -f 'src/thrift/plugin/plugin.cc' || echo '$(srcdir)/'`src/thrift/plugin/plugin.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin.Tpo src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/plugin/plugin.cc' object='src/thrift/plugin/libthriftc_la-plugin.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/plugin/libthriftc_la-plugin.lo `test -f 'src/thrift/plugin/plugin.cc' || echo '$(srcdir)/'`src/thrift/plugin/plugin.cc + +src/thrift/plugin/libthriftc_la-plugin_output.lo: src/thrift/plugin/plugin_output.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/plugin/libthriftc_la-plugin_output.lo -MD -MP -MF src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin_output.Tpo -c -o src/thrift/plugin/libthriftc_la-plugin_output.lo `test -f 'src/thrift/plugin/plugin_output.cc' || echo '$(srcdir)/'`src/thrift/plugin/plugin_output.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin_output.Tpo src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin_output.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/plugin/plugin_output.cc' object='src/thrift/plugin/libthriftc_la-plugin_output.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/plugin/libthriftc_la-plugin_output.lo `test -f 'src/thrift/plugin/plugin_output.cc' || echo '$(srcdir)/'`src/thrift/plugin/plugin_output.cc + +src/thrift/libthriftc_la-logging.lo: src/thrift/logging.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/libthriftc_la-logging.lo -MD -MP -MF src/thrift/$(DEPDIR)/libthriftc_la-logging.Tpo -c -o src/thrift/libthriftc_la-logging.lo `test -f 'src/thrift/logging.cc' || echo '$(srcdir)/'`src/thrift/logging.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/$(DEPDIR)/libthriftc_la-logging.Tpo src/thrift/$(DEPDIR)/libthriftc_la-logging.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/logging.cc' object='src/thrift/libthriftc_la-logging.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/libthriftc_la-logging.lo `test -f 'src/thrift/logging.cc' || echo '$(srcdir)/'`src/thrift/logging.cc + +src/thrift/plugin/libthriftc_la-plugin_types.lo: src/thrift/plugin/plugin_types.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/plugin/libthriftc_la-plugin_types.lo -MD -MP -MF src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin_types.Tpo -c -o src/thrift/plugin/libthriftc_la-plugin_types.lo `test -f 'src/thrift/plugin/plugin_types.cpp' || echo '$(srcdir)/'`src/thrift/plugin/plugin_types.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin_types.Tpo src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin_types.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/plugin/plugin_types.cpp' object='src/thrift/plugin/libthriftc_la-plugin_types.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/plugin/libthriftc_la-plugin_types.lo `test -f 'src/thrift/plugin/plugin_types.cpp' || echo '$(srcdir)/'`src/thrift/plugin/plugin_types.cpp + +src/thrift/plugin/libthriftc_la-plugin_constants.lo: src/thrift/plugin/plugin_constants.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/plugin/libthriftc_la-plugin_constants.lo -MD -MP -MF src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin_constants.Tpo -c -o src/thrift/plugin/libthriftc_la-plugin_constants.lo `test -f 'src/thrift/plugin/plugin_constants.cpp' || echo '$(srcdir)/'`src/thrift/plugin/plugin_constants.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin_constants.Tpo src/thrift/plugin/$(DEPDIR)/libthriftc_la-plugin_constants.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/plugin/plugin_constants.cpp' object='src/thrift/plugin/libthriftc_la-plugin_constants.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libthriftc_la_CPPFLAGS) $(CPPFLAGS) $(libthriftc_la_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/plugin/libthriftc_la-plugin_constants.lo `test -f 'src/thrift/plugin/plugin_constants.cpp' || echo '$(srcdir)/'`src/thrift/plugin/plugin_constants.cpp + +src/thrift/thrift-main.o: src/thrift/main.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/thrift-main.o -MD -MP -MF src/thrift/$(DEPDIR)/thrift-main.Tpo -c -o src/thrift/thrift-main.o `test -f 'src/thrift/main.cc' || echo '$(srcdir)/'`src/thrift/main.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/$(DEPDIR)/thrift-main.Tpo src/thrift/$(DEPDIR)/thrift-main.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/main.cc' object='src/thrift/thrift-main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/thrift-main.o `test -f 'src/thrift/main.cc' || echo '$(srcdir)/'`src/thrift/main.cc + +src/thrift/thrift-main.obj: src/thrift/main.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/thrift-main.obj -MD -MP -MF src/thrift/$(DEPDIR)/thrift-main.Tpo -c -o src/thrift/thrift-main.obj `if test -f 'src/thrift/main.cc'; then $(CYGPATH_W) 'src/thrift/main.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/main.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/$(DEPDIR)/thrift-main.Tpo src/thrift/$(DEPDIR)/thrift-main.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/main.cc' object='src/thrift/thrift-main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/thrift-main.obj `if test -f 'src/thrift/main.cc'; then $(CYGPATH_W) 'src/thrift/main.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/main.cc'; fi` + +src/thrift/audit/thrift-t_audit.o: src/thrift/audit/t_audit.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/audit/thrift-t_audit.o -MD -MP -MF src/thrift/audit/$(DEPDIR)/thrift-t_audit.Tpo -c -o src/thrift/audit/thrift-t_audit.o `test -f 'src/thrift/audit/t_audit.cpp' || echo '$(srcdir)/'`src/thrift/audit/t_audit.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/audit/$(DEPDIR)/thrift-t_audit.Tpo src/thrift/audit/$(DEPDIR)/thrift-t_audit.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/audit/t_audit.cpp' object='src/thrift/audit/thrift-t_audit.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/audit/thrift-t_audit.o `test -f 'src/thrift/audit/t_audit.cpp' || echo '$(srcdir)/'`src/thrift/audit/t_audit.cpp + +src/thrift/audit/thrift-t_audit.obj: src/thrift/audit/t_audit.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/audit/thrift-t_audit.obj -MD -MP -MF src/thrift/audit/$(DEPDIR)/thrift-t_audit.Tpo -c -o src/thrift/audit/thrift-t_audit.obj `if test -f 'src/thrift/audit/t_audit.cpp'; then $(CYGPATH_W) 'src/thrift/audit/t_audit.cpp'; else $(CYGPATH_W) '$(srcdir)/src/thrift/audit/t_audit.cpp'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/audit/$(DEPDIR)/thrift-t_audit.Tpo src/thrift/audit/$(DEPDIR)/thrift-t_audit.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/audit/t_audit.cpp' object='src/thrift/audit/thrift-t_audit.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/audit/thrift-t_audit.obj `if test -f 'src/thrift/audit/t_audit.cpp'; then $(CYGPATH_W) 'src/thrift/audit/t_audit.cpp'; else $(CYGPATH_W) '$(srcdir)/src/thrift/audit/t_audit.cpp'; fi` + +src/thrift/generate/thrift-t_c_glib_generator.o: src/thrift/generate/t_c_glib_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_c_glib_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_c_glib_generator.Tpo -c -o src/thrift/generate/thrift-t_c_glib_generator.o `test -f 'src/thrift/generate/t_c_glib_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_c_glib_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_c_glib_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_c_glib_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_c_glib_generator.cc' object='src/thrift/generate/thrift-t_c_glib_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_c_glib_generator.o `test -f 'src/thrift/generate/t_c_glib_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_c_glib_generator.cc + +src/thrift/generate/thrift-t_c_glib_generator.obj: src/thrift/generate/t_c_glib_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_c_glib_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_c_glib_generator.Tpo -c -o src/thrift/generate/thrift-t_c_glib_generator.obj `if test -f 'src/thrift/generate/t_c_glib_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_c_glib_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_c_glib_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_c_glib_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_c_glib_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_c_glib_generator.cc' object='src/thrift/generate/thrift-t_c_glib_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_c_glib_generator.obj `if test -f 'src/thrift/generate/t_c_glib_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_c_glib_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_c_glib_generator.cc'; fi` + +src/thrift/generate/thrift-t_cpp_generator.o: src/thrift/generate/t_cpp_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_cpp_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_cpp_generator.Tpo -c -o src/thrift/generate/thrift-t_cpp_generator.o `test -f 'src/thrift/generate/t_cpp_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_cpp_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_cpp_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_cpp_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_cpp_generator.cc' object='src/thrift/generate/thrift-t_cpp_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_cpp_generator.o `test -f 'src/thrift/generate/t_cpp_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_cpp_generator.cc + +src/thrift/generate/thrift-t_cpp_generator.obj: src/thrift/generate/t_cpp_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_cpp_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_cpp_generator.Tpo -c -o src/thrift/generate/thrift-t_cpp_generator.obj `if test -f 'src/thrift/generate/t_cpp_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_cpp_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_cpp_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_cpp_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_cpp_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_cpp_generator.cc' object='src/thrift/generate/thrift-t_cpp_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_cpp_generator.obj `if test -f 'src/thrift/generate/t_cpp_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_cpp_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_cpp_generator.cc'; fi` + +src/thrift/generate/thrift-t_java_generator.o: src/thrift/generate/t_java_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_java_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_java_generator.Tpo -c -o src/thrift/generate/thrift-t_java_generator.o `test -f 'src/thrift/generate/t_java_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_java_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_java_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_java_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_java_generator.cc' object='src/thrift/generate/thrift-t_java_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_java_generator.o `test -f 'src/thrift/generate/t_java_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_java_generator.cc + +src/thrift/generate/thrift-t_java_generator.obj: src/thrift/generate/t_java_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_java_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_java_generator.Tpo -c -o src/thrift/generate/thrift-t_java_generator.obj `if test -f 'src/thrift/generate/t_java_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_java_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_java_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_java_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_java_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_java_generator.cc' object='src/thrift/generate/thrift-t_java_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_java_generator.obj `if test -f 'src/thrift/generate/t_java_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_java_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_java_generator.cc'; fi` + +src/thrift/generate/thrift-t_json_generator.o: src/thrift/generate/t_json_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_json_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_json_generator.Tpo -c -o src/thrift/generate/thrift-t_json_generator.o `test -f 'src/thrift/generate/t_json_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_json_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_json_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_json_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_json_generator.cc' object='src/thrift/generate/thrift-t_json_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_json_generator.o `test -f 'src/thrift/generate/t_json_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_json_generator.cc + +src/thrift/generate/thrift-t_json_generator.obj: src/thrift/generate/t_json_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_json_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_json_generator.Tpo -c -o src/thrift/generate/thrift-t_json_generator.obj `if test -f 'src/thrift/generate/t_json_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_json_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_json_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_json_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_json_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_json_generator.cc' object='src/thrift/generate/thrift-t_json_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_json_generator.obj `if test -f 'src/thrift/generate/t_json_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_json_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_json_generator.cc'; fi` + +src/thrift/generate/thrift-t_as3_generator.o: src/thrift/generate/t_as3_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_as3_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_as3_generator.Tpo -c -o src/thrift/generate/thrift-t_as3_generator.o `test -f 'src/thrift/generate/t_as3_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_as3_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_as3_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_as3_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_as3_generator.cc' object='src/thrift/generate/thrift-t_as3_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_as3_generator.o `test -f 'src/thrift/generate/t_as3_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_as3_generator.cc + +src/thrift/generate/thrift-t_as3_generator.obj: src/thrift/generate/t_as3_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_as3_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_as3_generator.Tpo -c -o src/thrift/generate/thrift-t_as3_generator.obj `if test -f 'src/thrift/generate/t_as3_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_as3_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_as3_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_as3_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_as3_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_as3_generator.cc' object='src/thrift/generate/thrift-t_as3_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_as3_generator.obj `if test -f 'src/thrift/generate/t_as3_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_as3_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_as3_generator.cc'; fi` + +src/thrift/generate/thrift-t_dart_generator.o: src/thrift/generate/t_dart_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_dart_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_dart_generator.Tpo -c -o src/thrift/generate/thrift-t_dart_generator.o `test -f 'src/thrift/generate/t_dart_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_dart_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_dart_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_dart_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_dart_generator.cc' object='src/thrift/generate/thrift-t_dart_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_dart_generator.o `test -f 'src/thrift/generate/t_dart_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_dart_generator.cc + +src/thrift/generate/thrift-t_dart_generator.obj: src/thrift/generate/t_dart_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_dart_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_dart_generator.Tpo -c -o src/thrift/generate/thrift-t_dart_generator.obj `if test -f 'src/thrift/generate/t_dart_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_dart_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_dart_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_dart_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_dart_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_dart_generator.cc' object='src/thrift/generate/thrift-t_dart_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_dart_generator.obj `if test -f 'src/thrift/generate/t_dart_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_dart_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_dart_generator.cc'; fi` + +src/thrift/generate/thrift-t_haxe_generator.o: src/thrift/generate/t_haxe_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_haxe_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_haxe_generator.Tpo -c -o src/thrift/generate/thrift-t_haxe_generator.o `test -f 'src/thrift/generate/t_haxe_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_haxe_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_haxe_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_haxe_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_haxe_generator.cc' object='src/thrift/generate/thrift-t_haxe_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_haxe_generator.o `test -f 'src/thrift/generate/t_haxe_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_haxe_generator.cc + +src/thrift/generate/thrift-t_haxe_generator.obj: src/thrift/generate/t_haxe_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_haxe_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_haxe_generator.Tpo -c -o src/thrift/generate/thrift-t_haxe_generator.obj `if test -f 'src/thrift/generate/t_haxe_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_haxe_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_haxe_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_haxe_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_haxe_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_haxe_generator.cc' object='src/thrift/generate/thrift-t_haxe_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_haxe_generator.obj `if test -f 'src/thrift/generate/t_haxe_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_haxe_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_haxe_generator.cc'; fi` + +src/thrift/generate/thrift-t_csharp_generator.o: src/thrift/generate/t_csharp_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_csharp_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_csharp_generator.Tpo -c -o src/thrift/generate/thrift-t_csharp_generator.o `test -f 'src/thrift/generate/t_csharp_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_csharp_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_csharp_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_csharp_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_csharp_generator.cc' object='src/thrift/generate/thrift-t_csharp_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_csharp_generator.o `test -f 'src/thrift/generate/t_csharp_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_csharp_generator.cc + +src/thrift/generate/thrift-t_csharp_generator.obj: src/thrift/generate/t_csharp_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_csharp_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_csharp_generator.Tpo -c -o src/thrift/generate/thrift-t_csharp_generator.obj `if test -f 'src/thrift/generate/t_csharp_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_csharp_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_csharp_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_csharp_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_csharp_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_csharp_generator.cc' object='src/thrift/generate/thrift-t_csharp_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_csharp_generator.obj `if test -f 'src/thrift/generate/t_csharp_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_csharp_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_csharp_generator.cc'; fi` + +src/thrift/generate/thrift-t_netcore_generator.o: src/thrift/generate/t_netcore_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_netcore_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_netcore_generator.Tpo -c -o src/thrift/generate/thrift-t_netcore_generator.o `test -f 'src/thrift/generate/t_netcore_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_netcore_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_netcore_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_netcore_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_netcore_generator.cc' object='src/thrift/generate/thrift-t_netcore_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_netcore_generator.o `test -f 'src/thrift/generate/t_netcore_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_netcore_generator.cc + +src/thrift/generate/thrift-t_netcore_generator.obj: src/thrift/generate/t_netcore_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_netcore_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_netcore_generator.Tpo -c -o src/thrift/generate/thrift-t_netcore_generator.obj `if test -f 'src/thrift/generate/t_netcore_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_netcore_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_netcore_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_netcore_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_netcore_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_netcore_generator.cc' object='src/thrift/generate/thrift-t_netcore_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_netcore_generator.obj `if test -f 'src/thrift/generate/t_netcore_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_netcore_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_netcore_generator.cc'; fi` + +src/thrift/generate/thrift-t_py_generator.o: src/thrift/generate/t_py_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_py_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_py_generator.Tpo -c -o src/thrift/generate/thrift-t_py_generator.o `test -f 'src/thrift/generate/t_py_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_py_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_py_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_py_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_py_generator.cc' object='src/thrift/generate/thrift-t_py_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_py_generator.o `test -f 'src/thrift/generate/t_py_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_py_generator.cc + +src/thrift/generate/thrift-t_py_generator.obj: src/thrift/generate/t_py_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_py_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_py_generator.Tpo -c -o src/thrift/generate/thrift-t_py_generator.obj `if test -f 'src/thrift/generate/t_py_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_py_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_py_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_py_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_py_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_py_generator.cc' object='src/thrift/generate/thrift-t_py_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_py_generator.obj `if test -f 'src/thrift/generate/t_py_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_py_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_py_generator.cc'; fi` + +src/thrift/generate/thrift-t_rb_generator.o: src/thrift/generate/t_rb_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_rb_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_rb_generator.Tpo -c -o src/thrift/generate/thrift-t_rb_generator.o `test -f 'src/thrift/generate/t_rb_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_rb_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_rb_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_rb_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_rb_generator.cc' object='src/thrift/generate/thrift-t_rb_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_rb_generator.o `test -f 'src/thrift/generate/t_rb_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_rb_generator.cc + +src/thrift/generate/thrift-t_rb_generator.obj: src/thrift/generate/t_rb_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_rb_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_rb_generator.Tpo -c -o src/thrift/generate/thrift-t_rb_generator.obj `if test -f 'src/thrift/generate/t_rb_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_rb_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_rb_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_rb_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_rb_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_rb_generator.cc' object='src/thrift/generate/thrift-t_rb_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_rb_generator.obj `if test -f 'src/thrift/generate/t_rb_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_rb_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_rb_generator.cc'; fi` + +src/thrift/generate/thrift-t_perl_generator.o: src/thrift/generate/t_perl_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_perl_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_perl_generator.Tpo -c -o src/thrift/generate/thrift-t_perl_generator.o `test -f 'src/thrift/generate/t_perl_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_perl_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_perl_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_perl_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_perl_generator.cc' object='src/thrift/generate/thrift-t_perl_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_perl_generator.o `test -f 'src/thrift/generate/t_perl_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_perl_generator.cc + +src/thrift/generate/thrift-t_perl_generator.obj: src/thrift/generate/t_perl_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_perl_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_perl_generator.Tpo -c -o src/thrift/generate/thrift-t_perl_generator.obj `if test -f 'src/thrift/generate/t_perl_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_perl_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_perl_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_perl_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_perl_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_perl_generator.cc' object='src/thrift/generate/thrift-t_perl_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_perl_generator.obj `if test -f 'src/thrift/generate/t_perl_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_perl_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_perl_generator.cc'; fi` + +src/thrift/generate/thrift-t_php_generator.o: src/thrift/generate/t_php_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_php_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_php_generator.Tpo -c -o src/thrift/generate/thrift-t_php_generator.o `test -f 'src/thrift/generate/t_php_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_php_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_php_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_php_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_php_generator.cc' object='src/thrift/generate/thrift-t_php_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_php_generator.o `test -f 'src/thrift/generate/t_php_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_php_generator.cc + +src/thrift/generate/thrift-t_php_generator.obj: src/thrift/generate/t_php_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_php_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_php_generator.Tpo -c -o src/thrift/generate/thrift-t_php_generator.obj `if test -f 'src/thrift/generate/t_php_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_php_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_php_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_php_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_php_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_php_generator.cc' object='src/thrift/generate/thrift-t_php_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_php_generator.obj `if test -f 'src/thrift/generate/t_php_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_php_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_php_generator.cc'; fi` + +src/thrift/generate/thrift-t_erl_generator.o: src/thrift/generate/t_erl_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_erl_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_erl_generator.Tpo -c -o src/thrift/generate/thrift-t_erl_generator.o `test -f 'src/thrift/generate/t_erl_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_erl_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_erl_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_erl_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_erl_generator.cc' object='src/thrift/generate/thrift-t_erl_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_erl_generator.o `test -f 'src/thrift/generate/t_erl_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_erl_generator.cc + +src/thrift/generate/thrift-t_erl_generator.obj: src/thrift/generate/t_erl_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_erl_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_erl_generator.Tpo -c -o src/thrift/generate/thrift-t_erl_generator.obj `if test -f 'src/thrift/generate/t_erl_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_erl_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_erl_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_erl_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_erl_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_erl_generator.cc' object='src/thrift/generate/thrift-t_erl_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_erl_generator.obj `if test -f 'src/thrift/generate/t_erl_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_erl_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_erl_generator.cc'; fi` + +src/thrift/generate/thrift-t_cocoa_generator.o: src/thrift/generate/t_cocoa_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_cocoa_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_cocoa_generator.Tpo -c -o src/thrift/generate/thrift-t_cocoa_generator.o `test -f 'src/thrift/generate/t_cocoa_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_cocoa_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_cocoa_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_cocoa_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_cocoa_generator.cc' object='src/thrift/generate/thrift-t_cocoa_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_cocoa_generator.o `test -f 'src/thrift/generate/t_cocoa_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_cocoa_generator.cc + +src/thrift/generate/thrift-t_cocoa_generator.obj: src/thrift/generate/t_cocoa_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_cocoa_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_cocoa_generator.Tpo -c -o src/thrift/generate/thrift-t_cocoa_generator.obj `if test -f 'src/thrift/generate/t_cocoa_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_cocoa_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_cocoa_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_cocoa_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_cocoa_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_cocoa_generator.cc' object='src/thrift/generate/thrift-t_cocoa_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_cocoa_generator.obj `if test -f 'src/thrift/generate/t_cocoa_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_cocoa_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_cocoa_generator.cc'; fi` + +src/thrift/generate/thrift-t_swift_generator.o: src/thrift/generate/t_swift_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_swift_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_swift_generator.Tpo -c -o src/thrift/generate/thrift-t_swift_generator.o `test -f 'src/thrift/generate/t_swift_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_swift_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_swift_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_swift_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_swift_generator.cc' object='src/thrift/generate/thrift-t_swift_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_swift_generator.o `test -f 'src/thrift/generate/t_swift_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_swift_generator.cc + +src/thrift/generate/thrift-t_swift_generator.obj: src/thrift/generate/t_swift_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_swift_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_swift_generator.Tpo -c -o src/thrift/generate/thrift-t_swift_generator.obj `if test -f 'src/thrift/generate/t_swift_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_swift_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_swift_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_swift_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_swift_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_swift_generator.cc' object='src/thrift/generate/thrift-t_swift_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_swift_generator.obj `if test -f 'src/thrift/generate/t_swift_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_swift_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_swift_generator.cc'; fi` + +src/thrift/generate/thrift-t_st_generator.o: src/thrift/generate/t_st_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_st_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_st_generator.Tpo -c -o src/thrift/generate/thrift-t_st_generator.o `test -f 'src/thrift/generate/t_st_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_st_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_st_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_st_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_st_generator.cc' object='src/thrift/generate/thrift-t_st_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_st_generator.o `test -f 'src/thrift/generate/t_st_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_st_generator.cc + +src/thrift/generate/thrift-t_st_generator.obj: src/thrift/generate/t_st_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_st_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_st_generator.Tpo -c -o src/thrift/generate/thrift-t_st_generator.obj `if test -f 'src/thrift/generate/t_st_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_st_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_st_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_st_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_st_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_st_generator.cc' object='src/thrift/generate/thrift-t_st_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_st_generator.obj `if test -f 'src/thrift/generate/t_st_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_st_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_st_generator.cc'; fi` + +src/thrift/generate/thrift-t_ocaml_generator.o: src/thrift/generate/t_ocaml_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_ocaml_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_ocaml_generator.Tpo -c -o src/thrift/generate/thrift-t_ocaml_generator.o `test -f 'src/thrift/generate/t_ocaml_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_ocaml_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_ocaml_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_ocaml_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_ocaml_generator.cc' object='src/thrift/generate/thrift-t_ocaml_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_ocaml_generator.o `test -f 'src/thrift/generate/t_ocaml_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_ocaml_generator.cc + +src/thrift/generate/thrift-t_ocaml_generator.obj: src/thrift/generate/t_ocaml_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_ocaml_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_ocaml_generator.Tpo -c -o src/thrift/generate/thrift-t_ocaml_generator.obj `if test -f 'src/thrift/generate/t_ocaml_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_ocaml_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_ocaml_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_ocaml_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_ocaml_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_ocaml_generator.cc' object='src/thrift/generate/thrift-t_ocaml_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_ocaml_generator.obj `if test -f 'src/thrift/generate/t_ocaml_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_ocaml_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_ocaml_generator.cc'; fi` + +src/thrift/generate/thrift-t_hs_generator.o: src/thrift/generate/t_hs_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_hs_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_hs_generator.Tpo -c -o src/thrift/generate/thrift-t_hs_generator.o `test -f 'src/thrift/generate/t_hs_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_hs_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_hs_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_hs_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_hs_generator.cc' object='src/thrift/generate/thrift-t_hs_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_hs_generator.o `test -f 'src/thrift/generate/t_hs_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_hs_generator.cc + +src/thrift/generate/thrift-t_hs_generator.obj: src/thrift/generate/t_hs_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_hs_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_hs_generator.Tpo -c -o src/thrift/generate/thrift-t_hs_generator.obj `if test -f 'src/thrift/generate/t_hs_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_hs_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_hs_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_hs_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_hs_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_hs_generator.cc' object='src/thrift/generate/thrift-t_hs_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_hs_generator.obj `if test -f 'src/thrift/generate/t_hs_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_hs_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_hs_generator.cc'; fi` + +src/thrift/generate/thrift-t_xsd_generator.o: src/thrift/generate/t_xsd_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_xsd_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_xsd_generator.Tpo -c -o src/thrift/generate/thrift-t_xsd_generator.o `test -f 'src/thrift/generate/t_xsd_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_xsd_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_xsd_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_xsd_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_xsd_generator.cc' object='src/thrift/generate/thrift-t_xsd_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_xsd_generator.o `test -f 'src/thrift/generate/t_xsd_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_xsd_generator.cc + +src/thrift/generate/thrift-t_xsd_generator.obj: src/thrift/generate/t_xsd_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_xsd_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_xsd_generator.Tpo -c -o src/thrift/generate/thrift-t_xsd_generator.obj `if test -f 'src/thrift/generate/t_xsd_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_xsd_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_xsd_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_xsd_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_xsd_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_xsd_generator.cc' object='src/thrift/generate/thrift-t_xsd_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_xsd_generator.obj `if test -f 'src/thrift/generate/t_xsd_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_xsd_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_xsd_generator.cc'; fi` + +src/thrift/generate/thrift-t_xml_generator.o: src/thrift/generate/t_xml_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_xml_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_xml_generator.Tpo -c -o src/thrift/generate/thrift-t_xml_generator.o `test -f 'src/thrift/generate/t_xml_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_xml_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_xml_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_xml_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_xml_generator.cc' object='src/thrift/generate/thrift-t_xml_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_xml_generator.o `test -f 'src/thrift/generate/t_xml_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_xml_generator.cc + +src/thrift/generate/thrift-t_xml_generator.obj: src/thrift/generate/t_xml_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_xml_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_xml_generator.Tpo -c -o src/thrift/generate/thrift-t_xml_generator.obj `if test -f 'src/thrift/generate/t_xml_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_xml_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_xml_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_xml_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_xml_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_xml_generator.cc' object='src/thrift/generate/thrift-t_xml_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_xml_generator.obj `if test -f 'src/thrift/generate/t_xml_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_xml_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_xml_generator.cc'; fi` + +src/thrift/generate/thrift-t_html_generator.o: src/thrift/generate/t_html_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_html_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_html_generator.Tpo -c -o src/thrift/generate/thrift-t_html_generator.o `test -f 'src/thrift/generate/t_html_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_html_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_html_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_html_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_html_generator.cc' object='src/thrift/generate/thrift-t_html_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_html_generator.o `test -f 'src/thrift/generate/t_html_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_html_generator.cc + +src/thrift/generate/thrift-t_html_generator.obj: src/thrift/generate/t_html_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_html_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_html_generator.Tpo -c -o src/thrift/generate/thrift-t_html_generator.obj `if test -f 'src/thrift/generate/t_html_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_html_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_html_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_html_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_html_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_html_generator.cc' object='src/thrift/generate/thrift-t_html_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_html_generator.obj `if test -f 'src/thrift/generate/t_html_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_html_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_html_generator.cc'; fi` + +src/thrift/generate/thrift-t_js_generator.o: src/thrift/generate/t_js_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_js_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_js_generator.Tpo -c -o src/thrift/generate/thrift-t_js_generator.o `test -f 'src/thrift/generate/t_js_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_js_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_js_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_js_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_js_generator.cc' object='src/thrift/generate/thrift-t_js_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_js_generator.o `test -f 'src/thrift/generate/t_js_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_js_generator.cc + +src/thrift/generate/thrift-t_js_generator.obj: src/thrift/generate/t_js_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_js_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_js_generator.Tpo -c -o src/thrift/generate/thrift-t_js_generator.obj `if test -f 'src/thrift/generate/t_js_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_js_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_js_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_js_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_js_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_js_generator.cc' object='src/thrift/generate/thrift-t_js_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_js_generator.obj `if test -f 'src/thrift/generate/t_js_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_js_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_js_generator.cc'; fi` + +src/thrift/generate/thrift-t_javame_generator.o: src/thrift/generate/t_javame_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_javame_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_javame_generator.Tpo -c -o src/thrift/generate/thrift-t_javame_generator.o `test -f 'src/thrift/generate/t_javame_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_javame_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_javame_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_javame_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_javame_generator.cc' object='src/thrift/generate/thrift-t_javame_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_javame_generator.o `test -f 'src/thrift/generate/t_javame_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_javame_generator.cc + +src/thrift/generate/thrift-t_javame_generator.obj: src/thrift/generate/t_javame_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_javame_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_javame_generator.Tpo -c -o src/thrift/generate/thrift-t_javame_generator.obj `if test -f 'src/thrift/generate/t_javame_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_javame_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_javame_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_javame_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_javame_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_javame_generator.cc' object='src/thrift/generate/thrift-t_javame_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_javame_generator.obj `if test -f 'src/thrift/generate/t_javame_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_javame_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_javame_generator.cc'; fi` + +src/thrift/generate/thrift-t_delphi_generator.o: src/thrift/generate/t_delphi_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_delphi_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_delphi_generator.Tpo -c -o src/thrift/generate/thrift-t_delphi_generator.o `test -f 'src/thrift/generate/t_delphi_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_delphi_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_delphi_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_delphi_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_delphi_generator.cc' object='src/thrift/generate/thrift-t_delphi_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_delphi_generator.o `test -f 'src/thrift/generate/t_delphi_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_delphi_generator.cc + +src/thrift/generate/thrift-t_delphi_generator.obj: src/thrift/generate/t_delphi_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_delphi_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_delphi_generator.Tpo -c -o src/thrift/generate/thrift-t_delphi_generator.obj `if test -f 'src/thrift/generate/t_delphi_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_delphi_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_delphi_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_delphi_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_delphi_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_delphi_generator.cc' object='src/thrift/generate/thrift-t_delphi_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_delphi_generator.obj `if test -f 'src/thrift/generate/t_delphi_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_delphi_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_delphi_generator.cc'; fi` + +src/thrift/generate/thrift-t_go_generator.o: src/thrift/generate/t_go_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_go_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_go_generator.Tpo -c -o src/thrift/generate/thrift-t_go_generator.o `test -f 'src/thrift/generate/t_go_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_go_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_go_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_go_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_go_generator.cc' object='src/thrift/generate/thrift-t_go_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_go_generator.o `test -f 'src/thrift/generate/t_go_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_go_generator.cc + +src/thrift/generate/thrift-t_go_generator.obj: src/thrift/generate/t_go_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_go_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_go_generator.Tpo -c -o src/thrift/generate/thrift-t_go_generator.obj `if test -f 'src/thrift/generate/t_go_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_go_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_go_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_go_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_go_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_go_generator.cc' object='src/thrift/generate/thrift-t_go_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_go_generator.obj `if test -f 'src/thrift/generate/t_go_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_go_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_go_generator.cc'; fi` + +src/thrift/generate/thrift-t_gv_generator.o: src/thrift/generate/t_gv_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_gv_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_gv_generator.Tpo -c -o src/thrift/generate/thrift-t_gv_generator.o `test -f 'src/thrift/generate/t_gv_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_gv_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_gv_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_gv_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_gv_generator.cc' object='src/thrift/generate/thrift-t_gv_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_gv_generator.o `test -f 'src/thrift/generate/t_gv_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_gv_generator.cc + +src/thrift/generate/thrift-t_gv_generator.obj: src/thrift/generate/t_gv_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_gv_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_gv_generator.Tpo -c -o src/thrift/generate/thrift-t_gv_generator.obj `if test -f 'src/thrift/generate/t_gv_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_gv_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_gv_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_gv_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_gv_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_gv_generator.cc' object='src/thrift/generate/thrift-t_gv_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_gv_generator.obj `if test -f 'src/thrift/generate/t_gv_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_gv_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_gv_generator.cc'; fi` + +src/thrift/generate/thrift-t_d_generator.o: src/thrift/generate/t_d_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_d_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_d_generator.Tpo -c -o src/thrift/generate/thrift-t_d_generator.o `test -f 'src/thrift/generate/t_d_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_d_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_d_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_d_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_d_generator.cc' object='src/thrift/generate/thrift-t_d_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_d_generator.o `test -f 'src/thrift/generate/t_d_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_d_generator.cc + +src/thrift/generate/thrift-t_d_generator.obj: src/thrift/generate/t_d_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_d_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_d_generator.Tpo -c -o src/thrift/generate/thrift-t_d_generator.obj `if test -f 'src/thrift/generate/t_d_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_d_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_d_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_d_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_d_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_d_generator.cc' object='src/thrift/generate/thrift-t_d_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_d_generator.obj `if test -f 'src/thrift/generate/t_d_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_d_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_d_generator.cc'; fi` + +src/thrift/generate/thrift-t_lua_generator.o: src/thrift/generate/t_lua_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_lua_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_lua_generator.Tpo -c -o src/thrift/generate/thrift-t_lua_generator.o `test -f 'src/thrift/generate/t_lua_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_lua_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_lua_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_lua_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_lua_generator.cc' object='src/thrift/generate/thrift-t_lua_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_lua_generator.o `test -f 'src/thrift/generate/t_lua_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_lua_generator.cc + +src/thrift/generate/thrift-t_lua_generator.obj: src/thrift/generate/t_lua_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_lua_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_lua_generator.Tpo -c -o src/thrift/generate/thrift-t_lua_generator.obj `if test -f 'src/thrift/generate/t_lua_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_lua_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_lua_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_lua_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_lua_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_lua_generator.cc' object='src/thrift/generate/thrift-t_lua_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_lua_generator.obj `if test -f 'src/thrift/generate/t_lua_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_lua_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_lua_generator.cc'; fi` + +src/thrift/generate/thrift-t_rs_generator.o: src/thrift/generate/t_rs_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_rs_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_rs_generator.Tpo -c -o src/thrift/generate/thrift-t_rs_generator.o `test -f 'src/thrift/generate/t_rs_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_rs_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_rs_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_rs_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_rs_generator.cc' object='src/thrift/generate/thrift-t_rs_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_rs_generator.o `test -f 'src/thrift/generate/t_rs_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_rs_generator.cc + +src/thrift/generate/thrift-t_rs_generator.obj: src/thrift/generate/t_rs_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_rs_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_rs_generator.Tpo -c -o src/thrift/generate/thrift-t_rs_generator.obj `if test -f 'src/thrift/generate/t_rs_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_rs_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_rs_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_rs_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_rs_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_rs_generator.cc' object='src/thrift/generate/thrift-t_rs_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_rs_generator.obj `if test -f 'src/thrift/generate/t_rs_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_rs_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_rs_generator.cc'; fi` + +src/thrift/thrift-common.o: src/thrift/common.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/thrift-common.o -MD -MP -MF src/thrift/$(DEPDIR)/thrift-common.Tpo -c -o src/thrift/thrift-common.o `test -f 'src/thrift/common.cc' || echo '$(srcdir)/'`src/thrift/common.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/$(DEPDIR)/thrift-common.Tpo src/thrift/$(DEPDIR)/thrift-common.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/common.cc' object='src/thrift/thrift-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/thrift-common.o `test -f 'src/thrift/common.cc' || echo '$(srcdir)/'`src/thrift/common.cc + +src/thrift/thrift-common.obj: src/thrift/common.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/thrift-common.obj -MD -MP -MF src/thrift/$(DEPDIR)/thrift-common.Tpo -c -o src/thrift/thrift-common.obj `if test -f 'src/thrift/common.cc'; then $(CYGPATH_W) 'src/thrift/common.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/common.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/$(DEPDIR)/thrift-common.Tpo src/thrift/$(DEPDIR)/thrift-common.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/common.cc' object='src/thrift/thrift-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/thrift-common.obj `if test -f 'src/thrift/common.cc'; then $(CYGPATH_W) 'src/thrift/common.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/common.cc'; fi` + +src/thrift/generate/thrift-t_generator.o: src/thrift/generate/t_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_generator.o -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_generator.Tpo -c -o src/thrift/generate/thrift-t_generator.o `test -f 'src/thrift/generate/t_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_generator.cc' object='src/thrift/generate/thrift-t_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_generator.o `test -f 'src/thrift/generate/t_generator.cc' || echo '$(srcdir)/'`src/thrift/generate/t_generator.cc + +src/thrift/generate/thrift-t_generator.obj: src/thrift/generate/t_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/generate/thrift-t_generator.obj -MD -MP -MF src/thrift/generate/$(DEPDIR)/thrift-t_generator.Tpo -c -o src/thrift/generate/thrift-t_generator.obj `if test -f 'src/thrift/generate/t_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/generate/$(DEPDIR)/thrift-t_generator.Tpo src/thrift/generate/$(DEPDIR)/thrift-t_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/generate/t_generator.cc' object='src/thrift/generate/thrift-t_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/generate/thrift-t_generator.obj `if test -f 'src/thrift/generate/t_generator.cc'; then $(CYGPATH_W) 'src/thrift/generate/t_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/generate/t_generator.cc'; fi` + +src/thrift/parse/thrift-t_typedef.o: src/thrift/parse/t_typedef.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/parse/thrift-t_typedef.o -MD -MP -MF src/thrift/parse/$(DEPDIR)/thrift-t_typedef.Tpo -c -o src/thrift/parse/thrift-t_typedef.o `test -f 'src/thrift/parse/t_typedef.cc' || echo '$(srcdir)/'`src/thrift/parse/t_typedef.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/parse/$(DEPDIR)/thrift-t_typedef.Tpo src/thrift/parse/$(DEPDIR)/thrift-t_typedef.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/parse/t_typedef.cc' object='src/thrift/parse/thrift-t_typedef.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/parse/thrift-t_typedef.o `test -f 'src/thrift/parse/t_typedef.cc' || echo '$(srcdir)/'`src/thrift/parse/t_typedef.cc + +src/thrift/parse/thrift-t_typedef.obj: src/thrift/parse/t_typedef.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/parse/thrift-t_typedef.obj -MD -MP -MF src/thrift/parse/$(DEPDIR)/thrift-t_typedef.Tpo -c -o src/thrift/parse/thrift-t_typedef.obj `if test -f 'src/thrift/parse/t_typedef.cc'; then $(CYGPATH_W) 'src/thrift/parse/t_typedef.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/parse/t_typedef.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/parse/$(DEPDIR)/thrift-t_typedef.Tpo src/thrift/parse/$(DEPDIR)/thrift-t_typedef.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/parse/t_typedef.cc' object='src/thrift/parse/thrift-t_typedef.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/parse/thrift-t_typedef.obj `if test -f 'src/thrift/parse/t_typedef.cc'; then $(CYGPATH_W) 'src/thrift/parse/t_typedef.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/parse/t_typedef.cc'; fi` + +src/thrift/parse/thrift-parse.o: src/thrift/parse/parse.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/parse/thrift-parse.o -MD -MP -MF src/thrift/parse/$(DEPDIR)/thrift-parse.Tpo -c -o src/thrift/parse/thrift-parse.o `test -f 'src/thrift/parse/parse.cc' || echo '$(srcdir)/'`src/thrift/parse/parse.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/parse/$(DEPDIR)/thrift-parse.Tpo src/thrift/parse/$(DEPDIR)/thrift-parse.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/parse/parse.cc' object='src/thrift/parse/thrift-parse.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/parse/thrift-parse.o `test -f 'src/thrift/parse/parse.cc' || echo '$(srcdir)/'`src/thrift/parse/parse.cc + +src/thrift/parse/thrift-parse.obj: src/thrift/parse/parse.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -MT src/thrift/parse/thrift-parse.obj -MD -MP -MF src/thrift/parse/$(DEPDIR)/thrift-parse.Tpo -c -o src/thrift/parse/thrift-parse.obj `if test -f 'src/thrift/parse/parse.cc'; then $(CYGPATH_W) 'src/thrift/parse/parse.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/parse/parse.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/thrift/parse/$(DEPDIR)/thrift-parse.Tpo src/thrift/parse/$(DEPDIR)/thrift-parse.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/thrift/parse/parse.cc' object='src/thrift/parse/thrift-parse.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_CPPFLAGS) $(CPPFLAGS) $(thrift_CXXFLAGS) $(CXXFLAGS) -c -o src/thrift/parse/thrift-parse.obj `if test -f 'src/thrift/parse/parse.cc'; then $(CYGPATH_W) 'src/thrift/parse/parse.cc'; else $(CYGPATH_W) '$(srcdir)/src/thrift/parse/parse.cc'; fi` + +.cpp.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf src/thrift/.libs src/thrift/_libs + -rm -rf src/thrift/generate/.libs src/thrift/generate/_libs + -rm -rf src/thrift/parse/.libs src/thrift/parse/_libs + -rm -rf src/thrift/plugin/.libs src/thrift/plugin/_libs +install-include_auditHEADERS: $(include_audit_HEADERS) + @$(NORMAL_INSTALL) + @list='$(include_audit_HEADERS)'; test -n "$(include_auditdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(include_auditdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(include_auditdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(include_auditdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(include_auditdir)" || exit $$?; \ + done + +uninstall-include_auditHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_audit_HEADERS)'; test -n "$(include_auditdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(include_auditdir)'; $(am__uninstall_files_from_dir) +install-include_generateHEADERS: $(include_generate_HEADERS) + @$(NORMAL_INSTALL) + @list='$(include_generate_HEADERS)'; test -n "$(include_generatedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(include_generatedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(include_generatedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(include_generatedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(include_generatedir)" || exit $$?; \ + done + +uninstall-include_generateHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_generate_HEADERS)'; test -n "$(include_generatedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(include_generatedir)'; $(am__uninstall_files_from_dir) +install-include_parseHEADERS: $(include_parse_HEADERS) + @$(NORMAL_INSTALL) + @list='$(include_parse_HEADERS)'; test -n "$(include_parsedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(include_parsedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(include_parsedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(include_parsedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(include_parsedir)" || exit $$?; \ + done + +uninstall-include_parseHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_parse_HEADERS)'; test -n "$(include_parsedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(include_parsedir)'; $(am__uninstall_files_from_dir) +install-include_pluginHEADERS: $(include_plugin_HEADERS) + @$(NORMAL_INSTALL) + @list='$(include_plugin_HEADERS)'; test -n "$(include_plugindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(include_plugindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(include_plugindir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(include_plugindir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(include_plugindir)" || exit $$?; \ + done + +uninstall-include_pluginHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_plugin_HEADERS)'; test -n "$(include_plugindir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(include_plugindir)'; $(am__uninstall_files_from_dir) +install-include_thriftHEADERS: $(include_thrift_HEADERS) + @$(NORMAL_INSTALL) + @list='$(include_thrift_HEADERS)'; test -n "$(include_thriftdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(include_thriftdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(include_thriftdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(include_thriftdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(include_thriftdir)" || exit $$?; \ + done + +uninstall-include_thriftHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_thrift_HEADERS)'; test -n "$(include_thriftdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(include_thriftdir)'; $(am__uninstall_files_from_dir) +install-include_windowsHEADERS: $(include_windows_HEADERS) + @$(NORMAL_INSTALL) + @list='$(include_windows_HEADERS)'; test -n "$(include_windowsdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(include_windowsdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(include_windowsdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(include_windowsdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(include_windowsdir)" || exit $$?; \ + done + +uninstall-include_windowsHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_windows_HEADERS)'; test -n "$(include_windowsdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(include_windowsdir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(include_auditdir)" "$(DESTDIR)$(include_generatedir)" "$(DESTDIR)$(include_parsedir)" "$(DESTDIR)$(include_plugindir)" "$(DESTDIR)$(include_thriftdir)" "$(DESTDIR)$(include_windowsdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f src/thrift/$(DEPDIR)/$(am__dirstamp) + -rm -f src/thrift/$(am__dirstamp) + -rm -f src/thrift/audit/$(DEPDIR)/$(am__dirstamp) + -rm -f src/thrift/audit/$(am__dirstamp) + -rm -f src/thrift/generate/$(DEPDIR)/$(am__dirstamp) + -rm -f src/thrift/generate/$(am__dirstamp) + -rm -f src/thrift/parse/$(DEPDIR)/$(am__dirstamp) + -rm -f src/thrift/parse/$(am__dirstamp) + -rm -f src/thrift/plugin/$(DEPDIR)/$(am__dirstamp) + -rm -f src/thrift/plugin/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-local mostlyclean-am + +distclean: distclean-recursive + -rm -rf src/thrift/$(DEPDIR) src/thrift/audit/$(DEPDIR) src/thrift/generate/$(DEPDIR) src/thrift/parse/$(DEPDIR) src/thrift/plugin/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-include_auditHEADERS \ + install-include_generateHEADERS install-include_parseHEADERS \ + install-include_pluginHEADERS install-include_thriftHEADERS \ + install-include_windowsHEADERS + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf src/thrift/$(DEPDIR) src/thrift/audit/$(DEPDIR) src/thrift/generate/$(DEPDIR) src/thrift/parse/$(DEPDIR) src/thrift/plugin/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +style: style-recursive + +style-am: style-local + +uninstall-am: uninstall-binPROGRAMS uninstall-include_auditHEADERS \ + uninstall-include_generateHEADERS \ + uninstall-include_parseHEADERS uninstall-include_pluginHEADERS \ + uninstall-include_thriftHEADERS \ + uninstall-include_windowsHEADERS uninstall-libLTLIBRARIES + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-binPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-local cscopelist-am \ + ctags ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-include_auditHEADERS install-include_generateHEADERS \ + install-include_parseHEADERS install-include_pluginHEADERS \ + install-include_thriftHEADERS install-include_windowsHEADERS \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags tags-am uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-include_auditHEADERS \ + uninstall-include_generateHEADERS \ + uninstall-include_parseHEADERS uninstall-include_pluginHEADERS \ + uninstall-include_thriftHEADERS \ + uninstall-include_windowsHEADERS uninstall-libLTLIBRARIES + +.PRECIOUS: Makefile + + +clean-local: + $(RM) version.h $(plugin_gen) + +src/thrift/main.cc: src/thrift/version.h + +style-local: + $(CPPSTYLE_CMD) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/compiler/cpp/README.md b/compiler/cpp/README.md new file mode 100644 index 0000000..2fff0d8 --- /dev/null +++ b/compiler/cpp/README.md @@ -0,0 +1,101 @@ +# Build compiler using CMake + +## build on Unix-like System + +### build using cmake + +Use the following steps to build using cmake: + +``` +mkdir cmake-build +cd cmake-build +cmake .. +make +``` + +### Create an eclipse project + +``` +mkdir cmake-ec && cd cmake-ec +cmake -G "Eclipse CDT4 - Unix Makefiles" .. +make +``` + +Now open the folder cmake-ec using eclipse. + + +## Cross compile using mingw32 and generate a Windows Installer with CPack + +``` +mkdir cmake-mingw32 && cd cmake-mingw32 +cmake -DCMAKE_TOOLCHAIN_FILE=../build/cmake/mingw32-toolchain.cmake -DBUILD_COMPILER=ON -DBUILD_LIBRARIES=OFF -DBUILD_TESTING=OFF -DBUILD_EXAMPLES=OFF .. +cpack +``` + +# Build on windows + +### using Git Bash + +Git Bash provides flex and bison, so you just need to do this: + +``` +mkdir cmake-vs && cd cmake-vs +cmake -DWITH_SHARED_LIB=off .. +``` + +### using Win flex-bison + +In order to build on windows with winflexbison a few additional steps are necessary: + +1. Download winflexbison from http://sourceforge.net/projects/winflexbison/ +2. Extract the winflex bison files to for e.g. C:\winflexbison +3. Make the CMake variables point to the correct binaries. + * FLEX_EXECUTABLE = C:/winbuild/win_flex.exe + * BISON_EXECUTABLE = C:/winbuild/win_bison.exe +4. Generate a Visual Studio project: +``` +mkdir cmake-vs && cd cmake-vs +cmake -G "Visual Studio 12" -DWITH_SHARED_LIB=off .. +``` +5. Now open the folder build_vs using Visual Studio 2013. + +# Building the Thrift IDL compiler in Windows + +If you don't want to use CMake you can use the already available Visual Studio +2010 solution. +The Visual Studio project contains pre-build commands to generate the +thriftl.cc, thrifty.cc and thrifty.hh files which are necessary to build +the compiler. These depend on bison, flex and their dependencies to +work properly. +Download flex & bison as described above. +Place these binaries somewhere in the path and +rename win_flex.exe and win_bison.exe to flex.exe and bison.exe respectively. + +If this doesn't work on a system, try these manual pre-build steps. + +Open compiler.sln and remove the Pre-build commands under the project's + Properties -> Build Events -> Pre-Build Events. + +From a command prompt: +``` +cd thrift/compiler/cpp +flex -o src\thrift\thriftl.cc src\thrift\thriftl.ll +``` +In the generated thriftl.cc, comment out #include + +Place a copy of bison.simple in thrift/compiler/cpp +``` +bison -y -o "src/thrift/thrifty.cc" --defines src/thrift/thrifty.yy +move src\thrift\thrifty.cc.hh src\thrift\thrifty.hh +``` + +Bison might generate the yacc header file "thrifty.cc.h" with just one h ".h" extension; in this case you'll have to rename to "thrifty.h". + +``` +move src\thrift\version.h.in src\thrift\version.h +``` + +Download inttypes.h from the interwebs and place it in an include path +location (e.g. thrift/compiler/cpp/src). + +Build the compiler in Visual Studio. diff --git a/compiler/cpp/coding_standards.md b/compiler/cpp/coding_standards.md new file mode 100644 index 0000000..ea08946 --- /dev/null +++ b/compiler/cpp/coding_standards.md @@ -0,0 +1,4 @@ +## Compiler Coding Standards + + * When making small change / bugfix - follow style as seen in nearby code. + * When making major refactor and / or adding new feature - follow style for C++ library \ No newline at end of file diff --git a/compiler/cpp/compiler.sln b/compiler/cpp/compiler.sln new file mode 100644 index 0000000..94961aa --- /dev/null +++ b/compiler/cpp/compiler.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "compiler", "compiler.vcxproj", "{89975A1A-F799-4556-98B8-64E30AB39A90}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {89975A1A-F799-4556-98B8-64E30AB39A90}.Debug|Win32.ActiveCfg = Debug|Win32 + {89975A1A-F799-4556-98B8-64E30AB39A90}.Debug|Win32.Build.0 = Debug|Win32 + {89975A1A-F799-4556-98B8-64E30AB39A90}.Release|Win32.ActiveCfg = Release|Win32 + {89975A1A-F799-4556-98B8-64E30AB39A90}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/compiler/cpp/compiler.vcxproj b/compiler/cpp/compiler.vcxproj new file mode 100644 index 0000000..4b03253 --- /dev/null +++ b/compiler/cpp/compiler.vcxproj @@ -0,0 +1,251 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {89975A1A-F799-4556-98B8-64E30AB39A90} + Win32Proj + compiler + + + + Application + true + MultiByte + + + Application + true + MultiByte + + + Application + false + true + MultiByte + + + Application + false + true + MultiByte + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)\src\;$(ProjectDir)\src\windows\;$(IncludePath) + thrift + $(ExecutablePath);C:\Program Files (x86)\Git\bin + + + true + $(ProjectDir)\src\;$(ProjectDir)\src\windows\;$(IncludePath) + thrift + $(ExecutablePath);C:\Program Files (x86)\Git\bin + + + false + $(ProjectDir)\src\;$(ProjectDir)\src\windows\;$(IncludePath) + thrift + $(ExecutablePath);C:\Program Files (x86)\Git\bin + + + false + $(ProjectDir)\src\;$(ProjectDir)\src\windows\;$(IncludePath) + thrift + $(ExecutablePath);C:\Program Files (x86)\Git\bin + + + + + + Level3 + Disabled + WIN32;MINGW;YY_NO_UNISTD_H;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + thrift\windows\config.h + CompileAsCpp + + + Console + true + + + flex -o "src\\thrift\\thriftl.cc" src/thrift/thriftl.ll && bison -y -o "src\\thrift\\thrifty.cc" --defines="src\\thrift\\thrifty.hh" src/thrift/thrifty.yy + + + + + + + Level3 + Disabled + WIN32;MINGW;YY_NO_UNISTD_H;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + thrift\windows\config.h + CompileAsCpp + + + Console + true + + + flex -o "src\\thrift\\thriftl.cc" src/thrift/thriftl.ll && bison -y -o "src\\thrift\\thrifty.cc" --defines="src\\thrift\\thrifty.hh" src/thrift/thrifty.yy + + + + + + Level3 + + + MaxSpeed + true + true + WIN32;MINGW;YY_NO_UNISTD_H;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + thrift\windows\config.h + CompileAsCpp + + + Console + true + true + true + + + flex -o "src\\thrift\\thriftl.cc" src/thrift/thriftl.ll && bison -y -o "src\\thrift\\thrifty.cc" --defines="src\\thrift\\thrifty.hh" src/thrift/thrifty.yy + + + + + + Level3 + + + MaxSpeed + true + true + WIN32;MINGW;YY_NO_UNISTD_H;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + thrift\windows\config.h + CompileAsCpp + + + Console + true + true + true + + + flex -o "src\\thrift\\thriftl.cc" src/thrift/thriftl.ll && bison -y -o "src\\thrift\\thrifty.cc" --defines="src\\thrift\\thrifty.hh" src/thrift/thrifty.yy + + + + + + + diff --git a/compiler/cpp/compiler.vcxproj.filters b/compiler/cpp/compiler.vcxproj.filters new file mode 100644 index 0000000..b96865b --- /dev/null +++ b/compiler/cpp/compiler.vcxproj.filters @@ -0,0 +1,199 @@ + + + + + + generate + + + generate + + + generate + + + generate + + + + + parse + + + parse + + + parse + + + parse + + + parse + + + parse + + + parse + + + parse + + + parse + + + parse + + + parse + + + parse + + + parse + + + parse + + + parse + + + parse + + + parse + + + parse + + + + + windows + + + windows + + + + + {ae9d0a15-57ae-4f01-87a4-81f790249b83} + + + {5df016bb-591b-420a-a535-4330d9187fbf} + + + {b5c626af-afa5-433c-8e10-ee734533cb68} + + + + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + generate + + + + parse + + + + + parse + + + generate + + + generate + + + + + + + diff --git a/compiler/cpp/src/Makefile.am b/compiler/cpp/src/Makefile.am new file mode 100644 index 0000000..bc2c5cb --- /dev/null +++ b/compiler/cpp/src/Makefile.am @@ -0,0 +1,87 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# +# Contains some contributions under the Thrift Software License. +# Please see doc/old-thrift-license.txt in the Thrift distribution for +# details. + +AUTOMAKE_OPTIONS = subdir-objects + +AM_YFLAGS = -d + +BUILT_SOURCES = thrift/thrifty.cc + +noinst_LIBRARIES = thrift/libparse.a + +thrift_libparse_a_CPPFLAGS = -I$(srcdir) +thrift_libparse_a_CXXFLAGS = -Wall -Wno-sign-compare -Wno-unused + +thrift_libparse_a_SOURCES = thrift/thrifty.yy \ + thrift/thriftl.ll + +clean-local: + $(RM) thrift/thriftl.cc thrift/thrifty.cc thrift/thrifty.h thrift/thrifty.hh + +if WITH_PLUGIN +noinst_PROGRAMS = thrift/thrift-bootstrap + +thrift_thrift_bootstrap_SOURCES = \ + thrift/common.h \ + thrift/common.cc \ + thrift/audit/t_audit.h \ + thrift/audit/t_audit.cpp \ + thrift/generate/t_generator.cc \ + thrift/generate/t_generator_registry.h \ + thrift/globals.h \ + thrift/platform.h \ + thrift/logging.h \ + thrift/parse/t_doc.h \ + thrift/parse/t_type.h \ + thrift/parse/t_base_type.h \ + thrift/parse/t_enum.h \ + thrift/parse/t_enum_value.h \ + thrift/parse/t_typedef.h \ + thrift/parse/t_typedef.cc \ + thrift/parse/t_container.h \ + thrift/parse/t_list.h \ + thrift/parse/t_set.h \ + thrift/parse/t_map.h \ + thrift/parse/t_struct.h \ + thrift/parse/t_field.h \ + thrift/parse/t_service.h \ + thrift/parse/t_function.h \ + thrift/parse/t_program.h \ + thrift/parse/t_scope.h \ + thrift/parse/t_const.h \ + thrift/parse/t_const_value.h \ + thrift/parse/parse.cc \ + thrift/generate/t_generator.h \ + thrift/generate/t_oop_generator.h \ + thrift/generate/t_html_generator.h \ + thrift/windows/config.h \ + thrift/version.h \ + thrift/generate/t_cpp_generator.cc \ + thrift/main.h \ + thrift/main.cc + +main.cc: version.h + +thrift_thrift_bootstrap_CXXFLAGS = -Wall -Wextra -pedantic +thrift_thrift_bootstrap_LDADD = @LEXLIB@ thrift/libparse.a +endif diff --git a/compiler/cpp/src/Makefile.in b/compiler/cpp/src/Makefile.in new file mode 100644 index 0000000..9dc0f30 --- /dev/null +++ b/compiler/cpp/src/Makefile.in @@ -0,0 +1,1157 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# +# Contains some contributions under the Thrift Software License. +# Please see doc/old-thrift-license.txt in the Thrift distribution for +# details. + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@WITH_PLUGIN_TRUE@noinst_PROGRAMS = thrift/thrift-bootstrap$(EXEEXT) +subdir = compiler/cpp/src +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +thrift_libparse_a_AR = $(AR) $(ARFLAGS) +thrift_libparse_a_LIBADD = +am__dirstamp = $(am__leading_dot)dirstamp +am_thrift_libparse_a_OBJECTS = \ + thrift/thrift_libparse_a-thrifty.$(OBJEXT) \ + thrift/thrift_libparse_a-thriftl.$(OBJEXT) +thrift_libparse_a_OBJECTS = $(am_thrift_libparse_a_OBJECTS) +PROGRAMS = $(noinst_PROGRAMS) +am__thrift_thrift_bootstrap_SOURCES_DIST = thrift/common.h \ + thrift/common.cc thrift/audit/t_audit.h \ + thrift/audit/t_audit.cpp thrift/generate/t_generator.cc \ + thrift/generate/t_generator_registry.h thrift/globals.h \ + thrift/platform.h thrift/logging.h thrift/parse/t_doc.h \ + thrift/parse/t_type.h thrift/parse/t_base_type.h \ + thrift/parse/t_enum.h thrift/parse/t_enum_value.h \ + thrift/parse/t_typedef.h thrift/parse/t_typedef.cc \ + thrift/parse/t_container.h thrift/parse/t_list.h \ + thrift/parse/t_set.h thrift/parse/t_map.h \ + thrift/parse/t_struct.h thrift/parse/t_field.h \ + thrift/parse/t_service.h thrift/parse/t_function.h \ + thrift/parse/t_program.h thrift/parse/t_scope.h \ + thrift/parse/t_const.h thrift/parse/t_const_value.h \ + thrift/parse/parse.cc thrift/generate/t_generator.h \ + thrift/generate/t_oop_generator.h \ + thrift/generate/t_html_generator.h thrift/windows/config.h \ + thrift/version.h thrift/generate/t_cpp_generator.cc \ + thrift/main.h thrift/main.cc +@WITH_PLUGIN_TRUE@am_thrift_thrift_bootstrap_OBJECTS = thrift/thrift_thrift_bootstrap-common.$(OBJEXT) \ +@WITH_PLUGIN_TRUE@ thrift/audit/thrift_thrift_bootstrap-t_audit.$(OBJEXT) \ +@WITH_PLUGIN_TRUE@ thrift/generate/thrift_thrift_bootstrap-t_generator.$(OBJEXT) \ +@WITH_PLUGIN_TRUE@ thrift/parse/thrift_thrift_bootstrap-t_typedef.$(OBJEXT) \ +@WITH_PLUGIN_TRUE@ thrift/parse/thrift_thrift_bootstrap-parse.$(OBJEXT) \ +@WITH_PLUGIN_TRUE@ thrift/generate/thrift_thrift_bootstrap-t_cpp_generator.$(OBJEXT) \ +@WITH_PLUGIN_TRUE@ thrift/thrift_thrift_bootstrap-main.$(OBJEXT) +thrift_thrift_bootstrap_OBJECTS = \ + $(am_thrift_thrift_bootstrap_OBJECTS) +@WITH_PLUGIN_TRUE@thrift_thrift_bootstrap_DEPENDENCIES = \ +@WITH_PLUGIN_TRUE@ thrift/libparse.a +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +thrift_thrift_bootstrap_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/lib/cpp/src/thrift -I$(top_builddir)/lib/c_glib/src/thrift +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS) +LTLEXCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS) +AM_V_LEX = $(am__v_LEX_@AM_V@) +am__v_LEX_ = $(am__v_LEX_@AM_DEFAULT_V@) +am__v_LEX_0 = @echo " LEX " $@; +am__v_LEX_1 = +YLWRAP = $(top_srcdir)/ylwrap +am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ + -e s/c++$$/h++/ -e s/c$$/h/ +YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) +LTYACCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS) +AM_V_YACC = $(am__v_YACC_@AM_V@) +am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) +am__v_YACC_0 = @echo " YACC " $@; +am__v_YACC_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(thrift_libparse_a_SOURCES) \ + $(thrift_thrift_bootstrap_SOURCES) +DIST_SOURCES = $(thrift_libparse_a_SOURCES) \ + $(am__thrift_thrift_bootstrap_SOURCES_DIST) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \ + $(top_srcdir)/ylwrap thrift/thriftl.cc thrift/thrifty.cc \ + thrift/thrifty.hh +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = subdir-objects +AM_YFLAGS = -d +BUILT_SOURCES = thrift/thrifty.cc +noinst_LIBRARIES = thrift/libparse.a +thrift_libparse_a_CPPFLAGS = -I$(srcdir) +thrift_libparse_a_CXXFLAGS = -Wall -Wno-sign-compare -Wno-unused +thrift_libparse_a_SOURCES = thrift/thrifty.yy \ + thrift/thriftl.ll + +@WITH_PLUGIN_TRUE@thrift_thrift_bootstrap_SOURCES = \ +@WITH_PLUGIN_TRUE@ thrift/common.h \ +@WITH_PLUGIN_TRUE@ thrift/common.cc \ +@WITH_PLUGIN_TRUE@ thrift/audit/t_audit.h \ +@WITH_PLUGIN_TRUE@ thrift/audit/t_audit.cpp \ +@WITH_PLUGIN_TRUE@ thrift/generate/t_generator.cc \ +@WITH_PLUGIN_TRUE@ thrift/generate/t_generator_registry.h \ +@WITH_PLUGIN_TRUE@ thrift/globals.h \ +@WITH_PLUGIN_TRUE@ thrift/platform.h \ +@WITH_PLUGIN_TRUE@ thrift/logging.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_doc.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_type.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_base_type.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_enum.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_enum_value.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_typedef.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_typedef.cc \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_container.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_list.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_set.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_map.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_struct.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_field.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_service.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_function.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_program.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_scope.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_const.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/t_const_value.h \ +@WITH_PLUGIN_TRUE@ thrift/parse/parse.cc \ +@WITH_PLUGIN_TRUE@ thrift/generate/t_generator.h \ +@WITH_PLUGIN_TRUE@ thrift/generate/t_oop_generator.h \ +@WITH_PLUGIN_TRUE@ thrift/generate/t_html_generator.h \ +@WITH_PLUGIN_TRUE@ thrift/windows/config.h \ +@WITH_PLUGIN_TRUE@ thrift/version.h \ +@WITH_PLUGIN_TRUE@ thrift/generate/t_cpp_generator.cc \ +@WITH_PLUGIN_TRUE@ thrift/main.h \ +@WITH_PLUGIN_TRUE@ thrift/main.cc + +@WITH_PLUGIN_TRUE@thrift_thrift_bootstrap_CXXFLAGS = -Wall -Wextra -pedantic +@WITH_PLUGIN_TRUE@thrift_thrift_bootstrap_LDADD = @LEXLIB@ thrift/libparse.a +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .cc .cpp .ll .lo .o .obj .yy +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign compiler/cpp/src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign compiler/cpp/src/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +thrift/thrifty.hh: thrift/thrifty.cc + @if test ! -f $@; then rm -f thrift/thrifty.cc; else :; fi + @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) thrift/thrifty.cc; else :; fi +thrift/$(am__dirstamp): + @$(MKDIR_P) thrift + @: > thrift/$(am__dirstamp) +thrift/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) thrift/$(DEPDIR) + @: > thrift/$(DEPDIR)/$(am__dirstamp) +thrift/thrift_libparse_a-thrifty.$(OBJEXT): thrift/$(am__dirstamp) \ + thrift/$(DEPDIR)/$(am__dirstamp) +thrift/thrift_libparse_a-thriftl.$(OBJEXT): thrift/$(am__dirstamp) \ + thrift/$(DEPDIR)/$(am__dirstamp) + +thrift/libparse.a: $(thrift_libparse_a_OBJECTS) $(thrift_libparse_a_DEPENDENCIES) $(EXTRA_thrift_libparse_a_DEPENDENCIES) thrift/$(am__dirstamp) + $(AM_V_at)-rm -f thrift/libparse.a + $(AM_V_AR)$(thrift_libparse_a_AR) thrift/libparse.a $(thrift_libparse_a_OBJECTS) $(thrift_libparse_a_LIBADD) + $(AM_V_at)$(RANLIB) thrift/libparse.a + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +thrift/thrift_thrift_bootstrap-common.$(OBJEXT): \ + thrift/$(am__dirstamp) thrift/$(DEPDIR)/$(am__dirstamp) +thrift/audit/$(am__dirstamp): + @$(MKDIR_P) thrift/audit + @: > thrift/audit/$(am__dirstamp) +thrift/audit/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) thrift/audit/$(DEPDIR) + @: > thrift/audit/$(DEPDIR)/$(am__dirstamp) +thrift/audit/thrift_thrift_bootstrap-t_audit.$(OBJEXT): \ + thrift/audit/$(am__dirstamp) \ + thrift/audit/$(DEPDIR)/$(am__dirstamp) +thrift/generate/$(am__dirstamp): + @$(MKDIR_P) thrift/generate + @: > thrift/generate/$(am__dirstamp) +thrift/generate/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) thrift/generate/$(DEPDIR) + @: > thrift/generate/$(DEPDIR)/$(am__dirstamp) +thrift/generate/thrift_thrift_bootstrap-t_generator.$(OBJEXT): \ + thrift/generate/$(am__dirstamp) \ + thrift/generate/$(DEPDIR)/$(am__dirstamp) +thrift/parse/$(am__dirstamp): + @$(MKDIR_P) thrift/parse + @: > thrift/parse/$(am__dirstamp) +thrift/parse/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) thrift/parse/$(DEPDIR) + @: > thrift/parse/$(DEPDIR)/$(am__dirstamp) +thrift/parse/thrift_thrift_bootstrap-t_typedef.$(OBJEXT): \ + thrift/parse/$(am__dirstamp) \ + thrift/parse/$(DEPDIR)/$(am__dirstamp) +thrift/parse/thrift_thrift_bootstrap-parse.$(OBJEXT): \ + thrift/parse/$(am__dirstamp) \ + thrift/parse/$(DEPDIR)/$(am__dirstamp) +thrift/generate/thrift_thrift_bootstrap-t_cpp_generator.$(OBJEXT): \ + thrift/generate/$(am__dirstamp) \ + thrift/generate/$(DEPDIR)/$(am__dirstamp) +thrift/thrift_thrift_bootstrap-main.$(OBJEXT): thrift/$(am__dirstamp) \ + thrift/$(DEPDIR)/$(am__dirstamp) + +thrift/thrift-bootstrap$(EXEEXT): $(thrift_thrift_bootstrap_OBJECTS) $(thrift_thrift_bootstrap_DEPENDENCIES) $(EXTRA_thrift_thrift_bootstrap_DEPENDENCIES) thrift/$(am__dirstamp) + @rm -f thrift/thrift-bootstrap$(EXEEXT) + $(AM_V_CXXLD)$(thrift_thrift_bootstrap_LINK) $(thrift_thrift_bootstrap_OBJECTS) $(thrift_thrift_bootstrap_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f thrift/*.$(OBJEXT) + -rm -f thrift/audit/*.$(OBJEXT) + -rm -f thrift/generate/*.$(OBJEXT) + -rm -f thrift/parse/*.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@thrift/$(DEPDIR)/thrift_libparse_a-thriftl.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@thrift/$(DEPDIR)/thrift_libparse_a-thrifty.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@thrift/$(DEPDIR)/thrift_thrift_bootstrap-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@thrift/$(DEPDIR)/thrift_thrift_bootstrap-main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@thrift/audit/$(DEPDIR)/thrift_thrift_bootstrap-t_audit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_cpp_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-parse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-t_typedef.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +thrift/thrift_libparse_a-thrifty.o: thrift/thrifty.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_libparse_a_CPPFLAGS) $(CPPFLAGS) $(thrift_libparse_a_CXXFLAGS) $(CXXFLAGS) -MT thrift/thrift_libparse_a-thrifty.o -MD -MP -MF thrift/$(DEPDIR)/thrift_libparse_a-thrifty.Tpo -c -o thrift/thrift_libparse_a-thrifty.o `test -f 'thrift/thrifty.cc' || echo '$(srcdir)/'`thrift/thrifty.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/$(DEPDIR)/thrift_libparse_a-thrifty.Tpo thrift/$(DEPDIR)/thrift_libparse_a-thrifty.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/thrifty.cc' object='thrift/thrift_libparse_a-thrifty.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_libparse_a_CPPFLAGS) $(CPPFLAGS) $(thrift_libparse_a_CXXFLAGS) $(CXXFLAGS) -c -o thrift/thrift_libparse_a-thrifty.o `test -f 'thrift/thrifty.cc' || echo '$(srcdir)/'`thrift/thrifty.cc + +thrift/thrift_libparse_a-thrifty.obj: thrift/thrifty.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_libparse_a_CPPFLAGS) $(CPPFLAGS) $(thrift_libparse_a_CXXFLAGS) $(CXXFLAGS) -MT thrift/thrift_libparse_a-thrifty.obj -MD -MP -MF thrift/$(DEPDIR)/thrift_libparse_a-thrifty.Tpo -c -o thrift/thrift_libparse_a-thrifty.obj `if test -f 'thrift/thrifty.cc'; then $(CYGPATH_W) 'thrift/thrifty.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/thrifty.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/$(DEPDIR)/thrift_libparse_a-thrifty.Tpo thrift/$(DEPDIR)/thrift_libparse_a-thrifty.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/thrifty.cc' object='thrift/thrift_libparse_a-thrifty.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_libparse_a_CPPFLAGS) $(CPPFLAGS) $(thrift_libparse_a_CXXFLAGS) $(CXXFLAGS) -c -o thrift/thrift_libparse_a-thrifty.obj `if test -f 'thrift/thrifty.cc'; then $(CYGPATH_W) 'thrift/thrifty.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/thrifty.cc'; fi` + +thrift/thrift_libparse_a-thriftl.o: thrift/thriftl.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_libparse_a_CPPFLAGS) $(CPPFLAGS) $(thrift_libparse_a_CXXFLAGS) $(CXXFLAGS) -MT thrift/thrift_libparse_a-thriftl.o -MD -MP -MF thrift/$(DEPDIR)/thrift_libparse_a-thriftl.Tpo -c -o thrift/thrift_libparse_a-thriftl.o `test -f 'thrift/thriftl.cc' || echo '$(srcdir)/'`thrift/thriftl.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/$(DEPDIR)/thrift_libparse_a-thriftl.Tpo thrift/$(DEPDIR)/thrift_libparse_a-thriftl.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/thriftl.cc' object='thrift/thrift_libparse_a-thriftl.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_libparse_a_CPPFLAGS) $(CPPFLAGS) $(thrift_libparse_a_CXXFLAGS) $(CXXFLAGS) -c -o thrift/thrift_libparse_a-thriftl.o `test -f 'thrift/thriftl.cc' || echo '$(srcdir)/'`thrift/thriftl.cc + +thrift/thrift_libparse_a-thriftl.obj: thrift/thriftl.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_libparse_a_CPPFLAGS) $(CPPFLAGS) $(thrift_libparse_a_CXXFLAGS) $(CXXFLAGS) -MT thrift/thrift_libparse_a-thriftl.obj -MD -MP -MF thrift/$(DEPDIR)/thrift_libparse_a-thriftl.Tpo -c -o thrift/thrift_libparse_a-thriftl.obj `if test -f 'thrift/thriftl.cc'; then $(CYGPATH_W) 'thrift/thriftl.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/thriftl.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/$(DEPDIR)/thrift_libparse_a-thriftl.Tpo thrift/$(DEPDIR)/thrift_libparse_a-thriftl.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/thriftl.cc' object='thrift/thrift_libparse_a-thriftl.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_libparse_a_CPPFLAGS) $(CPPFLAGS) $(thrift_libparse_a_CXXFLAGS) $(CXXFLAGS) -c -o thrift/thrift_libparse_a-thriftl.obj `if test -f 'thrift/thriftl.cc'; then $(CYGPATH_W) 'thrift/thriftl.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/thriftl.cc'; fi` + +thrift/thrift_thrift_bootstrap-common.o: thrift/common.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/thrift_thrift_bootstrap-common.o -MD -MP -MF thrift/$(DEPDIR)/thrift_thrift_bootstrap-common.Tpo -c -o thrift/thrift_thrift_bootstrap-common.o `test -f 'thrift/common.cc' || echo '$(srcdir)/'`thrift/common.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/$(DEPDIR)/thrift_thrift_bootstrap-common.Tpo thrift/$(DEPDIR)/thrift_thrift_bootstrap-common.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/common.cc' object='thrift/thrift_thrift_bootstrap-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/thrift_thrift_bootstrap-common.o `test -f 'thrift/common.cc' || echo '$(srcdir)/'`thrift/common.cc + +thrift/thrift_thrift_bootstrap-common.obj: thrift/common.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/thrift_thrift_bootstrap-common.obj -MD -MP -MF thrift/$(DEPDIR)/thrift_thrift_bootstrap-common.Tpo -c -o thrift/thrift_thrift_bootstrap-common.obj `if test -f 'thrift/common.cc'; then $(CYGPATH_W) 'thrift/common.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/common.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/$(DEPDIR)/thrift_thrift_bootstrap-common.Tpo thrift/$(DEPDIR)/thrift_thrift_bootstrap-common.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/common.cc' object='thrift/thrift_thrift_bootstrap-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/thrift_thrift_bootstrap-common.obj `if test -f 'thrift/common.cc'; then $(CYGPATH_W) 'thrift/common.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/common.cc'; fi` + +thrift/audit/thrift_thrift_bootstrap-t_audit.o: thrift/audit/t_audit.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/audit/thrift_thrift_bootstrap-t_audit.o -MD -MP -MF thrift/audit/$(DEPDIR)/thrift_thrift_bootstrap-t_audit.Tpo -c -o thrift/audit/thrift_thrift_bootstrap-t_audit.o `test -f 'thrift/audit/t_audit.cpp' || echo '$(srcdir)/'`thrift/audit/t_audit.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/audit/$(DEPDIR)/thrift_thrift_bootstrap-t_audit.Tpo thrift/audit/$(DEPDIR)/thrift_thrift_bootstrap-t_audit.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/audit/t_audit.cpp' object='thrift/audit/thrift_thrift_bootstrap-t_audit.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/audit/thrift_thrift_bootstrap-t_audit.o `test -f 'thrift/audit/t_audit.cpp' || echo '$(srcdir)/'`thrift/audit/t_audit.cpp + +thrift/audit/thrift_thrift_bootstrap-t_audit.obj: thrift/audit/t_audit.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/audit/thrift_thrift_bootstrap-t_audit.obj -MD -MP -MF thrift/audit/$(DEPDIR)/thrift_thrift_bootstrap-t_audit.Tpo -c -o thrift/audit/thrift_thrift_bootstrap-t_audit.obj `if test -f 'thrift/audit/t_audit.cpp'; then $(CYGPATH_W) 'thrift/audit/t_audit.cpp'; else $(CYGPATH_W) '$(srcdir)/thrift/audit/t_audit.cpp'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/audit/$(DEPDIR)/thrift_thrift_bootstrap-t_audit.Tpo thrift/audit/$(DEPDIR)/thrift_thrift_bootstrap-t_audit.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/audit/t_audit.cpp' object='thrift/audit/thrift_thrift_bootstrap-t_audit.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/audit/thrift_thrift_bootstrap-t_audit.obj `if test -f 'thrift/audit/t_audit.cpp'; then $(CYGPATH_W) 'thrift/audit/t_audit.cpp'; else $(CYGPATH_W) '$(srcdir)/thrift/audit/t_audit.cpp'; fi` + +thrift/generate/thrift_thrift_bootstrap-t_generator.o: thrift/generate/t_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/generate/thrift_thrift_bootstrap-t_generator.o -MD -MP -MF thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_generator.Tpo -c -o thrift/generate/thrift_thrift_bootstrap-t_generator.o `test -f 'thrift/generate/t_generator.cc' || echo '$(srcdir)/'`thrift/generate/t_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_generator.Tpo thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/generate/t_generator.cc' object='thrift/generate/thrift_thrift_bootstrap-t_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/generate/thrift_thrift_bootstrap-t_generator.o `test -f 'thrift/generate/t_generator.cc' || echo '$(srcdir)/'`thrift/generate/t_generator.cc + +thrift/generate/thrift_thrift_bootstrap-t_generator.obj: thrift/generate/t_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/generate/thrift_thrift_bootstrap-t_generator.obj -MD -MP -MF thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_generator.Tpo -c -o thrift/generate/thrift_thrift_bootstrap-t_generator.obj `if test -f 'thrift/generate/t_generator.cc'; then $(CYGPATH_W) 'thrift/generate/t_generator.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/generate/t_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_generator.Tpo thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/generate/t_generator.cc' object='thrift/generate/thrift_thrift_bootstrap-t_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/generate/thrift_thrift_bootstrap-t_generator.obj `if test -f 'thrift/generate/t_generator.cc'; then $(CYGPATH_W) 'thrift/generate/t_generator.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/generate/t_generator.cc'; fi` + +thrift/parse/thrift_thrift_bootstrap-t_typedef.o: thrift/parse/t_typedef.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/parse/thrift_thrift_bootstrap-t_typedef.o -MD -MP -MF thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-t_typedef.Tpo -c -o thrift/parse/thrift_thrift_bootstrap-t_typedef.o `test -f 'thrift/parse/t_typedef.cc' || echo '$(srcdir)/'`thrift/parse/t_typedef.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-t_typedef.Tpo thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-t_typedef.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/parse/t_typedef.cc' object='thrift/parse/thrift_thrift_bootstrap-t_typedef.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/parse/thrift_thrift_bootstrap-t_typedef.o `test -f 'thrift/parse/t_typedef.cc' || echo '$(srcdir)/'`thrift/parse/t_typedef.cc + +thrift/parse/thrift_thrift_bootstrap-t_typedef.obj: thrift/parse/t_typedef.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/parse/thrift_thrift_bootstrap-t_typedef.obj -MD -MP -MF thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-t_typedef.Tpo -c -o thrift/parse/thrift_thrift_bootstrap-t_typedef.obj `if test -f 'thrift/parse/t_typedef.cc'; then $(CYGPATH_W) 'thrift/parse/t_typedef.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/parse/t_typedef.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-t_typedef.Tpo thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-t_typedef.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/parse/t_typedef.cc' object='thrift/parse/thrift_thrift_bootstrap-t_typedef.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/parse/thrift_thrift_bootstrap-t_typedef.obj `if test -f 'thrift/parse/t_typedef.cc'; then $(CYGPATH_W) 'thrift/parse/t_typedef.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/parse/t_typedef.cc'; fi` + +thrift/parse/thrift_thrift_bootstrap-parse.o: thrift/parse/parse.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/parse/thrift_thrift_bootstrap-parse.o -MD -MP -MF thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-parse.Tpo -c -o thrift/parse/thrift_thrift_bootstrap-parse.o `test -f 'thrift/parse/parse.cc' || echo '$(srcdir)/'`thrift/parse/parse.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-parse.Tpo thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-parse.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/parse/parse.cc' object='thrift/parse/thrift_thrift_bootstrap-parse.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/parse/thrift_thrift_bootstrap-parse.o `test -f 'thrift/parse/parse.cc' || echo '$(srcdir)/'`thrift/parse/parse.cc + +thrift/parse/thrift_thrift_bootstrap-parse.obj: thrift/parse/parse.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/parse/thrift_thrift_bootstrap-parse.obj -MD -MP -MF thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-parse.Tpo -c -o thrift/parse/thrift_thrift_bootstrap-parse.obj `if test -f 'thrift/parse/parse.cc'; then $(CYGPATH_W) 'thrift/parse/parse.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/parse/parse.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-parse.Tpo thrift/parse/$(DEPDIR)/thrift_thrift_bootstrap-parse.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/parse/parse.cc' object='thrift/parse/thrift_thrift_bootstrap-parse.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/parse/thrift_thrift_bootstrap-parse.obj `if test -f 'thrift/parse/parse.cc'; then $(CYGPATH_W) 'thrift/parse/parse.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/parse/parse.cc'; fi` + +thrift/generate/thrift_thrift_bootstrap-t_cpp_generator.o: thrift/generate/t_cpp_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/generate/thrift_thrift_bootstrap-t_cpp_generator.o -MD -MP -MF thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_cpp_generator.Tpo -c -o thrift/generate/thrift_thrift_bootstrap-t_cpp_generator.o `test -f 'thrift/generate/t_cpp_generator.cc' || echo '$(srcdir)/'`thrift/generate/t_cpp_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_cpp_generator.Tpo thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_cpp_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/generate/t_cpp_generator.cc' object='thrift/generate/thrift_thrift_bootstrap-t_cpp_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/generate/thrift_thrift_bootstrap-t_cpp_generator.o `test -f 'thrift/generate/t_cpp_generator.cc' || echo '$(srcdir)/'`thrift/generate/t_cpp_generator.cc + +thrift/generate/thrift_thrift_bootstrap-t_cpp_generator.obj: thrift/generate/t_cpp_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/generate/thrift_thrift_bootstrap-t_cpp_generator.obj -MD -MP -MF thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_cpp_generator.Tpo -c -o thrift/generate/thrift_thrift_bootstrap-t_cpp_generator.obj `if test -f 'thrift/generate/t_cpp_generator.cc'; then $(CYGPATH_W) 'thrift/generate/t_cpp_generator.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/generate/t_cpp_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_cpp_generator.Tpo thrift/generate/$(DEPDIR)/thrift_thrift_bootstrap-t_cpp_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/generate/t_cpp_generator.cc' object='thrift/generate/thrift_thrift_bootstrap-t_cpp_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/generate/thrift_thrift_bootstrap-t_cpp_generator.obj `if test -f 'thrift/generate/t_cpp_generator.cc'; then $(CYGPATH_W) 'thrift/generate/t_cpp_generator.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/generate/t_cpp_generator.cc'; fi` + +thrift/thrift_thrift_bootstrap-main.o: thrift/main.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/thrift_thrift_bootstrap-main.o -MD -MP -MF thrift/$(DEPDIR)/thrift_thrift_bootstrap-main.Tpo -c -o thrift/thrift_thrift_bootstrap-main.o `test -f 'thrift/main.cc' || echo '$(srcdir)/'`thrift/main.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/$(DEPDIR)/thrift_thrift_bootstrap-main.Tpo thrift/$(DEPDIR)/thrift_thrift_bootstrap-main.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/main.cc' object='thrift/thrift_thrift_bootstrap-main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/thrift_thrift_bootstrap-main.o `test -f 'thrift/main.cc' || echo '$(srcdir)/'`thrift/main.cc + +thrift/thrift_thrift_bootstrap-main.obj: thrift/main.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -MT thrift/thrift_thrift_bootstrap-main.obj -MD -MP -MF thrift/$(DEPDIR)/thrift_thrift_bootstrap-main.Tpo -c -o thrift/thrift_thrift_bootstrap-main.obj `if test -f 'thrift/main.cc'; then $(CYGPATH_W) 'thrift/main.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/main.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) thrift/$(DEPDIR)/thrift_thrift_bootstrap-main.Tpo thrift/$(DEPDIR)/thrift_thrift_bootstrap-main.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thrift/main.cc' object='thrift/thrift_thrift_bootstrap-main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thrift_thrift_bootstrap_CXXFLAGS) $(CXXFLAGS) -c -o thrift/thrift_thrift_bootstrap-main.obj `if test -f 'thrift/main.cc'; then $(CYGPATH_W) 'thrift/main.cc'; else $(CYGPATH_W) '$(srcdir)/thrift/main.cc'; fi` + +.cpp.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +.ll.cc: + $(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE) + +.yy.cc: + $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf thrift/.libs thrift/_libs +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) +installdirs: +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f thrift/$(DEPDIR)/$(am__dirstamp) + -rm -f thrift/$(am__dirstamp) + -rm -f thrift/audit/$(DEPDIR)/$(am__dirstamp) + -rm -f thrift/audit/$(am__dirstamp) + -rm -f thrift/generate/$(DEPDIR)/$(am__dirstamp) + -rm -f thrift/generate/$(am__dirstamp) + -rm -f thrift/parse/$(DEPDIR)/$(am__dirstamp) + -rm -f thrift/parse/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -rm -f thrift/thriftl.cc + -rm -f thrift/thrifty.cc + -rm -f thrift/thrifty.hh + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local \ + clean-noinstLIBRARIES clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf thrift/$(DEPDIR) thrift/audit/$(DEPDIR) thrift/generate/$(DEPDIR) thrift/parse/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf thrift/$(DEPDIR) thrift/audit/$(DEPDIR) thrift/generate/$(DEPDIR) thrift/parse/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: all check install install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-local clean-noinstLIBRARIES \ + clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am style-am style-local tags tags-am \ + uninstall uninstall-am + +.PRECIOUS: Makefile + + +clean-local: + $(RM) thrift/thriftl.cc thrift/thrifty.cc thrift/thrifty.h thrift/thrifty.hh + +@WITH_PLUGIN_TRUE@main.cc: version.h + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/compiler/cpp/src/thrift/audit/t_audit.cpp b/compiler/cpp/src/thrift/audit/t_audit.cpp new file mode 100644 index 0000000..1386f3b --- /dev/null +++ b/compiler/cpp/src/thrift/audit/t_audit.cpp @@ -0,0 +1,464 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Careful: must include globals first for extern definitions +#include "thrift/globals.h" + +#include "thrift/parse/t_program.h" +#include "thrift/parse/t_scope.h" +#include "thrift/parse/t_const.h" +#include "thrift/parse/t_field.h" + +#include "thrift/version.h" + +#include "thrift/audit/t_audit.h" + +extern int g_warn; +extern std::string g_curpath; +extern bool g_return_failure; + +void thrift_audit_warning(int level, const char* fmt, ...) { + if (g_warn < level) { + return; + } + va_list args; + printf("[Thrift Audit Warning:%s] ", g_curpath.c_str()); + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + printf("\n"); +} + +void thrift_audit_failure(const char* fmt, ...) { + va_list args; + fprintf(stderr, "[Thrift Audit Failure:%s] ", g_curpath.c_str()); + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + g_return_failure = true; +} + +void compare_namespace(t_program* newProgram, t_program* oldProgram) +{ + const std::map& newNamespaceMap = newProgram->get_all_namespaces(); + const std::map& oldNamespaceMap = oldProgram->get_all_namespaces(); + + for(std::map::const_iterator oldNamespaceMapIt = oldNamespaceMap.begin(); + oldNamespaceMapIt != oldNamespaceMap.end(); + oldNamespaceMapIt++) + { + std::map::const_iterator newNamespaceMapIt = newNamespaceMap.find(oldNamespaceMapIt->first); + if(newNamespaceMapIt == newNamespaceMap.end()) + { + thrift_audit_warning(1, "Language %s not found in new thrift file\n", (oldNamespaceMapIt->first).c_str()); + } + else if((newNamespaceMapIt->second) != oldNamespaceMapIt->second) + { + thrift_audit_warning(1, "Namespace %s changed in new thrift file\n", (oldNamespaceMapIt->second).c_str()); + } + } +} + +void compare_enum_values(t_enum* newEnum,t_enum* oldEnum) +{ + const std::vector& oldEnumValues = oldEnum->get_constants(); + for(std::vector::const_iterator oldEnumValuesIt = oldEnumValues.begin(); + oldEnumValuesIt != oldEnumValues.end(); + oldEnumValuesIt++) + { + int enumValue = (*oldEnumValuesIt)->get_value(); + t_enum_value* newEnumValue = newEnum->get_constant_by_value(enumValue); + if(newEnumValue != NULL) + { + std::string enumName = (*oldEnumValuesIt)->get_name(); + if(enumName != newEnumValue->get_name()) + { + thrift_audit_warning(1, "Name of the value %d changed in enum %s\n", enumValue, oldEnum->get_name().c_str()); + } + } + else + { + thrift_audit_failure("Enum value %d missing in %s\n", enumValue, oldEnum->get_name().c_str()); + } + + } +} + +void compare_enums(const std::vector& newEnumList, const std::vector& oldEnumList) +{ + std::map newEnumMap; + std::vector::const_iterator newEnumIt; + for(newEnumIt = newEnumList.begin(); newEnumIt != newEnumList.end(); newEnumIt++) + { + newEnumMap[(*newEnumIt)->get_name()] = *newEnumIt; + } + std::vector::const_iterator oldEnumIt; + for(oldEnumIt = oldEnumList.begin(); oldEnumIt != oldEnumList.end(); oldEnumIt++) + { + std::map::iterator newEnumMapIt; + newEnumMapIt = newEnumMap.find((*oldEnumIt)->get_name()); + + if(newEnumMapIt == newEnumMap.end()) + { + thrift_audit_warning(1, "Enum %s not found in new thrift file\n",(*oldEnumIt)->get_name().c_str()); + } + else + { + compare_enum_values(newEnumMapIt->second, *oldEnumIt); + } + } +} + +//This function returns 'true' if the two arguements are of same types. +//Returns false if they are of different type +bool compare_type(t_type* newType, t_type* oldType) +{ + //Comparing names of two types will work when the newType and oldType are basic types or structs or enums. + //However, when they are containers, get_name() returns empty for which we have to compare the type of + //their elements as well. + if((newType->get_name()).empty() && (oldType->get_name()).empty()) + { + + if(newType->is_list() && oldType->is_list()) + { + t_type* newElementType = ((t_list*)newType)->get_elem_type(); + t_type* oldElementType = ((t_list*)oldType)->get_elem_type(); + return compare_type(newElementType, oldElementType); + } + else if(newType->is_map() && oldType->is_map()) + { + t_type* newKeyType = ((t_map*)newType)->get_key_type(); + t_type* oldKeyType = ((t_map*)oldType)->get_key_type(); + + t_type* newValType = ((t_map*)newType)->get_val_type(); + t_type* oldValType = ((t_map*)oldType)->get_val_type(); + + return (compare_type(newKeyType, oldKeyType) && compare_type(newValType, oldValType)); + } + else if(newType->is_set() && oldType->is_set()) + { + t_type* newElementType = ((t_set*)newType)->get_elem_type(); + t_type* oldElementType = ((t_set*)oldType)->get_elem_type(); + return compare_type(newElementType, oldElementType); + } + else + { + return false; + } + } + else if(newType->get_name() == oldType->get_name()) + { + return true; + } + else + { + return false; + } +} + +bool compare_pair(std::pair newMapPair, std::pair oldMapPair) +{ + return compare_defaults(newMapPair.first, oldMapPair.first) && compare_defaults(newMapPair.second, oldMapPair.second); +} + +// This function returns 'true' if the default values are same. Returns false if they are different. +bool compare_defaults(t_const_value* newStructDefault, t_const_value* oldStructDefault) +{ + if(newStructDefault == NULL && oldStructDefault == NULL) return true; + else if(newStructDefault == NULL && oldStructDefault != NULL) return false; + else if (newStructDefault != NULL && oldStructDefault == NULL) return false; + + if(newStructDefault->get_type() != oldStructDefault->get_type()) + { + return false; + } + + switch(newStructDefault->get_type()) + { + case t_const_value::CV_INTEGER: + return (newStructDefault->get_integer() == oldStructDefault->get_integer()); + case t_const_value::CV_DOUBLE: + return (newStructDefault->get_double() == oldStructDefault->get_double()); + case t_const_value::CV_STRING: + return (newStructDefault->get_string() == oldStructDefault->get_string()); + case t_const_value::CV_LIST: + { + const std::vector& oldDefaultList = oldStructDefault->get_list(); + const std::vector& newDefaultList = newStructDefault->get_list(); + bool defaultValuesCompare = (oldDefaultList.size() == newDefaultList.size()); + + return defaultValuesCompare && std::equal(newDefaultList.begin(), newDefaultList.end(), oldDefaultList.begin(), compare_defaults); + } + case t_const_value::CV_MAP: + { + const std::map newMap = newStructDefault->get_map(); + const std::map oldMap = oldStructDefault->get_map(); + + bool defaultValuesCompare = (oldMap.size() == newMap.size()); + + return defaultValuesCompare && std::equal(newMap.begin(), newMap.end(), oldMap.begin(), compare_pair); + } + case t_const_value::CV_IDENTIFIER: + return (newStructDefault->get_identifier() == oldStructDefault->get_identifier()); + default: + return false; + } + +} + +void compare_struct_field(t_field* newField, t_field* oldField, std::string oldStructName) +{ + t_type* newFieldType = newField->get_type(); + t_type* oldFieldType = oldField->get_type(); + if(!compare_type(newFieldType, oldFieldType)) + { + thrift_audit_failure("Struct Field Type Changed for Id = %d in %s \n", newField->get_key(), oldStructName.c_str()); + } + + // A Struct member can be optional if it is mentioned explicitly, or if it is assigned with default values. + bool newStructFieldOptional = (newField->get_req() != t_field::T_REQUIRED); + bool oldStructFieldOptional = (oldField->get_req() != t_field::T_REQUIRED); + + if(newStructFieldOptional != oldStructFieldOptional) + { + thrift_audit_failure("Struct Field Requiredness Changed for Id = %d in %s \n", newField->get_key(), oldStructName.c_str()); + } + if(newStructFieldOptional || oldStructFieldOptional) + { + if(!compare_defaults(newField->get_value(), oldField->get_value())) + { + thrift_audit_warning(1, "Default value changed for Id = %d in %s \n", newField->get_key(), oldStructName.c_str()); + } + } + + std::string fieldName = newField->get_name(); + if(fieldName != oldField->get_name()) + { + thrift_audit_warning(1, "Struct field name changed for Id = %d in %s\n", newField->get_key(), oldStructName.c_str()); + } + +} + +void compare_single_struct(t_struct* newStruct, t_struct* oldStruct, const std::string& oldStructName = std::string()) +{ + std::string structName = oldStructName.empty() ? oldStruct->get_name() : oldStructName; + const std::vector& oldStructMembersInIdOrder = oldStruct->get_sorted_members(); + const std::vector& newStructMembersInIdOrder = newStruct->get_sorted_members(); + std::vector::const_iterator oldStructMemberIt = oldStructMembersInIdOrder.begin(); + std::vector::const_iterator newStructMemberIt = newStructMembersInIdOrder.begin(); + + // Since we have the struct members in their ID order, comparing their IDs can be done by traversing the two member + // lists together. + while(!(oldStructMemberIt == oldStructMembersInIdOrder.end() && newStructMemberIt == newStructMembersInIdOrder.end())) + { + if(newStructMemberIt == newStructMembersInIdOrder.end() && oldStructMemberIt != oldStructMembersInIdOrder.end()) + { + // A field ID has been removed from the end. + thrift_audit_failure("Struct Field removed for Id = %d in %s \n", (*oldStructMemberIt)->get_key(), structName.c_str()); + oldStructMemberIt++; + } + else if(newStructMemberIt != newStructMembersInIdOrder.end() && oldStructMemberIt == oldStructMembersInIdOrder.end()) + { + //New field ID has been added to the end. + if((*newStructMemberIt)->get_req() == t_field::T_REQUIRED) + { + thrift_audit_failure("Required Struct Field Added for Id = %d in %s \n", (*newStructMemberIt)->get_key(), structName.c_str()); + } + newStructMemberIt++; + } + else if((*newStructMemberIt)->get_key() == (*oldStructMemberIt)->get_key()) + { + //Field ID found in both structs. Compare field types, default values. + compare_struct_field(*newStructMemberIt, *oldStructMemberIt, structName); + + newStructMemberIt++; + oldStructMemberIt++; + } + else if((*newStructMemberIt)->get_key() < (*oldStructMemberIt)->get_key()) + { + //New Field Id is inserted in between + //Adding fields to struct is fine, but adding them in the middle is suspicious. Error!! + thrift_audit_failure("Struct field is added in the middle with Id = %d in %s\n", (*newStructMemberIt)->get_key(), structName.c_str()); + newStructMemberIt++; + } + else if((*newStructMemberIt)->get_key() > (*oldStructMemberIt)->get_key()) + { + //A field is deleted in newStruct. + thrift_audit_failure("Struct Field removed for Id = %d in %s \n", (*oldStructMemberIt)->get_key(), structName.c_str()); + oldStructMemberIt++; + } + + } +} + +void compare_structs(const std::vector& newStructList, const std::vector& oldStructList) +{ + std::map newStructMap; + std::vector::const_iterator newStructListIt; + for(newStructListIt = newStructList.begin(); newStructListIt != newStructList.end(); newStructListIt++) + { + newStructMap[(*newStructListIt)->get_name()] = *newStructListIt; + } + + std::vector::const_iterator oldStructListIt; + for(oldStructListIt = oldStructList.begin(); oldStructListIt != oldStructList.end(); oldStructListIt++) + { + std::map::iterator newStructMapIt; + newStructMapIt = newStructMap.find((*oldStructListIt)->get_name()); + if(newStructMapIt == newStructMap.end()) + { + thrift_audit_failure("Struct %s not found in new thrift file\n", (*oldStructListIt)->get_name().c_str()); + } + else + { + compare_single_struct(newStructMapIt->second, *oldStructListIt); + } + } + +} + +void compare_single_function(t_function* newFunction, t_function* oldFunction) +{ + t_type* newFunctionReturnType = newFunction->get_returntype(); + + if(newFunction->is_oneway() != oldFunction->is_oneway()) + { + thrift_audit_failure("Oneway attribute changed for function %s\n",oldFunction->get_name().c_str()); + } + if(!compare_type(newFunctionReturnType, oldFunction->get_returntype())) + { + thrift_audit_failure("Return type changed for function %s\n",oldFunction->get_name().c_str()); + } + + //Compare function arguments. + compare_single_struct(newFunction->get_arglist(), oldFunction->get_arglist()); + std::string exceptionName = oldFunction->get_name(); + exceptionName += "_exception"; + compare_single_struct(newFunction->get_xceptions(), oldFunction->get_xceptions(), exceptionName); +} + +void compare_functions(const std::vector& newFunctionList, const std::vector& oldFunctionList) +{ + std::map newFunctionMap; + std::map::iterator newFunctionMapIt; + for(std::vector::const_iterator newFunctionIt = newFunctionList.begin(); + newFunctionIt != newFunctionList.end(); + newFunctionIt++) + { + newFunctionMap[(*newFunctionIt)->get_name()] = *newFunctionIt; + } + + for(std::vector::const_iterator oldFunctionIt = oldFunctionList.begin(); + oldFunctionIt != oldFunctionList.end(); + oldFunctionIt++) + { + newFunctionMapIt = newFunctionMap.find((*oldFunctionIt)->get_name()); + if(newFunctionMapIt == newFunctionMap.end()) + { + thrift_audit_failure("New Thrift File has missing function %s\n",(*oldFunctionIt)->get_name().c_str()); + continue; + } + else + { + //Function is found in both thrift files. Compare return type and argument list + compare_single_function(newFunctionMapIt->second, *oldFunctionIt); + } + } + +} + +void compare_services(const std::vector& newServices, const std::vector& oldServices) +{ + std::vector::const_iterator oldServiceIt; + + std::map newServiceMap; + for(std::vector::const_iterator newServiceIt = newServices.begin(); + newServiceIt != newServices.end(); + newServiceIt++) + { + newServiceMap[(*newServiceIt)->get_name()] = *newServiceIt; + } + + + for(oldServiceIt = oldServices.begin(); oldServiceIt != oldServices.end(); oldServiceIt++) + { + const std::string oldServiceName = (*oldServiceIt)->get_name(); + std::map::iterator newServiceMapIt = newServiceMap.find(oldServiceName); + + if(newServiceMapIt == newServiceMap.end()) + { + thrift_audit_failure("New Thrift file is missing a service %s\n", oldServiceName.c_str()); + } + else + { + t_service* oldServiceExtends = (*oldServiceIt)->get_extends(); + t_service* newServiceExtends = (newServiceMapIt->second)->get_extends(); + + if(oldServiceExtends == NULL) + { + // It is fine to add extends. So if service in older thrift did not have any extends, we are fine. + // DO Nothing + } + else if(oldServiceExtends != NULL && newServiceExtends == NULL) + { + thrift_audit_failure("Change in Service inheritance for %s\n", oldServiceName.c_str()); + } + else + { + std::string oldExtendsName = oldServiceExtends->get_name(); + std::string newExtendsName = newServiceExtends->get_name(); + + if( newExtendsName != oldExtendsName) + { + thrift_audit_failure("Change in Service inheritance for %s\n", oldServiceName.c_str()); + } + } + + compare_functions((newServiceMapIt->second)->get_functions(), (*oldServiceIt)->get_functions()); + } + + } + +} + +void compare_consts(const std::vector& newConst, const std::vector& oldConst) +{ + std::vector::const_iterator newConstIt; + std::vector::const_iterator oldConstIt; + + std::map newConstMap; + + for(newConstIt = newConst.begin(); newConstIt != newConst.end(); newConstIt++) + { + newConstMap[(*newConstIt)->get_name()] = *newConstIt; + } + + std::map::const_iterator newConstMapIt; + for(oldConstIt = oldConst.begin(); oldConstIt != oldConst.end(); oldConstIt++) + { + newConstMapIt = newConstMap.find((*oldConstIt)->get_name()); + if(newConstMapIt == newConstMap.end()) + { + thrift_audit_warning(1, "Constants Missing %s \n", ((*oldConstIt)->get_name()).c_str()); + } + else if(!compare_type((newConstMapIt->second)->get_type(), (*oldConstIt)->get_type())) + { + thrift_audit_warning(1, "Constant %s is of different type \n", ((*oldConstIt)->get_name()).c_str()); + } + else if(!compare_defaults((newConstMapIt->second)->get_value(), (*oldConstIt)->get_value())) + { + thrift_audit_warning(1, "Constant %s has different value\n", ((*oldConstIt)->get_name()).c_str()); + } + } +} diff --git a/compiler/cpp/src/thrift/audit/t_audit.h b/compiler/cpp/src/thrift/audit/t_audit.h new file mode 100644 index 0000000..be79e31 --- /dev/null +++ b/compiler/cpp/src/thrift/audit/t_audit.h @@ -0,0 +1,14 @@ +#ifndef T_AUDIT_H +#define T_AUDIT_H + +void compare_namespace(t_program* newProgram, t_program* oldProgram); +void compare_enums(const std::vector& newEnumList, + const std::vector& oldEnumList); +bool compare_defaults(t_const_value* newStructDefault, t_const_value* oldStructDefault); +void compare_structs(const std::vector& newStructList, + const std::vector& oldStructList); +void compare_services(const std::vector& newServices, + const std::vector& oldServices); +void compare_consts(const std::vector& newConst, const std::vector& oldConst); + +#endif diff --git a/compiler/cpp/src/thrift/common.cc b/compiler/cpp/src/thrift/common.cc new file mode 100644 index 0000000..3a2b9d3 --- /dev/null +++ b/compiler/cpp/src/thrift/common.cc @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "thrift/common.h" +#include "thrift/parse/t_base_type.h" + +t_type* g_type_void; +t_type* g_type_string; +t_type* g_type_binary; +t_type* g_type_slist; +t_type* g_type_bool; +t_type* g_type_i8; +t_type* g_type_i16; +t_type* g_type_i32; +t_type* g_type_i64; +t_type* g_type_double; + +void initGlobals() { + g_type_void = new t_base_type("void", t_base_type::TYPE_VOID); + g_type_string = new t_base_type("string", t_base_type::TYPE_STRING); + g_type_binary = new t_base_type("string", t_base_type::TYPE_STRING); + ((t_base_type*)g_type_binary)->set_binary(true); + g_type_slist = new t_base_type("string", t_base_type::TYPE_STRING); + ((t_base_type*)g_type_slist)->set_string_list(true); + g_type_bool = new t_base_type("bool", t_base_type::TYPE_BOOL); + g_type_i8 = new t_base_type("i8", t_base_type::TYPE_I8); + g_type_i16 = new t_base_type("i16", t_base_type::TYPE_I16); + g_type_i32 = new t_base_type("i32", t_base_type::TYPE_I32); + g_type_i64 = new t_base_type("i64", t_base_type::TYPE_I64); + g_type_double = new t_base_type("double", t_base_type::TYPE_DOUBLE); +} + +void clearGlobals() { + delete g_type_void; + delete g_type_string; + delete g_type_bool; + delete g_type_i8; + delete g_type_i16; + delete g_type_i32; + delete g_type_i64; + delete g_type_double; +} + +/** + * Those are not really needed for plugins but causes link errors without + */ + +/** + * The location of the last parsed doctext comment. + */ +int g_doctext_lineno; +int g_program_doctext_lineno = 0; +PROGDOCTEXT_STATUS g_program_doctext_status = INVALID; diff --git a/compiler/cpp/src/thrift/common.h b/compiler/cpp/src/thrift/common.h new file mode 100644 index 0000000..6948846 --- /dev/null +++ b/compiler/cpp/src/thrift/common.h @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_COMMON_H +#define T_COMMON_H + +#include "thrift/parse/t_type.h" + +/** + * Global types for the parser to be able to reference + */ + +extern t_type* g_type_void; +extern t_type* g_type_string; +extern t_type* g_type_binary; +extern t_type* g_type_slist; +extern t_type* g_type_bool; +extern t_type* g_type_i8; +extern t_type* g_type_i16; +extern t_type* g_type_i32; +extern t_type* g_type_i64; +extern t_type* g_type_double; + +void initGlobals(); +void clearGlobals(); + +#endif diff --git a/compiler/cpp/src/thrift/generate/t_as3_generator.cc b/compiler/cpp/src/thrift/generate/t_as3_generator.cc new file mode 100644 index 0000000..fc92de9 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_as3_generator.cc @@ -0,0 +1,2594 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * AS3 code generator. + * + */ +class t_as3_generator : public t_oop_generator { +public: + t_as3_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + bindable_ = false; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("bindable") == 0) { + bindable_ = true; + } else { + throw "unknown option as3:" + iter->first; + } + } + + out_dir_base_ = "gen-as3"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + void generate_consts(std::vector consts); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + void print_const_value(std::ofstream& out, + std::string name, + t_type* type, + t_const_value* value, + bool in_static, + bool defval = false); + std::string render_const_value(ofstream& out, + std::string name, + t_type* type, + t_const_value* value); + + /** + * Service-level generation functions + */ + + void generate_as3_struct(t_struct* tstruct, bool is_exception); + + void generate_as3_struct_definition(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false, + bool in_class = false, + bool is_result = false); + // removed -- equality,compare_to + void generate_as3_struct_reader(std::ofstream& out, t_struct* tstruct); + void generate_as3_validator(std::ofstream& out, t_struct* tstruct); + void generate_as3_struct_result_writer(std::ofstream& out, t_struct* tstruct); + void generate_as3_struct_writer(std::ofstream& out, t_struct* tstruct); + void generate_as3_struct_tostring(std::ofstream& out, t_struct* tstruct, bool bindable); + void generate_as3_meta_data_map(std::ofstream& out, t_struct* tstruct); + void generate_field_value_meta_data(std::ofstream& out, t_type* type); + std::string get_as3_type_string(t_type* type); + void generate_reflection_setters(std::ostringstream& out, + t_type* type, + std::string field_name, + std::string cap_name); + void generate_reflection_getters(std::ostringstream& out, + t_type* type, + std::string field_name, + std::string cap_name); + void generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct); + void generate_generic_isset_method(std::ofstream& out, t_struct* tstruct); + void generate_as3_bean_boilerplate(std::ofstream& out, t_struct* tstruct, bool bindable); + + void generate_function_helpers(t_function* tfunction); + std::string get_cap_name(std::string name); + std::string generate_isset_check(t_field* field); + std::string generate_isset_check(std::string field); + void generate_isset_set(ofstream& out, t_field* field); + // removed std::string isset_field_id(t_field* field); + + void generate_service_interface(t_service* tservice); + void generate_service_helpers(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* tfunction); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + + void generate_deserialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_deserialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_deserialize_set_element(std::ofstream& out, t_set* tset, std::string prefix = ""); + + void generate_deserialize_map_element(std::ofstream& out, t_map* tmap, std::string prefix = ""); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix = ""); + + void generate_serialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string iter, + std::string map); + + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + + void generate_as3_doc(std::ofstream& out, t_doc* tdoc); + + void generate_as3_doc(std::ofstream& out, t_function* tdoc); + + /** + * Helper rendering functions + */ + + std::string as3_package(); + std::string as3_type_imports(); + std::string as3_thrift_imports(); + std::string as3_thrift_gen_imports(t_struct* tstruct, string& imports); + std::string as3_thrift_gen_imports(t_service* tservice); + std::string type_name(t_type* ttype, bool in_container = false, bool in_init = false); + std::string base_type_name(t_base_type* tbase, bool in_container = false); + std::string declare_field(t_field* tfield, bool init = false); + std::string function_signature(t_function* tfunction, std::string prefix = ""); + std::string argument_list(t_struct* tstruct); + std::string type_to_enum(t_type* ttype); + std::string get_enum_class_name(t_type* type); + + bool type_can_be_null(t_type* ttype) { + ttype = get_true_type(ttype); + + return ttype->is_container() || ttype->is_struct() || ttype->is_xception() + || ttype->is_string(); + } + + std::string constant_name(std::string name); + +private: + /** + * File streams + */ + + std::string package_name_; + std::ofstream f_service_; + std::string package_dir_; + + bool bindable_; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_as3_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + package_name_ = program_->get_namespace("as3"); + + string dir = package_name_; + string subdir = get_out_dir(); + string::size_type loc; + while ((loc = dir.find(".")) != string::npos) { + subdir = subdir + "/" + dir.substr(0, loc); + MKDIR(subdir.c_str()); + dir = dir.substr(loc + 1); + } + if (dir.size() > 0) { + subdir = subdir + "/" + dir; + MKDIR(subdir.c_str()); + } + + package_dir_ = subdir; +} + +/** + * Packages the generated file + * + * @return String of the package, i.e. "package org.apache.thriftdemo;" + */ +string t_as3_generator::as3_package() { + if (!package_name_.empty()) { + return string("package ") + package_name_ + " "; + } + return "package "; +} + +/** + * Prints standard as3 imports + * + * @return List of imports for As3 types that are used in here + */ +string t_as3_generator::as3_type_imports() { + return string() + "import org.apache.thrift.Set;\n" + "import flash.utils.ByteArray;\n" + + "import flash.utils.Dictionary;\n\n"; +} + +/** + * Prints standard as3 imports + * + * @return List of imports necessary for thrift + */ +string t_as3_generator::as3_thrift_imports() { + return string() + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n" + + "import org.apache.thrift.protocol.*;\n\n"; +} + +/** + * Prints imports needed for a given type + * + * @return List of imports necessary for a given t_struct + */ +string t_as3_generator::as3_thrift_gen_imports(t_struct* tstruct, string& imports) { + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + // For each type check if it is from a differnet namespace + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_program* program = (*m_iter)->get_type()->get_program(); + if (program != NULL && program != program_) { + string package = program->get_namespace("as3"); + if (!package.empty()) { + if (imports.find(package + "." + (*m_iter)->get_type()->get_name()) == string::npos) { + imports.append("import " + package + "." + (*m_iter)->get_type()->get_name() + ";\n"); + } + } + } + } + return imports; +} + +/** + * Prints imports needed for a given type + * + * @return List of imports necessary for a given t_service + */ +string t_as3_generator::as3_thrift_gen_imports(t_service* tservice) { + string imports; + const vector& functions = tservice->get_functions(); + vector::const_iterator f_iter; + + // For each type check if it is from a differnet namespace + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_program* program = (*f_iter)->get_returntype()->get_program(); + if (program != NULL && program != program_) { + string package = program->get_namespace("as3"); + if (!package.empty()) { + if (imports.find(package + "." + (*f_iter)->get_returntype()->get_name()) == string::npos) { + imports.append("import " + package + "." + (*f_iter)->get_returntype()->get_name() + + ";\n"); + } + } + } + + as3_thrift_gen_imports((*f_iter)->get_arglist(), imports); + as3_thrift_gen_imports((*f_iter)->get_xceptions(), imports); + } + + return imports; +} + +/** + * Nothing in As3 + */ +void t_as3_generator::close_generator() { +} + +/** + * Generates a typedef. This is not done in As3, since it does + * not support arbitrary name replacements, and it'd be a wacky waste + * of overhead to make wrapper classes. + * + * @param ttypedef The type definition + */ +void t_as3_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + +/** + * Enums are a class with a set of static constants. + * + * @param tenum The enumeration + */ +void t_as3_generator::generate_enum(t_enum* tenum) { + // Make output file + string f_enum_name = package_dir_ + "/" + (tenum->get_name()) + ".as"; + ofstream f_enum; + f_enum.open(f_enum_name.c_str()); + + // Comment and package it + f_enum << autogen_comment() << as3_package() << endl; + + scope_up(f_enum); + // Add as3 imports + f_enum << string() + "import org.apache.thrift.Set;" << endl << "import flash.utils.Dictionary;" + << endl; + + indent(f_enum) << "public class " << tenum->get_name() << " "; + scope_up(f_enum); + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + indent(f_enum) << "public static const " << (*c_iter)->get_name() << ":int = " << value << ";" + << endl; + } + + // Create a static Set with all valid values for this enum + f_enum << endl; + + indent(f_enum) << "public static const VALID_VALUES:Set = new Set("; + indent_up(); + bool firstValue = true; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + // populate set + f_enum << (firstValue ? "" : ", ") << (*c_iter)->get_name(); + firstValue = false; + } + indent_down(); + f_enum << ");" << endl; + + indent(f_enum) << "public static const VALUES_TO_NAMES:Dictionary = new Dictionary();" << endl; + + scope_up(f_enum); + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + indent(f_enum) << "VALUES_TO_NAMES[" << (*c_iter)->get_name() << "] = \"" + << (*c_iter)->get_name() << "\";" << endl; + } + f_enum << endl; + + scope_down(f_enum); + + scope_down(f_enum); // end class + + scope_down(f_enum); // end package + + f_enum.close(); +} + +/** + * Generates a class that holds all the constants. + */ +void t_as3_generator::generate_consts(std::vector consts) { + if (consts.empty()) { + return; + } + + string f_consts_name = package_dir_ + "/" + program_name_ + "Constants.as"; + ofstream f_consts; + f_consts.open(f_consts_name.c_str()); + + // Print header + f_consts << autogen_comment() << as3_package(); + + scope_up(f_consts); + f_consts << endl; + + f_consts << as3_type_imports(); + + indent(f_consts) << "public class " << program_name_ << "Constants {" << endl << endl; + indent_up(); + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + print_const_value(f_consts, + (*c_iter)->get_name(), + (*c_iter)->get_type(), + (*c_iter)->get_value(), + false); + } + indent_down(); + indent(f_consts) << "}" << endl; + scope_down(f_consts); + f_consts.close(); +} + +void t_as3_generator::print_const_value(std::ofstream& out, + string name, + t_type* type, + t_const_value* value, + bool in_static, + bool defval) { + type = get_true_type(type); + + indent(out); + if (!defval) { + out << (in_static ? "var " : "public static const "); + } + if (type->is_base_type()) { + string v2 = render_const_value(out, name, type, value); + out << name; + if (!defval) { + out << ":" << type_name(type); + } + out << " = " << v2 << ";" << endl << endl; + } else if (type->is_enum()) { + out << name; + if (!defval) { + out << ":" << type_name(type); + } + out << " = " << value->get_integer() << ";" << endl << endl; + } else if (type->is_struct() || type->is_xception()) { + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + out << name << ":" << type_name(type) << " = new " << type_name(type, false, true) << "();" + << endl; + if (!in_static) { + indent(out) << "{" << endl; + indent_up(); + indent(out) << "new function():void {" << endl; + indent_up(); + } + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + string val = render_const_value(out, name, field_type, v_iter->second); + indent(out) << name << "."; + out << v_iter->first->get_string() << " = " << val << ";" << endl; + } + if (!in_static) { + indent_down(); + indent(out) << "}();" << endl; + indent_down(); + indent(out) << "}" << endl; + } + out << endl; + } else if (type->is_map()) { + out << name; + if (!defval) { + out << ":" << type_name(type); + } + out << " = new " << type_name(type, false, true) << "();" << endl; + if (!in_static) { + indent(out) << "{" << endl; + indent_up(); + indent(out) << "new function():void {" << endl; + indent_up(); + } + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string key = render_const_value(out, name, ktype, v_iter->first); + string val = render_const_value(out, name, vtype, v_iter->second); + indent(out) << name << "[" << key << "] = " << val << ";" << endl; + } + if (!in_static) { + indent_down(); + indent(out) << "}();" << endl; + indent_down(); + indent(out) << "}" << endl; + } + out << endl; + } else if (type->is_list() || type->is_set()) { + out << name; + if (!defval) { + out << ":" << type_name(type); + } + out << " = new " << type_name(type, false, true) << "();" << endl; + if (!in_static) { + indent(out) << "{" << endl; + indent_up(); + indent(out) << "new function():void {" << endl; + indent_up(); + } + t_type* etype; + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(out, name, etype, *v_iter); + indent(out) << name << "." << (type->is_list() ? "push" : "add") << "(" << val << ");" + << endl; + } + if (!in_static) { + indent_down(); + indent(out) << "}();" << endl; + indent_down(); + indent(out) << "}" << endl; + } + out << endl; + } else { + throw "compiler error: no const of type " + type->get_name(); + } +} + +string t_as3_generator::render_const_value(ofstream& out, + string name, + t_type* type, + t_const_value* value) { + (void)name; + type = get_true_type(type); + std::ostringstream render; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + render << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() > 0) ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + render << "(byte)" << value->get_integer(); + break; + case t_base_type::TYPE_I16: + render << "(short)" << value->get_integer(); + break; + case t_base_type::TYPE_I32: + render << value->get_integer(); + break; + case t_base_type::TYPE_I64: + render << value->get_integer() << "L"; + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + render << "(double)" << value->get_integer(); + } else { + render << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + render << value->get_integer(); + } else { + string t = tmp("tmp"); + print_const_value(out, t, type, value, true); + render << t; + } + + return render.str(); +} + +/** + * Generates a struct definition for a thrift data type. This is a class + * with data members, read(), write(), and an inner Isset class. + * + * @param tstruct The struct definition + */ +void t_as3_generator::generate_struct(t_struct* tstruct) { + generate_as3_struct(tstruct, false); +} + +/** + * Exceptions are structs, but they inherit from Exception + * + * @param tstruct The struct definition + */ +void t_as3_generator::generate_xception(t_struct* txception) { + generate_as3_struct(txception, true); +} + +/** + * As3 struct definition. + * + * @param tstruct The struct definition + */ +void t_as3_generator::generate_as3_struct(t_struct* tstruct, bool is_exception) { + // Make output file + string f_struct_name = package_dir_ + "/" + (tstruct->get_name()) + ".as"; + ofstream f_struct; + f_struct.open(f_struct_name.c_str()); + + f_struct << autogen_comment() << as3_package(); + + scope_up(f_struct); + f_struct << endl; + + string imports; + + f_struct << as3_type_imports() << as3_thrift_imports() << as3_thrift_gen_imports(tstruct, imports) + << endl; + + if (bindable_ && !is_exception) { + f_struct << "import flash.events.Event;" << endl << "import flash.events.EventDispatcher;" + << endl << "import mx.events.PropertyChangeEvent;" << endl; + } + + generate_as3_struct_definition(f_struct, tstruct, is_exception); + + scope_down(f_struct); // end of package + f_struct.close(); +} + +/** + * As3 struct definition. This has various parameters, as it could be + * generated standalone or inside another class as a helper. If it + * is a helper than it is a static class. + * + * @param tstruct The struct definition + * @param is_exception Is this an exception? + * @param in_class If inside a class, needs to be static class + * @param is_result If this is a result it needs a different writer + */ +void t_as3_generator::generate_as3_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool in_class, + bool is_result) { + generate_as3_doc(out, tstruct); + + bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); + bool bindable = !is_exception && !in_class && bindable_; + + indent(out) << (in_class ? "" : "public ") << (is_final ? "final " : "") << "class " + << tstruct->get_name() << " "; + + if (is_exception) { + out << "extends Error "; + } else if (bindable) { + out << "extends EventDispatcher "; + } + out << "implements TBase "; + + scope_up(out); + + indent(out) << "private static const STRUCT_DESC:TStruct = new TStruct(\"" << tstruct->get_name() + << "\");" << endl; + + // Members are public for -as3, private for -as3bean + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << "private static const " << constant_name((*m_iter)->get_name()) + << "_FIELD_DESC:TField = new TField(\"" << (*m_iter)->get_name() << "\", " + << type_to_enum((*m_iter)->get_type()) << ", " << (*m_iter)->get_key() << ");" + << endl; + } + + out << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + generate_as3_doc(out, *m_iter); + indent(out) << "private var _" << (*m_iter)->get_name() + ":" + type_name((*m_iter)->get_type()) + << ";" << endl; + + indent(out) << "public static const " << upcase_string((*m_iter)->get_name()) + << ":int = " << (*m_iter)->get_key() << ";" << endl; + } + + out << endl; + + // Inner Isset class + if (members.size() > 0) { + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (!type_can_be_null((*m_iter)->get_type())) { + indent(out) << "private var __isset_" << (*m_iter)->get_name() << ":Boolean = false;" + << endl; + } + } + } + + out << endl; + + generate_as3_meta_data_map(out, tstruct); + + // Static initializer to populate global class to struct metadata map + indent(out) << "{" << endl; + indent_up(); + indent(out) << "FieldMetaData.addStructMetaDataMap(" << type_name(tstruct) << ", metaDataMap);" + << endl; + indent_down(); + indent(out) << "}" << endl << endl; + + // Default constructor + indent(out) << "public function " << tstruct->get_name() << "() {" << endl; + indent_up(); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_value() != NULL) { + indent(out) << "this._" << (*m_iter)->get_name() << " = " + << (*m_iter)->get_value()->get_integer() << ";" << endl; + } + } + indent_down(); + indent(out) << "}" << endl << endl; + + generate_as3_bean_boilerplate(out, tstruct, bindable); + generate_generic_field_getters_setters(out, tstruct); + generate_generic_isset_method(out, tstruct); + + generate_as3_struct_reader(out, tstruct); + if (is_result) { + generate_as3_struct_result_writer(out, tstruct); + } else { + generate_as3_struct_writer(out, tstruct); + } + generate_as3_struct_tostring(out, tstruct, bindable); + generate_as3_validator(out, tstruct); + scope_down(out); + out << endl; +} + +/** + * Generates a function to read all the fields of the struct. + * + * @param tstruct The struct definition + */ +void t_as3_generator::generate_as3_struct_reader(ofstream& out, t_struct* tstruct) { + out << indent() << "public function read(iprot:TProtocol):void {" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Declare stack tmp variables and read struct header + out << indent() << "var field:TField;" << endl << indent() << "iprot.readStructBegin();" << endl; + + // Loop over reading in fields + indent(out) << "while (true)" << endl; + scope_up(out); + + // Read beginning field marker + indent(out) << "field = iprot.readFieldBegin();" << endl; + + // Check for field STOP marker and break + indent(out) << "if (field.type == TType.STOP) { " << endl; + indent_up(); + indent(out) << "break;" << endl; + indent_down(); + indent(out) << "}" << endl; + + // Switch statement on the field we are reading + indent(out) << "switch (field.id)" << endl; + + scope_up(out); + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << "case " << upcase_string((*f_iter)->get_name()) << ":" << endl; + indent_up(); + indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; + indent_up(); + + generate_deserialize_field(out, *f_iter, "this."); + generate_isset_set(out, *f_iter); + indent_down(); + out << indent() << "} else { " << endl << indent() << " TProtocolUtil.skip(iprot, field.type);" + << endl << indent() << "}" << endl << indent() << "break;" << endl; + indent_down(); + } + + // In the default case we skip the field + out << indent() << "default:" << endl << indent() << " TProtocolUtil.skip(iprot, field.type);" + << endl << indent() << " break;" << endl; + + scope_down(out); + + // Read field end marker + indent(out) << "iprot.readFieldEnd();" << endl; + + scope_down(out); + + out << indent() << "iprot.readStructEnd();" << endl << endl; + + // in non-beans style, check for required fields of primitive type + // (which can be checked here but not in the general validate method) + out << endl << indent() << "// check for required fields of primitive type, which can't be " + "checked in the validate method" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) { + out << indent() << "if (!__isset_" << (*f_iter)->get_name() << ") {" << endl << indent() + << " throw new TProtocolError(TProtocolError.UNKNOWN, \"Required field '" + << (*f_iter)->get_name() + << "' was not found in serialized data! Struct: \" + toString());" << endl << indent() + << "}" << endl; + } + } + + // performs various checks (e.g. check that all required fields are set) + indent(out) << "validate();" << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +// generates as3 method to perform various checks +// (e.g. check that all required fields are set) +void t_as3_generator::generate_as3_validator(ofstream& out, t_struct* tstruct) { + indent(out) << "public function validate():void {" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out << indent() << "// check for required fields" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + if (type_can_be_null((*f_iter)->get_type())) { + indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl; + indent(out) << " throw new TProtocolError(TProtocolError.UNKNOWN, \"Required field '" + << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" + << endl; + indent(out) << "}" << endl; + } else { + indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name() + << "' because it's a primitive and you chose the non-beans generator." << endl; + } + } + } + + // check that fields of type enum have valid values + out << indent() << "// check that fields of type enum have valid values" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = (*f_iter); + t_type* type = field->get_type(); + // if field is an enum, check that its value is valid + if (type->is_enum()) { + indent(out) << "if (" << generate_isset_check(field) << " && !" << get_enum_class_name(type) + << ".VALID_VALUES.contains(" << field->get_name() << ")){" << endl; + indent_up(); + indent(out) << "throw new TProtocolError(TProtocolError.UNKNOWN, \"The field '" + << field->get_name() << "' has been assigned the invalid value \" + " + << field->get_name() << ");" << endl; + indent_down(); + indent(out) << "}" << endl; + } + } + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a function to write all the fields of the struct + * + * @param tstruct The struct definition + */ +void t_as3_generator::generate_as3_struct_writer(ofstream& out, t_struct* tstruct) { + out << indent() << "public function write(oprot:TProtocol):void {" << endl; + indent_up(); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + // performs various checks (e.g. check that all required fields are set) + indent(out) << "validate();" << endl << endl; + + indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; + if (could_be_unset) { + indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl; + indent_up(); + } + bool null_allowed = type_can_be_null((*f_iter)->get_type()); + if (null_allowed) { + out << indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl; + indent_up(); + } + + indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) + << "_FIELD_DESC);" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "this."); + + // Write field closer + indent(out) << "oprot.writeFieldEnd();" << endl; + + if (null_allowed) { + indent_down(); + indent(out) << "}" << endl; + } + if (could_be_unset) { + indent_down(); + indent(out) << "}" << endl; + } + } + // Write the struct map + out << indent() << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();" + << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +/** + * Generates a function to write all the fields of the struct, + * which is a function result. These fields are only written + * if they are set in the Isset array, and only one of them + * can be set at a time. + * + * @param tstruct The struct definition + */ +void t_as3_generator::generate_as3_struct_result_writer(ofstream& out, t_struct* tstruct) { + out << indent() << "public function write(oprot:TProtocol):void {" << endl; + indent_up(); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; + + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + out << endl << indent() << "if "; + } else { + out << " else if "; + } + + out << "(this." << generate_isset_check(*f_iter) << ") {" << endl; + + indent_up(); + + indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) + << "_FIELD_DESC);" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "this."); + + // Write field closer + indent(out) << "oprot.writeFieldEnd();" << endl; + + indent_down(); + indent(out) << "}"; + } + // Write the struct map + out << endl << indent() << "oprot.writeFieldStop();" << endl << indent() + << "oprot.writeStructEnd();" << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_as3_generator::generate_reflection_getters(ostringstream& out, + t_type* type, + string field_name, + string cap_name) { + (void)type; + (void)cap_name; + indent(out) << "case " << upcase_string(field_name) << ":" << endl; + indent_up(); + indent(out) << "return this." << field_name << ";" << endl; + indent_down(); +} + +void t_as3_generator::generate_reflection_setters(ostringstream& out, + t_type* type, + string field_name, + string cap_name) { + (void)type; + (void)cap_name; + indent(out) << "case " << upcase_string(field_name) << ":" << endl; + indent_up(); + indent(out) << "if (value == null) {" << endl; + indent(out) << " unset" << get_cap_name(field_name) << "();" << endl; + indent(out) << "} else {" << endl; + indent(out) << " this." << field_name << " = value;" << endl; + indent(out) << "}" << endl; + indent(out) << "break;" << endl << endl; + + indent_down(); +} + +void t_as3_generator::generate_generic_field_getters_setters(std::ofstream& out, + t_struct* tstruct) { + + std::ostringstream getter_stream; + std::ostringstream setter_stream; + + // build up the bodies of both the getter and setter at once + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + t_type* type = get_true_type(field->get_type()); + std::string field_name = field->get_name(); + std::string cap_name = get_cap_name(field_name); + + indent_up(); + generate_reflection_setters(setter_stream, type, field_name, cap_name); + generate_reflection_getters(getter_stream, type, field_name, cap_name); + indent_down(); + } + + // create the setter + indent(out) << "public function setFieldValue(fieldID:int, value:*):void {" << endl; + indent_up(); + + indent(out) << "switch (fieldID) {" << endl; + + out << setter_stream.str(); + + indent(out) << "default:" << endl; + indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; + + indent(out) << "}" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; + + // create the getter + indent(out) << "public function getFieldValue(fieldID:int):* {" << endl; + indent_up(); + + indent(out) << "switch (fieldID) {" << endl; + + out << getter_stream.str(); + + indent(out) << "default:" << endl; + indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; + + indent(out) << "}" << endl; + + indent_down(); + + indent(out) << "}" << endl << endl; +} + +// Creates a generic isSet method that takes the field number as argument +void t_as3_generator::generate_generic_isset_method(std::ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // create the isSet method + indent(out) << "// Returns true if field corresponding to fieldID is set (has been assigned a " + "value) and false otherwise" << endl; + indent(out) << "public function isSet(fieldID:int):Boolean {" << endl; + indent_up(); + indent(out) << "switch (fieldID) {" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl; + indent_up(); + indent(out) << "return " << generate_isset_check(field) << ";" << endl; + indent_down(); + } + + indent(out) << "default:" << endl; + indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; + + indent(out) << "}" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a set of As3 Bean boilerplate functions (setters, getters, etc.) + * for the given struct. + * + * @param tstruct The struct definition + */ +void t_as3_generator::generate_as3_bean_boilerplate(ofstream& out, + t_struct* tstruct, + bool bindable) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + t_type* type = get_true_type(field->get_type()); + std::string field_name = field->get_name(); + std::string cap_name = get_cap_name(field_name); + + // Simple getter + generate_as3_doc(out, field); + indent(out) << "public function get " << field_name << "():" << type_name(type) << " {" << endl; + indent_up(); + indent(out) << "return this._" << field_name << ";" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + + // Simple setter + generate_as3_doc(out, field); + std::string propName = tmp("thriftPropertyChange"); + if (bindable) { + indent(out) << "[Bindable(event=\"" << propName << "\")]" << endl; + } + indent(out) << "public function set " << field_name << "(" << field_name << ":" + << type_name(type) << "):void {" << endl; + indent_up(); + indent(out) << "this._" << field_name << " = " << field_name << ";" << endl; + generate_isset_set(out, field); + + if (bindable) { + // We have to use a custom event rather than the default, because if you use the default, + // the setter only gets called if the value has changed - this means calling + // foo.setIntValue(0) + // will not cause foo.isIntValueSet() to return true since the value of foo._intValue wasn't + // changed + // so the setter was never called. + indent(out) << "dispatchEvent(new Event(\"" << propName << "\"));" << endl; + + // However, if you just use a custom event, then collections won't be able to detect when + // elements + // in the collections have changed since they listed for PropertyChangeEvents. So, we + // dispatch both. + indent(out) << "dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE));" + << endl; + } + indent_down(); + indent(out) << "}" << endl << endl; + + // Unsetter + indent(out) << "public function unset" << cap_name << "():void {" << endl; + indent_up(); + if (type_can_be_null(type)) { + indent(out) << "this." << field_name << " = null;" << endl; + } else { + indent(out) << "this.__isset_" << field_name << " = false;" << endl; + } + indent_down(); + indent(out) << "}" << endl << endl; + + // isSet method + indent(out) << "// Returns true if field " << field_name + << " is set (has been assigned a value) and false otherwise" << endl; + indent(out) << "public function is" << get_cap_name("set") << cap_name << "():Boolean {" + << endl; + indent_up(); + if (type_can_be_null(type)) { + indent(out) << "return this." << field_name << " != null;" << endl; + } else { + indent(out) << "return this.__isset_" << field_name << ";" << endl; + } + indent_down(); + indent(out) << "}" << endl << endl; + } +} + +/** + * Generates a toString() method for the given struct + * + * @param tstruct The struct definition + */ +void t_as3_generator::generate_as3_struct_tostring(ofstream& out, + t_struct* tstruct, + bool bindable) { + // If it's bindable, it extends EventDispatcher so toString is an override. + out << indent() << "public " << (bindable ? "override " : "") << "function toString():String {" + << endl; + indent_up(); + + out << indent() << "var ret:String = new String(\"" << tstruct->get_name() << "(\");" << endl; + out << indent() << "var first:Boolean = true;" << endl << endl; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; + if (could_be_unset) { + indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl; + indent_up(); + } + + t_field* field = (*f_iter); + + if (!first) { + indent(out) << "if (!first) ret += \", \";" << endl; + } + indent(out) << "ret += \"" << (*f_iter)->get_name() << ":\";" << endl; + bool can_be_null = type_can_be_null(field->get_type()); + if (can_be_null) { + indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl; + indent(out) << " ret += \"null\";" << endl; + indent(out) << "} else {" << endl; + indent_up(); + } + + if (field->get_type()->is_binary()) { + indent(out) << " ret += \"BINARY\";" << endl; + } else if (field->get_type()->is_enum()) { + indent(out) << "var " << field->get_name() + << "_name:String = " << get_enum_class_name(field->get_type()) + << ".VALUES_TO_NAMES[this." << (*f_iter)->get_name() << "];" << endl; + indent(out) << "if (" << field->get_name() << "_name != null) {" << endl; + indent(out) << " ret += " << field->get_name() << "_name;" << endl; + indent(out) << " ret += \" (\";" << endl; + indent(out) << "}" << endl; + indent(out) << "ret += this." << field->get_name() << ";" << endl; + indent(out) << "if (" << field->get_name() << "_name != null) {" << endl; + indent(out) << " ret += \")\";" << endl; + indent(out) << "}" << endl; + } else { + indent(out) << "ret += this." << (*f_iter)->get_name() << ";" << endl; + } + + if (can_be_null) { + indent_down(); + indent(out) << "}" << endl; + } + indent(out) << "first = false;" << endl; + + if (could_be_unset) { + indent_down(); + indent(out) << "}" << endl; + } + first = false; + } + out << indent() << "ret += \")\";" << endl << indent() << "return ret;" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a static map with meta data to store information such as fieldID to + * fieldName mapping + * + * @param tstruct The struct definition + */ +void t_as3_generator::generate_as3_meta_data_map(ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Static Map with fieldID -> FieldMetaData mappings + indent(out) << "public static const metaDataMap:Dictionary = new Dictionary();" << endl; + + if (fields.size() > 0) { + // Populate map + scope_up(out); + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + std::string field_name = field->get_name(); + indent(out) << "metaDataMap[" << upcase_string(field_name) << "] = new FieldMetaData(\"" + << field_name << "\", "; + + // Set field requirement type (required, optional, etc.) + if (field->get_req() == t_field::T_REQUIRED) { + out << "TFieldRequirementType.REQUIRED, "; + } else if (field->get_req() == t_field::T_OPTIONAL) { + out << "TFieldRequirementType.OPTIONAL, "; + } else { + out << "TFieldRequirementType.DEFAULT, "; + } + + // Create value meta data + generate_field_value_meta_data(out, field->get_type()); + out << ");" << endl; + } + scope_down(out); + } +} + +/** + * Returns a string with the as3 representation of the given thrift type + * (e.g. for the type struct it returns "TType.STRUCT") + */ +std::string t_as3_generator::get_as3_type_string(t_type* type) { + if (type->is_list()) { + return "TType.LIST"; + } else if (type->is_map()) { + return "TType.MAP"; + } else if (type->is_set()) { + return "TType.SET"; + } else if (type->is_struct() || type->is_xception()) { + return "TType.STRUCT"; + } else if (type->is_enum()) { + return "TType.I32"; + } else if (type->is_typedef()) { + return get_as3_type_string(((t_typedef*)type)->get_type()); + } else if (type->is_base_type()) { + switch (((t_base_type*)type)->get_base()) { + case t_base_type::TYPE_VOID: + return "TType.VOID"; + break; + case t_base_type::TYPE_STRING: + return "TType.STRING"; + break; + case t_base_type::TYPE_BOOL: + return "TType.BOOL"; + break; + case t_base_type::TYPE_I8: + return "TType.BYTE"; + break; + case t_base_type::TYPE_I16: + return "TType.I16"; + break; + case t_base_type::TYPE_I32: + return "TType.I32"; + break; + case t_base_type::TYPE_I64: + return "TType.I64"; + break; + case t_base_type::TYPE_DOUBLE: + return "TType.DOUBLE"; + break; + default: + throw std::runtime_error("Unknown thrift type \"" + type->get_name() + + "\" passed to t_as3_generator::get_as3_type_string!"); + break; // This should never happen! + } + } else { + throw std::runtime_error( + "Unknown thrift type \"" + type->get_name() + + "\" passed to t_as3_generator::get_as3_type_string!"); // This should never happen! + } +} + +void t_as3_generator::generate_field_value_meta_data(std::ofstream& out, t_type* type) { + out << endl; + indent_up(); + indent_up(); + if (type->is_struct() || type->is_xception()) { + indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type); + } else if (type->is_container()) { + if (type->is_list()) { + indent(out) << "new ListMetaData(TType.LIST, "; + t_type* elem_type = ((t_list*)type)->get_elem_type(); + generate_field_value_meta_data(out, elem_type); + } else if (type->is_set()) { + indent(out) << "new SetMetaData(TType.SET, "; + t_type* elem_type = ((t_list*)type)->get_elem_type(); + generate_field_value_meta_data(out, elem_type); + } else { // map + indent(out) << "new MapMetaData(TType.MAP, "; + t_type* key_type = ((t_map*)type)->get_key_type(); + t_type* val_type = ((t_map*)type)->get_val_type(); + generate_field_value_meta_data(out, key_type); + out << ", "; + generate_field_value_meta_data(out, val_type); + } + } else { + indent(out) << "new FieldValueMetaData(" << get_as3_type_string(type); + } + out << ")"; + indent_down(); + indent_down(); +} + +/** + * Generates a thrift service. In C++, this comprises an entirely separate + * header and source file. The header file defines the methods and includes + * the data types defined in the main header file, and the implementation + * file contains implementations of the basic printer and default interfaces. + * + * @param tservice The service definition + */ +void t_as3_generator::generate_service(t_service* tservice) { + // Make interface file + string f_service_name = package_dir_ + "/" + service_name_ + ".as"; + f_service_.open(f_service_name.c_str()); + + f_service_ << autogen_comment() << as3_package(); + + scope_up(f_service_); + + f_service_ << endl << as3_type_imports() << as3_thrift_imports() + << as3_thrift_gen_imports(tservice); + + if (tservice->get_extends() != NULL) { + t_type* parent = tservice->get_extends(); + string parent_namespace = parent->get_program()->get_namespace("as3"); + if (!parent_namespace.empty() && parent_namespace != package_name_) { + f_service_ << "import " << type_name(parent) << ";" << endl; + } + } + + f_service_ << endl; + + generate_service_interface(tservice); + + scope_down(f_service_); + f_service_.close(); + + // Now make the implementation/client file + f_service_name = package_dir_ + "/" + service_name_ + "Impl.as"; + f_service_.open(f_service_name.c_str()); + + f_service_ << autogen_comment() << as3_package(); + + scope_up(f_service_); + + f_service_ << endl << as3_type_imports() << as3_thrift_imports() + << as3_thrift_gen_imports(tservice); + + if (tservice->get_extends() != NULL) { + t_type* parent = tservice->get_extends(); + string parent_namespace = parent->get_program()->get_namespace("as3"); + if (!parent_namespace.empty() && parent_namespace != package_name_) { + f_service_ << "import " << type_name(parent) << "Impl;" << endl; + } + } + + f_service_ << endl; + + generate_service_client(tservice); + scope_down(f_service_); + + f_service_ << as3_type_imports(); + f_service_ << as3_thrift_imports(); + f_service_ << as3_thrift_gen_imports(tservice); + if (!package_name_.empty()) { + f_service_ << "import " << package_name_ << ".*;" << endl; + } + + generate_service_helpers(tservice); + + f_service_.close(); + + // Now make the processor/server file + f_service_name = package_dir_ + "/" + service_name_ + "Processor.as"; + f_service_.open(f_service_name.c_str()); + + f_service_ << autogen_comment() << as3_package(); + + scope_up(f_service_); + + f_service_ << endl << as3_type_imports() << as3_thrift_imports() + << as3_thrift_gen_imports(tservice) << endl; + + generate_service_server(tservice); + scope_down(f_service_); + + f_service_ << as3_type_imports(); + f_service_ << as3_thrift_imports(); + f_service_ << as3_thrift_gen_imports(tservice) << endl; + if (!package_name_.empty()) { + f_service_ << "import " << package_name_ << ".*;" << endl; + } + + generate_service_helpers(tservice); + + f_service_.close(); +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_as3_generator::generate_service_interface(t_service* tservice) { + string extends_iface = ""; + if (tservice->get_extends() != NULL) { + extends_iface = " extends " + tservice->get_extends()->get_name(); + } + + generate_as3_doc(f_service_, tservice); + f_service_ << indent() << "public interface " << service_name_ << extends_iface << " {" << endl + << endl; + indent_up(); + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_as3_doc(f_service_, *f_iter); + if (!(*f_iter)->is_oneway()) { + if ((*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << "//function onError(Error):void;" << endl; + indent(f_service_) << "//function onSuccess():void;" << endl; + } else { + indent(f_service_) << "//function onError(Error):void;" << endl; + indent(f_service_) << "//function onSuccess(" << type_name((*f_iter)->get_returntype()) + << "):void;" << endl; + } + } + indent(f_service_) << function_signature(*f_iter) << ";" << endl << endl; + } + indent_down(); + f_service_ << indent() << "}" << endl << endl; +} + +/** + * Generates structs for all the service args and return types + * + * @param tservice The service + */ +void t_as3_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_as3_struct_definition(f_service_, ts, false, true); + generate_function_helpers(*f_iter); + } +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_as3_generator::generate_service_client(t_service* tservice) { + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() != NULL) { + extends = tservice->get_extends()->get_name(); + extends_client = " extends " + extends + "Impl"; + } + + indent(f_service_) << "public class " << service_name_ << "Impl" << extends_client + << " implements " << service_name_ << " {" << endl; + indent_up(); + + indent(f_service_) << "public function " << service_name_ << "Impl" + << "(iprot:TProtocol, oprot:TProtocol=null)" << endl; + scope_up(f_service_); + if (extends.empty()) { + f_service_ << indent() << "iprot_ = iprot;" << endl; + f_service_ << indent() << "if (oprot == null) {" << endl; + indent_up(); + f_service_ << indent() << "oprot_ = iprot;" << endl; + indent_down(); + f_service_ << indent() << "} else {" << endl; + indent_up(); + f_service_ << indent() << "oprot_ = oprot;" << endl; + indent_down(); + f_service_ << indent() << "}"; + } else { + f_service_ << indent() << "super(iprot, oprot);" << endl; + } + scope_down(f_service_); + f_service_ << endl; + + if (extends.empty()) { + f_service_ << indent() << "protected var iprot_:TProtocol;" << endl << indent() + << "protected var oprot_:TProtocol;" << endl << endl << indent() + << "protected var seqid_:int;" << endl << endl; + + indent(f_service_) << "public function getInputProtocol():TProtocol" << endl; + scope_up(f_service_); + indent(f_service_) << "return this.iprot_;" << endl; + scope_down(f_service_); + f_service_ << endl; + + indent(f_service_) << "public function getOutputProtocol():TProtocol" << endl; + scope_up(f_service_); + indent(f_service_) << "return this.oprot_;" << endl; + scope_down(f_service_); + f_service_ << endl; + } + + // Generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string funname = (*f_iter)->get_name(); + + // Open function + if (!(*f_iter)->is_oneway()) { + if ((*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << "//function onError(Error):void;" << endl; + indent(f_service_) << "//function onSuccess():void;" << endl; + } else { + indent(f_service_) << "//function onError(Error):void;" << endl; + indent(f_service_) << "//function onSuccess(" << type_name((*f_iter)->get_returntype()) + << "):void;" << endl; + } + } + indent(f_service_) << "public " << function_signature(*f_iter) << endl; + scope_up(f_service_); + + // Get the struct of function call params + t_struct* arg_struct = (*f_iter)->get_arglist(); + + string argsname = (*f_iter)->get_name() + "_args"; + vector::const_iterator fld_iter; + const vector& fields = arg_struct->get_members(); + + // Serialize the request + f_service_ << indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", " + << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL") + << ", seqid_));" << endl << indent() << "var args:" << argsname << " = new " + << argsname << "();" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << indent() << "args." << (*fld_iter)->get_name() << " = " + << (*fld_iter)->get_name() << ";" << endl; + } + + f_service_ << indent() << "args.write(oprot_);" << endl << indent() + << "oprot_.writeMessageEnd();" << endl; + + if ((*f_iter)->is_oneway()) { + f_service_ << indent() << "oprot_.getTransport().flush();" << endl; + } else { + f_service_ << indent() << "oprot_.getTransport().flush(function(error:Error):void {" << endl; + indent_up(); + f_service_ << indent() << "try {" << endl; + indent_up(); + string resultname = (*f_iter)->get_name() + "_result"; + f_service_ << indent() << "if (error != null) {" << endl << indent() + << " if (onError != null) onError(error);" << endl << indent() << " return;" + << endl << indent() << "}" << endl << indent() + << "var msg:TMessage = iprot_.readMessageBegin();" << endl << indent() + << "if (msg.type == TMessageType.EXCEPTION) {" << endl << indent() + << " var x:TApplicationError = TApplicationError.read(iprot_);" << endl + << indent() << " iprot_.readMessageEnd();" << endl << indent() + << " if (onError != null) onError(x);" << endl << indent() << " return;" << endl + << indent() << "}" << endl << indent() << "var result :" << resultname << " = new " + << resultname << "();" << endl << indent() << "result.read(iprot_);" << endl + << indent() << "iprot_.readMessageEnd();" << endl; + + // Careful, only return _result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << indent() << "if (result." << generate_isset_check("success") << ") {" << endl + << indent() << " if (onSuccess != null) onSuccess(result.success);" << endl + << indent() << " return;" << endl << indent() << "}" << endl; + } + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << indent() << "if (result." << (*x_iter)->get_name() << " != null) {" << endl + << indent() << " if (onError != null) onError(result." << (*x_iter)->get_name() + << ");" << endl << indent() << " return;" << endl << indent() << "}" << endl; + } + + // If you get here it's an exception, unless a void function + if ((*f_iter)->get_returntype()->is_void()) { + f_service_ << indent() << "if (onSuccess != null) onSuccess();" << endl << indent() + << "return;" << endl; + } else { + + f_service_ << indent() << "if (onError != null) onError(new " + "TApplicationError(TApplicationError.MISSING_RESULT, \"" + << (*f_iter)->get_name() << " failed: unknown result\"));" << endl; + } + indent_down(); + f_service_ << indent() << "} catch (e:TError) {" << endl << indent() + << " if (onError != null) onError(e);" << endl << indent() << "}" << endl; + + indent_down(); + indent(f_service_) << "});" << endl; + } + // Close function + scope_down(f_service_); + f_service_ << endl; + } + + indent_down(); + indent(f_service_) << "}" << endl; +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_as3_generator::generate_service_server(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + // Extends stuff + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_processor = " extends " + extends + "Processor"; + } + + // Generate the header portion + indent(f_service_) << "public class " << service_name_ << "Processor" << extends_processor + << " implements TProcessor {" << endl; + indent_up(); + + indent(f_service_) << "public function " << service_name_ << "Processor(iface:" << service_name_ + << ")" << endl; + scope_up(f_service_); + if (!extends.empty()) { + f_service_ << indent() << "super(iface);" << endl; + } + f_service_ << indent() << "iface_ = iface;" << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << indent() << "PROCESS_MAP[\"" << (*f_iter)->get_name() + << "\"] = " << (*f_iter)->get_name() << "();" << endl; + } + + scope_down(f_service_); + f_service_ << endl; + + f_service_ << indent() << "private var iface_:" << service_name_ << ";" << endl; + + if (extends.empty()) { + f_service_ << indent() << "protected const PROCESS_MAP:Dictionary = new Dictionary();" << endl; + } + + f_service_ << endl; + + // Generate the server implementation + string override = ""; + if (tservice->get_extends() != NULL) { + override = "override "; + } + indent(f_service_) << override + << "public function process(iprot:TProtocol, oprot:TProtocol):Boolean" << endl; + scope_up(f_service_); + + f_service_ << indent() << "var msg:TMessage = iprot.readMessageBegin();" << endl; + + // TODO(mcslee): validate message, was the seqid etc. legit? + // AS- If all method is oneway: + // do you have an oprot? + // do you you need nullcheck? + f_service_ + << indent() << "var fn:Function = PROCESS_MAP[msg.name];" << endl << indent() + << "if (fn == null) {" << endl << indent() << " TProtocolUtil.skip(iprot, TType.STRUCT);" + << endl << indent() << " iprot.readMessageEnd();" << endl << indent() + << " var x:TApplicationError = new TApplicationError(TApplicationError.UNKNOWN_METHOD, " + "\"Invalid method name: '\"+msg.name+\"'\");" << endl << indent() + << " oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" + << endl << indent() << " x.write(oprot);" << endl << indent() << " oprot.writeMessageEnd();" + << endl << indent() << " oprot.getTransport().flush();" << endl << indent() + << " return true;" << endl << indent() << "}" << endl << indent() + << "fn.call(this,msg.seqid, iprot, oprot);" << endl; + + f_service_ << indent() << "return true;" << endl; + + scope_down(f_service_); + f_service_ << endl; + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(tservice, *f_iter); + } + + indent_down(); + indent(f_service_) << "}" << endl << endl; +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_as3_generator::generate_function_helpers(t_function* tfunction) { + if (tfunction->is_oneway()) { + return; + } + + t_struct result(program_, tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + generate_as3_struct_definition(f_service_, &result, false, true, true); +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_as3_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + (void)tservice; + // Open class + indent(f_service_) << "private function " << tfunction->get_name() << "():Function {" << endl; + indent_up(); + + // Open function + indent(f_service_) << "return function(seqid:int, iprot:TProtocol, oprot:TProtocol):void" << endl; + scope_up(f_service_); + + string argsname = tfunction->get_name() + "_args"; + string resultname = tfunction->get_name() + "_result"; + + f_service_ << indent() << "var args:" << argsname << " = new " << argsname << "();" << endl + << indent() << "args.read(iprot);" << endl << indent() << "iprot.readMessageEnd();" + << endl; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + // Declare result for non oneway function + if (!tfunction->is_oneway()) { + f_service_ << indent() << "var result:" << resultname << " = new " << resultname << "();" + << endl; + } + + // Try block for a function with exceptions + if (xceptions.size() > 0) { + f_service_ << indent() << "try {" << endl; + indent_up(); + } + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + f_service_ << indent(); + if (tfunction->is_oneway()) { + f_service_ << "iface_." << tfunction->get_name() << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "args." << (*f_iter)->get_name(); + } + f_service_ << ");" << endl; + } else { + f_service_ << "// sorry this operation is not supported yet" << endl; + f_service_ << indent() << "throw new Error(\"This is not yet supported\");" << endl; + } + + // Set isset on success field + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void() + && !type_can_be_null(tfunction->get_returntype())) { + f_service_ << indent() << "result.set" << get_cap_name("success") << get_cap_name("isSet") + << "(true);" << endl; + } + + if (!tfunction->is_oneway() && xceptions.size() > 0) { + indent_down(); + f_service_ << indent() << "}"; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << " catch (" << (*x_iter)->get_name() << ":" + << type_name((*x_iter)->get_type(), false, false) << ") {" << endl; + if (!tfunction->is_oneway()) { + indent_up(); + f_service_ << indent() << "result." << (*x_iter)->get_name() << " = " + << (*x_iter)->get_name() << ";" << endl; + indent_down(); + f_service_ << indent() << "}"; + } else { + f_service_ << "}"; + } + } + f_service_ << " catch (th:Error) {" << endl; + indent_up(); + f_service_ << indent() << "trace(\"Internal error processing " << tfunction->get_name() + << "\", th);" << endl << indent() + << "var x:TApplicationError = new " + "TApplicationError(TApplicationError.INTERNAL_ERROR, \"Internal error processing " + << tfunction->get_name() << "\");" << endl << indent() + << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() + << "\", TMessageType.EXCEPTION, seqid));" << endl << indent() << "x.write(oprot);" + << endl << indent() << "oprot.writeMessageEnd();" << endl << indent() + << "oprot.getTransport().flush();" << endl << indent() << "return;" << endl; + indent_down(); + f_service_ << indent() << "}" << endl; + } + + // Shortcut out here for oneway functions + if (tfunction->is_oneway()) { + f_service_ << indent() << "return;" << endl; + scope_down(f_service_); + + // Close class + indent_down(); + f_service_ << indent() << "}" << endl << endl; + return; + } + + f_service_ << indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() + << "\", TMessageType.REPLY, seqid));" << endl << indent() << "result.write(oprot);" + << endl << indent() << "oprot.writeMessageEnd();" << endl << indent() + << "oprot.getTransport().flush();" << endl; + + // Close function + scope_down(f_service_); + f_service_ << endl; + + // Close class + indent_down(); + f_service_ << indent() << "}" << endl << endl; +} + +/** + * Deserializes a field of any type. + * + * @param tfield The field + * @param prefix The variable name or container for this field + */ +void t_as3_generator::generate_deserialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = prefix + tfield->get_name(); + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name); + } else if (type->is_container()) { + generate_deserialize_container(out, type, name); + } else if (type->is_base_type() || type->is_enum()) { + + indent(out) << name << " = iprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "readBinary();"; + } else { + out << "readString();"; + } + break; + case t_base_type::TYPE_BOOL: + out << "readBool();"; + break; + case t_base_type::TYPE_I8: + out << "readByte();"; + break; + case t_base_type::TYPE_I16: + out << "readI16();"; + break; + case t_base_type::TYPE_I32: + out << "readI32();"; + break; + case t_base_type::TYPE_I64: + out << "readI64();"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble();"; + break; + default: + throw "compiler error: no As3 name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "readI32();"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +/** + * Generates an unserializer for a struct, invokes read() + */ +void t_as3_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl << indent() + << prefix << ".read(iprot);" << endl; +} + +/** + * Deserializes a container by reading its size and then iterating + */ +void t_as3_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) { + scope_up(out); + + string obj; + + if (ttype->is_map()) { + obj = tmp("_map"); + } else if (ttype->is_set()) { + obj = tmp("_set"); + } else if (ttype->is_list()) { + obj = tmp("_list"); + } + + // Declare variables, read header + if (ttype->is_map()) { + indent(out) << "var " << obj << ":TMap = iprot.readMapBegin();" << endl; + } else if (ttype->is_set()) { + indent(out) << "var " << obj << ":TSet = iprot.readSetBegin();" << endl; + } else if (ttype->is_list()) { + indent(out) << "var " << obj << ":TList = iprot.readListBegin();" << endl; + } + + indent(out) << prefix << " = new " << type_name(ttype, false, true) + // size the collection correctly + << "(" + << ");" << endl; + + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << "for (var " << i << ":int = 0; " << i << " < " << obj << ".size" + << "; " + << "++" << i << ")" << endl; + + scope_up(out); + + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, prefix); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, prefix); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, prefix); + } + + scope_down(out); + + // Read container end + if (ttype->is_map()) { + indent(out) << "iprot.readMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "iprot.readSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "iprot.readListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Generates code to deserialize a map + */ +void t_as3_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) { + string key = tmp("_key"); + string val = tmp("_val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + indent(out) << declare_field(&fkey) << endl; + indent(out) << declare_field(&fval) << endl; + + generate_deserialize_field(out, &fkey); + generate_deserialize_field(out, &fval); + + indent(out) << prefix << "[" << key << "] = " << val << ";" << endl; +} + +/** + * Deserializes a set element + */ +void t_as3_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) { + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); + + indent(out) << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".add(" << elem << ");" << endl; +} + +/** + * Deserializes a list element + */ +void t_as3_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix) { + string elem = tmp("_elem"); + t_field felem(tlist->get_elem_type(), elem); + + indent(out) << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".push(" << elem << ");" << endl; +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_as3_generator::generate_serialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = get_true_type(tfield->get_type()); + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); + } else if (type->is_container()) { + generate_serialize_container(out, type, prefix + tfield->get_name()); + } else if (type->is_base_type() || type->is_enum()) { + + string name = prefix + tfield->get_name(); + indent(out) << "oprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "writeBinary(" << name << ");"; + } else { + out << "writeString(" << name << ");"; + } + break; + case t_base_type::TYPE_BOOL: + out << "writeBool(" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "writeByte(" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "writeI16(" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "writeI32(" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "writeI64(" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble(" << name << ");"; + break; + default: + throw "compiler error: no As3 name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "writeI32(" << name << ");"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", + prefix.c_str(), + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_as3_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + (void)tstruct; + out << indent() << prefix << ".write(oprot);" << endl; +} + +/** + * Serializes a container by writing its size then the elements. + * + * @param ttype The type of container + * @param prefix String prefix for fields + */ +void t_as3_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + scope_up(out); + + if (ttype->is_map()) { + string iter = tmp("_key"); + string counter = tmp("_sizeCounter"); + indent(out) << "var " << counter << ":int = 0;" << endl; + indent(out) << "for (var " << iter << ":* in " << prefix << ") {" << endl; + indent(out) << " " << counter << +"++;" << endl; + indent(out) << "}" << endl; + + indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type()) + << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << counter << "));" + << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type()) + << ", " << prefix << ".size));" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.writeListBegin(new TList(" + << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".length));" + << endl; + } + + string iter = tmp("elem"); + if (ttype->is_map()) { + indent(out) << "for (var " << iter << ":* in " << prefix << ")"; + } else if (ttype->is_set()) { + indent(out) << "for each (var " << iter << ":* in " << prefix << ".toArray())"; + } else if (ttype->is_list()) { + indent(out) << "for each (var " << iter << ":* in " << prefix << ")"; + } + + scope_up(out); + + if (ttype->is_map()) { + generate_serialize_map_element(out, (t_map*)ttype, iter, prefix); + } else if (ttype->is_set()) { + generate_serialize_set_element(out, (t_set*)ttype, iter); + } else if (ttype->is_list()) { + generate_serialize_list_element(out, (t_list*)ttype, iter); + } + + scope_down(out); + + if (ttype->is_map()) { + indent(out) << "oprot.writeMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.writeSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.writeListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Serializes the members of a map. + */ +void t_as3_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string iter, + string map) { + t_field kfield(tmap->get_key_type(), iter); + generate_serialize_field(out, &kfield, ""); + t_field vfield(tmap->get_val_type(), map + "[" + iter + "]"); + generate_serialize_field(out, &vfield, ""); +} + +/** + * Serializes the members of a set. + */ +void t_as3_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) { + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +/** + * Serializes the members of a list. + */ +void t_as3_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) { + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +/** + * Returns a As3 type name + * + * @param ttype The type + * @param container Is the type going inside a container? + * @return As3 type name, i.e. HashMap + */ +string t_as3_generator::type_name(t_type* ttype, bool in_container, bool in_init) { + (void)in_init; + // In As3 typedefs are just resolved to their real type + ttype = get_true_type(ttype); + string prefix; + + if (ttype->is_base_type()) { + return base_type_name((t_base_type*)ttype, in_container); + } else if (ttype->is_enum()) { + return "int"; + } else if (ttype->is_map()) { + return "Dictionary"; + } else if (ttype->is_set()) { + return "Set"; + } else if (ttype->is_list()) { + return "Array"; + } + + // Check for namespacing + t_program* program = ttype->get_program(); + if (program != NULL && program != program_) { + string package = program->get_namespace("as3"); + if (!package.empty()) { + return package + "." + ttype->get_name(); + } + } + + return ttype->get_name(); +} + +/** + * Returns the AS3 type that corresponds to the thrift type. + * + * @param tbase The base type + * @param container Is it going in a As3 container? + */ +string t_as3_generator::base_type_name(t_base_type* type, bool in_container) { + (void)in_container; + t_base_type::t_base tbase = type->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + return "void"; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + return "ByteArray"; + } else { + return "String"; + } + case t_base_type::TYPE_BOOL: + return "Boolean"; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + return "int"; + case t_base_type::TYPE_I64: + throw "i64 is not yet supported in as3"; + case t_base_type::TYPE_DOUBLE: + return "Number"; + default: + throw "compiler error: no As3 name for base type " + t_base_type::t_base_name(tbase); + } +} + +/** + * Declares a field, which may include initialization as necessary. + * + * @param ttype The type + */ +string t_as3_generator::declare_field(t_field* tfield, bool init) { + // TODO(mcslee): do we ever need to initialize the field? + string result = "var " + tfield->get_name() + ":" + type_name(tfield->get_type()); + if (init) { + t_type* ttype = get_true_type(tfield->get_type()); + if (ttype->is_base_type() && tfield->get_value() != NULL) { + ofstream dummy; + result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value()); + } else if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + result += " = null"; + break; + case t_base_type::TYPE_BOOL: + result += " = false"; + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + result += " = 0"; + break; + case t_base_type::TYPE_DOUBLE: + result += " = (double)0"; + break; + } + + } else if (ttype->is_enum()) { + result += " = 0"; + } else if (ttype->is_container()) { + result += " = new " + type_name(ttype, false, true) + "()"; + } else { + result += " = new " + type_name(ttype, false, true) + "()"; + ; + } + } + return result + ";"; +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_as3_generator::function_signature(t_function* tfunction, string prefix) { + std::string arguments = argument_list(tfunction->get_arglist()); + if (!tfunction->is_oneway()) { + if (arguments != "") { + arguments += ", "; + } + arguments += "onError:Function, onSuccess:Function"; + } + + std::string result = "function " + prefix + tfunction->get_name() + "(" + arguments + "):void"; + return result; +} + +/** + * Renders a comma separated field list, with type names + */ +string t_as3_generator::argument_list(t_struct* tstruct) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + result += (*f_iter)->get_name() + ":" + type_name((*f_iter)->get_type()); + } + return result; +} + +/** + * Converts the parse type to a C++ enum string for the given type. + */ +string t_as3_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "TType.STRING"; + case t_base_type::TYPE_BOOL: + return "TType.BOOL"; + case t_base_type::TYPE_I8: + return "TType.BYTE"; + case t_base_type::TYPE_I16: + return "TType.I16"; + case t_base_type::TYPE_I32: + return "TType.I32"; + case t_base_type::TYPE_I64: + return "TType.I64"; + case t_base_type::TYPE_DOUBLE: + return "TType.DOUBLE"; + } + } else if (type->is_enum()) { + return "TType.I32"; + } else if (type->is_struct() || type->is_xception()) { + return "TType.STRUCT"; + } else if (type->is_map()) { + return "TType.MAP"; + } else if (type->is_set()) { + return "TType.SET"; + } else if (type->is_list()) { + return "TType.LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** + * Applies the correct style to a string based on the value of nocamel_style_ + */ +std::string t_as3_generator::get_cap_name(std::string name) { + name[0] = toupper(name[0]); + return name; +} + +string t_as3_generator::constant_name(string name) { + string constant_name; + + bool is_first = true; + bool was_previous_char_upper = false; + for (string::iterator iter = name.begin(); iter != name.end(); ++iter) { + string::value_type character = (*iter); + + bool is_upper = isupper(character); + + if (is_upper && !is_first && !was_previous_char_upper) { + constant_name += '_'; + } + constant_name += toupper(character); + + is_first = false; + was_previous_char_upper = is_upper; + } + + return constant_name; +} + +/** + * Emits a As3Doc comment if the provided object has a doc in Thrift + */ +void t_as3_generator::generate_as3_doc(ofstream& out, t_doc* tdoc) { + if (tdoc->has_doc()) { + generate_docstring_comment(out, "/**\n", " * ", tdoc->get_doc(), " */\n"); + } +} + +/** + * Emits a As3Doc comment if the provided function object has a doc in Thrift + */ +void t_as3_generator::generate_as3_doc(ofstream& out, t_function* tfunction) { + if (tfunction->has_doc()) { + stringstream ss; + ss << tfunction->get_doc(); + const vector& fields = tfunction->get_arglist()->get_members(); + vector::const_iterator p_iter; + for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { + t_field* p = *p_iter; + ss << "\n@param " << p->get_name(); + if (p->has_doc()) { + ss << " " << p->get_doc(); + } + } + generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n"); + } +} + +std::string t_as3_generator::generate_isset_check(t_field* field) { + return generate_isset_check(field->get_name()); +} + +std::string t_as3_generator::generate_isset_check(std::string field_name) { + return "is" + get_cap_name("set") + get_cap_name(field_name) + "()"; +} + +void t_as3_generator::generate_isset_set(ofstream& out, t_field* field) { + if (!type_can_be_null(field->get_type())) { + indent(out) << "this.__isset_" << field->get_name() << " = true;" << endl; + } +} + +std::string t_as3_generator::get_enum_class_name(t_type* type) { + string package = ""; + t_program* program = type->get_program(); + if (program != NULL && program != program_) { + package = program->get_namespace("as3") + "."; + } + return package + type->get_name(); +} + +THRIFT_REGISTER_GENERATOR( + as3, + "AS3", + " bindable: Add [bindable] metadata to all the struct classes.\n") diff --git a/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc b/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc new file mode 100644 index 0000000..a7beca7 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc @@ -0,0 +1,4562 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +#include +#include +#include +#include +#include + +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/* forward declarations */ +string initial_caps_to_underscores(string name); +string underscores_to_initial_caps(string name); +string to_upper_case(string name); +string to_lower_case(string name); + +/** + * C code generator, using glib for C typing. + */ +class t_c_glib_generator : public t_oop_generator { +public: + /* constructor */ + t_c_glib_generator(t_program* program, + const map& parsed_options, + const string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + /* set the output directory */ + this->out_dir_base_ = "gen-c_glib"; + + /* no options yet */ + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + throw "unknown option c_glib:" + iter->first; + } + + /* set the namespace */ + this->nspace = program_->get_namespace("c_glib"); + + if (this->nspace.empty()) { + this->nspace = ""; + this->nspace_u = ""; + this->nspace_uc = ""; + this->nspace_lc = ""; + } else { + /* replace dots with underscores */ + char* tmp = strdup(this->nspace.c_str()); + for (unsigned int i = 0; i < strlen(tmp); i++) { + if (tmp[i] == '.') { + tmp[i] = '_'; + } + } + this->nspace = string(tmp, strlen(tmp)); + free(tmp); + + /* clean up the namespace for C. + * An input of 'namespace foo' should result in: + * - nspace = foo - for thrift objects and typedefs + * - nspace_u = Foo - for internal GObject prefixes + * - nspace_uc = FOO_ - for macro prefixes + * - nspace_lc = foo_ - for filename and method prefixes + * The underscores are there since uc and lc strings are used as file and + * variable prefixes. + */ + this->nspace_u = initial_caps_to_underscores(this->nspace); + this->nspace_uc = to_upper_case(this->nspace_u) + "_"; + this->nspace_lc = to_lower_case(this->nspace_u) + "_"; + } + } + + /* initialization and destruction */ + void init_generator(); + void close_generator(); + + /* generation functions */ + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_consts(vector consts); + void generate_struct(t_struct* tstruct); + void generate_service(t_service* tservice); + void generate_xception(t_struct* tstruct); + +private: + /* file streams */ + ofstream f_types_; + ofstream f_types_impl_; + ofstream f_header_; + ofstream f_service_; + + /* namespace variables */ + string nspace; + string nspace_u; + string nspace_uc; + string nspace_lc; + + /* helper functions */ + bool is_complex_type(t_type* ttype); + bool is_numeric(t_type* ttype); + string type_name(t_type* ttype, bool in_typedef = false, bool is_const = false); + string property_type_name(t_type* ttype, bool in_typedef = false, bool is_const = false); + string base_type_name(t_type* type); + string type_to_enum(t_type* type); + string constant_literal(t_type* type, t_const_value* value); + string constant_value(string name, t_type* type, t_const_value* value); + string constant_value_with_storage(string name, t_type* type, t_const_value* value); + string function_signature(t_function* tfunction); + string argument_list(t_struct* tstruct); + string xception_list(t_struct* tstruct); + string declare_field(t_field* tfield, + bool init = false, + bool pointer = false, + bool constant = false, + bool reference = false); + void declare_local_variable(ofstream& out, t_type* ttype, string& base_name, bool for_hash_table); + void declore_local_variable_for_write(ofstream& out, t_type* ttype, string& base_name); + + /* generation functions */ + void generate_const_initializer(string name, + t_type* type, + t_const_value* value, + bool top_level = false); + void generate_service_helpers(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_handler(t_service* tservice); + void generate_service_processor(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_object(t_struct* tstruct); + void generate_struct_writer(ofstream& out, + t_struct* tstruct, + string this_name, + string this_get = "", + bool is_function = true); + void generate_struct_reader(ofstream& out, + t_struct* tstruct, + string this_name, + string this_get = "", + bool is_function = true); + + void generate_serialize_field(ofstream& out, + t_field* tfield, + string prefix, + string suffix, + int error_ret); + void generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix, int error_ret); + void generate_serialize_container(ofstream& out, t_type* ttype, string prefix, int error_ret); + void generate_serialize_map_element(ofstream& out, + t_map* tmap, + string key, + string value, + int error_ret); + void generate_serialize_set_element(ofstream& out, t_set* tset, string element, int error_ret); + void generate_serialize_list_element(ofstream& out, + t_list* tlist, + string list, + string index, + int error_ret); + + void generate_deserialize_field(ofstream& out, + t_field* tfield, + string prefix, + string suffix, + int error_ret, + bool allocate = true); + void generate_deserialize_struct(ofstream& out, + t_struct* tstruct, + string prefix, + int error_ret, + bool allocate = true); + void generate_deserialize_container(ofstream& out, t_type* ttype, string prefix, int error_ret); + void generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix, int error_ret); + void generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix, int error_ret); + void generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix, + string index, + int error_ret); + + string generate_new_hash_from_type(t_type* key, t_type* value); + string generate_new_array_from_type(t_type* ttype); + + string generate_free_func_from_type(t_type* ttype); + string generate_hash_func_from_type(t_type* ttype); + string generate_cmp_func_from_type(t_type* ttype); +}; + +/** + * Prepare for file generation by opening up the necessary file + * output streams. + */ +void t_c_glib_generator::init_generator() { + /* create output directory */ + MKDIR(get_out_dir().c_str()); + + string program_name_u = initial_caps_to_underscores(program_name_); + string program_name_uc = to_upper_case(program_name_u); + string program_name_lc = to_lower_case(program_name_u); + + /* create output files */ + string f_types_name = get_out_dir() + this->nspace_lc + program_name_lc + "_types.h"; + f_types_.open(f_types_name.c_str()); + string f_types_impl_name = get_out_dir() + this->nspace_lc + program_name_lc + "_types.c"; + f_types_impl_.open(f_types_impl_name.c_str()); + + /* add thrift boilerplate headers */ + f_types_ << autogen_comment(); + f_types_impl_ << autogen_comment(); + + /* include inclusion guard */ + f_types_ << "#ifndef " << this->nspace_uc << program_name_uc << "_TYPES_H" << endl << "#define " + << this->nspace_uc << program_name_uc << "_TYPES_H" << endl << endl; + + /* include base types */ + f_types_ << "/* base includes */" << endl << "#include " << endl + << "#include " << endl + << "#include " << endl; + + /* include other thrift includes */ + const vector& includes = program_->get_includes(); + for (size_t i = 0; i < includes.size(); ++i) { + f_types_ << "/* other thrift includes */" << endl << "#include \"" << this->nspace_lc + << initial_caps_to_underscores(includes[i]->get_name()) << "_types.h\"" << endl; + } + f_types_ << endl; + + /* include custom headers */ + const vector& c_includes = program_->get_c_includes(); + f_types_ << "/* custom thrift includes */" << endl; + for (size_t i = 0; i < c_includes.size(); ++i) { + if (c_includes[i][0] == '<') { + f_types_ << "#include " << c_includes[i] << endl; + } else { + f_types_ << "#include \"" << c_includes[i] << "\"" << endl; + } + } + f_types_ << endl; + + /* include math.h (for "INFINITY") in the implementation file, in case we + encounter a struct with a member of type double */ + f_types_impl_ << endl << "#include " << endl; + + // include the types file + f_types_impl_ << endl << "#include \"" << this->nspace_lc << program_name_u << "_types.h\"" + << endl << "#include " << endl << endl; + + f_types_ << "/* begin types */" << endl << endl; +} + +/** + * Finish up generation and close all file streams. + */ +void t_c_glib_generator::close_generator() { + string program_name_uc = to_upper_case(initial_caps_to_underscores(program_name_)); + + /* end the header inclusion guard */ + f_types_ << "#endif /* " << this->nspace_uc << program_name_uc << "_TYPES_H */" << endl; + + /* close output file */ + f_types_.close(); + f_types_impl_.close(); +} + +/** + * Generates a Thrift typedef in C code. For example: + * + * Thrift: + * typedef map SomeMap + * + * C: + * typedef GHashTable * ThriftSomeMap; + */ +void t_c_glib_generator::generate_typedef(t_typedef* ttypedef) { + f_types_ << indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " << this->nspace + << ttypedef->get_symbolic() << ";" << endl << endl; +} + +/** + * Generates a C enumeration. For example: + * + * Thrift: + * enum MyEnum { + * ONE = 1, + * TWO + * } + * + * C: + * enum _ThriftMyEnum { + * THRIFT_MY_ENUM_ONE = 1, + * THRIFT_MY_ENUM_TWO + * }; + * typedef enum _ThriftMyEnum ThriftMyEnum; + */ +void t_c_glib_generator::generate_enum(t_enum* tenum) { + string name = tenum->get_name(); + string name_uc = to_upper_case(initial_caps_to_underscores(name)); + + f_types_ << indent() << "enum _" << this->nspace << name << " {" << endl; + + indent_up(); + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + bool first = true; + + /* output each of the enumeration elements */ + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + if (first) { + first = false; + } else { + f_types_ << "," << endl; + } + + f_types_ << indent() << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name(); + f_types_ << " = " << (*c_iter)->get_value(); + } + + indent_down(); + f_types_ << endl << "};" << endl << "typedef enum _" << this->nspace << name << " " + << this->nspace << name << ";" << endl << endl; + + f_types_ << "/* return the name of the constant */" << endl; + f_types_ << "const char *" << endl; + f_types_ << "toString_" << name << "(int value); " << endl << endl; + ; + f_types_impl_ << "/* return the name of the constant */" << endl; + f_types_impl_ << "const char *" << endl; + f_types_impl_ << "toString_" << name << "(int value) " << endl; + f_types_impl_ << "{" << endl; + f_types_impl_ << " static __thread char buf[16] = {0};" << endl; + f_types_impl_ << " switch(value) {" << endl; + std::set done; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + // Skipping duplicate value + if (done.find(value) == done.end()) { + done.insert(value); + f_types_impl_ << " case " << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name() + << ":" + << "return \"" << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name() + << "\";" << endl; + } + } + f_types_impl_ << " default: g_snprintf(buf, 16, \"%d\", value); return buf;" << endl; + f_types_impl_ << " }" << endl; + f_types_impl_ << "}" << endl << endl; +} + +/** + * Generates Thrift constants in C code. + */ +void t_c_glib_generator::generate_consts(vector consts) { + f_types_ << "/* constants */" << endl; + f_types_impl_ << "/* constants */" << endl; + + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + string name = (*c_iter)->get_name(); + string name_uc = to_upper_case(name); + string name_lc = to_lower_case(name); + t_type* type = (*c_iter)->get_type(); + t_const_value* value = (*c_iter)->get_value(); + + if (is_complex_type(type)) { + f_types_ << type_name(type) << indent() << this->nspace_lc << name_lc + << "_constant();" << endl; + } + + f_types_ << indent() << "#define " << this->nspace_uc << name_uc << " " + << constant_value(name_lc, type, value) << endl; + + generate_const_initializer(name_lc, type, value, true); + } + + f_types_ << endl; + f_types_impl_ << endl; +} + +/** + * Generate Thrift structs in C code, as GObjects. Example: + * + * Thrift: + * struct Bonk + * { + * 1: string message, + * 2: i32 type + * } + * + * C GObject instance header: + * struct _ThriftBonk + * { + * GObject parent; + * + * gchar * message; + * gint32 type; + * }; + * typedef struct _ThriftBonk ThriftBonk + * // ... additional GObject boilerplate ... + */ +void t_c_glib_generator::generate_struct(t_struct* tstruct) { + f_types_ << "/* struct " << tstruct->get_name() << " */" << endl; + generate_object(tstruct); +} + +/** + * Generate C code to represent Thrift services. Creates a new GObject + * which can be used to access the service. + */ +void t_c_glib_generator::generate_service(t_service* tservice) { + string svcname_u = initial_caps_to_underscores(tservice->get_name()); + string svcname_uc = this->nspace_uc + to_upper_case(svcname_u); + string filename = this->nspace_lc + to_lower_case(svcname_u); + + // make output files + string f_header_name = get_out_dir() + filename + ".h"; + f_header_.open(f_header_name.c_str()); + + string program_name_u = initial_caps_to_underscores(program_name_); + string program_name_lc = to_lower_case(program_name_u); + + // add header file boilerplate + f_header_ << autogen_comment(); + + // add an inclusion guard + f_header_ << "#ifndef " << svcname_uc << "_H" << endl << "#define " << svcname_uc << "_H" << endl + << endl; + + // add standard includes + f_header_ << "#include " << endl << endl; + f_header_ << "#include \"" << this->nspace_lc << program_name_lc << "_types.h\"" << endl; + + // if we are inheriting from another service, include its header + t_service* extends_service = tservice->get_extends(); + if (extends_service != NULL) { + f_header_ << "#include \"" << this->nspace_lc + << to_lower_case(initial_caps_to_underscores(extends_service->get_name())) << ".h\"" + << endl; + } + f_header_ << endl; + + // create the service implementation + string f_service_name = get_out_dir() + filename + ".c"; + f_service_.open(f_service_name.c_str()); + + // add the boilerplace header + f_service_ << autogen_comment(); + + // include the headers + f_service_ << "#include " << endl << "#include " << endl + << "#include " << endl << "#include \"" + << filename << ".h\"" << endl << endl; + + // generate the service-helper classes + generate_service_helpers(tservice); + + // generate the client objects + generate_service_client(tservice); + + // generate the server objects + generate_service_server(tservice); + + // end the header inclusion guard + f_header_ << "#endif /* " << svcname_uc << "_H */" << endl; + + // close the files + f_service_.close(); + f_header_.close(); +} + +/** + * + */ +void t_c_glib_generator::generate_xception(t_struct* tstruct) { + string name = tstruct->get_name(); + string name_u = initial_caps_to_underscores(name); + string name_lc = to_lower_case(name_u); + string name_uc = to_upper_case(name_u); + + generate_object(tstruct); + + f_types_ << "/* exception */" << endl + << "typedef enum" << endl + << "{" << endl; + indent_up(); + f_types_ << indent() << this->nspace_uc << name_uc << "_ERROR_CODE" << endl; + indent_down(); + f_types_ << "} " << this->nspace << name << "Error;" << endl + << endl + << "GQuark " << this->nspace_lc << name_lc + << "_error_quark (void);" << endl + << "#define " << this->nspace_uc << name_uc << "_ERROR (" + << this->nspace_lc << name_lc << "_error_quark())" << endl + << endl + << endl; + + f_types_impl_ << "/* define the GError domain for exceptions */" << endl << "#define " + << this->nspace_uc << name_uc << "_ERROR_DOMAIN \"" << this->nspace_lc << name_lc + << "_error_quark\"" << endl << "GQuark" << endl << this->nspace_lc << name_lc + << "_error_quark (void)" << endl << "{" << endl + << " return g_quark_from_static_string (" << this->nspace_uc << name_uc + << "_ERROR_DOMAIN);" << endl << "}" << endl << endl; +} + +/******************** + * HELPER FUNCTIONS * + ********************/ + +/** + * Returns true if ttype is not a primitive. + */ +bool t_c_glib_generator::is_complex_type(t_type* ttype) { + ttype = get_true_type(ttype); + + return ttype->is_container() || ttype->is_struct() || ttype->is_xception(); +} + +bool t_c_glib_generator::is_numeric(t_type* ttype) { + return ttype->is_enum() || (ttype->is_base_type() && !ttype->is_string()); +} + +/** + * Maps a Thrift t_type to a C type. + */ +string t_c_glib_generator::type_name(t_type* ttype, bool in_typedef, bool is_const) { + if (ttype->is_base_type()) { + string bname = base_type_name(ttype); + + if (is_const) { + return "const " + bname; + } else { + return bname; + } + } + + if (ttype->is_container()) { + string cname; + + t_container* tcontainer = (t_container*)ttype; + if (tcontainer->has_cpp_name()) { + cname = tcontainer->get_cpp_name(); + } else if (ttype->is_map()) { + cname = "GHashTable"; + } else if (ttype->is_set()) { + // since a set requires unique elements, use a GHashTable, and + // populate the keys and values with the same data, using keys for + // the actual writes and reads. + // TODO: discuss whether or not to implement TSet, THashSet or GHashSet + cname = "GHashTable"; + } else if (ttype->is_list()) { + t_type* etype = ((t_list*)ttype)->get_elem_type(); + if (etype->is_void()) { + throw std::runtime_error("compiler error: list element type cannot be void"); + } + // TODO: investigate other implementations besides GPtrArray + cname = is_numeric(etype) ? "GArray" : "GPtrArray"; + } + + /* Omit the dereference operator if we are aliasing this type within a + typedef, to allow the type to be used more naturally in client code; + otherwise, include it */ + if (!in_typedef) { + cname += " *"; + } + + if (is_const) { + return "const " + cname; + } else { + return cname; + } + } + + // check for a namespace + string pname = this->nspace + ttype->get_name(); + + if (is_complex_type(ttype)) { + pname += " *"; + } + + if (is_const) { + return "const " + pname; + } else { + return pname; + } +} + +/** + * Maps a Thrift primitive to the type needed to hold its value when used as an + * object property. + * + * This method is needed because all integer properties of width less than 64 + * bits map to the same type, gint, as opposed to their width-specific type + * (gint8, gint16 or gint32). + */ +string t_c_glib_generator::property_type_name(t_type* ttype, bool in_typedef, bool is_const) { + string result; + + if (ttype->is_base_type()) { + switch (((t_base_type*)ttype)->get_base()) { + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + if (is_const) { + result = "const gint"; + } else { + result = "gint"; + } + break; + + default: + result = type_name(ttype, in_typedef, is_const); + } + } else { + result = type_name(ttype, in_typedef, is_const); + } + + return result; +} + +/** + * Maps a Thrift primitive to a C primitive. + */ +string t_c_glib_generator::base_type_name(t_type* type) { + if (type->is_enum()) { + return type_name(type); + } + if (!type->is_base_type()) { + throw std::invalid_argument("Only base types are suppported."); + } + t_base_type* base_type = reinterpret_cast(type); + t_base_type::t_base tbase = base_type->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + return "void"; + case t_base_type::TYPE_STRING: + if (base_type->is_binary()) { + return "GByteArray *"; + } else { + return "gchar *"; + } + case t_base_type::TYPE_BOOL: + return "gboolean"; + case t_base_type::TYPE_I8: + return "gint8"; + case t_base_type::TYPE_I16: + return "gint16"; + case t_base_type::TYPE_I32: + return "gint32"; + case t_base_type::TYPE_I64: + return "gint64"; + case t_base_type::TYPE_DOUBLE: + return "gdouble"; + default: + throw std::logic_error("compiler error: no C base type name for base type " + + t_base_type::t_base_name(tbase)); + } +} + +/** + * Returns a member of the ThriftType C enumeration in thrift_protocol.h + * for a Thrift type. + */ +string t_c_glib_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "T_STRING"; + case t_base_type::TYPE_BOOL: + return "T_BOOL"; + case t_base_type::TYPE_I8: + return "T_BYTE"; + case t_base_type::TYPE_I16: + return "T_I16"; + case t_base_type::TYPE_I32: + return "T_I32"; + case t_base_type::TYPE_I64: + return "T_I64"; + case t_base_type::TYPE_DOUBLE: + return "T_DOUBLE"; + } + } else if (type->is_enum()) { + return "T_I32"; + } else if (type->is_struct()) { + return "T_STRUCT"; + } else if (type->is_xception()) { + return "T_STRUCT"; + } else if (type->is_map()) { + return "T_MAP"; + } else if (type->is_set()) { + return "T_SET"; + } else if (type->is_list()) { + return "T_LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** + * Returns a Thrift constant formatted as a literal for inclusion in C code. + */ +string t_c_glib_generator::constant_literal(t_type* type, t_const_value* value) { + ostringstream render; + + if (type->is_base_type()) { + /* primitives */ + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + + switch (tbase) { + case t_base_type::TYPE_STRING: + render << "\"" + value->get_string() + "\""; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() != 0) ? "TRUE" : "FALSE"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + render << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + render << value->get_double(); + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else { + t_const_value::t_const_value_type value_type = value->get_type(); + + switch (value_type) { + case t_const_value::CV_IDENTIFIER: + render << value->get_integer(); + break; + case t_const_value::CV_LIST: + render << "{ "; + { + t_type* elem_type = ((t_list*)type)->get_elem_type(); + const vector& list = value->get_list(); + vector::const_iterator list_iter; + + if (list.size() > 0) { + list_iter = list.begin(); + render << constant_literal(elem_type, *list_iter); + + while (++list_iter != list.end()) { + render << ", " << constant_literal(elem_type, *list_iter); + } + } + } + render << " }"; + break; + case t_const_value::CV_MAP: + default: + render << "NULL /* not supported */"; + } + } + + return render.str(); +} + +/** + * Returns C code that represents a Thrift constant. + */ +string t_c_glib_generator::constant_value(string name, t_type* type, t_const_value* value) { + ostringstream render; + + if (type->is_base_type()) { + /* primitives */ + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + render << "g_strdup (\"" + value->get_string() + "\")"; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() != 0) ? 1 : 0); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + render << value->get_integer(); + break; + case t_base_type::TYPE_I64: + render << "G_GINT64_CONSTANT (" << value->get_integer() << ")"; + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + render << value->get_integer(); + } else { + render << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + render << "(" << type_name(type) << ")" << value->get_integer(); + } else if (is_complex_type(type)) { + render << "(" << this->nspace_lc << to_lower_case(name) << "_constant())"; + } else { + render << "NULL /* not supported */"; + } + + return render.str(); +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_c_glib_generator::function_signature(t_function* tfunction) { + t_type* ttype = tfunction->get_returntype(); + t_struct* arglist = tfunction->get_arglist(); + t_struct* xlist = tfunction->get_xceptions(); + string fname = initial_caps_to_underscores(tfunction->get_name()); + + bool has_return = !ttype->is_void(); + bool has_args = arglist->get_members().size() == 0; + bool has_xceptions = xlist->get_members().size() == 0; + return "gboolean " + this->nspace_lc + fname + " (" + this->nspace + service_name_ + "If * iface" + + (has_return ? ", " + type_name(ttype) + "* _return" : "") + + (has_args ? "" : (", " + argument_list(arglist))) + + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError ** error)"; +} + +/** + * Renders a field list + * + * @param tstruct The struct definition + * @return Comma sepearated list of all field names in that struct + */ +string t_c_glib_generator::argument_list(t_struct* tstruct) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + result += type_name((*f_iter)->get_type(), false, true) + " " + (*f_iter)->get_name(); + } + return result; +} + +/** + * Renders mutable exception lists + * + * @param tstruct The struct definition + * @return Comma sepearated list of all field names in that struct + */ +string t_c_glib_generator::xception_list(t_struct* tstruct) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + result += type_name((*f_iter)->get_type(), false, false) + "* " + (*f_iter)->get_name(); + } + return result; +} + +/** + * Declares a field, including any necessary initialization. + */ +string t_c_glib_generator::declare_field(t_field* tfield, + bool init, + bool pointer, + bool constant, + bool reference) { + string result = ""; + if (constant) { + result += "const "; + } + result += type_name(tfield->get_type()); + if (pointer) { + result += "*"; + } + if (reference) { + result += "*"; + } + result += " " + tfield->get_name(); + if (init) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + break; + case t_base_type::TYPE_BOOL: + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + result += " = 0"; + break; + case t_base_type::TYPE_DOUBLE: + result += " = (gdouble) 0"; + break; + case t_base_type::TYPE_STRING: + result += " = NULL"; + break; + default: + throw "compiler error: no C intializer for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + result += " = (" + type_name(type) + ") 0"; + } else if (type->is_struct() || type->is_container()) { + result += " = NULL"; + } + } + + if (!reference) { + result += ";"; + } + + return result; +} + +string t_c_glib_generator::constant_value_with_storage(string fname, + t_type* etype, + t_const_value* value) { + ostringstream render; + if (is_numeric(etype)) { + render << " " << type_name(etype) << " *" << fname << " = " + << "g_new (" << base_type_name(etype) << ", 1);" << endl + << " *" << fname << " = " << constant_value(fname, (t_type*)etype, value) << ";" + << endl; + } else { + render << " " << type_name(etype) << " " << fname << " = " + << constant_value(fname, (t_type*)etype, value) << ";" << endl; + } + return render.str(); +} + +/** + * Generates C code that initializes complex constants. + */ +void t_c_glib_generator::generate_const_initializer(string name, + t_type* type, + t_const_value* value, + bool top_level) { + string name_u = initial_caps_to_underscores(name); + string name_lc = to_lower_case(name_u); + string type_u = initial_caps_to_underscores(type->get_name()); + string type_uc = to_upper_case(type_u); + string maybe_static = top_level ? "" : "static "; + + if (type->is_struct() || type->is_xception()) { + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + ostringstream initializers; + + // initialize any constants that may be referenced by this initializer + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + string field_name = ""; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + field_name = (*f_iter)->get_name(); + break; + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + + v_iter->first->get_string(); + } + field_name = tmp(field_name); + + generate_const_initializer(name + "_constant_" + field_name, + field_type, + v_iter->second); + initializers << " constant->" << v_iter->first->get_string() << " = " + << constant_value(name + "_constant_" + field_name, + field_type, + v_iter->second) << ";" << endl + << " constant->__isset_" << v_iter->first->get_string() + << " = TRUE;" << endl; + } + + // implement the initializer + f_types_impl_ << maybe_static << this->nspace << type->get_name() << " *" + << endl + << this->nspace_lc << name_lc << "_constant (void)" << endl; + scope_up(f_types_impl_); + f_types_impl_ << indent() << "static " << this->nspace << type->get_name() + << " *constant = NULL;" << endl + << indent() << "if (constant == NULL)" << endl; + scope_up(f_types_impl_); + f_types_impl_ << indent() << "constant = g_object_new (" << this->nspace_uc + << "TYPE_" << type_uc << ", NULL);" << endl + << initializers.str(); + scope_down(f_types_impl_); + + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + string field_name = ""; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + field_name = (*f_iter)->get_name(); + break; + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + + v_iter->first->get_string(); + } + field_name = tmp(field_name); + } + + f_types_impl_ << indent() << "return constant;" << endl; + scope_down(f_types_impl_); + f_types_impl_ << endl; + } else if (type->is_list()) { + string list_type = "GPtrArray *"; + string free_func + = generate_free_func_from_type(reinterpret_cast(type)->get_elem_type()); + string list_initializer = "g_ptr_array_new_with_free_func (" + free_func + ");"; + string list_appender = "g_ptr_array_add"; + bool list_variable = false; + + t_type* etype = ((t_list*)type)->get_elem_type(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + ostringstream initializers; + ostringstream appenders; + + list_initializer = generate_new_array_from_type(etype); + if (etype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)etype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot determine array type"; + case t_base_type::TYPE_BOOL: + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + case t_base_type::TYPE_DOUBLE: + list_type = "GArray *"; + list_appender = "g_array_append_val"; + list_variable = true; + break; + case t_base_type::TYPE_STRING: + break; + default: + throw "compiler error: no array info for type"; + } + } else if (etype->is_enum()) { + list_type = "GArray *"; + list_appender = "g_array_append_val"; + list_variable = true; + } + + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string fname = tmp(name); + + generate_const_initializer(fname, etype, (*v_iter)); + if (list_variable) { + initializers << " " << type_name(etype) << " " << fname << " = " + << constant_value(fname, (t_type*)etype, (*v_iter)) << ";" + << endl; + appenders << " " << list_appender << "(constant, " << fname << ");" + << endl; + } else { + appenders << " " << list_appender << "(constant, " + << constant_value(fname, (t_type*)etype, (*v_iter)) << ");" + << endl; + } + } + + f_types_impl_ << maybe_static << list_type << endl + << this->nspace_lc << name_lc << "_constant (void)" << endl; + scope_up(f_types_impl_); + f_types_impl_ << indent() << "static " << list_type << " constant = NULL;" + << endl + << indent() << "if (constant == NULL)" << endl; + scope_up(f_types_impl_); + if (!initializers.str().empty()) { + f_types_impl_ << initializers.str() + << endl; + } + f_types_impl_ << indent() << "constant = " << list_initializer << endl + << appenders.str(); + scope_down(f_types_impl_); + f_types_impl_ << indent() << "return constant;" << endl; + scope_down(f_types_impl_); + f_types_impl_ << endl; + } else if (type->is_set()) { + t_type* etype = ((t_set*)type)->get_elem_type(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + ostringstream initializers; + ostringstream appenders; + + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string fname = tmp(name); + string ptr = is_numeric(etype) ? "*" : ""; + generate_const_initializer(fname, etype, (*v_iter)); + initializers << constant_value_with_storage(fname, (t_type*)etype, *v_iter); + appenders << " g_hash_table_insert (constant, " << fname << ", 0);" << endl; + } + + f_types_impl_ << maybe_static << "GHashTable *" << endl + << this->nspace_lc << name_lc << "_constant (void)" << endl; + scope_up(f_types_impl_); + f_types_impl_ << indent() << "static GHashTable *constant = NULL;" << endl + << indent() << "if (constant == NULL)" << endl; + scope_up(f_types_impl_); + f_types_impl_ << initializers.str() << endl + << indent() << "constant = " << generate_new_hash_from_type(etype, NULL) << endl + << appenders.str(); + scope_down(f_types_impl_); + f_types_impl_ << indent() << "return constant;" << endl; + scope_down(f_types_impl_); + f_types_impl_ << endl; + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + ostringstream initializers; + ostringstream appenders; + + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string fname = tmp(name); + string kname = fname + "key"; + string vname = fname + "val"; + generate_const_initializer(kname, ktype, v_iter->first); + generate_const_initializer(vname, vtype, v_iter->second); + + initializers << constant_value_with_storage(kname, (t_type*)ktype, v_iter->first); + initializers << constant_value_with_storage(vname, (t_type*)vtype, v_iter->second); + appenders << " g_hash_table_insert (constant, " << kname << ", " << vname << ");" << endl; + } + + f_types_impl_ << maybe_static << "GHashTable *" << endl + << this->nspace_lc << name_lc << "_constant (void)" << endl; + scope_up(f_types_impl_); + f_types_impl_ << indent() << "static GHashTable *constant = NULL;" << endl + << indent() << "if (constant == NULL)" << endl; + scope_up(f_types_impl_); + f_types_impl_ << initializers.str() << endl + << indent() << "constant = " << generate_new_hash_from_type(ktype, vtype) << endl + << appenders.str(); + scope_down(f_types_impl_); + f_types_impl_ << indent() << "return constant;" << endl; + scope_down(f_types_impl_); + f_types_impl_ << endl; + } +} + +/** + * Generates helper classes for a service, consisting of a ThriftStruct subclass + * for the arguments to and the result from each method. + * + * @param tservice The service for which to generate helper classes + */ +void t_c_glib_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator function_iter; + + // Iterate through the service's methods + for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { + string function_name = (*function_iter)->get_name(); + t_struct* arg_list = (*function_iter)->get_arglist(); + string arg_list_name_orig = arg_list->get_name(); + + // Generate the arguments class + arg_list->set_name(tservice->get_name() + underscores_to_initial_caps(function_name) + "Args"); + generate_struct(arg_list); + + arg_list->set_name(arg_list_name_orig); + + // Generate the result class + if (!(*function_iter)->is_oneway()) { + t_struct result(program_, + tservice->get_name() + underscores_to_initial_caps(function_name) + "Result"); + t_field success((*function_iter)->get_returntype(), "success", 0); + success.set_req(t_field::T_OPTIONAL); + if (!(*function_iter)->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = (*function_iter)->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator field_iter; + for (field_iter = fields.begin(); field_iter != fields.end(); ++field_iter) { + (*field_iter)->set_req(t_field::T_OPTIONAL); + result.append(*field_iter); + } + + generate_struct(&result); + } + } +} + +/** + * Generates C code that represents a Thrift service client. + */ +void t_c_glib_generator::generate_service_client(t_service* tservice) { + /* get some C friendly service names */ + string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_)); + string service_name_uc = to_upper_case(service_name_lc); + + string parent_service_name; + string parent_service_name_lc; + string parent_service_name_uc; + + string parent_class_name = "GObject"; + string parent_type_name = "G_TYPE_OBJECT"; + + // The service this service extends, or NULL if it extends no + // service + t_service* extends_service = tservice->get_extends(); + if (extends_service) { + // The name of the parent service + parent_service_name = extends_service->get_name(); + parent_service_name_lc = to_lower_case(initial_caps_to_underscores(parent_service_name)); + parent_service_name_uc = to_upper_case(parent_service_name_lc); + + // The names of the client class' parent class and type + parent_class_name = this->nspace + parent_service_name + "Client"; + parent_type_name = this->nspace_uc + "TYPE_" + parent_service_name_uc + "_CLIENT"; + } + + // The base service (the topmost in the "extends" hierarchy), on + // whose client class the "input_protocol" and "output_protocol" + // properties are defined + t_service* base_service = tservice; + while (base_service->get_extends()) { + base_service = base_service->get_extends(); + } + + string base_service_name = base_service->get_name(); + string base_service_name_lc = to_lower_case(initial_caps_to_underscores(base_service_name)); + string base_service_name_uc = to_upper_case(base_service_name_lc); + + // Generate the client interface dummy object in the header. + f_header_ << "/* " << service_name_ << " service interface */" << endl << "typedef struct _" + << this->nspace << service_name_ << "If " << this->nspace << service_name_ << "If; " + << " /* dummy object */" << endl << endl; + + // Generate the client interface object in the header. + f_header_ << "struct _" << this->nspace << service_name_ << "IfInterface" << endl << "{" << endl + << " GTypeInterface parent;" << endl << endl; + + /* write out the functions for this interface */ + indent_up(); + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + /* make the function name C friendly */ + string funname = initial_caps_to_underscores((*f_iter)->get_name()); + t_type* ttype = (*f_iter)->get_returntype(); + t_struct* arglist = (*f_iter)->get_arglist(); + t_struct* xlist = (*f_iter)->get_xceptions(); + bool has_return = !ttype->is_void(); + bool has_args = arglist->get_members().size() == 0; + bool has_xceptions = xlist->get_members().size() == 0; + + string params = "(" + this->nspace + service_name_ + "If *iface" + + (has_return ? ", " + type_name(ttype) + "* _return" : "") + + (has_args ? "" : (", " + argument_list(arglist))) + + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError **error)"; + + indent(f_header_) << "gboolean (*" << funname << ") " << params << ";" << endl; + } + indent_down(); + + f_header_ << "};" << endl << "typedef struct _" << this->nspace << service_name_ << "IfInterface " + << this->nspace << service_name_ << "IfInterface;" << endl << endl; + + // generate all the interface boilerplate + f_header_ << "GType " << this->nspace_lc << service_name_lc << "_if_get_type (void);" << endl + << "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_IF " + << "(" << this->nspace_lc << service_name_lc << "_if_get_type())" << endl << "#define " + << this->nspace_uc << service_name_uc << "_IF(obj) " + << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" + << service_name_uc << "_IF, " << this->nspace << service_name_ << "If))" << endl + << "#define " << this->nspace_uc << "IS_" << service_name_uc << "_IF(obj) " + << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_" + << service_name_uc << "_IF))" << endl << "#define " << this->nspace_uc + << service_name_uc << "_IF_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), " + << this->nspace_uc << "TYPE_" << service_name_uc << "_IF, " << this->nspace + << service_name_ << "IfInterface))" << endl << endl; + + // write out all the interface function prototypes + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + /* make the function name C friendly */ + string funname = initial_caps_to_underscores((*f_iter)->get_name()); + t_type* ttype = (*f_iter)->get_returntype(); + t_struct* arglist = (*f_iter)->get_arglist(); + t_struct* xlist = (*f_iter)->get_xceptions(); + bool has_return = !ttype->is_void(); + bool has_args = arglist->get_members().size() == 0; + bool has_xceptions = xlist->get_members().size() == 0; + + string params = "(" + this->nspace + service_name_ + "If *iface" + + (has_return ? ", " + type_name(ttype) + "* _return" : "") + + (has_args ? "" : (", " + argument_list(arglist))) + + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError **error)"; + + f_header_ << "gboolean " << this->nspace_lc << service_name_lc << "_if_" << funname << " " + << params << ";" << endl; + } + f_header_ << endl; + + // Generate the client object instance definition in the header. + f_header_ << "/* " << service_name_ << " service client */" << endl << "struct _" << this->nspace + << service_name_ << "Client" << endl << "{" << endl << " " << parent_class_name + << " parent;" << endl; + if (!extends_service) { + // Define "input_protocol" and "output_protocol" properties only + // for base services; child service-client classes will inherit + // these + f_header_ << endl << " ThriftProtocol *input_protocol;" << endl + << " ThriftProtocol *output_protocol;" << endl; + } + f_header_ << "};" << endl << "typedef struct _" << this->nspace << service_name_ << "Client " + << this->nspace << service_name_ << "Client;" << endl << endl; + + // Generate the class definition in the header. + f_header_ << "struct _" << this->nspace << service_name_ << "ClientClass" << endl << "{" << endl + << " " << parent_class_name << "Class parent;" << endl << "};" << endl + << "typedef struct _" << this->nspace << service_name_ << "ClientClass " << this->nspace + << service_name_ << "ClientClass;" << endl << endl; + + // Create all the GObject boilerplate + f_header_ << "GType " << this->nspace_lc << service_name_lc << "_client_get_type (void);" << endl + << "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT " + << "(" << this->nspace_lc << service_name_lc << "_client_get_type())" << endl + << "#define " << this->nspace_uc << service_name_uc << "_CLIENT(obj) " + << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" + << service_name_uc << "_CLIENT, " << this->nspace << service_name_ << "Client))" << endl + << "#define " << this->nspace_uc << service_name_uc << "_CLIENT_CLASS(c) " + << "(G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_" << service_name_uc + << "_CLIENT, " << this->nspace << service_name_ << "ClientClass))" << endl << "#define " + << this->nspace_uc << service_name_uc << "_IS_CLIENT(obj) " + << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_" + << service_name_uc << "_CLIENT))" << endl << "#define " << this->nspace_uc + << service_name_uc << "_IS_CLIENT_CLASS(c) " + << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << service_name_uc + << "_CLIENT))" << endl << "#define " << this->nspace_uc << service_name_uc + << "_CLIENT_GET_CLASS(obj) " + << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_" + << service_name_uc << "_CLIENT, " << this->nspace << service_name_ << "ClientClass))" + << endl << endl; + + /* write out the function prototypes */ + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + /* make the function name C friendly */ + string funname = to_lower_case(initial_caps_to_underscores((*f_iter)->get_name())); + + t_function service_function((*f_iter)->get_returntype(), + service_name_lc + string("_client_") + funname, + (*f_iter)->get_arglist(), + (*f_iter)->get_xceptions()); + indent(f_header_) << function_signature(&service_function) << ";" << endl; + + t_function send_function(g_type_void, + service_name_lc + string("_client_send_") + funname, + (*f_iter)->get_arglist()); + indent(f_header_) << function_signature(&send_function) << ";" << endl; + + // implement recv if not a oneway service + if (!(*f_iter)->is_oneway()) { + t_struct noargs(program_); + t_function recv_function((*f_iter)->get_returntype(), + service_name_lc + string("_client_recv_") + funname, + &noargs, + (*f_iter)->get_xceptions()); + indent(f_header_) << function_signature(&recv_function) << ";" << endl; + } + } + + /* write out the get/set function prototypes */ + f_header_ << "void " + service_name_lc + "_client_set_property (GObject *object, guint " + "property_id, const GValue *value, GParamSpec *pspec);" + << endl; + f_header_ << "void " + service_name_lc + "_client_get_property (GObject *object, guint " + "property_id, GValue *value, GParamSpec *pspec);" + << endl; + + f_header_ << endl; + // end of header code + + // Generate interface method implementations + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + /* make the function name C friendly */ + string funname = initial_caps_to_underscores((*f_iter)->get_name()); + t_type* ttype = (*f_iter)->get_returntype(); + t_struct* arglist = (*f_iter)->get_arglist(); + t_struct* xlist = (*f_iter)->get_xceptions(); + bool has_return = !ttype->is_void(); + bool has_args = arglist->get_members().size() == 0; + bool has_xceptions = xlist->get_members().size() == 0; + + string params = "(" + this->nspace + service_name_ + "If *iface" + + (has_return ? ", " + type_name(ttype) + "* _return" : "") + + (has_args ? "" : (", " + argument_list(arglist))) + + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError **error)"; + + string params_without_type = string("iface, ") + (has_return ? "_return, " : ""); + + const vector& fields = arglist->get_members(); + vector::const_iterator f_iter_field; + for (f_iter_field = fields.begin(); f_iter_field != fields.end(); ++f_iter_field) { + params_without_type += (*f_iter_field)->get_name(); + params_without_type += ", "; + } + + const vector& xceptions = xlist->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + params_without_type += (*x_iter)->get_name(); + params_without_type += ", "; + } + + f_service_ << "gboolean" << endl << this->nspace_lc << service_name_lc << "_if_" << funname + << " " << params << endl << "{" << endl << " return " << this->nspace_uc + << service_name_uc << "_IF_GET_INTERFACE (iface)->" << funname << " (" + << params_without_type << "error);" << endl << "}" << endl << endl; + } + + // Generate interface boilerplate + f_service_ << "GType" << endl << this->nspace_lc << service_name_lc << "_if_get_type (void)" + << endl << "{" << endl << " static GType type = 0;" << endl << " if (type == 0)" + << endl << " {" << endl << " static const GTypeInfo type_info =" << endl << " {" + << endl << " sizeof (" << this->nspace << service_name_ << "IfInterface)," << endl + << " NULL, /* base_init */" << endl << " NULL, /* base_finalize */" << endl + << " NULL, /* class_init */" << endl << " NULL, /* class_finalize */" + << endl << " NULL, /* class_data */" << endl + << " 0, /* instance_size */" << endl << " 0, /* n_preallocs */" + << endl << " NULL, /* instance_init */" << endl + << " NULL /* value_table */" << endl << " };" << endl + << " type = g_type_register_static (G_TYPE_INTERFACE," << endl + << " \"" << this->nspace << service_name_ << "If\"," + << endl << " &type_info, 0);" << endl << " }" + << endl << " return type;" << endl << "}" << endl << endl; + + // Generate client boilerplate + f_service_ << "static void " << endl << this->nspace_lc << service_name_lc + << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface);" + << endl << endl << "G_DEFINE_TYPE_WITH_CODE (" << this->nspace << service_name_ + << "Client, " << this->nspace_lc << service_name_lc << "_client," << endl + << " " << parent_type_name << ", " << endl + << " G_IMPLEMENT_INTERFACE (" << this->nspace_uc << "TYPE_" + << service_name_uc << "_IF," << endl + << " " << this->nspace_lc + << service_name_lc << "_if_interface_init))" << endl << endl; + + // Generate property-related code only for base services---child + // service-client classes have only properties inherited from their + // parent class + if (!extends_service) { + // Generate client properties + f_service_ << "enum _" << this->nspace << service_name_ << "ClientProperties" << endl << "{" + << endl << " PROP_0," << endl << " PROP_" << this->nspace_uc << service_name_uc + << "_CLIENT_INPUT_PROTOCOL," << endl << " PROP_" << this->nspace_uc + << service_name_uc << "_CLIENT_OUTPUT_PROTOCOL" << endl << "};" << endl << endl; + + // generate property setter + f_service_ << "void" << endl << this->nspace_lc << service_name_lc << "_client_set_property (" + << "GObject *object, guint property_id, const GValue *value, " + << "GParamSpec *pspec)" << endl << "{" << endl << " " << this->nspace + << service_name_ << "Client *client = " << this->nspace_uc << service_name_uc + << "_CLIENT (object);" << endl << endl << " THRIFT_UNUSED_VAR (pspec);" << endl + << endl << " switch (property_id)" << endl << " {" << endl << " case PROP_" + << this->nspace_uc << service_name_uc << "_CLIENT_INPUT_PROTOCOL:" << endl + << " client->input_protocol = g_value_get_object (value);" << endl + << " break;" << endl << " case PROP_" << this->nspace_uc << service_name_uc + << "_CLIENT_OUTPUT_PROTOCOL:" << endl + << " client->output_protocol = g_value_get_object (value);" << endl + << " break;" << endl << " }" << endl << "}" << endl << endl; + + // generate property getter + f_service_ << "void" << endl << this->nspace_lc << service_name_lc << "_client_get_property (" + << "GObject *object, guint property_id, GValue *value, " + << "GParamSpec *pspec)" << endl << "{" << endl << " " << this->nspace + << service_name_ << "Client *client = " << this->nspace_uc << service_name_uc + << "_CLIENT (object);" << endl << endl << " THRIFT_UNUSED_VAR (pspec);" << endl + << endl << " switch (property_id)" << endl << " {" << endl << " case PROP_" + << this->nspace_uc << service_name_uc << "_CLIENT_INPUT_PROTOCOL:" << endl + << " g_value_set_object (value, client->input_protocol);" << endl + << " break;" << endl << " case PROP_" << this->nspace_uc << service_name_uc + << "_CLIENT_OUTPUT_PROTOCOL:" << endl + << " g_value_set_object (value, client->output_protocol);" << endl + << " break;" << endl << " }" << endl << "}" << endl << endl; + } + + // Generate client method implementations + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string name = (*f_iter)->get_name(); + string funname = initial_caps_to_underscores(name); + + // Get the struct of function call params and exceptions + t_struct* arg_struct = (*f_iter)->get_arglist(); + + // Function for sending + t_function send_function(g_type_void, + service_name_lc + string("_client_send_") + funname, + (*f_iter)->get_arglist()); + + // Open the send function + indent(f_service_) << function_signature(&send_function) << endl; + scope_up(f_service_); + + string reqType = (*f_iter)->is_oneway() ? "T_ONEWAY" : "T_CALL"; + + // Serialize the request + f_service_ << indent() << "gint32 cseqid = 0;" << endl << indent() + << "ThriftProtocol * protocol = " << this->nspace_uc << base_service_name_uc + << "_CLIENT (iface)->output_protocol;" << endl << endl << indent() + << "if (thrift_protocol_write_message_begin (protocol, \"" << name << "\", " + << reqType << ", cseqid, error) < 0)" << endl << indent() << " return FALSE;" + << endl << endl; + + generate_struct_writer(f_service_, arg_struct, "", "", false); + + f_service_ << indent() << "if (thrift_protocol_write_message_end (protocol, error) < 0)" << endl + << indent() << " return FALSE;" << endl << indent() + << "if (!thrift_transport_flush (protocol->transport, error))" << endl << indent() + << " return FALSE;" << endl << indent() + << "if (!thrift_transport_write_end (protocol->transport, error))" << endl + << indent() << " return FALSE;" << endl << endl << indent() << "return TRUE;" + << endl; + + scope_down(f_service_); + f_service_ << endl; + + // Generate recv function only if not an async function + if (!(*f_iter)->is_oneway()) { + t_struct noargs(program_); + t_function recv_function((*f_iter)->get_returntype(), + service_name_lc + string("_client_recv_") + funname, + &noargs, + (*f_iter)->get_xceptions()); + // Open function + indent(f_service_) << function_signature(&recv_function) << endl; + scope_up(f_service_); + + f_service_ << indent() << "gint32 rseqid;" << endl + << indent() << "gchar * fname = NULL;" << endl + << indent() << "ThriftMessageType mtype;" << endl + << indent() << "ThriftProtocol * protocol = " + << this->nspace_uc << base_service_name_uc + << "_CLIENT (iface)->input_protocol;" << endl + << indent() << "ThriftApplicationException *xception;" << endl + << endl + << indent() << "if (thrift_protocol_read_message_begin " + "(protocol, &fname, &mtype, &rseqid, error) < 0) {" << endl; + indent_up(); + f_service_ << indent() << "if (fname) g_free (fname);" << endl + << indent() << "return FALSE;" << endl; + indent_down(); + f_service_ << indent() << "}" << endl + << endl + << indent() << "if (mtype == T_EXCEPTION) {" << endl; + indent_up(); + f_service_ << indent() << "if (fname) g_free (fname);" << endl + << indent() << "xception = g_object_new " + "(THRIFT_TYPE_APPLICATION_EXCEPTION, NULL);" << endl + << indent() << "thrift_struct_read (THRIFT_STRUCT (xception), " + "protocol, NULL);" << endl + << indent() << "thrift_protocol_read_message_end " + "(protocol, NULL);" << endl + << indent() << "thrift_transport_read_end " + "(protocol->transport, NULL);" << endl + << indent() << "g_set_error (error, " + "THRIFT_APPLICATION_EXCEPTION_ERROR,xception->type, " + "\"application error: %s\", xception->message);" << endl + << indent() << "g_object_unref (xception);" << endl + << indent() << "return FALSE;" << endl; + indent_down(); + f_service_ << indent() << "} else if (mtype != T_REPLY) {" << endl; + indent_up(); + f_service_ << indent() << "if (fname) g_free (fname);" << endl + << indent() << "thrift_protocol_skip (protocol, T_STRUCT, " + "NULL);" << endl + << indent() << "thrift_protocol_read_message_end (protocol, " + "NULL);" << endl + << indent() << "thrift_transport_read_end (" + "protocol->transport, NULL);" << endl + << indent() << "g_set_error (error, " + "THRIFT_APPLICATION_EXCEPTION_ERROR, " + "THRIFT_APPLICATION_EXCEPTION_ERROR_INVALID_MESSAGE_TYPE, " + "\"invalid message type %d, expected T_REPLY\", mtype);" + << endl + << indent() << "return FALSE;" << endl; + indent_down(); + f_service_ << indent() << "} else if (strncmp (fname, \"" << name + << "\", " << name.length() << ") != 0) {" << endl; + indent_up(); + f_service_ << indent() << "thrift_protocol_skip (protocol, T_STRUCT, " + "NULL);" << endl + << indent() << "thrift_protocol_read_message_end (protocol," + "error);" << endl + << indent() << "thrift_transport_read_end (" + "protocol->transport, error);" << endl + << indent() << "g_set_error (error, " + "THRIFT_APPLICATION_EXCEPTION_ERROR, " + "THRIFT_APPLICATION_EXCEPTION_ERROR_WRONG_METHOD_NAME, " + "\"wrong method name %s, expected " << name + << "\", fname);" << endl + << indent() << "if (fname) g_free (fname);" << endl + << indent() << "return FALSE;" << endl; + indent_down(); + f_service_ << indent() << "}" << endl + << indent() << "if (fname) g_free (fname);" << endl + << endl; + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + { + t_struct result(program_, tservice->get_name() + "_" + (*f_iter)->get_name() + "_result"); + t_field success((*f_iter)->get_returntype(), "*_return", 0); + if (!(*f_iter)->get_returntype()->is_void()) { + result.append(&success); + } + + // add readers for exceptions, dereferencing the pointer. + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) { + t_field* xception = new t_field((*x_iter)->get_type(), + "*" + (*x_iter)->get_name(), + (*x_iter)->get_key()); + result.append(xception); + } + + generate_struct_reader(f_service_, &result, "", "", false); + } + + f_service_ << indent() << "if (thrift_protocol_read_message_end (protocol, error) < 0)" + << endl << indent() << " return FALSE;" << endl << endl << indent() + << "if (!thrift_transport_read_end (protocol->transport, error))" << endl + << indent() << " return FALSE;" << endl << endl; + + // copy over any throw exceptions and return failure + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) { + f_service_ << indent() << "if (*" << (*x_iter)->get_name() << " != NULL)" << endl + << indent() << "{" << endl << indent() << " g_set_error (error, " + << this->nspace_uc + << to_upper_case(initial_caps_to_underscores((*x_iter)->get_type()->get_name())) + << "_ERROR, " << this->nspace_uc + << to_upper_case(initial_caps_to_underscores((*x_iter)->get_type()->get_name())) + << "_ERROR_CODE, \"" << (*x_iter)->get_type()->get_name() << "\");" << endl + << indent() << " return FALSE;" << endl << indent() << "}" << endl; + } + // Close function + indent(f_service_) << "return TRUE;" << endl; + scope_down(f_service_); + f_service_ << endl; + } + + // Open function + t_function service_function((*f_iter)->get_returntype(), + service_name_lc + string("_client_") + funname, + (*f_iter)->get_arglist(), + (*f_iter)->get_xceptions()); + indent(f_service_) << function_signature(&service_function) << endl; + scope_up(f_service_); + + // wrap each function + f_service_ << indent() << "if (!" << this->nspace_lc << service_name_lc << "_client_send_" + << funname << " (iface"; + + // Declare the function arguments + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << ", " << (*fld_iter)->get_name(); + } + f_service_ << ", error))" << endl << indent() << " return FALSE;" << endl; + + // if not oneway, implement recv + if (!(*f_iter)->is_oneway()) { + string ret = (*f_iter)->get_returntype()->is_void() ? "" : "_return, "; + + const vector& xceptions = (*f_iter)->get_xceptions()->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + ret += (*x_iter)->get_name(); + ret += ", "; + } + + f_service_ << indent() << "if (!" << this->nspace_lc << service_name_lc << "_client_recv_" + << funname << " (iface, " << ret << "error))" << endl << indent() + << " return FALSE;" << endl; + } + + // return TRUE which means all functions were called OK + indent(f_service_) << "return TRUE;" << endl; + scope_down(f_service_); + f_service_ << endl; + } + + // create the interface initializer + f_service_ << "static void" << endl + << this->nspace_lc << service_name_lc << "_if_interface_init (" + << this->nspace << service_name_ << "IfInterface *iface)" << endl; + scope_up(f_service_); + if (functions.size() > 0) { + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + /* make the function name C friendly */ + string funname = initial_caps_to_underscores((*f_iter)->get_name()); + + f_service_ << indent() << "iface->" << funname << " = " << this->nspace_lc + << service_name_lc << "_client_" << funname << ";" << endl; + } + } + else { + f_service_ << indent() << "THRIFT_UNUSED_VAR (iface);" << endl; + } + scope_down(f_service_); + f_service_ << endl; + + // create the client instance initializer + f_service_ << "static void" << endl + << this->nspace_lc << service_name_lc << "_client_init (" + << this->nspace << service_name_ << "Client *client)" << endl; + scope_up(f_service_); + if (!extends_service) { + f_service_ << indent() << "client->input_protocol = NULL;" << endl + << indent() << "client->output_protocol = NULL;" << endl; + } + else { + f_service_ << indent() << "THRIFT_UNUSED_VAR (client);" << endl; + } + scope_down(f_service_); + f_service_ << endl; + + // create the client class initializer + f_service_ << "static void" << endl << this->nspace_lc << service_name_lc + << "_client_class_init (" << this->nspace << service_name_ << "ClientClass *cls)" + << endl << "{" << endl; + if (!extends_service) { + f_service_ << " GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl + << " GParamSpec *param_spec;" << endl << endl + << " gobject_class->set_property = " << this->nspace_lc << service_name_lc + << "_client_set_property;" << endl + << " gobject_class->get_property = " << this->nspace_lc << service_name_lc + << "_client_get_property;" << endl << endl + << " param_spec = g_param_spec_object (\"input_protocol\"," << endl + << " \"input protocol (construct)\"," << endl + << " \"Set the client input protocol\"," << endl + << " THRIFT_TYPE_PROTOCOL," << endl + << " G_PARAM_READWRITE);" << endl + << " g_object_class_install_property (gobject_class," << endl + << " PROP_" << this->nspace_uc << service_name_uc + << "_CLIENT_INPUT_PROTOCOL, param_spec);" << endl << endl + << " param_spec = g_param_spec_object (\"output_protocol\"," << endl + << " \"output protocol (construct)\"," << endl + << " \"Set the client output protocol\"," << endl + << " THRIFT_TYPE_PROTOCOL," << endl + << " G_PARAM_READWRITE);" << endl + << " g_object_class_install_property (gobject_class," << endl + << " PROP_" << this->nspace_uc << service_name_uc + << "_CLIENT_OUTPUT_PROTOCOL, param_spec);" << endl; + } + else { + f_service_ << " THRIFT_UNUSED_VAR (cls);" << endl; + } + f_service_ << "}" << endl << endl; +} + +/** + * Generates C code that represents a Thrift service handler. + * + * @param tservice The service for which to generate a handler. + */ +void t_c_glib_generator::generate_service_handler(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::const_iterator function_iter; + + string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_)); + string service_name_uc = to_upper_case(service_name_lc); + + string class_name = this->nspace + service_name_ + "Handler"; + string class_name_lc = to_lower_case(initial_caps_to_underscores(class_name)); + string class_name_uc = to_upper_case(class_name_lc); + + string parent_class_name; + string parent_type_name; + + string args_indent; + + // The service this service extends, or NULL if it extends no service + t_service* extends_service = tservice->get_extends(); + + // Determine the name of our parent service (if any) and the handler class' + // parent class name and type + if (extends_service) { + string parent_service_name = extends_service->get_name(); + string parent_service_name_lc = to_lower_case(initial_caps_to_underscores(parent_service_name)); + string parent_service_name_uc = to_upper_case(parent_service_name_lc); + + parent_class_name = this->nspace + parent_service_name + "Handler"; + parent_type_name = this->nspace_uc + "TYPE_" + parent_service_name_uc + "_HANDLER"; + } else { + parent_class_name = "GObject"; + parent_type_name = "G_TYPE_OBJECT"; + } + + // Generate the handler class' definition in the header file + + // Generate the handler instance definition + f_header_ << "/* " << service_name_ << " handler (abstract base class) */" << endl << "struct _" + << class_name << endl << "{" << endl; + indent_up(); + f_header_ << indent() << parent_class_name << " parent;" << endl; + indent_down(); + f_header_ << "};" << endl << "typedef struct _" << class_name << " " << class_name << ";" << endl + << endl; + + // Generate the handler class definition, including its class members + // (methods) + f_header_ << "struct _" << class_name << "Class" << endl << "{" << endl; + indent_up(); + f_header_ << indent() << parent_class_name << "Class parent;" << endl << endl; + + for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { + string method_name = initial_caps_to_underscores((*function_iter)->get_name()); + t_type* return_type = (*function_iter)->get_returntype(); + t_struct* arg_list = (*function_iter)->get_arglist(); + t_struct* x_list = (*function_iter)->get_xceptions(); + bool has_return = !return_type->is_void(); + bool has_args = arg_list->get_members().size() == 0; + bool has_xceptions = x_list->get_members().size() == 0; + + string params = "(" + this->nspace + service_name_ + "If *iface" + + (has_return ? ", " + type_name(return_type) + "* _return" : "") + + (has_args ? "" : (", " + argument_list(arg_list))) + + (has_xceptions ? "" : (", " + xception_list(x_list))) + ", GError **error)"; + + indent(f_header_) << "gboolean (*" << method_name << ") " << params << ";" << endl; + } + indent_down(); + + f_header_ << "};" << endl << "typedef struct _" << class_name << "Class " << class_name + << "Class;" << endl << endl; + + // Generate the remaining header boilerplate + f_header_ << "GType " << class_name_lc << "_get_type (void);" << endl << "#define " + << this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER " + << "(" << class_name_lc << "_get_type())" << endl << "#define " << class_name_uc + << "(obj) " + << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" + << service_name_uc << "_HANDLER, " << class_name << "))" << endl << "#define " + << this->nspace_uc << "IS_" << service_name_uc << "_HANDLER(obj) " + << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_" + << service_name_uc << "_HANDLER))" << endl << "#define " << class_name_uc + << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_" + << service_name_uc << "_HANDLER, " << class_name << "Class))" << endl << "#define " + << this->nspace_uc << "IS_" << service_name_uc << "_HANDLER_CLASS(c) " + << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << service_name_uc + << "_HANDLER))" << endl << "#define " << this->nspace_uc << service_name_uc + << "_HANDLER_GET_CLASS(obj) " + << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_" + << service_name_uc << "_HANDLER, " << class_name << "Class))" << endl << endl; + + // Generate the handler class' method definitions + for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { + string method_name = initial_caps_to_underscores((*function_iter)->get_name()); + t_type* return_type = (*function_iter)->get_returntype(); + t_struct* arg_list = (*function_iter)->get_arglist(); + t_struct* x_list = (*function_iter)->get_xceptions(); + bool has_return = !return_type->is_void(); + bool has_args = arg_list->get_members().size() == 0; + bool has_xceptions = x_list->get_members().size() == 0; + + string params = "(" + this->nspace + service_name_ + "If *iface" + + (has_return ? ", " + type_name(return_type) + "* _return" : "") + + (has_args ? "" : (", " + argument_list(arg_list))) + + (has_xceptions ? "" : (", " + xception_list(x_list))) + ", GError **error)"; + + f_header_ << "gboolean " << class_name_lc << "_" << method_name << " " << params << ";" << endl; + } + f_header_ << endl; + + // Generate the handler's implementation in the implementation file + + // Generate the implementation boilerplate + f_service_ << "static void" << endl << class_name_lc << "_" << service_name_lc + << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface);" + << endl << endl; + + args_indent = string(25, ' '); + f_service_ << "G_DEFINE_TYPE_WITH_CODE (" << class_name << ", " << endl << args_indent + << class_name_lc << "," << endl << args_indent << parent_type_name << "," << endl + << args_indent << "G_IMPLEMENT_INTERFACE (" << this->nspace_uc << "TYPE_" + << service_name_uc << "_IF," << endl; + args_indent += string(23, ' '); + f_service_ << args_indent << class_name_lc << "_" << service_name_lc << "_if_interface_init))" + << endl << endl; + + // Generate the handler method implementations + for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { + string function_name = (*function_iter)->get_name(); + string method_name = initial_caps_to_underscores(function_name); + t_type* return_type = (*function_iter)->get_returntype(); + t_struct* arg_list = (*function_iter)->get_arglist(); + t_struct* x_list = (*function_iter)->get_xceptions(); + + const vector& args = arg_list->get_members(); + const vector& xceptions = x_list->get_members(); + + vector::const_iterator field_iter; + + t_function implementing_function(return_type, + service_name_lc + "_handler_" + method_name, + arg_list, + x_list, + (*function_iter)->is_oneway()); + + indent(f_service_) << function_signature(&implementing_function) << endl; + scope_up(f_service_); + f_service_ << indent() << "g_return_val_if_fail (" << this->nspace_uc << "IS_" + << service_name_uc << "_HANDLER (iface), FALSE);" << endl << endl << indent() + << "return " << class_name_uc << "_GET_CLASS (iface)" + << "->" << method_name << " (iface, "; + + if (!return_type->is_void()) { + f_service_ << "_return, "; + } + for (field_iter = args.begin(); field_iter != args.end(); ++field_iter) { + f_service_ << (*field_iter)->get_name() << ", "; + } + for (field_iter = xceptions.begin(); field_iter != xceptions.end(); ++field_iter) { + f_service_ << (*field_iter)->get_name() << ", "; + } + f_service_ << "error);" << endl; + scope_down(f_service_); + f_service_ << endl; + } + + // Generate the handler interface initializer + f_service_ << "static void" << endl << class_name_lc << "_" << service_name_lc + << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface)" + << endl; + scope_up(f_service_); + if (functions.size() > 0) { + for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { + string method_name = initial_caps_to_underscores((*function_iter)->get_name()); + + f_service_ << indent() << "iface->" << method_name << " = " << class_name_lc << "_" + << method_name << ";" << endl; + } + } + else { + f_service_ << "THRIFT_UNUSED_VAR (iface);" << endl; + } + scope_down(f_service_); + f_service_ << endl; + + // Generate the handler instance initializer + f_service_ << "static void" << endl << class_name_lc << "_init (" << class_name << " *self)" + << endl; + scope_up(f_service_); + f_service_ << indent() << "THRIFT_UNUSED_VAR (self);" << endl; + scope_down(f_service_); + f_service_ << endl; + + // Generate the handler class initializer + f_service_ << "static void" << endl + << class_name_lc << "_class_init (" << class_name << "Class *cls)" + << endl; + scope_up(f_service_); + if (functions.size() > 0) { + for (function_iter = functions.begin(); + function_iter != functions.end(); + ++function_iter) { + string function_name = (*function_iter)->get_name(); + string method_name = initial_caps_to_underscores(function_name); + + // All methods are pure virtual and must be implemented by subclasses + f_service_ << indent() << "cls->" << method_name << " = NULL;" << endl; + } + } + else { + f_service_ << indent() << "THRIFT_UNUSED_VAR (cls);" << endl; + } + scope_down(f_service_); + f_service_ << endl; +} + +/** + * Generates C code that represents a Thrift service processor. + * + * @param tservice The service for which to generate a processor + */ +void t_c_glib_generator::generate_service_processor(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::const_iterator function_iter; + + string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_)); + string service_name_uc = to_upper_case(service_name_lc); + + string class_name = this->nspace + service_name_ + "Processor"; + string class_name_lc = to_lower_case(initial_caps_to_underscores(class_name)); + string class_name_uc = to_upper_case(class_name_lc); + + string parent_class_name; + string parent_type_name; + + string handler_class_name = this->nspace + service_name_ + "Handler"; + string handler_class_name_lc = initial_caps_to_underscores(handler_class_name); + + string process_function_type_name = class_name + "ProcessFunction"; + string process_function_def_type_name = + class_name_lc + "_process_function_def"; + + string function_name; + string args_indent; + + // The service this service extends, or NULL if it extends no service + t_service* extends_service = tservice->get_extends(); + + // Determine the name of our parent service (if any) and the + // processor class' parent class name and type + if (extends_service) { + string parent_service_name = extends_service->get_name(); + string parent_service_name_lc = to_lower_case(initial_caps_to_underscores(parent_service_name)); + string parent_service_name_uc = to_upper_case(parent_service_name_lc); + + parent_class_name = this->nspace + parent_service_name + "Processor"; + parent_type_name = this->nspace_uc + "TYPE_" + parent_service_name_uc + "_PROCESSOR"; + } else { + parent_class_name = "ThriftDispatchProcessor"; + parent_type_name = "THRIFT_TYPE_DISPATCH_PROCESSOR"; + } + + // Generate the processor class' definition in the header file + + // Generate the processor instance definition + f_header_ << "/* " << service_name_ << " processor */" << endl << "struct _" << class_name << endl + << "{" << endl; + indent_up(); + f_header_ << indent() << parent_class_name << " parent;" << endl << endl << indent() + << "/* protected */" << endl << indent() + << this->nspace + service_name_ + "Handler *handler;" << endl << indent() + << "GHashTable *process_map;" << endl; + indent_down(); + f_header_ << "};" << endl << "typedef struct _" << class_name << " " << class_name << ";" << endl + << endl; + + // Generate the processor class definition + f_header_ << "struct _" << class_name << "Class" << endl << "{" << endl; + indent_up(); + f_header_ << indent() << parent_class_name << "Class parent;" << endl << endl << indent() + << "/* protected */" << endl << indent() + << "gboolean (*dispatch_call) (ThriftDispatchProcessor *processor," << endl; + args_indent = indent() + string(27, ' '); + f_header_ << args_indent << "ThriftProtocol *in," << endl << args_indent << "ThriftProtocol *out," + << endl << args_indent << "gchar *fname," << endl << args_indent << "gint32 seqid," + << endl << args_indent << "GError **error);" << endl; + indent_down(); + f_header_ << "};" << endl << "typedef struct _" << class_name << "Class " << class_name + << "Class;" << endl << endl; + + // Generate the remaining header boilerplate + f_header_ << "GType " << class_name_lc << "_get_type (void);" << endl << "#define " + << this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR " + << "(" << class_name_lc << "_get_type())" << endl << "#define " << class_name_uc + << "(obj) " + << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" + << service_name_uc << "_PROCESSOR, " << class_name << "))" << endl << "#define " + << this->nspace_uc << "IS_" << service_name_uc << "_PROCESSOR(obj) " + << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_" + << service_name_uc << "_PROCESSOR))" << endl << "#define " << class_name_uc + << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_" + << service_name_uc << "_PROCESSOR, " << class_name << "Class))" << endl << "#define " + << this->nspace_uc << "IS_" << service_name_uc << "_PROCESSOR_CLASS(c) " + << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << service_name_uc + << "_PROCESSOR))" << endl << "#define " << this->nspace_uc << service_name_uc + << "_PROCESSOR_GET_CLASS(obj) " + << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_" + << service_name_uc << "_PROCESSOR, " << class_name << "Class))" << endl << endl; + + // Generate the processor's implementation in the implementation file + + // Generate the processor's properties enum + f_service_ << "enum _" << class_name << "Properties" << endl << "{" << endl; + indent_up(); + f_service_ << indent() << "PROP_" << class_name_uc << "_0," << endl << indent() << "PROP_" + << class_name_uc << "_HANDLER" << endl; + indent_down(); + f_service_ << "};" << endl << endl; + + // Generate the implementation boilerplate + args_indent = string(15, ' '); + f_service_ << "G_DEFINE_TYPE (" << class_name << "," << endl << args_indent << class_name_lc + << "," << endl << args_indent << parent_type_name << ")" << endl << endl; + + // Generate the processor's processing-function type + args_indent = string(process_function_type_name.length() + 23, ' '); + f_service_ << "typedef gboolean (* " << process_function_type_name << ") (" + << class_name << " *, " << endl + << args_indent << "gint32," << endl + << args_indent << "ThriftProtocol *," << endl + << args_indent << "ThriftProtocol *," << endl + << args_indent << "GError **);" << endl + << endl; + + // Generate the processor's processing-function-definition type + f_service_ << "typedef struct" << endl + << "{" << endl; + indent_up(); + f_service_ << indent() << "gchar *name;" << endl + << indent() << process_function_type_name << " function;" << endl; + indent_down(); + f_service_ << "} " << process_function_def_type_name << ";" << endl + << endl; + + // Generate forward declarations of the processor's processing functions so we + // can refer to them in the processing-function-definition struct below and + // keep all of the processor's declarations in one place + for (function_iter = functions.begin(); + function_iter != functions.end(); + ++function_iter) { + function_name = class_name_lc + "_process_" + + initial_caps_to_underscores((*function_iter)->get_name()); + + args_indent = string(function_name.length() + 2, ' '); + f_service_ << "static gboolean" << endl + << function_name << " (" + << class_name << " *," << endl + << args_indent << "gint32," << endl + << args_indent << "ThriftProtocol *," << endl + << args_indent << "ThriftProtocol *," << endl + << args_indent << "GError **);" << endl; + } + f_service_ << endl; + + // Generate the processor's processing-function definitions, if the service + // defines any methods + if (functions.size() > 0) { + f_service_ << indent() << "static " << process_function_def_type_name + << endl + << indent() << class_name_lc << "_process_function_defs[" + << functions.size() << "] = {" << endl; + indent_up(); + for (function_iter = functions.begin(); + function_iter != functions.end(); + ++function_iter) { + string service_function_name = (*function_iter)->get_name(); + string process_function_name = class_name_lc + "_process_" + + initial_caps_to_underscores(service_function_name); + + f_service_ << indent() << "{" << endl; + indent_up(); + f_service_ << indent() << "\"" << service_function_name << "\"," << endl + << indent() << process_function_name << endl; + indent_down(); + f_service_ << indent() << "}" + << (function_iter == --functions.end() ? "" : ",") << endl; + } + indent_down(); + f_service_ << indent() << "};" << endl + << endl; + } + + // Generate the processor's processing functions + for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { + string service_function_name = (*function_iter)->get_name(); + string service_function_name_ic = underscores_to_initial_caps(service_function_name); + string service_function_name_lc = initial_caps_to_underscores(service_function_name); + string service_function_name_uc = to_upper_case(service_function_name_lc); + + t_type* return_type = (*function_iter)->get_returntype(); + bool has_return_value = !return_type->is_void(); + + t_struct* arg_list = (*function_iter)->get_arglist(); + const vector& args = arg_list->get_members(); + vector::const_iterator arg_iter; + + const vector& xceptions = (*function_iter)->get_xceptions()->get_members(); + vector::const_iterator xception_iter; + + string args_class_name = this->nspace + service_name_ + service_function_name_ic + "Args"; + string args_class_type = this->nspace_uc + "TYPE_" + service_name_uc + "_" + + service_function_name_uc + "_ARGS"; + + string result_class_name = this->nspace + service_name_ + service_function_name_ic + "Result"; + string result_class_type = this->nspace_uc + "TYPE_" + service_name_uc + "_" + + service_function_name_uc + "_RESULT"; + + string handler_function_name = handler_class_name_lc + "_" + service_function_name_lc; + + function_name = class_name_lc + "_process_" + + initial_caps_to_underscores(service_function_name); + + args_indent = string(function_name.length() + 2, ' '); + f_service_ << "static gboolean" << endl << function_name << " (" << class_name << " *self," + << endl << args_indent << "gint32 sequence_id," << endl << args_indent + << "ThriftProtocol *input_protocol," << endl << args_indent + << "ThriftProtocol *output_protocol," << endl << args_indent << "GError **error)" + << endl; + scope_up(f_service_); + f_service_ << indent() << "gboolean result = TRUE;" << endl + << indent() << "ThriftTransport * transport;" << endl + << indent() << "ThriftApplicationException *xception;" << endl + << indent() << args_class_name + " * args =" << endl; + indent_up(); + f_service_ << indent() << "g_object_new (" << args_class_type << ", NULL);" << endl << endl; + indent_down(); + if ((*function_iter)->is_oneway()) { + f_service_ << indent() << "THRIFT_UNUSED_VAR (sequence_id);" << endl << indent() + << "THRIFT_UNUSED_VAR (output_protocol);" << endl << endl; + } + f_service_ << indent() << "g_object_get (input_protocol, \"transport\", " + << "&transport, NULL);" << endl << endl; + + // Read the method's arguments from the caller + f_service_ << indent() << "if ((thrift_struct_read (THRIFT_STRUCT (args), " + << "input_protocol, error) != -1) &&" << endl << indent() + << " (thrift_protocol_read_message_end (input_protocol, " + << "error) != -1) &&" << endl << indent() + << " (thrift_transport_read_end (transport, error) != FALSE))" << endl; + scope_up(f_service_); + + for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) { + f_service_ << indent() << property_type_name((*arg_iter)->get_type()) << " " + << (*arg_iter)->get_name() << ";" << endl; + } + for (xception_iter = xceptions.begin(); xception_iter != xceptions.end(); ++xception_iter) { + f_service_ << indent() << type_name((*xception_iter)->get_type()) << " " + << initial_caps_to_underscores((*xception_iter)->get_name()) << " = NULL;" << endl; + } + if (has_return_value) { + f_service_ << indent() << property_type_name(return_type) << " return_value;" << endl; + } + if (!(*function_iter)->is_oneway()) { + f_service_ << indent() << result_class_name << " * result_struct;" << endl; + } + f_service_ << endl; + + if (args.size() > 0) { + f_service_ << indent() << "g_object_get (args," << endl; + args_indent = indent() + string(14, ' '); + for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) { + string arg_name = (*arg_iter)->get_name(); + + f_service_ << args_indent << "\"" << arg_name << "\", &" << arg_name << "," << endl; + } + f_service_ << args_indent << "NULL);" << endl << endl; + } + + if (!(*function_iter)->is_oneway()) { + f_service_ << indent() << "g_object_unref (transport);" << endl << indent() + << "g_object_get (output_protocol, \"transport\", " + << "&transport, NULL);" << endl << endl << indent() + << "result_struct = g_object_new (" << result_class_type << ", NULL);" << endl; + if (has_return_value) { + f_service_ << indent() << "g_object_get (result_struct, " + "\"success\", &return_value, NULL);" << endl; + } + f_service_ << endl; + } + + // Pass the arguments to the corresponding method in the handler + f_service_ << indent() << "if (" << handler_function_name << " (" << this->nspace_uc + << service_name_uc << "_IF (self->handler)," << endl; + args_indent = indent() + string(handler_function_name.length() + 6, ' '); + if (has_return_value) { + string return_type_name = type_name(return_type); + + f_service_ << args_indent; + + // Cast return_value if it was declared as a type other than the return + // value's actual type---this is true for integer values 32 bits or fewer + // in width, for which GLib requires a plain gint type be used when + // storing or retrieving as an object property + if (return_type_name != property_type_name(return_type)) { + if (return_type_name[return_type_name.length() - 1] != '*') { + return_type_name += ' '; + } + return_type_name += '*'; + + f_service_ << "(" << return_type_name << ")"; + } + + f_service_ << "&return_value," << endl; + } + for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) { + f_service_ << args_indent << (*arg_iter)->get_name() << "," << endl; + } + for (xception_iter = xceptions.begin(); xception_iter != xceptions.end(); ++xception_iter) { + f_service_ << args_indent << "&" << initial_caps_to_underscores((*xception_iter)->get_name()) + << "," << endl; + } + f_service_ << args_indent << "error) == TRUE)" << endl; + scope_up(f_service_); + + // The handler reported success; return the result, if any, to the caller + if (!(*function_iter)->is_oneway()) { + if (has_return_value) { + f_service_ << indent() << "g_object_set (result_struct, \"success\", "; + if (type_name(return_type) != property_type_name(return_type)) { + // Roundtrip cast to fix the position of sign bit. + f_service_ << "(" << property_type_name(return_type) << ")" + << "(" << type_name(return_type) << ")"; + } + f_service_ << "return_value, " + << "NULL);" << endl; + + // Deallocate (or unref) return_value + return_type = get_true_type(return_type); + if (return_type->is_base_type()) { + t_base_type* base_type = ((t_base_type*)return_type); + + if (base_type->get_base() == t_base_type::TYPE_STRING) { + f_service_ << indent() << "if (return_value != NULL)" << endl; + indent_up(); + if (base_type->is_binary()) { + f_service_ << indent() << "g_byte_array_unref (return_value);" << endl; + } else { + f_service_ << indent() << "g_free (return_value);" << endl; + } + indent_down(); + } + } else if (return_type->is_container()) { + f_service_ << indent() << "if (return_value != NULL)" << endl; + indent_up(); + + if (return_type->is_list()) { + t_type* elem_type = ((t_list*)return_type)->get_elem_type(); + + f_service_ << indent(); + if (is_numeric(elem_type)) { + f_service_ << "g_array_unref"; + } else { + f_service_ << "g_ptr_array_unref"; + } + f_service_ << " (return_value);" << endl; + } else if (return_type->is_map() || return_type->is_set()) { + f_service_ << indent() << "g_hash_table_unref (return_value);" << endl; + } + + indent_down(); + } else if (return_type->is_struct()) { + f_service_ << indent() << "if (return_value != NULL)" << endl; + indent_up(); + f_service_ << indent() << "g_object_unref (return_value);" << endl; + indent_down(); + } + + f_service_ << endl; + } + f_service_ << indent() << "result =" << endl; + indent_up(); + f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl; + args_indent = indent() + string(39, ' '); + f_service_ << args_indent << "\"" << service_function_name << "\"," << endl << args_indent + << "T_REPLY," << endl << args_indent << "sequence_id," << endl << args_indent + << "error) != -1) &&" << endl << indent() + << " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << endl; + args_indent = indent() + string(23, ' '); + f_service_ << args_indent << "output_protocol," << endl << args_indent << "error) != -1));" + << endl; + indent_down(); + } + scope_down(f_service_); + f_service_ << indent() << "else" << endl; + scope_up(f_service_); + + // The handler reported failure; check to see if an application-defined + // exception was raised and if so, return it to the caller + f_service_ << indent(); + if (xceptions.size() > 0) { + for (xception_iter = xceptions.begin(); xception_iter != xceptions.end(); ++xception_iter) { + f_service_ << "if (" << initial_caps_to_underscores((*xception_iter)->get_name()) + << " != NULL)" << endl; + scope_up(f_service_); + f_service_ << indent() << "g_object_set (result_struct," << endl; + args_indent = indent() + string(14, ' '); + f_service_ << args_indent << "\"" << (*xception_iter)->get_name() << "\", " + << (*xception_iter)->get_name() << "," << endl << args_indent << "NULL);" << endl + << endl; + f_service_ << indent() << "result =" << endl; + indent_up(); + f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl; + args_indent = indent() + string(39, ' '); + f_service_ << args_indent << "\"" << service_function_name << "\"," << endl << args_indent + << "T_REPLY," << endl << args_indent << "sequence_id," << endl << args_indent + << "error) != -1) &&" << endl << indent() + << " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << endl; + args_indent = indent() + string(23, ' '); + f_service_ << args_indent << "output_protocol," << endl << args_indent << "error) != -1));" + << endl; + indent_down(); + scope_down(f_service_); + f_service_ << indent() << "else" << endl; + } + + scope_up(f_service_); + f_service_ << indent(); + } + + // If the handler reported failure but raised no application-defined + // exception, return a Thrift application exception with the information + // returned via GLib's own error-reporting mechanism + f_service_ << "if (*error == NULL)" << endl; + indent_up(); + f_service_ << indent() << "g_warning (\"" << service_name_ << "." + << (*function_iter)->get_name() << " implementation returned FALSE \"" << endl + << indent() << string(11, ' ') << "\"but did not set an error\");" << endl << endl; + indent_down(); + f_service_ << indent() << "xception =" << endl; + indent_up(); + f_service_ << indent() << "g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION," << endl; + args_indent = indent() + string(14, ' '); + f_service_ << args_indent << "\"type\", *error != NULL ? (*error)->code :" << endl + << args_indent << string(11, ' ') << "THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN," + << endl << args_indent << "\"message\", *error != NULL ? (*error)->message : NULL," + << endl << args_indent << "NULL);" << endl; + indent_down(); + f_service_ << indent() << "g_clear_error (error);" << endl << endl << indent() + << "result =" << endl; + indent_up(); + f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl; + args_indent = indent() + string(39, ' '); + f_service_ << args_indent << "\"" << service_function_name << "\"," << endl << args_indent + << "T_EXCEPTION," << endl << args_indent << "sequence_id," << endl << args_indent + << "error) != -1) &&" << endl << indent() + << " (thrift_struct_write (THRIFT_STRUCT (xception)," << endl; + args_indent = indent() + string(23, ' '); + f_service_ << args_indent << "output_protocol," << endl << args_indent << "error) != -1));" + << endl; + indent_down(); + f_service_ << endl << indent() << "g_object_unref (xception);" << endl; + + if (xceptions.size() > 0) { + scope_down(f_service_); + } + scope_down(f_service_); + f_service_ << endl; + + // Dellocate or unref retrieved argument values as necessary + for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) { + string arg_name = (*arg_iter)->get_name(); + t_type* arg_type = get_true_type((*arg_iter)->get_type()); + + if (arg_type->is_base_type()) { + t_base_type* base_type = ((t_base_type*)arg_type); + + if (base_type->get_base() == t_base_type::TYPE_STRING) { + f_service_ << indent() << "if (" << arg_name << " != NULL)" << endl; + indent_up(); + if (base_type->is_binary()) { + f_service_ << indent() << "g_byte_array_unref (" << arg_name << ");" << endl; + } else { + f_service_ << indent() << "g_free (" << arg_name << ");" << endl; + } + indent_down(); + } + } else if (arg_type->is_container()) { + f_service_ << indent() << "if (" << arg_name << " != NULL)" << endl; + indent_up(); + + if (arg_type->is_list()) { + t_type* elem_type = ((t_list*)arg_type)->get_elem_type(); + + f_service_ << indent(); + if (is_numeric(elem_type)) { + f_service_ << "g_array_unref"; + } else { + f_service_ << "g_ptr_array_unref"; + } + f_service_ << " (" << arg_name << ");" << endl; + } else if (arg_type->is_map() || arg_type->is_set()) { + f_service_ << indent() << "g_hash_table_unref (" << arg_name << ");" << endl; + } + + indent_down(); + } else if (arg_type->is_struct()) { + f_service_ << indent() << "if (" << arg_name << " != NULL)" << endl; + indent_up(); + f_service_ << indent() << "g_object_unref (" << arg_name << ");" << endl; + indent_down(); + } + } + + if (!(*function_iter)->is_oneway()) { + f_service_ << indent() << "g_object_unref (result_struct);" << endl << endl << indent() + << "if (result == TRUE)" << endl; + indent_up(); + f_service_ << indent() << "result =" << endl; + indent_up(); + f_service_ << indent() << "((thrift_protocol_write_message_end " + << "(output_protocol, error) != -1) &&" << endl << indent() + << " (thrift_transport_write_end (transport, error) " + << "!= FALSE) &&" << endl << indent() + << " (thrift_transport_flush (transport, error) " + << "!= FALSE));" << endl; + indent_down(); + indent_down(); + } + scope_down(f_service_); + f_service_ << indent() << "else" << endl; + indent_up(); + f_service_ << indent() << "result = FALSE;" << endl; + indent_down(); + + f_service_ << endl << indent() << "g_object_unref (transport);" << endl << indent() + << "g_object_unref (args);" << endl << endl << indent() << "return result;" << endl; + scope_down(f_service_); + + f_service_ << endl; + } + + // Generate the processor's dispatch_call implementation + function_name = class_name_lc + "_dispatch_call"; + args_indent = indent() + string(function_name.length() + 2, ' '); + f_service_ << "static gboolean" << endl << function_name + << " (ThriftDispatchProcessor *dispatch_processor," << endl << args_indent + << "ThriftProtocol *input_protocol," << endl << args_indent + << "ThriftProtocol *output_protocol," << endl << args_indent << "gchar *method_name," + << endl << args_indent << "gint32 sequence_id," << endl << args_indent + << "GError **error)" << endl; + scope_up(f_service_); + f_service_ << indent() << class_name_lc << "_process_function_def *" + << "process_function_def;" << endl; + f_service_ << indent() << "gboolean dispatch_result = FALSE;" << endl << endl << indent() + << class_name << " *self = " << class_name_uc << " (dispatch_processor);" << endl; + f_service_ << indent() << parent_class_name << "Class " + "*parent_class =" << endl; + indent_up(); + f_service_ << indent() << "g_type_class_peek_parent (" << class_name_uc << "_GET_CLASS (self));" + << endl; + indent_down(); + f_service_ << endl + << indent() << "process_function_def = " + << "g_hash_table_lookup (self->process_map, method_name);" << endl + << indent() << "if (process_function_def != NULL)" << endl; + scope_up(f_service_); + args_indent = indent() + string(53, ' '); + f_service_ << indent() << "g_free (method_name);" << endl + << indent() << "dispatch_result = " + << "(*process_function_def->function) (self," << endl + << args_indent << "sequence_id," << endl + << args_indent << "input_protocol," << endl + << args_indent << "output_protocol," << endl + << args_indent << "error);" << endl; + scope_down(f_service_); + f_service_ << indent() << "else" << endl; + scope_up(f_service_); + + // Method name not recognized; chain up to our parent processor---note the + // top-most implementation of this method, in ThriftDispatchProcessor itself, + // will return an application exception to the caller if no class in the + // hierarchy recognizes the method name + f_service_ << indent() << "dispatch_result = parent_class->dispatch_call " + "(dispatch_processor," << endl; + args_indent = indent() + string(47, ' '); + f_service_ << args_indent << "input_protocol," << endl << args_indent << "output_protocol," + << endl << args_indent << "method_name," << endl << args_indent << "sequence_id," + << endl << args_indent << "error);" << endl; + scope_down(f_service_); + f_service_ << endl << indent() << "return dispatch_result;" << endl; + scope_down(f_service_); + f_service_ << endl; + + // Generate the processor's property setter + function_name = class_name_lc + "_set_property"; + args_indent = string(function_name.length() + 2, ' '); + f_service_ << "static void" << endl << function_name << " (GObject *object," << endl + << args_indent << "guint property_id," << endl << args_indent << "const GValue *value," + << endl << args_indent << "GParamSpec *pspec)" << endl; + scope_up(f_service_); + f_service_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl + << endl << indent() << "switch (property_id)" << endl; + scope_up(f_service_); + f_service_ << indent() << "case PROP_" << class_name_uc << "_HANDLER:" << endl; + indent_up(); + f_service_ << indent() << "if (self->handler != NULL)" << endl; + indent_up(); + f_service_ << indent() << "g_object_unref (self->handler);" << endl; + indent_down(); + f_service_ << indent() << "self->handler = g_value_get_object (value);" << endl << indent() + << "g_object_ref (self->handler);" << endl; + if (extends_service) { + // Chain up to set the handler in every superclass as well + f_service_ << endl << indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)->" + << endl; + indent_up(); + f_service_ << indent() << "set_property (object, property_id, value, pspec);" << endl; + indent_down(); + } + f_service_ << indent() << "break;" << endl; + indent_down(); + f_service_ << indent() << "default:" << endl; + indent_up(); + f_service_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);" + << endl << indent() << "break;" << endl; + indent_down(); + scope_down(f_service_); + scope_down(f_service_); + f_service_ << endl; + + // Generate processor's property getter + function_name = class_name_lc + "_get_property"; + args_indent = string(function_name.length() + 2, ' '); + f_service_ << "static void" << endl << function_name << " (GObject *object," << endl + << args_indent << "guint property_id," << endl << args_indent << "GValue *value," + << endl << args_indent << "GParamSpec *pspec)" << endl; + scope_up(f_service_); + f_service_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl + << endl << indent() << "switch (property_id)" << endl; + scope_up(f_service_); + f_service_ << indent() << "case PROP_" << class_name_uc << "_HANDLER:" << endl; + indent_up(); + f_service_ << indent() << "g_value_set_object (value, self->handler);" << endl << indent() + << "break;" << endl; + indent_down(); + f_service_ << indent() << "default:" << endl; + indent_up(); + f_service_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);" + << endl << indent() << "break;" << endl; + indent_down(); + scope_down(f_service_); + scope_down(f_service_); + f_service_ << endl; + + // Generator the processor's dispose function + f_service_ << "static void" << endl << class_name_lc << "_dispose (GObject *gobject)" << endl; + scope_up(f_service_); + f_service_ << indent() << class_name << " *self = " << class_name_uc << " (gobject);" << endl + << endl << indent() << "if (self->handler != NULL)" << endl; + scope_up(f_service_); + f_service_ << indent() << "g_object_unref (self->handler);" << endl << indent() + << "self->handler = NULL;" << endl; + scope_down(f_service_); + f_service_ << endl << indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)" + "->dispose (gobject);" + << endl; + scope_down(f_service_); + f_service_ << endl; + + // Generate processor finalize function + f_service_ << "static void" << endl << class_name_lc << "_finalize (GObject *gobject)" << endl; + scope_up(f_service_); + f_service_ << indent() << this->nspace << service_name_ << "Processor *self = " << this->nspace_uc + << service_name_uc << "_PROCESSOR (gobject);" << endl << endl << indent() + << "thrift_safe_hash_table_destroy (self->process_map);" << endl << endl << indent() + << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)" + "->finalize (gobject);" << endl; + scope_down(f_service_); + f_service_ << endl; + + // Generate processor instance initializer + f_service_ << "static void" << endl << class_name_lc << "_init (" << class_name << " *self)" + << endl; + scope_up(f_service_); + if (functions.size() > 0) { + f_service_ << indent() << "guint index;" << endl + << endl; + } + f_service_ << indent() << "self->handler = NULL;" << endl << indent() + << "self->process_map = " + "g_hash_table_new (g_str_hash, g_str_equal);" << endl; + if (functions.size() > 0) { + args_indent = string(21, ' '); + f_service_ << endl + << indent() << "for (index = 0; index < " + << functions.size() << "; index += 1)" << endl; + indent_up(); + f_service_ << indent() << "g_hash_table_insert (self->process_map," << endl + << indent() << args_indent + << class_name_lc << "_process_function_defs[index].name," << endl + << indent() << args_indent + << "&" << class_name_lc << "_process_function_defs[index]" << ");" + << endl; + indent_down(); + } + scope_down(f_service_); + f_service_ << endl; + + // Generate processor class initializer + f_service_ << "static void" << endl << class_name_lc << "_class_init (" << class_name + << "Class *cls)" << endl; + scope_up(f_service_); + f_service_ << indent() << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl + << indent() << "ThriftDispatchProcessorClass *dispatch_processor_class =" << endl; + indent_up(); + f_service_ << indent() << "THRIFT_DISPATCH_PROCESSOR_CLASS (cls);" << endl; + indent_down(); + f_service_ << indent() << "GParamSpec *param_spec;" << endl << endl << indent() + << "gobject_class->dispose = " << class_name_lc << "_dispose;" << endl << indent() + << "gobject_class->finalize = " << class_name_lc << "_finalize;" << endl << indent() + << "gobject_class->set_property = " << class_name_lc << "_set_property;" << endl + << indent() << "gobject_class->get_property = " << class_name_lc << "_get_property;" + << endl << endl << indent() + << "dispatch_processor_class->dispatch_call = " << class_name_lc << "_dispatch_call;" + << endl << indent() << "cls->dispatch_call = " << class_name_lc << "_dispatch_call;" + << endl << endl << indent() << "param_spec = g_param_spec_object (\"handler\"," + << endl; + args_indent = indent() + string(34, ' '); + f_service_ << args_indent << "\"Service handler implementation\"," << endl << args_indent + << "\"The service handler implementation \"" << endl << args_indent + << "\"to which method calls are dispatched.\"," << endl << args_indent + << this->nspace_uc + "TYPE_" + service_name_uc + "_HANDLER," << endl << args_indent + << "G_PARAM_READWRITE);" << endl; + f_service_ << indent() << "g_object_class_install_property (gobject_class," << endl; + args_indent = indent() + string(33, ' '); + f_service_ << args_indent << "PROP_" << class_name_uc << "_HANDLER," << endl << args_indent + << "param_spec);" << endl; + scope_down(f_service_); +} + +/** + * Generates C code that represents a Thrift service server. + */ +void t_c_glib_generator::generate_service_server(t_service* tservice) { + (void)tservice; + // Generate the service's handler class + generate_service_handler(tservice); + + // Generate the service's processor class + generate_service_processor(tservice); +} + +/** + * Generates C code to represent a THrift structure as a GObject. + */ +void t_c_glib_generator::generate_object(t_struct* tstruct) { + string name = tstruct->get_name(); + string name_u = initial_caps_to_underscores(name); + string name_uc = to_upper_case(name_u); + + string class_name = this->nspace + name; + string class_name_lc = to_lower_case(initial_caps_to_underscores(class_name)); + string class_name_uc = to_upper_case(class_name_lc); + + string function_name; + string args_indent; + + // write the instance definition + f_types_ << "struct _" << this->nspace << name << endl << "{ " << endl + << " ThriftStruct parent; " << endl << endl << " /* public */" << endl; + + // for each field, add a member variable + vector::const_iterator m_iter; + const vector& members = tstruct->get_members(); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + f_types_ << " " << type_name(t) << " " << (*m_iter)->get_name() << ";" << endl; + if ((*m_iter)->get_req() != t_field::T_REQUIRED) { + f_types_ << " gboolean __isset_" << (*m_iter)->get_name() << ";" << endl; + } + } + + // close the structure definition and create a typedef + f_types_ << "};" << endl << "typedef struct _" << this->nspace << name << " " << this->nspace + << name << ";" << endl << endl; + + // write the class definition + f_types_ << "struct _" << this->nspace << name << "Class" << endl << "{" << endl + << " ThriftStructClass parent;" << endl << "};" << endl << "typedef struct _" + << this->nspace << name << "Class " << this->nspace << name << "Class;" << endl << endl; + + // write the standard GObject boilerplate + f_types_ << "GType " << this->nspace_lc << name_u << "_get_type (void);" << endl << "#define " + << this->nspace_uc << "TYPE_" << name_uc << " (" << this->nspace_lc << name_u + << "_get_type())" << endl << "#define " << this->nspace_uc << name_uc + << "(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" << name_uc + << ", " << this->nspace << name << "))" << endl << "#define " << this->nspace_uc + << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "_TYPE_" + << name_uc << ", " << this->nspace << name << "Class))" << endl << "#define " + << this->nspace_uc << "IS_" << name_uc << "(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), " + << this->nspace_uc << "TYPE_" << name_uc << "))" << endl << "#define " << this->nspace_uc + << "IS_" << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc + << "TYPE_" << name_uc << "))" << endl << "#define " << this->nspace_uc << name_uc + << "_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_" + << name_uc << ", " << this->nspace << name << "Class))" << endl << endl; + + // start writing the object implementation .c file + + // generate properties enum + if (members.size() > 0) { + f_types_impl_ << "enum _" << class_name << "Properties" << endl << "{" << endl; + indent_up(); + f_types_impl_ << indent() << "PROP_" << class_name_uc << "_0"; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + string member_name_uc + = to_upper_case(to_lower_case(initial_caps_to_underscores((*m_iter)->get_name()))); + + f_types_impl_ << "," << endl << indent() << "PROP_" << class_name_uc << "_" << member_name_uc; + } + f_types_impl_ << endl; + indent_down(); + f_types_impl_ << "};" << endl << endl; + } + + // generate struct I/O methods + string this_get = this->nspace + name + " * this_object = " + this->nspace_uc + name_uc + + "(object);"; + generate_struct_reader(f_types_impl_, tstruct, "this_object->", this_get); + generate_struct_writer(f_types_impl_, tstruct, "this_object->", this_get); + + // generate property setter and getter + if (members.size() > 0) { + // generate property setter + function_name = class_name_lc + "_set_property"; + args_indent = string(function_name.length() + 2, ' '); + f_types_impl_ << "static void" << endl << function_name << " (GObject *object," << endl + << args_indent << "guint property_id," << endl << args_indent + << "const GValue *value," << endl << args_indent << "GParamSpec *pspec)" << endl; + scope_up(f_types_impl_); + f_types_impl_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl + << endl << indent() << "switch (property_id)" << endl; + scope_up(f_types_impl_); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* member = (*m_iter); + string member_name = member->get_name(); + string member_name_uc + = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name))); + t_type* member_type = get_true_type(member->get_type()); + + string property_identifier = "PROP_" + class_name_uc + "_" + member_name_uc; + + f_types_impl_ << indent() << "case " << property_identifier + ":" << endl; + indent_up(); + + if (member_type->is_base_type()) { + t_base_type* base_type = ((t_base_type*)member_type); + string assign_function_name; + + if (base_type->get_base() == t_base_type::TYPE_STRING) { + string release_function_name; + + f_types_impl_ << indent() << "if (self->" << member_name << " != NULL)" << endl; + indent_up(); + + if (base_type->is_binary()) { + release_function_name = "g_byte_array_unref"; + assign_function_name = "g_value_dup_boxed"; + } else { + release_function_name = "g_free"; + assign_function_name = "g_value_dup_string"; + } + + f_types_impl_ << indent() << release_function_name << " (self->" << member_name << ");" + << endl; + indent_down(); + } else { + switch (base_type->get_base()) { + case t_base_type::TYPE_BOOL: + assign_function_name = "g_value_get_boolean"; + break; + + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + assign_function_name = "g_value_get_int"; + break; + + case t_base_type::TYPE_I64: + assign_function_name = "g_value_get_int64"; + break; + + case t_base_type::TYPE_DOUBLE: + assign_function_name = "g_value_get_double"; + break; + + default: + throw "compiler error: " + "unrecognized base type \"" + base_type->get_name() + "\" " + "for struct member \"" + + member_name + "\""; + break; + } + } + + f_types_impl_ << indent() << "self->" << member_name << " = " << assign_function_name + << " (value);" << endl; + } else if (member_type->is_enum()) { + f_types_impl_ << indent() << "self->" << member_name << " = g_value_get_int (value);" + << endl; + } else if (member_type->is_container()) { + string release_function_name; + string assign_function_name; + + if (member_type->is_list()) { + t_type* elem_type = ((t_list*)member_type)->get_elem_type(); + + // Lists of base types other than strings are represented as GArrays; + // all others as GPtrArrays + if (is_numeric(elem_type)) { + release_function_name = "g_array_unref"; + } else { + release_function_name = "g_ptr_array_unref"; + } + + assign_function_name = "g_value_dup_boxed"; + } else if (member_type->is_set() || member_type->is_map()) { + release_function_name = "g_hash_table_unref"; + assign_function_name = "g_value_dup_boxed"; + } + + f_types_impl_ << indent() << "if (self->" << member_name << " != NULL)" << endl; + indent_up(); + f_types_impl_ << indent() << release_function_name << " (self->" << member_name << ");" + << endl; + indent_down(); + f_types_impl_ << indent() << "self->" << member_name << " = " << assign_function_name + << " (value);" << endl; + } else if (member_type->is_struct() || member_type->is_xception()) { + f_types_impl_ << indent() << "if (self->" << member_name << " != NULL)" << endl; + indent_up(); + f_types_impl_ << indent() << "g_object_unref (self->" << member_name << ");" << endl; + indent_down(); + f_types_impl_ << indent() << "self->" << member_name << " = g_value_dup_object (value);" + << endl; + } + + if (member->get_req() != t_field::T_REQUIRED) { + f_types_impl_ << indent() << "self->__isset_" << member_name << " = TRUE;" << endl; + } + + f_types_impl_ << indent() << "break;" << endl << endl; + indent_down(); + } + f_types_impl_ << indent() << "default:" << endl; + indent_up(); + f_types_impl_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);" + << endl << indent() << "break;" << endl; + indent_down(); + scope_down(f_types_impl_); + scope_down(f_types_impl_); + f_types_impl_ << endl; + + // generate property getter + function_name = class_name_lc + "_get_property"; + args_indent = string(function_name.length() + 2, ' '); + f_types_impl_ << "static void" << endl << function_name << " (GObject *object," << endl + << args_indent << "guint property_id," << endl << args_indent << "GValue *value," + << endl << args_indent << "GParamSpec *pspec)" << endl; + scope_up(f_types_impl_); + f_types_impl_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl + << endl << indent() << "switch (property_id)" << endl; + scope_up(f_types_impl_); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* member = (*m_iter); + string member_name = (*m_iter)->get_name(); + string member_name_uc + = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name))); + t_type* member_type = get_true_type(member->get_type()); + + string property_identifier = "PROP_" + class_name_uc + "_" + member_name_uc; + + string setter_function_name; + + if (member_type->is_base_type()) { + t_base_type* base_type = ((t_base_type*)member_type); + + switch (base_type->get_base()) { + case t_base_type::TYPE_BOOL: + setter_function_name = "g_value_set_boolean"; + break; + + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + setter_function_name = "g_value_set_int"; + break; + + case t_base_type::TYPE_I64: + setter_function_name = "g_value_set_int64"; + break; + + case t_base_type::TYPE_DOUBLE: + setter_function_name = "g_value_set_double"; + break; + + case t_base_type::TYPE_STRING: + if (base_type->is_binary()) { + setter_function_name = "g_value_set_boxed"; + } else { + setter_function_name = "g_value_set_string"; + } + break; + + default: + throw "compiler error: " + "unrecognized base type \"" + base_type->get_name() + "\" " + "for struct member \"" + + member_name + "\""; + break; + } + } else if (member_type->is_enum()) { + setter_function_name = "g_value_set_int"; + } else if (member_type->is_struct() || member_type->is_xception()) { + setter_function_name = "g_value_set_object"; + } else if (member_type->is_container()) { + setter_function_name = "g_value_set_boxed"; + } else { + throw "compiler error: " + "unrecognized type for struct member \"" + member_name + "\""; + } + + f_types_impl_ << indent() << "case " << property_identifier + ":" << endl; + indent_up(); + f_types_impl_ << indent() << setter_function_name << " (value, self->" << member_name << ");" + << endl << indent() << "break;" << endl << endl; + indent_down(); + } + f_types_impl_ << indent() << "default:" << endl; + indent_up(); + f_types_impl_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);" + << endl << indent() << "break;" << endl; + indent_down(); + scope_down(f_types_impl_); + scope_down(f_types_impl_); + f_types_impl_ << endl; + } + + // generate the instance init function + + f_types_impl_ << "static void " << endl << this->nspace_lc << name_u << "_instance_init (" + << this->nspace << name << " * object)" << endl << "{" << endl; + indent_up(); + + // generate default-value structures for container-type members + bool constant_declaration_output = false; + bool string_list_constant_output = false; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* member = *m_iter; + t_const_value* member_value = member->get_value(); + + if (member_value != NULL) { + string member_name = member->get_name(); + t_type* member_type = get_true_type(member->get_type()); + + if (member_type->is_list()) { + const vector& list = member_value->get_list(); + t_type* elem_type = ((t_list*)member_type)->get_elem_type(); + + // Generate an array with the list literal + indent(f_types_impl_) << "static " << type_name(elem_type, false, true) << " __default_" + << member_name << "[" << list.size() << "] = " << endl; + indent_up(); + f_types_impl_ << indent() << constant_literal(member_type, member_value) << ";" << endl; + indent_down(); + + constant_declaration_output = true; + + // If we are generating values for a pointer array (i.e. a list of + // strings), set a flag so we know to also declare an index variable to + // use in pre-populating the array + if (elem_type->is_string()) { + string_list_constant_output = true; + } + } + + // TODO: Handle container types other than list + } + } + if (constant_declaration_output) { + if (string_list_constant_output) { + indent(f_types_impl_) << "unsigned int list_index;" << endl; + } + + f_types_impl_ << endl; + } + + // satisfy compilers with -Wall turned on + indent(f_types_impl_) << "/* satisfy -Wall */" << endl << indent() + << "THRIFT_UNUSED_VAR (object);" << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if (t->is_base_type()) { + string dval = " = "; + if (t->is_enum()) { + dval += "(" + type_name(t) + ")"; + } + t_const_value* cv = (*m_iter)->get_value(); + if (cv != NULL) { + dval += constant_value("", t, cv); + } else { + dval += t->is_string() ? "NULL" : "0"; + } + indent(f_types_impl_) << "object->" << (*m_iter)->get_name() << dval << ";" << endl; + } else if (t->is_struct()) { + string name = (*m_iter)->get_name(); + string type_name_uc + = to_upper_case(initial_caps_to_underscores((*m_iter)->get_type()->get_name())); + indent(f_types_impl_) << "object->" << name << " = g_object_new (" << this->nspace_uc + << "TYPE_" << type_name_uc << ", NULL);" << endl; + } else if (t->is_xception()) { + string name = (*m_iter)->get_name(); + indent(f_types_impl_) << "object->" << name << " = NULL;" << endl; + } else if (t->is_container()) { + string name = (*m_iter)->get_name(); + string init_function; + t_type* etype = NULL; + + if (t->is_map()) { + t_type* key = ((t_map*)t)->get_key_type(); + t_type* value = ((t_map*)t)->get_val_type(); + init_function = generate_new_hash_from_type(key, value); + } else if (t->is_set()) { + etype = ((t_set*)t)->get_elem_type(); + init_function = generate_new_hash_from_type(etype, NULL); + } else if (t->is_list()) { + etype = ((t_list*)t)->get_elem_type(); + init_function = generate_new_array_from_type(etype); + } + + indent(f_types_impl_) << "object->" << name << " = " << init_function << endl; + + // Pre-populate the container with the specified default values, if any + if ((*m_iter)->get_value()) { + t_const_value* member_value = (*m_iter)->get_value(); + + if (t->is_list()) { + const vector& list = member_value->get_list(); + + if (is_numeric(etype)) { + indent(f_types_impl_) << + "g_array_append_vals (object->" << name << ", &__default_" << + name << ", " << list.size() << ");" << endl; + } + else { + indent(f_types_impl_) << + "for (list_index = 0; list_index < " << list.size() << "; " << + "list_index += 1)" << endl; + indent_up(); + indent(f_types_impl_) << + "g_ptr_array_add (object->" << name << "," << endl << + indent() << string(17, ' ') << "g_strdup (__default_" << + name << "[list_index]));" << endl; + indent_down(); + } + } + + // TODO: Handle container types other than list + } + } + + /* if not required, initialize the __isset variable */ + if ((*m_iter)->get_req() != t_field::T_REQUIRED) { + indent(f_types_impl_) << "object->__isset_" << (*m_iter)->get_name() << " = FALSE;" << endl; + } + } + + indent_down(); + f_types_impl_ << "}" << endl << endl; + + /* create the destructor */ + f_types_impl_ << "static void " << endl << this->nspace_lc << name_u + << "_finalize (GObject *object)" << endl << "{" << endl; + indent_up(); + + f_types_impl_ << indent() << this->nspace << name << " *tobject = " << this->nspace_uc << name_uc + << " (object);" << endl << endl; + + f_types_impl_ << indent() << "/* satisfy -Wall in case we don't use tobject */" << endl + << indent() << "THRIFT_UNUSED_VAR (tobject);" << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if (t->is_container()) { + string name = (*m_iter)->get_name(); + if (t->is_map() || t->is_set()) { + f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl; + f_types_impl_ << indent() << "{" << endl; + indent_up(); + f_types_impl_ << indent() << "g_hash_table_destroy (tobject->" << name << ");" << endl; + f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl; + indent_down(); + f_types_impl_ << indent() << "}" << endl; + } else if (t->is_list()) { + t_type* etype = ((t_list*)t)->get_elem_type(); + string destructor_function = "g_ptr_array_unref"; + + if (etype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)etype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot determine array type"; + case t_base_type::TYPE_BOOL: + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + case t_base_type::TYPE_DOUBLE: + destructor_function = "g_array_unref"; + break; + case t_base_type::TYPE_STRING: + break; + default: + throw "compiler error: no array info for type"; + } + } else if (etype->is_enum()) { + destructor_function = "g_array_unref"; + } + + f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl; + f_types_impl_ << indent() << "{" << endl; + indent_up(); + f_types_impl_ << indent() << destructor_function << " (tobject->" << name << ");" << endl; + f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl; + indent_down(); + f_types_impl_ << indent() << "}" << endl; + } + } else if (t->is_struct() || t->is_xception()) { + string name = (*m_iter)->get_name(); + // TODO: g_clear_object needs glib >= 2.28 + // f_types_impl_ << indent() << "g_clear_object (&(tobject->" << name << "));" << endl; + // does g_object_unref the trick? + f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl; + f_types_impl_ << indent() << "{" << endl; + indent_up(); + f_types_impl_ << indent() << "g_object_unref(tobject->" << name << ");" << endl; + f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl; + indent_down(); + f_types_impl_ << indent() << "}" << endl; + } else if (t->is_string()) { + string name = (*m_iter)->get_name(); + f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl; + f_types_impl_ << indent() << "{" << endl; + indent_up(); + f_types_impl_ << indent() << generate_free_func_from_type(t) << "(tobject->" << name << ");" + << endl; + f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl; + indent_down(); + f_types_impl_ << indent() << "}" << endl; + } + } + + indent_down(); + f_types_impl_ << "}" << endl << endl; + + // generate the class init function + + f_types_impl_ << "static void" << endl << class_name_lc << "_class_init (" << class_name + << "Class * cls)" << endl; + scope_up(f_types_impl_); + + f_types_impl_ << indent() << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl + << indent() << "ThriftStructClass *struct_class = " + << "THRIFT_STRUCT_CLASS (cls);" << endl << endl << indent() + << "struct_class->read = " << class_name_lc << "_read;" << endl << indent() + << "struct_class->write = " << class_name_lc << "_write;" << endl << endl + << indent() << "gobject_class->finalize = " << class_name_lc << "_finalize;" + << endl; + if (members.size() > 0) { + f_types_impl_ << indent() << "gobject_class->get_property = " << class_name_lc + << "_get_property;" << endl << indent() + << "gobject_class->set_property = " << class_name_lc << "_set_property;" << endl; + + // install a property for each member + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* member = (*m_iter); + string member_name = member->get_name(); + string member_name_uc + = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name))); + t_type* member_type = get_true_type(member->get_type()); + t_const_value* member_value = member->get_value(); + + string property_identifier = "PROP_" + class_name_uc + "_" + member_name_uc; + + f_types_impl_ << endl << indent() << "g_object_class_install_property" << endl; + indent_up(); + args_indent = indent() + ' '; + f_types_impl_ << indent() << "(gobject_class," << endl << args_indent << property_identifier + << "," << endl << args_indent; + + if (member_type->is_base_type()) { + t_base_type::t_base base_type = ((t_base_type*)member_type)->get_base(); + + if (base_type == t_base_type::TYPE_STRING) { + if (((t_base_type*)member_type)->is_binary()) { + args_indent += string(20, ' '); + f_types_impl_ << "g_param_spec_boxed (\"" << member_name << "\"," << endl << args_indent + << "NULL," << endl << args_indent << "NULL," << endl << args_indent + << "G_TYPE_BYTE_ARRAY," << endl << args_indent << "G_PARAM_READWRITE));" + << endl; + } else { + args_indent += string(21, ' '); + f_types_impl_ << "g_param_spec_string (\"" << member_name << "\"," << endl + << args_indent << "NULL," << endl << args_indent << "NULL," << endl + << args_indent + << ((member_value != NULL) ? "\"" + member_value->get_string() + "\"" + : "NULL") << "," << endl << args_indent + << "G_PARAM_READWRITE));" << endl; + } + } else if (base_type == t_base_type::TYPE_BOOL) { + args_indent += string(22, ' '); + f_types_impl_ << "g_param_spec_boolean (\"" << member_name << "\"," << endl << args_indent + << "NULL," << endl << args_indent << "NULL," << endl << args_indent + << (((member_value != NULL) && (member_value->get_integer() != 0)) + ? "TRUE" + : "FALSE") << "," << endl << args_indent << "G_PARAM_READWRITE));" + << endl; + } else if ((base_type == t_base_type::TYPE_I8) || (base_type == t_base_type::TYPE_I16) + || (base_type == t_base_type::TYPE_I32) || (base_type == t_base_type::TYPE_I64) + || (base_type == t_base_type::TYPE_DOUBLE)) { + string param_spec_function_name = "g_param_spec_int"; + string min_value; + string max_value; + ostringstream default_value; + + switch (base_type) { + case t_base_type::TYPE_I8: + min_value = "G_MININT8"; + max_value = "G_MAXINT8"; + break; + + case t_base_type::TYPE_I16: + min_value = "G_MININT16"; + max_value = "G_MAXINT16"; + break; + + case t_base_type::TYPE_I32: + min_value = "G_MININT32"; + max_value = "G_MAXINT32"; + break; + + case t_base_type::TYPE_I64: + param_spec_function_name = "g_param_spec_int64"; + min_value = "G_MININT64"; + max_value = "G_MAXINT64"; + break; + + case t_base_type::TYPE_DOUBLE: + param_spec_function_name = "g_param_spec_double"; + min_value = "-INFINITY"; + max_value = "INFINITY"; + break; + + default: + throw "compiler error: " + "unrecognized base type \"" + member_type->get_name() + "\" " + "for struct member \"" + + member_name + "\""; + break; + } + + if (member_value != NULL) { + default_value << (base_type == t_base_type::TYPE_DOUBLE ? member_value->get_double() + : member_value->get_integer()); + } else { + default_value << "0"; + } + + args_indent += string(param_spec_function_name.length() + 2, ' '); + f_types_impl_ << param_spec_function_name << " (\"" << member_name << "\"," << endl + << args_indent << "NULL," << endl << args_indent << "NULL," << endl + << args_indent << min_value << "," << endl << args_indent << max_value + << "," << endl << args_indent << default_value.str() << "," << endl + << args_indent << "G_PARAM_READWRITE));" << endl; + } + + indent_down(); + } else if (member_type->is_enum()) { + t_enum_value* enum_min_value = ((t_enum*)member_type)->get_min_value(); + t_enum_value* enum_max_value = ((t_enum*)member_type)->get_max_value(); + int min_value = (enum_min_value != NULL) ? enum_min_value->get_value() : 0; + int max_value = (enum_max_value != NULL) ? enum_max_value->get_value() : 0; + + args_indent += string(18, ' '); + f_types_impl_ << "g_param_spec_int (\"" << member_name << "\"," << endl << args_indent + << "NULL," << endl << args_indent << "NULL," << endl << args_indent + << min_value << "," << endl << args_indent << max_value << "," << endl + << args_indent << min_value << "," << endl << args_indent + << "G_PARAM_READWRITE));" << endl; + indent_down(); + } else if (member_type->is_struct() || member_type->is_xception()) { + string param_type = this->nspace_uc + "TYPE_" + + to_upper_case(initial_caps_to_underscores(member_type->get_name())); + + args_indent += string(20, ' '); + f_types_impl_ << "g_param_spec_object (\"" << member_name << "\"," << endl << args_indent + << "NULL," << endl << args_indent << "NULL," << endl << args_indent + << param_type << "," << endl << args_indent << "G_PARAM_READWRITE));" << endl; + indent_down(); + } else if (member_type->is_list()) { + t_type* elem_type = ((t_list*)member_type)->get_elem_type(); + string param_type; + + if (elem_type->is_base_type() && !elem_type->is_string()) { + param_type = "G_TYPE_ARRAY"; + } else { + param_type = "G_TYPE_PTR_ARRAY"; + } + + args_indent += string(20, ' '); + f_types_impl_ << "g_param_spec_boxed (\"" << member_name << "\"," << endl << args_indent + << "NULL," << endl << args_indent << "NULL," << endl << args_indent + << param_type << "," << endl << args_indent << "G_PARAM_READWRITE));" << endl; + indent_down(); + } else if (member_type->is_set() || member_type->is_map()) { + args_indent += string(20, ' '); + f_types_impl_ << "g_param_spec_boxed (\"" << member_name << "\"," << endl << args_indent + << "NULL," << endl << args_indent << "NULL," << endl << args_indent + << "G_TYPE_HASH_TABLE," << endl << args_indent << "G_PARAM_READWRITE));" + << endl; + indent_down(); + } + } + } + scope_down(f_types_impl_); + f_types_impl_ << endl; + + f_types_impl_ << "GType" << endl << this->nspace_lc << name_u << "_get_type (void)" << endl << "{" + << endl << " static GType type = 0;" << endl << endl << " if (type == 0) " << endl + << " {" << endl << " static const GTypeInfo type_info = " << endl << " {" + << endl << " sizeof (" << this->nspace << name << "Class)," << endl + << " NULL, /* base_init */" << endl << " NULL, /* base_finalize */" + << endl << " (GClassInitFunc) " << this->nspace_lc << name_u << "_class_init," + << endl << " NULL, /* class_finalize */" << endl + << " NULL, /* class_data */" << endl << " sizeof (" << this->nspace + << name << ")," << endl << " 0, /* n_preallocs */" << endl + << " (GInstanceInitFunc) " << this->nspace_lc << name_u << "_instance_init," + << endl << " NULL, /* value_table */" << endl << " };" << endl << endl + << " type = g_type_register_static (THRIFT_TYPE_STRUCT, " << endl + << " \"" << this->nspace << name << "Type\"," + << endl << " &type_info, 0);" << endl << " }" + << endl << endl << " return type;" << endl << "}" << endl << endl; +} + +/** + * Generates functions to write Thrift structures to a stream. + */ +void t_c_glib_generator::generate_struct_writer(ofstream& out, + t_struct* tstruct, + string this_name, + string this_get, + bool is_function) { + string name = tstruct->get_name(); + string name_u = initial_caps_to_underscores(name); + string name_uc = to_upper_case(name_u); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + int error_ret = 0; + + if (is_function) { + error_ret = -1; + indent(out) << "static gint32" << endl << this->nspace_lc << name_u + << "_write (ThriftStruct *object, ThriftProtocol *protocol, GError **error)" + << endl; + } + indent(out) << "{" << endl; + indent_up(); + + out << indent() << "gint32 ret;" << endl << indent() << "gint32 xfer = 0;" << endl << endl; + + indent(out) << this_get << endl; + // satisfy -Wall in the case of an empty struct + if (!this_get.empty()) { + indent(out) << "THRIFT_UNUSED_VAR (this_object);" << endl; + } + + out << indent() << "if ((ret = thrift_protocol_write_struct_begin (protocol, \"" << name + << "\", error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl + << indent() << "xfer += ret;" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_OPTIONAL) { + indent(out) << "if (this_object->__isset_" << (*f_iter)->get_name() << " == TRUE) {" << endl; + indent_up(); + } + + out << indent() << "if ((ret = thrift_protocol_write_field_begin (protocol, " + << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", " + << (*f_iter)->get_key() << ", error)) < 0)" << endl << indent() << " return " << error_ret + << ";" << endl << indent() << "xfer += ret;" << endl; + generate_serialize_field(out, *f_iter, this_name, "", error_ret); + out << indent() << "if ((ret = thrift_protocol_write_field_end (protocol, error)) < 0)" << endl + << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" + << endl; + + if ((*f_iter)->get_req() == t_field::T_OPTIONAL) { + indent_down(); + indent(out) << "}" << endl; + } + } + + // write the struct map + out << indent() << "if ((ret = thrift_protocol_write_field_stop (protocol, error)) < 0)" << endl + << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl + << indent() << "if ((ret = thrift_protocol_write_struct_end (protocol, error)) < 0)" << endl + << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl + << endl; + + if (is_function) { + indent(out) << "return xfer;" << endl; + } + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates code to read Thrift structures from a stream. + */ +void t_c_glib_generator::generate_struct_reader(ofstream& out, + t_struct* tstruct, + string this_name, + string this_get, + bool is_function) { + string name = tstruct->get_name(); + string name_u = initial_caps_to_underscores(name); + string name_uc = to_upper_case(name_u); + int error_ret = 0; + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + if (is_function) { + error_ret = -1; + indent(out) << "/* reads a " << name_u << " object */" << endl << "static gint32" << endl + << this->nspace_lc << name_u + << "_read (ThriftStruct *object, ThriftProtocol *protocol, GError **error)" << endl; + } + + indent(out) << "{" << endl; + indent_up(); + + // declare stack temp variables + out << indent() << "gint32 ret;" << endl << indent() << "gint32 xfer = 0;" << endl << indent() + << "gchar *name = NULL;" << endl << indent() << "ThriftType ftype;" << endl << indent() + << "gint16 fid;" << endl << indent() << "guint32 len = 0;" << endl << indent() + << "gpointer data = NULL;" << endl << indent() << this_get << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + indent(out) << "gboolean isset_" << (*f_iter)->get_name() << " = FALSE;" << endl; + } + } + + out << endl; + + // satisfy -Wall in case we don't use some variables + out << indent() << "/* satisfy -Wall in case these aren't used */" << endl << indent() + << "THRIFT_UNUSED_VAR (len);" << endl << indent() << "THRIFT_UNUSED_VAR (data);" << endl; + + if (!this_get.empty()) { + out << indent() << "THRIFT_UNUSED_VAR (this_object);" << endl; + } + out << endl; + + // read the beginning of the structure marker + out << indent() << "/* read the struct begin marker */" << endl << indent() + << "if ((ret = thrift_protocol_read_struct_begin (protocol, &name, error)) < 0)" << endl + << indent() << "{" << endl << indent() << " if (name) g_free (name);" << endl << indent() + << " return " << error_ret << ";" << endl << indent() << "}" << endl << indent() + << "xfer += ret;" << endl << indent() << "if (name) g_free (name);" << endl << indent() + << "name = NULL;" << endl << endl; + + // read the struct fields + out << indent() << "/* read the struct fields */" << endl << indent() << "while (1)" << endl; + scope_up(out); + + // read beginning field marker + out << indent() << "/* read the beginning of a field */" << endl << indent() + << "if ((ret = thrift_protocol_read_field_begin (protocol, &name, &ftype, &fid, error)) < 0)" + << endl << indent() << "{" << endl << indent() << " if (name) g_free (name);" << endl + << indent() << " return " << error_ret << ";" << endl << indent() << "}" << endl << indent() + << "xfer += ret;" << endl << indent() << "if (name) g_free (name);" << endl << indent() + << "name = NULL;" << endl << endl; + + // check for field STOP marker + out << indent() << "/* break if we get a STOP field */" << endl << indent() + << "if (ftype == T_STOP)" << endl << indent() << "{" << endl << indent() << " break;" << endl + << indent() << "}" << endl << endl; + + // switch depending on the field type + indent(out) << "switch (fid)" << endl; + + // start switch + scope_up(out); + + // generate deserialization code for known types + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << "case " << (*f_iter)->get_key() << ":" << endl; + indent_up(); + indent(out) << "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ")" << endl; + indent(out) << "{" << endl; + + indent_up(); + // generate deserialize field + generate_deserialize_field(out, *f_iter, this_name, "", error_ret, false); + indent_down(); + + out << indent() << "} else {" << endl << indent() + << " if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl << indent() + << " return " << error_ret << ";" << endl << indent() << " xfer += ret;" << endl + << indent() << "}" << endl << indent() << "break;" << endl; + indent_down(); + } + + // create the default case + out << indent() << "default:" << endl << indent() + << " if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl << indent() + << " return " << error_ret << ";" << endl << indent() << " xfer += ret;" << endl + << indent() << " break;" << endl; + + // end switch + scope_down(out); + + // read field end marker + out << indent() << "if ((ret = thrift_protocol_read_field_end (protocol, error)) < 0)" << endl + << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl; + + // end while loop + scope_down(out); + out << endl; + + // read the end of the structure + out << indent() << "if ((ret = thrift_protocol_read_struct_end (protocol, error)) < 0)" << endl + << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl + << endl; + + // if a required field is missing, throw an error + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + out << indent() << "if (!isset_" << (*f_iter)->get_name() << ")" << endl << indent() << "{" + << endl << indent() << " g_set_error (error, THRIFT_PROTOCOL_ERROR," << endl << indent() + << " THRIFT_PROTOCOL_ERROR_INVALID_DATA," << endl << indent() + << " \"missing field\");" << endl << indent() << " return -1;" << endl + << indent() << "}" << endl << endl; + } + } + + if (is_function) { + indent(out) << "return xfer;" << endl; + } + + // end the function/structure + indent_down(); + indent(out) << "}" << endl << endl; +} + +void t_c_glib_generator::generate_serialize_field(ofstream& out, + t_field* tfield, + string prefix, + string suffix, + int error_ret) { + t_type* type = get_true_type(tfield->get_type()); + string name = prefix + tfield->get_name() + suffix; + + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name; + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, name, error_ret); + } else if (type->is_container()) { + generate_serialize_container(out, type, name, error_ret); + } else if (type->is_base_type() || type->is_enum()) { + indent(out) << "if ((ret = thrift_protocol_write_"; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_BOOL: + out << "bool (protocol, " << name; + break; + case t_base_type::TYPE_I8: + out << "byte (protocol, " << name; + break; + case t_base_type::TYPE_I16: + out << "i16 (protocol, " << name; + break; + case t_base_type::TYPE_I32: + out << "i32 (protocol, " << name; + break; + case t_base_type::TYPE_I64: + out << "i64 (protocol, " << name; + break; + case t_base_type::TYPE_DOUBLE: + out << "double (protocol, " << name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "binary (protocol, " << name << " ? ((GByteArray *) " << name << ")->data : NULL, " + << name << " ? ((GByteArray *) " << name << ")->len : 0"; + } else { + out << "string (protocol, " << name; + } + break; + default: + throw "compiler error: no C writer for base type " + t_base_type::t_base_name(tbase) + name; + } + } else { + out << "i32 (protocol, (gint32) " << name; + } + out << ", error)) < 0)" << endl + << indent() << " return " << error_ret << ";" << endl + << indent() << "xfer += ret;" << endl << endl; + } else { + throw std::logic_error("DO NOT KNOW HOW TO SERIALIZE FIELD '" + name + "' TYPE '" + + type_name(type)); + } +} + +void t_c_glib_generator::generate_serialize_struct(ofstream& out, + t_struct* tstruct, + string prefix, + int error_ret) { + (void)tstruct; + out << indent() << "if ((ret = thrift_struct_write (THRIFT_STRUCT (" << prefix + << "), protocol, error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl + << indent() << "xfer += ret;" << endl << endl; +} + +void t_c_glib_generator::generate_serialize_container(ofstream& out, + t_type* ttype, + string prefix, + int error_ret) { + scope_up(out); + + if (ttype->is_map()) { + t_type* tkey = ((t_map*)ttype)->get_key_type(); + t_type* tval = ((t_map*)ttype)->get_val_type(); + string tkey_name = type_name(tkey); + string tval_name = type_name(tval); + string tkey_ptr; + string tval_ptr; + string keyname = tmp("key"); + string valname = tmp("val"); + + declore_local_variable_for_write(out, tkey, keyname); + declore_local_variable_for_write(out, tval, valname); + + /* If either the key or value type is a typedef, find its underlying type so + we can correctly determine how to generate a pointer to it */ + tkey = get_true_type(tkey); + tval = get_true_type(tval); + + tkey_ptr = tkey->is_string() || !tkey->is_base_type() ? "" : "*"; + tval_ptr = tval->is_string() || !tval->is_base_type() ? "" : "*"; + + /* + * Some ugliness here. To maximize backwards compatibility, we + * avoid using GHashTableIter and instead get a GList of all keys, + * then copy it into a array on the stack, and free it. + * This is because we may exit early before we get a chance to free the + * GList. + */ + out << indent() << "GList *key_list = NULL, *iter = NULL;" << endl + << indent() << tkey_name << tkey_ptr << "* keys;" << endl + << indent() << "int i = 0, key_count;" << endl + << endl + << indent() << "if ((ret = thrift_protocol_write_map_begin (protocol, " + << type_to_enum(tkey) << ", " << type_to_enum(tval) << ", " << prefix << " ? " + << "(gint32) g_hash_table_size ((GHashTable *) " << prefix << ") : 0" + << ", error)) < 0)" << endl; + indent_up(); + out << indent() << "return " << error_ret << ";" << endl; + indent_down(); + out << indent() << "xfer += ret;" << endl + << indent() << "if (" << prefix << ")" << endl + << indent() << " g_hash_table_foreach ((GHashTable *) " << prefix + << ", thrift_hash_table_get_keys, &key_list);" << endl + << indent() << "key_count = g_list_length (key_list);" << endl + << indent() << "keys = g_newa (" << tkey_name << tkey_ptr + << ", key_count);" << endl + << indent() << "for (iter = g_list_first (key_list); iter; " + "iter = iter->next)" << endl; + indent_up(); + out << indent() << "keys[i++] = (" << tkey_name << tkey_ptr + << ") iter->data;" << endl; + indent_down(); + out << indent() << "g_list_free (key_list);" << endl + << endl + << indent() << "for (i = 0; i < key_count; ++i)" << endl; + scope_up(out); + out << indent() << keyname << " = keys[i];" << endl + << indent() << valname << " = (" << tval_name << tval_ptr + << ") g_hash_table_lookup (((GHashTable *) " << prefix + << "), (gpointer) " << keyname << ");" << endl + << endl; + generate_serialize_map_element(out, + (t_map*)ttype, + tkey_ptr + " " + keyname, + tval_ptr + " " + valname, + error_ret); + scope_down(out); + out << indent() << "if ((ret = thrift_protocol_write_map_end (protocol, " + "error)) < 0)" << endl; + indent_up(); + out << indent() << "return " << error_ret << ";" << endl; + indent_down(); + out << indent() << "xfer += ret;" << endl; + } else if (ttype->is_set()) { + t_type* telem = ((t_set*)ttype)->get_elem_type(); + string telem_name = type_name(telem); + string telem_ptr = telem->is_string() || !telem->is_base_type() ? "" : "*"; + out << indent() << "GList *key_list = NULL, *iter = NULL;" << endl + << indent() << telem_name << telem_ptr << "* keys;" << endl + << indent() << "int i = 0, key_count;" << endl + << indent() << telem_name << telem_ptr << " elem;" << endl + << indent() << "gpointer value;" << endl + << indent() << "THRIFT_UNUSED_VAR (value);" << endl + << endl + << indent() << "if ((ret = thrift_protocol_write_set_begin (protocol, " + << type_to_enum(telem) << ", " << prefix << " ? " + << "(gint32) g_hash_table_size ((GHashTable *) " << prefix << ") : 0" + << ", error)) < 0)" << endl; + indent_up(); + out << indent() << "return " << error_ret << ";" << endl; + indent_down(); + out << indent() << "xfer += ret;" << endl + << indent() << "if (" << prefix << ")" << endl + << indent() << " g_hash_table_foreach ((GHashTable *) " << prefix + << ", thrift_hash_table_get_keys, &key_list);" << endl + << indent() << "key_count = g_list_length (key_list);" << endl + << indent() << "keys = g_newa (" << telem_name << telem_ptr + << ", key_count);" << endl + << indent() << "for (iter = g_list_first (key_list); iter; " + "iter = iter->next)" << endl; + indent_up(); + out << indent() << "keys[i++] = (" << telem_name << telem_ptr + << ") iter->data;" << endl; + indent_down(); + out << indent() << "g_list_free (key_list);" << endl + << endl + << indent() << "for (i = 0; i < key_count; ++i)" << endl; + scope_up(out); + out << indent() << "elem = keys[i];" << endl + << indent() << "value = (gpointer) g_hash_table_lookup " + "(((GHashTable *) " << prefix << "), (gpointer) elem);" << endl + << endl; + generate_serialize_set_element(out, + (t_set*)ttype, + telem_ptr + "elem", + error_ret); + scope_down(out); + out << indent() << "if ((ret = thrift_protocol_write_set_end (protocol, " + "error)) < 0)" << endl; + indent_up(); + out << indent() << "return " << error_ret << ";" << endl; + indent_down(); + out << indent() << "xfer += ret;" << endl; + } else if (ttype->is_list()) { + string length = "(" + prefix + " ? " + prefix + "->len : 0)"; + string i = tmp("i"); + out << indent() << "guint " << i << ";" << endl + << endl + << indent() << "if ((ret = thrift_protocol_write_list_begin (protocol, " + << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", (gint32) " + << length << ", error)) < 0)" << endl; + indent_up(); + out << indent() << "return " << error_ret << ";" << endl; + indent_down(); + out << indent() << "xfer += ret;" << endl + << indent() << "for (" << i << " = 0; " << i << " < " << length << "; " + << i << "++)" << endl; + scope_up(out); + generate_serialize_list_element(out, (t_list*)ttype, prefix, i, error_ret); + scope_down(out); + out << indent() << "if ((ret = thrift_protocol_write_list_end (protocol, " + "error)) < 0)" << endl; + indent_up(); + out << indent() << "return " << error_ret << ";" << endl; + indent_down(); + out << indent() << "xfer += ret;" << endl; + } + + scope_down(out); +} + +void t_c_glib_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string key, + string value, + int error_ret) { + t_field kfield(tmap->get_key_type(), key); + generate_serialize_field(out, &kfield, "", "", error_ret); + + t_field vfield(tmap->get_val_type(), value); + generate_serialize_field(out, &vfield, "", "", error_ret); +} + +void t_c_glib_generator::generate_serialize_set_element(ofstream& out, + t_set* tset, + string element, + int error_ret) { + t_field efield(tset->get_elem_type(), element); + generate_serialize_field(out, &efield, "", "", error_ret); +} + +void t_c_glib_generator::generate_serialize_list_element(ofstream& out, + t_list* tlist, + string list, + string index, + int error_ret) { + t_type* ttype = get_true_type(tlist->get_elem_type()); + + // cast to non-const + string cast = ""; + string name = "g_ptr_array_index ((GPtrArray *) " + list + ", " + index + ")"; + + if (ttype->is_void()) { + throw std::runtime_error("compiler error: list element type cannot be void"); + } else if (is_numeric(ttype)) { + name = "g_array_index (" + list + ", " + base_type_name(ttype) + ", " + index + ")"; + } else if (ttype->is_string()) { + cast = "(gchar*)"; + } else if (ttype->is_map() || ttype->is_set()) { + cast = "(GHashTable*)"; + } else if (ttype->is_list()) { + t_type* etype = ((t_list*)ttype)->get_elem_type(); + if (etype->is_void()) { + throw std::runtime_error("compiler error: list element type cannot be void"); + } + cast = is_numeric(etype) ? "(GArray*)" : "(GPtrArray*)"; + } + + t_field efield(ttype, "(" + cast + name + ")"); + generate_serialize_field(out, &efield, "", "", error_ret); +} + +/* deserializes a field of any type. */ +void t_c_glib_generator::generate_deserialize_field(ofstream& out, + t_field* tfield, + string prefix, + string suffix, + int error_ret, + bool allocate) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_void()) { + throw std::runtime_error("CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + + tfield->get_name()); + } + + string name = prefix + tfield->get_name() + suffix; + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name, error_ret, allocate); + } else if (type->is_container()) { + generate_deserialize_container(out, type, name, error_ret); + } else if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + if (tbase == t_base_type::TYPE_STRING) { + indent(out) << "if (" << name << " != NULL)" << endl << indent() << "{" << endl; + indent_up(); + indent(out) << "g_free(" << name << ");" << endl << indent() << name << " = NULL;" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } + indent(out) << "if ((ret = thrift_protocol_read_"; + + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "binary (protocol, &data, &len"; + } else { + out << "string (protocol, &" << name; + } + break; + case t_base_type::TYPE_BOOL: + out << "bool (protocol, &" << name; + break; + case t_base_type::TYPE_I8: + out << "byte (protocol, &" << name; + break; + case t_base_type::TYPE_I16: + out << "i16 (protocol, &" << name; + break; + case t_base_type::TYPE_I32: + out << "i32 (protocol, &" << name; + break; + case t_base_type::TYPE_I64: + out << "i64 (protocol, &" << name; + break; + case t_base_type::TYPE_DOUBLE: + out << "double (protocol, &" << name; + break; + default: + throw "compiler error: no C reader for base type " + t_base_type::t_base_name(tbase) + name; + } + out << ", error)) < 0)" << endl; + out << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" + << endl; + + // load the byte array with the data + if (tbase == t_base_type::TYPE_STRING && type->is_binary()) { + indent(out) << name << " = g_byte_array_new();" << endl; + indent(out) << "g_byte_array_append (" << name << ", (guint8 *) data, (guint) len);" << endl; + indent(out) << "g_free (data);" << endl; + } + } else if (type->is_enum()) { + string t = tmp("ecast"); + out << indent() << "gint32 " << t << ";" << endl << indent() + << "if ((ret = thrift_protocol_read_i32 (protocol, &" << t << ", error)) < 0)" << endl + << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl + << indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl; + } else { + throw std::logic_error("DO NOT KNOW HOW TO SERIALIZE FIELD '" + tfield->get_name() + "' TYPE '" + + type_name(type)); + } + + // if the type is not required and this is a thrift struct (no prefix), + // set the isset variable. if the type is required, then set the + // local variable indicating the value was set, so that we can do // validation later. + if (prefix != "" && tfield->get_req() != t_field::T_REQUIRED) { + indent(out) << prefix << "__isset_" << tfield->get_name() << suffix << " = TRUE;" << endl; + } else if (prefix != "" && tfield->get_req() == t_field::T_REQUIRED) { + indent(out) << "isset_" << tfield->get_name() << " = TRUE;" << endl; + } +} + +void t_c_glib_generator::generate_deserialize_struct(ofstream& out, + t_struct* tstruct, + string prefix, + int error_ret, + bool allocate) { + string name_uc = to_upper_case(initial_caps_to_underscores(tstruct->get_name())); + if (tstruct->is_xception()) { + out << indent() << "/* This struct is an exception */" << endl; + allocate = true; + } + + if (allocate) { + out << indent() << "if ( " << prefix << " != NULL)" << endl << indent() << "{" << endl; + indent_up(); + out << indent() << "g_object_unref (" << prefix << ");" << endl; + indent_down(); + out << indent() << "}" << endl << indent() << prefix << " = g_object_new (" << this->nspace_uc + << "TYPE_" << name_uc << ", NULL);" << endl; + } + out << indent() << "if ((ret = thrift_struct_read (THRIFT_STRUCT (" << prefix + << "), protocol, error)) < 0)" << endl << indent() << "{" << endl; + indent_up(); + if (allocate) { + indent(out) << "g_object_unref (" << prefix << ");" << endl; + if (tstruct->is_xception()) { + indent(out) << prefix << " = NULL;" << endl; + } + } + out << indent() << "return " << error_ret << ";" << endl; + indent_down(); + out << indent() << "}" << endl << indent() << "xfer += ret;" << endl; +} + +void t_c_glib_generator::generate_deserialize_container(ofstream& out, + t_type* ttype, + string prefix, + int error_ret) { + scope_up(out); + + if (ttype->is_map()) { + out << indent() << "guint32 size;" << endl + << indent() << "guint32 i;" << endl + << indent() << "ThriftType key_type;" << endl + << indent() << "ThriftType value_type;" << endl + << endl + << indent() << "/* read the map begin marker */" << endl + << indent() << "if ((ret = thrift_protocol_read_map_begin (protocol, " + "&key_type, &value_type, &size, error)) < 0)" << endl; + indent_up(); + out << indent() << "return " << error_ret << ";" << endl; + indent_down(); + out << indent() << "xfer += ret;" << endl + << endl; + + // iterate over map elements + out << indent() << "/* iterate through each of the map's fields */" << endl + << indent() << "for (i = 0; i < size; i++)" << endl; + scope_up(out); + generate_deserialize_map_element(out, (t_map*)ttype, prefix, error_ret); + scope_down(out); + out << endl; + + // read map end + out << indent() << "/* read the map end marker */" << endl + << indent() << "if ((ret = thrift_protocol_read_map_end (protocol, " + "error)) < 0)" << endl; + indent_up(); + out << indent() << "return " << error_ret << ";" << endl; + indent_down(); + out << indent() << "xfer += ret;" << endl; + } else if (ttype->is_set()) { + out << indent() << "guint32 size;" << endl + << indent() << "guint32 i;" << endl + << indent() << "ThriftType element_type;" << endl + << endl + << indent() << "if ((ret = thrift_protocol_read_set_begin (protocol, " + "&element_type, &size, error)) < 0)" << endl; + indent_up(); + out << indent() << "return " << error_ret << ";" << endl; + indent_down(); + out << indent() << "xfer += ret;" << endl + << endl; + + // iterate over the elements + out << indent() << "/* iterate through the set elements */" << endl + << indent() << "for (i = 0; i < size; ++i)" << endl; + scope_up(out); + generate_deserialize_set_element(out, (t_set*)ttype, prefix, error_ret); + scope_down(out); + + // read set end + out << indent() << "if ((ret = thrift_protocol_read_set_end (protocol, " + "error)) < 0)" << endl; + indent_up(); + out << indent() << "return " << error_ret << ";" << endl; + indent_down(); + out << indent() << "xfer += ret;" << endl + << endl; + } else if (ttype->is_list()) { + out << indent() << "guint32 size;" << endl + << indent() << "guint32 i;" << endl + << indent() << "ThriftType element_type;" << endl + << endl + << indent() << "if ((ret = thrift_protocol_read_list_begin (protocol, " + "&element_type,&size, error)) < 0)" << endl; + indent_up(); + out << indent() << "return " << error_ret << ";" << endl; + indent_down(); + out << indent() << "xfer += ret;" << endl + << endl; + + // iterate over the elements + out << indent() << "/* iterate through list elements */" << endl + << indent() << "for (i = 0; i < size; i++)" << endl; + scope_up(out); + generate_deserialize_list_element(out, + (t_list*)ttype, + prefix, + "i", + error_ret); + scope_down(out); + + // read list end + out << indent() << "if ((ret = thrift_protocol_read_list_end (protocol, " + "error)) < 0)" << endl; + indent_up(); + out << indent() << "return " << error_ret << ";" << endl; + indent_down(); + out << indent() << "xfer += ret;" << endl; + } + + scope_down(out); +} + +void t_c_glib_generator::declare_local_variable(ofstream& out, t_type* ttype, string& name, bool for_hash_table) { + string tname = type_name(ttype); + + /* If the given type is a typedef, find its underlying type so we + can correctly determine how to generate a pointer to it */ + ttype = get_true_type(ttype); + string ptr = !is_numeric(ttype) ? "" : "*"; + + if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + out << indent() << tname << ptr << " " << name << " = " + << generate_new_hash_from_type(tmap->get_key_type(), tmap->get_val_type()) << endl; + } else if (ttype->is_list()) { + t_list* tlist = (t_list*)ttype; + out << indent() << tname << ptr << " " << name << " = " + << generate_new_array_from_type(tlist->get_elem_type()) << endl; + } else if (for_hash_table && ttype->is_enum()) { + out << indent() << tname << " " << name << ";" << endl; + } else { + out << indent() << tname << ptr << " " << name + << (ptr != "" ? " = g_new (" + tname + ", 1)" : " = NULL") << ";" << endl; + } +} + +void t_c_glib_generator::declore_local_variable_for_write(ofstream& out, + t_type* ttype, + string& name) { + string tname = type_name(ttype); + ttype = get_true_type(ttype); + string ptr = ttype->is_string() || !ttype->is_base_type() ? " " : "* "; + string init_val = ttype->is_enum() ? "" : " = NULL"; + out << indent() << tname << ptr << name << init_val << ";" << endl; +} + +void t_c_glib_generator::generate_deserialize_map_element(ofstream& out, + t_map* tmap, + string prefix, + int error_ret) { + t_type* tkey = tmap->get_key_type(); + t_type* tval = tmap->get_val_type(); + string keyname = tmp("key"); + string valname = tmp("val"); + + declare_local_variable(out, tkey, keyname, true); + declare_local_variable(out, tval, valname, true); + + /* If either the key or value type is a typedef, find its underlying + type so we can correctly determine how to generate a pointer to + it */ + tkey = get_true_type(tkey); + tval = get_true_type(tval); + + string tkey_ptr = tkey->is_string() || !tkey->is_base_type() ? "" : "*"; + string tval_ptr = tval->is_string() || !tval->is_base_type() ? "" : "*"; + + // deserialize the fields of the map element + t_field fkey(tkey, tkey_ptr + keyname); + generate_deserialize_field(out, &fkey, "", "", error_ret); + t_field fval(tval, tval_ptr + valname); + generate_deserialize_field(out, &fval, "", "", error_ret); + + indent(out) << "if (" << prefix << " && " << keyname << ")" << endl; + indent_up(); + indent(out) << "g_hash_table_insert ((GHashTable *)" << prefix << ", (gpointer) " << keyname + << ", (gpointer) " << valname << ");" << endl; + indent_down(); +} + +void t_c_glib_generator::generate_deserialize_set_element(ofstream& out, + t_set* tset, + string prefix, + int error_ret) { + t_type* telem = tset->get_elem_type(); + string elem = tmp("_elem"); + string telem_ptr = telem->is_string() || !telem->is_base_type() ? "" : "*"; + + declare_local_variable(out, telem, elem, true); + + t_field felem(telem, telem_ptr + elem); + generate_deserialize_field(out, &felem, "", "", error_ret); + + indent(out) << "if (" << prefix << " && " << elem << ")" << endl; + indent_up(); + indent(out) << "g_hash_table_insert ((GHashTable *) " << prefix << ", (gpointer) " << elem + << ", (gpointer) " << elem << ");" << endl; + indent_down(); +} + +void t_c_glib_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix, + string index, + int error_ret) { + (void)index; + t_type* ttype = get_true_type(tlist->get_elem_type()); + string elem = tmp("_elem"); + string telem_ptr = !is_numeric(ttype) ? "" : "*"; + + declare_local_variable(out, ttype, elem, false); + + t_field felem(ttype, telem_ptr + elem); + generate_deserialize_field(out, &felem, "", "", error_ret); + + if (ttype->is_void()) { + throw std::runtime_error("compiler error: list element type cannot be void"); + } else if (is_numeric(ttype)) { + indent(out) << "g_array_append_vals (" << prefix << ", " << elem << ", 1);" << endl; + } else { + indent(out) << "g_ptr_array_add (" << prefix << ", " << elem << ");" << endl; + } +} + +string t_c_glib_generator::generate_free_func_from_type(t_type* ttype) { + if (ttype == NULL) + return "NULL"; + + if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot determine hash type"; + break; + case t_base_type::TYPE_BOOL: + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + case t_base_type::TYPE_DOUBLE: + return "g_free"; + case t_base_type::TYPE_STRING: + if (((t_base_type*)ttype)->is_binary()) { + return "thrift_string_free"; + } + return "g_free"; + default: + throw "compiler error: no hash table info for type"; + } + } else if (ttype->is_enum()) { + return "NULL"; + } else if (ttype->is_map() || ttype->is_set()) { + return "(GDestroyNotify) thrift_safe_hash_table_destroy"; + } else if (ttype->is_struct()) { + return "g_object_unref"; + } else if (ttype->is_list()) { + t_type* etype = ((t_list*)ttype)->get_elem_type(); + if (etype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)etype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot determine array type"; + break; + case t_base_type::TYPE_BOOL: + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + case t_base_type::TYPE_DOUBLE: + return "(GDestroyNotify) g_array_unref"; + case t_base_type::TYPE_STRING: + return "(GDestroyNotify) g_ptr_array_unref"; + default: + throw "compiler error: no array info for type"; + } + } else if (etype->is_container() || etype->is_struct()) { + return "(GDestroyNotify) g_ptr_array_unref"; + ; + } else if (etype->is_enum()) { + return "(GDestroyNotify) g_array_unref"; + } + printf("Type not expected inside the array: %s\n", etype->get_name().c_str()); + throw "Type not expected inside array"; + } else if (ttype->is_typedef()) { + return generate_free_func_from_type(((t_typedef*)ttype)->get_type()); + } + printf("Type not expected: %s\n", ttype->get_name().c_str()); + throw "Type not expected"; +} + +string t_c_glib_generator::generate_hash_func_from_type(t_type* ttype) { + if (ttype == NULL) + return "NULL"; + + if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot determine hash type"; + break; + case t_base_type::TYPE_BOOL: + return "thrift_boolean_hash"; + case t_base_type::TYPE_I8: + return "thrift_int8_hash"; + case t_base_type::TYPE_I16: + return "thrift_int16_hash"; + case t_base_type::TYPE_I32: + return "g_int_hash"; + case t_base_type::TYPE_I64: + return "g_int64_hash"; + case t_base_type::TYPE_DOUBLE: + return "g_double_hash"; + case t_base_type::TYPE_STRING: + return "g_str_hash"; + default: + throw "compiler error: no hash table info for type"; + } + } else if (ttype->is_enum()) { + return "g_direct_hash"; + } else if (ttype->is_container() || ttype->is_struct()) { + return "g_direct_hash"; + } else if (ttype->is_typedef()) { + return generate_hash_func_from_type(((t_typedef*)ttype)->get_type()); + } + printf("Type not expected: %s\n", ttype->get_name().c_str()); + throw "Type not expected"; +} + +string t_c_glib_generator::generate_cmp_func_from_type(t_type* ttype) { + if (ttype == NULL) + return "NULL"; + + if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot determine hash type"; + break; + case t_base_type::TYPE_BOOL: + return "thrift_boolean_equal"; + case t_base_type::TYPE_I8: + return "thrift_int8_equal"; + case t_base_type::TYPE_I16: + return "thrift_int16_equal"; + case t_base_type::TYPE_I32: + return "g_int_equal"; + case t_base_type::TYPE_I64: + return "g_int64_equal"; + case t_base_type::TYPE_DOUBLE: + return "g_double_equal"; + case t_base_type::TYPE_STRING: + return "g_str_equal"; + default: + throw "compiler error: no hash table info for type"; + } + } else if (ttype->is_enum()) { + return "g_direct_equal"; + } else if (ttype->is_container() || ttype->is_struct()) { + return "g_direct_equal"; + } else if (ttype->is_typedef()) { + return generate_cmp_func_from_type(((t_typedef*)ttype)->get_type()); + } + printf("Type not expected: %s\n", ttype->get_name().c_str()); + throw "Type not expected"; +} + +string t_c_glib_generator::generate_new_hash_from_type(t_type* key, t_type* value) { + string hash_func = generate_hash_func_from_type(key); + string cmp_func = generate_cmp_func_from_type(key); + string key_free_func = generate_free_func_from_type(key); + string value_free_func = generate_free_func_from_type(value); + + return "g_hash_table_new_full (" + hash_func + ", " + cmp_func + ", " + key_free_func + ", " + + value_free_func + ");"; +} + +string t_c_glib_generator::generate_new_array_from_type(t_type* ttype) { + if (ttype->is_void()) { + throw std::runtime_error("compiler error: cannot determine array type"); + } else if (is_numeric(ttype)) { + return "g_array_new (0, 1, sizeof (" + base_type_name(ttype) + "));"; + } else { + string free_func = generate_free_func_from_type(ttype); + return "g_ptr_array_new_with_free_func (" + free_func + ");"; + } +} + +/*************************************** + * UTILITY FUNCTIONS * + ***************************************/ + +/** + * Upper case a string. Wraps boost's string utility. + */ +string to_upper_case(string name) { + string s(name); + std::transform(s.begin(), s.end(), s.begin(), ::toupper); + return s; + // return boost::to_upper_copy (name); +} + +/** + * Lower case a string. Wraps boost's string utility. + */ +string to_lower_case(string name) { + string s(name); + std::transform(s.begin(), s.end(), s.begin(), ::tolower); + return s; + // return boost::to_lower_copy (name); +} + +/** + * Makes a string friendly to C code standards by lowercasing and adding + * underscores, with the exception of the first character. For example: + * + * Input: "ZomgCamelCase" + * Output: "zomg_camel_case" + */ +string initial_caps_to_underscores(string name) { + string ret; + const char* tmp = name.c_str(); + int pos = 0; + + /* the first character isn't underscored if uppercase, just lowercased */ + ret += tolower(tmp[pos]); + pos++; + for (unsigned int i = pos; i < name.length(); i++) { + char lc = tolower(tmp[i]); + if (lc != tmp[i]) { + ret += '_'; + } + ret += lc; + } + + return ret; +} + +/** + * Performs the reverse operation of initial_caps_to_underscores: The first + * character of the string is made uppercase, along with each character that + * follows an underscore (which is removed). Useful for converting Thrift + * service-method names into GObject-style class names. + * + * Input: "zomg_camel_case" + * Output: "ZomgCamelCase" + */ +string underscores_to_initial_caps(string name) { + string ret; + const char* tmp = name.c_str(); + bool uppercase_next = true; + + for (unsigned int i = 0; i < name.length(); i++) { + char c = tmp[i]; + if (c == '_') { + uppercase_next = true; + } else { + if (uppercase_next) { + ret += toupper(c); + uppercase_next = false; + } else { + ret += c; + } + } + } + + return ret; +} + +/* register this generator with the main program */ +THRIFT_REGISTER_GENERATOR(c_glib, "C, using GLib", "") diff --git a/compiler/cpp/src/thrift/generate/t_cocoa_generator.cc b/compiler/cpp/src/thrift/generate/t_cocoa_generator.cc new file mode 100644 index 0000000..c2f09e8 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_cocoa_generator.cc @@ -0,0 +1,3301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ostream; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * Objective-C code generator. + * + * mostly copy/pasting/tweaking from mcslee's work. + */ +class t_cocoa_generator : public t_oop_generator { +public: + t_cocoa_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + log_unexpected_ = false; + validate_required_ = false; + async_clients_ = false; + promise_kit_ = false; + debug_descriptions_ = false; + pods_ = false; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("log_unexpected") == 0) { + log_unexpected_ = true; + } else if( iter->first.compare("validate_required") == 0) { + validate_required_ = true; + } else if( iter->first.compare("async_clients") == 0) { + async_clients_ = true; + } else if( iter->first.compare("promise_kit") == 0) { + promise_kit_ = true; + } else if( iter->first.compare("debug_descriptions") == 0) { + debug_descriptions_ = true; + } else if( iter->first.compare("pods") == 0) { + pods_ = true; + } else { + throw "unknown option cocoa:" + iter->first; + } + } + + out_dir_base_ = "gen-cocoa"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + void generate_consts(std::vector consts); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + void print_const_value(ostream& out, + string name, + t_type* type, + t_const_value* value, + bool defval = false); + std::string render_const_value(ostream& out, + t_type* type, + t_const_value* value, + bool box_it = false); + + void generate_cocoa_struct(t_struct* tstruct, bool is_exception); + void generate_cocoa_struct_interface(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false); + void generate_cocoa_struct_implementation(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false, + bool is_result = false); + void generate_cocoa_struct_initializer_signature(std::ofstream& out, t_struct* tstruct); + void generate_cocoa_struct_init_with_coder_method(ofstream& out, + t_struct* tstruct, + bool is_exception); + void generate_cocoa_struct_encode_with_coder_method(ofstream& out, + t_struct* tstruct, + bool is_exception); + void generate_cocoa_struct_copy_method(ofstream& out, + t_struct* tstruct, + bool is_exception); + void generate_cocoa_struct_hash_method(ofstream& out, t_struct* tstruct); + void generate_cocoa_struct_is_equal_method(ofstream& out, + t_struct* tstruct, + bool is_exception); + void generate_cocoa_struct_field_accessor_implementations(std::ofstream& out, + t_struct* tstruct, + bool is_exception); + void generate_cocoa_struct_reader(std::ofstream& out, t_struct* tstruct); + void generate_cocoa_struct_result_writer(std::ofstream& out, t_struct* tstruct); + void generate_cocoa_struct_writer(std::ofstream& out, t_struct* tstruct); + void generate_cocoa_struct_validator(std::ofstream& out, t_struct* tstruct); + void generate_cocoa_struct_description(std::ofstream& out, t_struct* tstruct); + + std::string function_result_helper_struct_type(t_service *tservice, t_function* tfunction); + std::string function_args_helper_struct_type(t_service* tservice, t_function* tfunction); + void generate_function_helpers(t_service *tservice, t_function* tfunction); + + /** + * Service-level generation functions + */ + + void generate_cocoa_service_protocol(std::ofstream& out, t_service* tservice); + void generate_cocoa_service_async_protocol(std::ofstream& out, t_service* tservice); + + void generate_cocoa_service_client_interface(std::ofstream& out, t_service* tservice); + void generate_cocoa_service_client_async_interface(std::ofstream& out, t_service* tservice); + + void generate_cocoa_service_client_send_function_implementation(ofstream& out, + t_service* tservice, + t_function* tfunction, + bool needs_protocol); + void generate_cocoa_service_client_send_function_invocation(ofstream& out, t_function* tfunction); + void generate_cocoa_service_client_send_async_function_invocation(ofstream& out, + t_function* tfunction, + string failureBlockName); + void generate_cocoa_service_client_recv_function_implementation(ofstream& out, + t_service* tservice, + t_function* tfunction, + bool needs_protocol); + void generate_cocoa_service_client_implementation(std::ofstream& out, t_service* tservice); + void generate_cocoa_service_client_async_implementation(std::ofstream& out, t_service* tservice); + + void generate_cocoa_service_server_interface(std::ofstream& out, t_service* tservice); + void generate_cocoa_service_server_implementation(std::ofstream& out, t_service* tservice); + void generate_cocoa_service_helpers(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* tfunction); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, t_field* tfield, std::string fieldName); + + void generate_deserialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_deserialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_deserialize_set_element(std::ofstream& out, t_set* tset, std::string prefix = ""); + + void generate_deserialize_map_element(std::ofstream& out, t_map* tmap, std::string prefix = ""); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix = ""); + + void generate_serialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string fieldName = ""); + + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string iter, + std::string map); + + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(std::ofstream& out, + t_list* tlist, + std::string index, + std::string listName); + + /** + * Helper rendering functions + */ + + std::string cocoa_prefix(); + std::string cocoa_imports(); + std::string cocoa_thrift_imports(); + std::string type_name(t_type* ttype, bool class_ref = false, bool needs_mutable = false); + std::string element_type_name(t_type* ttype); + std::string base_type_name(t_base_type* tbase); + std::string declare_property(t_field* tfield); + std::string declare_property_isset(t_field* tfield); + std::string declare_property_unset(t_field* tfield); + std::string invalid_return_statement(t_function* tfunction); + std::string function_signature(t_function* tfunction, bool include_error); + std::string async_function_signature(t_function* tfunction, bool include_error); + std::string promise_function_signature(t_function* tfunction); + std::string argument_list(t_struct* tstruct, string protocol_name, bool include_error); + std::string type_to_enum(t_type* ttype); + std::string format_string_for_type(t_type* type); + std::string format_cast_for_type(t_type* type); + std::string call_field_setter(t_field* tfield, std::string fieldName); + std::string box(t_type *ttype, std::string field_name); + std::string unbox(t_type* ttype, std::string field_name); + std::string getter_name(string field_name); + std::string setter_name(string field_name); + + bool type_can_be_null(t_type* ttype) { + ttype = get_true_type(ttype); + + return ttype->is_container() || ttype->is_struct() || ttype->is_xception() + || ttype->is_string(); + } + +private: + std::string cocoa_prefix_; + std::string constants_declarations_; + int error_constant_; + + /** + * File streams + */ + + std::ofstream f_header_; + std::ofstream f_impl_; + + bool log_unexpected_; + bool validate_required_; + bool async_clients_; + bool promise_kit_; + bool debug_descriptions_; + bool pods_; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + */ +void t_cocoa_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + cocoa_prefix_ = program_->get_namespace("cocoa"); + + // we have a .h header file... + string f_header_name = cocoa_prefix_ + capitalize(program_name_) + ".h"; + string f_header_fullname = get_out_dir() + f_header_name; + f_header_.open(f_header_fullname.c_str()); + + f_header_ << autogen_comment() << endl; + + f_header_ << cocoa_imports() << cocoa_thrift_imports(); + + // ...and a .m implementation file + string f_impl_name = cocoa_prefix_ + capitalize(program_name_) + ".m"; + string f_impl_fullname = get_out_dir() + f_impl_name; + f_impl_.open(f_impl_fullname.c_str()); + + f_impl_ << autogen_comment() << endl; + + f_impl_ << cocoa_imports() << cocoa_thrift_imports() << "#import \"" << f_header_name << "\"" + << endl << endl; + + error_constant_ = 60000; +} + +/** + * Prints standard Cocoa imports + * + * @return List of imports for Cocoa libraries + */ +string t_cocoa_generator::cocoa_imports() { + return string() + "#import \n" + "\n"; +} + +/** + * Prints thrift runtime imports + * + * @return List of imports necessary for thrift runtime + */ +string t_cocoa_generator::cocoa_thrift_imports() { + + vector includes_list; + includes_list.push_back("TProtocol.h"); + includes_list.push_back("TProtocolFactory.h"); + includes_list.push_back("TApplicationError.h"); + includes_list.push_back("TProtocolError.h"); + includes_list.push_back("TProtocolUtil.h"); + includes_list.push_back("TProcessor.h"); + includes_list.push_back("TBase.h"); + includes_list.push_back("TAsyncTransport.h"); + includes_list.push_back("TBaseClient.h"); + + std::ostringstream includes; + + vector::const_iterator i_iter; + for (i_iter=includes_list.begin(); i_iter!=includes_list.end(); ++i_iter) { + includes << "#import "; + if (pods_) { + includes << ""; + } else { + includes << "\"" << *i_iter << "\""; + } + includes << endl; + } + + includes << endl; + + if (promise_kit_) { + includes << "#import "; + if (pods_) { + includes << ""; + } else { + includes << "\"PromiseKit.h\""; + } + includes << endl; + } + + // Include other Thrift includes + const vector& other_includes = program_->get_includes(); + for (size_t i = 0; i < other_includes.size(); ++i) { + includes << "#import \"" + << other_includes[i]->get_namespace("cocoa") + << capitalize(other_includes[i]->get_name()) + << ".h\"" << endl; + } + + includes << endl; + + return includes.str(); +} + +/** + * Finish up generation. + */ +void t_cocoa_generator::close_generator() { + // stick our constants declarations at the end of the header file + // since they refer to things we are defining. + f_header_ << constants_declarations_ << endl; +} + +/** + * Generates a typedef. This is just a simple 1-liner in objective-c + * + * @param ttypedef The type definition + */ +void t_cocoa_generator::generate_typedef(t_typedef* ttypedef) { + if (ttypedef->get_type()->is_map()) { + t_map *map = (t_map *)ttypedef->get_type(); + if (map->get_key_type()->is_struct()) { + f_header_ << indent() << "@class " << type_name(map->get_key_type(), true) << ";" << endl; + } + if (map->get_val_type()->is_struct()) { + f_header_ << indent() << "@class " << type_name(map->get_val_type(), true) << ";" << endl; + } + } + else if (ttypedef->get_type()->is_set()) { + t_set *set = (t_set *)ttypedef->get_type(); + if (set->get_elem_type()->is_struct()) { + f_header_ << indent() << "@class " << type_name(set->get_elem_type(), true) << ";" << endl; + } + } + else if (ttypedef->get_type()->is_list()) { + t_list *list = (t_list *)ttypedef->get_type(); + if (list->get_elem_type()->is_struct()) { + f_header_ << indent() << "@class " << type_name(list->get_elem_type(), true) << ";" << endl; + } + } + f_header_ << indent() << "typedef " << type_name(ttypedef->get_type()) << " " << cocoa_prefix_ + << ttypedef->get_symbolic() << ";" << endl << endl; + if (ttypedef->get_type()->is_container()) { + f_header_ << indent() << "typedef " << type_name(ttypedef->get_type(), false, true) << " " << cocoa_prefix_ + << "Mutable" << ttypedef->get_symbolic() << ";" << endl << endl; + } +} + +/** + * Generates code for an enumerated type. In Objective-C, this is + * essentially the same as the thrift definition itself, instead using + * NS_ENUM keyword in Objective-C. For namespace purposes, the name of + * the enum is prefixed to each element in keeping with Cocoa & Swift + * standards. + * + * @param tenum The enumeration + */ +void t_cocoa_generator::generate_enum(t_enum* tenum) { + f_header_ << indent() << "typedef NS_ENUM(SInt32, " << cocoa_prefix_ << tenum->get_name() << ") {" << endl; + indent_up(); + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + bool first = true; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + if (first) { + first = false; + } else { + f_header_ << "," << endl; + } + f_header_ << indent() << cocoa_prefix_ << tenum->get_name() << (*c_iter)->get_name(); + f_header_ << " = " << (*c_iter)->get_value(); + } + + indent_down(); + f_header_ << endl << "};" << endl << endl; +} + +/** + * Generates a class that holds all the constants. + */ +void t_cocoa_generator::generate_consts(std::vector consts) { + std::ostringstream const_interface; + + const_interface << "FOUNDATION_EXPORT NSString *" << cocoa_prefix_ << capitalize(program_name_) << "ErrorDomain;" << endl + << endl; + + + bool needs_class = false; + + // Public constants for base types & strings + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + t_type* type = (*c_iter)->get_type()->get_true_type(); + if (!type->is_container() && !type->is_struct()) { + const_interface << "FOUNDATION_EXPORT " << type_name(type) << " " + << cocoa_prefix_ << capitalize((*c_iter)->get_name()) << ";" << endl; + } + else { + needs_class = true; + } + } + + + string constants_class_name = cocoa_prefix_ + capitalize(program_name_) + "Constants"; + + if (needs_class) { + + const_interface << endl; + + const_interface << "@interface " << constants_class_name << " : NSObject "; + scope_up(const_interface); + scope_down(const_interface); + + // getter method for each constant defined. + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + string name = (*c_iter)->get_name(); + t_type* type = (*c_iter)->get_type()->get_true_type(); + if (type->is_container() || type->is_struct()) { + t_type* type = (*c_iter)->get_type(); + const_interface << endl << "+ (" << type_name(type) << ") " << name << ";" << endl; + } + } + + const_interface << endl << "@end"; + } + + // this gets spit into the header file in ::close_generator + constants_declarations_ = const_interface.str(); + + f_impl_ << "NSString *" << cocoa_prefix_ << capitalize(program_name_) << "ErrorDomain = " + << "@\"" << cocoa_prefix_ << capitalize(program_name_) << "ErrorDomain\";" << endl << endl; + + // variables in the .m hold all simple constant values + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + string name = (*c_iter)->get_name(); + t_type* type = (*c_iter)->get_type(); + f_impl_ << type_name(type) << " " << cocoa_prefix_ << name; + t_type* ttype = type->get_true_type(); + if (!ttype->is_container() && !ttype->is_struct()) { + f_impl_ << " = " << render_const_value(f_impl_, type, (*c_iter)->get_value()); + } + f_impl_ << ";" << endl; + } + f_impl_ << endl; + + if (needs_class) { + + f_impl_ << "@implementation " << constants_class_name << endl << endl; + + // initialize complex constants when the class is loaded + f_impl_ << "+ (void) initialize "; + scope_up(f_impl_); + + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + t_type* ttype = (*c_iter)->get_type()->get_true_type(); + if (ttype->is_container() || ttype->is_struct()) { + f_impl_ << endl; + print_const_value(f_impl_, + cocoa_prefix_ + (*c_iter)->get_name(), + (*c_iter)->get_type(), + (*c_iter)->get_value(), + false); + f_impl_ << ";" << endl; + } + } + scope_down(f_impl_); + + // getter method for each constant + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + string name = (*c_iter)->get_name(); + t_type* type = (*c_iter)->get_type()->get_true_type(); + if (type->is_container() || type->is_struct()) { + f_impl_ << endl << "+ (" << type_name(type) << ") " << name << " "; + scope_up(f_impl_); + indent(f_impl_) << "return " << cocoa_prefix_ << name << ";" << endl; + scope_down(f_impl_); + } + } + + f_impl_ << "@end" << endl << endl; + } +} + +/** + * Generates a struct definition for a thrift data type. This is a class + * with protected data members, read(), write(), and getters and setters. + * + * @param tstruct The struct definition + */ +void t_cocoa_generator::generate_struct(t_struct* tstruct) { + generate_cocoa_struct_interface(f_header_, tstruct, false); + generate_cocoa_struct_implementation(f_impl_, tstruct, false); +} + +/** + * Exceptions are structs, but they inherit from NSException + * + * @param tstruct The struct definition + */ +void t_cocoa_generator::generate_xception(t_struct* txception) { + generate_cocoa_struct_interface(f_header_, txception, true); + generate_cocoa_struct_implementation(f_impl_, txception, true); +} + +/** + * Generate the interface for a struct + * + * @param tstruct The struct definition + */ +void t_cocoa_generator::generate_cocoa_struct_interface(ofstream& out, + t_struct* tstruct, + bool is_exception) { + + if (is_exception) { + out << "enum {" << endl + << " " << cocoa_prefix_ << capitalize(program_name_) << "Error" << tstruct->get_name() << " = -" << error_constant_++ << endl + << "};" << endl + << endl; + } + + out << "@interface " << cocoa_prefix_ << tstruct->get_name() << " : "; + + if (is_exception) { + out << "NSError "; + } else { + out << "NSObject "; + } + out << " " << endl; + + out << endl; + + // properties + const vector& members = tstruct->get_members(); + if (members.size() > 0) { + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + out << indent() << declare_property(*m_iter) << endl; + out << indent() << declare_property_isset(*m_iter) << endl; + out << indent() << declare_property_unset(*m_iter) << endl; + out << endl; + } + } + + out << endl; + + // initializer for all fields + if (!members.empty()) { + generate_cocoa_struct_initializer_signature(out, tstruct); + out << ";" << endl; + } + out << endl; + + out << "@end" << endl << endl; +} + +/** + * Generate signature for initializer of struct with a parameter for + * each field. + */ +void t_cocoa_generator::generate_cocoa_struct_initializer_signature(ofstream& out, + t_struct* tstruct) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + indent(out) << "- (instancetype) initWith"; + for (m_iter = members.begin(); m_iter != members.end();) { + if (m_iter == members.begin()) { + out << capitalize((*m_iter)->get_name()); + } else { + out << (*m_iter)->get_name(); + } + out << ": (" << type_name((*m_iter)->get_type()) << ") " << (*m_iter)->get_name(); + ++m_iter; + if (m_iter != members.end()) { + out << " "; + } + } +} + +/** + * Generate the initWithCoder method for this struct so it's compatible with + * the NSCoding protocol + */ +void t_cocoa_generator::generate_cocoa_struct_init_with_coder_method(ofstream& out, + t_struct* tstruct, + bool is_exception) { + + indent(out) << "- (instancetype) initWithCoder: (NSCoder *) decoder" << endl; + scope_up(out); + + if (is_exception) { + // NSExceptions conform to NSCoding, so we can call super + indent(out) << "self = [super initWithCoder: decoder];" << endl; + } else { + indent(out) << "self = [super init];" << endl; + } + + indent(out) << "if (self) "; + scope_up(out); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + out << indent() << "if ([decoder containsValueForKey: @\"" << (*m_iter)->get_name() << "\"])" + << endl; + scope_up(out); + out << indent() << "_" << (*m_iter)->get_name() << " = "; + if (type_can_be_null(t)) { + out << "[decoder decodeObjectForKey: @\"" << (*m_iter)->get_name() << "\"];" + << endl; + } else if (t->is_enum()) { + out << "[decoder decodeIntForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl; + } else { + t_base_type::t_base tbase = ((t_base_type*)t)->get_base(); + switch (tbase) { + case t_base_type::TYPE_BOOL: + out << "[decoder decodeBoolForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl; + break; + case t_base_type::TYPE_I8: + out << "[decoder decodeIntForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl; + break; + case t_base_type::TYPE_I16: + out << "[decoder decodeIntForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl; + break; + case t_base_type::TYPE_I32: + out << "[decoder decodeInt32ForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl; + break; + case t_base_type::TYPE_I64: + out << "[decoder decodeInt64ForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl; + break; + case t_base_type::TYPE_DOUBLE: + out << "[decoder decodeDoubleForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl; + break; + default: + throw "compiler error: don't know how to decode thrift type: " + + t_base_type::t_base_name(tbase); + } + } + out << indent() << "_" << (*m_iter)->get_name() << "IsSet = YES;" << endl; + scope_down(out); + } + + scope_down(out); + + out << indent() << "return self;" << endl; + scope_down(out); + out << endl; +} + +/** + * Generate the encodeWithCoder method for this struct so it's compatible with + * the NSCoding protocol + */ +void t_cocoa_generator::generate_cocoa_struct_encode_with_coder_method(ofstream& out, + t_struct* tstruct, + bool is_exception) { + + indent(out) << "- (void) encodeWithCoder: (NSCoder *) encoder" << endl; + scope_up(out); + + if (is_exception) { + // NSExceptions conform to NSCoding, so we can call super + out << indent() << "[super encodeWithCoder: encoder];" << endl; + } + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + out << indent() << "if (_" << (*m_iter)->get_name() << "IsSet)" << endl; + scope_up(out); + if (type_can_be_null(t)) { + out << indent() << "[encoder encodeObject: _" << (*m_iter)->get_name() << " forKey: @\"" + << (*m_iter)->get_name() << "\"];" << endl; + } else if (t->is_enum()) { + out << indent() << "[encoder encodeInt: _" << (*m_iter)->get_name() << " forKey: @\"" + << (*m_iter)->get_name() << "\"];" << endl; + } else { + t_base_type::t_base tbase = ((t_base_type*)t)->get_base(); + switch (tbase) { + case t_base_type::TYPE_BOOL: + out << indent() << "[encoder encodeBool: _" << (*m_iter)->get_name() << " forKey: @\"" + << (*m_iter)->get_name() << "\"];" << endl; + break; + case t_base_type::TYPE_I8: + out << indent() << "[encoder encodeInt: _" << (*m_iter)->get_name() << " forKey: @\"" + << (*m_iter)->get_name() << "\"];" << endl; + break; + case t_base_type::TYPE_I16: + out << indent() << "[encoder encodeInt: _" << (*m_iter)->get_name() << " forKey: @\"" + << (*m_iter)->get_name() << "\"];" << endl; + break; + case t_base_type::TYPE_I32: + out << indent() << "[encoder encodeInt32: _" << (*m_iter)->get_name() << " forKey: @\"" + << (*m_iter)->get_name() << "\"];" << endl; + break; + case t_base_type::TYPE_I64: + out << indent() << "[encoder encodeInt64: _" << (*m_iter)->get_name() << " forKey: @\"" + << (*m_iter)->get_name() << "\"];" << endl; + break; + case t_base_type::TYPE_DOUBLE: + out << indent() << "[encoder encodeDouble: _" << (*m_iter)->get_name() << " forKey: @\"" + << (*m_iter)->get_name() << "\"];" << endl; + break; + default: + throw "compiler error: don't know how to encode thrift type: " + + t_base_type::t_base_name(tbase); + } + } + scope_down(out); + } + + scope_down(out); + out << endl; +} + +/** + * Generate the copy method for this struct + */ +void t_cocoa_generator::generate_cocoa_struct_copy_method(ofstream& out, t_struct* tstruct, bool is_exception) { + out << indent() << "- (instancetype) copyWithZone:(NSZone *)zone" << endl; + scope_up(out); + + if (is_exception) { + out << indent() << type_name(tstruct) << " val = [" << cocoa_prefix_ << tstruct->get_name() << " errorWithDomain: self.domain code: self.code userInfo: self.userInfo];" << endl; + } else { + out << indent() << type_name(tstruct) << " val = [" << cocoa_prefix_ << tstruct->get_name() << " new];" << endl; + } + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + out << indent() << "if (_" << (*m_iter)->get_name() << "IsSet)" << endl; + scope_up(out); + if (type_can_be_null(t)) { + out << indent() << "val." << (*m_iter)->get_name() << " = [self." << (*m_iter)->get_name() << " copy];"; + } else { + out << indent() << "val." << (*m_iter)->get_name() << " = self." << (*m_iter)->get_name() << ";"; + } + out << endl; + scope_down(out); + } + + out << indent() << "return val;" << endl; + + scope_down(out); + out << endl; +} + +/** + * Generate the hash method for this struct + */ +void t_cocoa_generator::generate_cocoa_struct_hash_method(ofstream& out, t_struct* tstruct) { + indent(out) << "- (NSUInteger) hash" << endl; + scope_up(out); + out << indent() << "NSUInteger hash = 17;" << endl; + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + out << indent() << "hash = (hash * 31) ^ _" << (*m_iter)->get_name() + << "IsSet ? 2654435761 : 0;" << endl; + out << indent() << "if (_" << (*m_iter)->get_name() << "IsSet)" << endl; + scope_up(out); + if (type_can_be_null(t)) { + out << indent() << "hash = (hash * 31) ^ [_" << (*m_iter)->get_name() << " hash];" << endl; + } else { + out << indent() << "hash = (hash * 31) ^ [@(_" << (*m_iter)->get_name() << ") hash];" + << endl; + } + scope_down(out); + } + + out << indent() << "return hash;" << endl; + scope_down(out); + out << endl; +} + +/** + * Generate the isEqual method for this struct + */ +void t_cocoa_generator::generate_cocoa_struct_is_equal_method(ofstream& out, t_struct* tstruct, bool is_exception) { + indent(out) << "- (BOOL) isEqual: (id) anObject" << endl; + scope_up(out); + + indent(out) << "if (self == anObject) {" << endl; + indent_up(); + indent(out) << "return YES;" << endl; + indent_down(); + indent(out) << "}" << endl; + + string class_name = cocoa_prefix_ + tstruct->get_name(); + + if (is_exception) { + indent(out) << "if (![super isEqual:anObject]) {" << endl; + indent_up(); + indent(out) << "return NO;" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } + else { + indent(out) << "if (![anObject isKindOfClass:[" << class_name << " class]]) {" << endl; + indent_up(); + indent(out) << "return NO;" << endl; + indent_down(); + indent(out) << "}" << endl; + } + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + if (!members.empty()) { + indent(out) << class_name << " *other = (" << class_name << " *)anObject;" << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + string name = (*m_iter)->get_name(); + if (type_can_be_null(t)) { + out << indent() << "if ((_" << name << "IsSet != other->_" << name << "IsSet) ||" << endl + << indent() << " " + << "(_" << name << "IsSet && " + << "((_" << name << " || other->_" << name << ") && " + << "![_" << name << " isEqual:other->_" << name << "]))) {" << endl; + } else { + out << indent() << "if ((_" << name << "IsSet != other->_" << name << "IsSet) ||" << endl + << indent() << " " + << "(_" << name << "IsSet && " + << "(_" << name << " != other->_" << name << "))) {" << endl; + } + indent_up(); + indent(out) << "return NO;" << endl; + indent_down(); + indent(out) << "}" << endl; + } + } + + out << indent() << "return YES;" << endl; + scope_down(out); + out << endl; +} + +/** + * Generate struct implementation. + * + * @param tstruct The struct definition + * @param is_exception Is this an exception? + * @param is_result If this is a result it needs a different writer + */ +void t_cocoa_generator::generate_cocoa_struct_implementation(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool is_result) { + indent(out) << "@implementation " << cocoa_prefix_ << tstruct->get_name() << endl << endl; + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + // exceptions need to call the designated initializer on NSException + if (is_exception) { + out << indent() << "- (instancetype) init" << endl; + scope_up(out); + out << indent() << "return [super initWithDomain: " << cocoa_prefix_ << capitalize(program_name_) << "ErrorDomain" << endl + << indent() << " code: " << cocoa_prefix_ << capitalize(program_name_) << "Error" << tstruct->get_name() << endl + << indent() << " userInfo: nil];" << endl; + scope_down(out); + out << endl; + } else { + // struct + + // default initializer + // setup instance variables with default values + indent(out) << "- (instancetype) init" << endl; + scope_up(out); + indent(out) << "self = [super init];" << endl; + indent(out) << "if (self)"; + scope_up(out); + if (members.size() > 0) { + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if ((*m_iter)->get_value() != NULL) { + print_const_value(out, + "self." + (*m_iter)->get_name(), + t, + (*m_iter)->get_value(), + false); + } + } + } + scope_down(out); + indent(out) << "return self;" << endl; + scope_down(out); + out << endl; + } + + // initializer with all fields as params + if (!members.empty()) { + generate_cocoa_struct_initializer_signature(out, tstruct); + out << endl; + scope_up(out); + if (is_exception) { + out << indent() << "self = [self init];" << endl; + } else { + out << indent() << "self = [super init];" << endl; + } + + indent(out) << "if (self)"; + scope_up(out); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + out << indent() << "_" << (*m_iter)->get_name() << " = "; + if (get_true_type((*m_iter)->get_type())->is_container()) { + out << "[" << (*m_iter)->get_name() << " mutableCopy];" << endl; + } else { + out << (*m_iter)->get_name() << ";" << endl; + } + out << indent() << "_" << (*m_iter)->get_name() << "IsSet = YES;" << endl; + } + scope_down(out); + + out << indent() << "return self;" << endl; + scope_down(out); + out << endl; + } + + // initWithCoder for NSCoding + generate_cocoa_struct_init_with_coder_method(out, tstruct, is_exception); + // encodeWithCoder for NSCoding + generate_cocoa_struct_encode_with_coder_method(out, tstruct, is_exception); + // hash and isEqual for NSObject + generate_cocoa_struct_hash_method(out, tstruct); + generate_cocoa_struct_is_equal_method(out, tstruct, is_exception); + // copy for NSObject + generate_cocoa_struct_copy_method(out, tstruct, is_exception); + + // the rest of the methods + generate_cocoa_struct_field_accessor_implementations(out, tstruct, is_exception); + generate_cocoa_struct_reader(out, tstruct); + if (is_result) { + generate_cocoa_struct_result_writer(out, tstruct); + } else { + generate_cocoa_struct_writer(out, tstruct); + } + generate_cocoa_struct_validator(out, tstruct); + generate_cocoa_struct_description(out, tstruct); + + out << "@end" << endl << endl; +} + +/** + * Generates a function to read all the fields of the struct. + * + * @param tstruct The struct definition + */ +void t_cocoa_generator::generate_cocoa_struct_reader(ofstream& out, t_struct* tstruct) { + out << "- (BOOL) read: (id ) inProtocol error: (NSError *__autoreleasing *)__thriftError" << endl; + scope_up(out); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Declare stack tmp variables + indent(out) << "NSString * fieldName;" << endl; + indent(out) << "SInt32 fieldType;" << endl; + indent(out) << "SInt32 fieldID;" << endl; + out << endl; + + indent(out) << "if (![inProtocol readStructBeginReturningName: NULL error: __thriftError]) return NO;" << endl; + + // Loop over reading in fields + indent(out) << "while (true)" << endl; + scope_up(out); + + // Read beginning field marker + indent(out) + << "if (![inProtocol readFieldBeginReturningName: &fieldName type: &fieldType fieldID: &fieldID error: __thriftError]) return NO;" + << endl; + + // Check for field STOP marker and break + indent(out) << "if (fieldType == TTypeSTOP) { " << endl; + indent_up(); + indent(out) << "break;" << endl; + indent_down(); + indent(out) << "}" << endl; + + // Switch statement on the field we are reading + indent(out) << "switch (fieldID)" << endl; + + scope_up(out); + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << "case " << (*f_iter)->get_key() << ":" << endl; + indent_up(); + indent(out) << "if (fieldType == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; + indent_up(); + + generate_deserialize_field(out, *f_iter, "fieldValue"); + indent(out) << call_field_setter(*f_iter, "fieldValue") << endl; + + indent_down(); + out << indent() << "} else { " << endl; + if (log_unexpected_) { + out << indent() << " NSLog(@\"%s: field ID %i has unexpected type %i. Skipping.\", " + "__PRETTY_FUNCTION__, (int)fieldID, (int)fieldType);" << endl; + } + + out << indent() << " if (![TProtocolUtil skipType: fieldType onProtocol: inProtocol error: __thriftError]) return NO;" << endl; + out << indent() << "}" << endl << indent() << "break;" << endl; + indent_down(); + } + + // In the default case we skip the field + out << indent() << "default:" << endl; + if (log_unexpected_) { + out << indent() << " NSLog(@\"%s: unexpected field ID %i with type %i. Skipping.\", " + "__PRETTY_FUNCTION__, (int)fieldID, (int)fieldType);" << endl; + } + + out << indent() << " if (![TProtocolUtil skipType: fieldType onProtocol: inProtocol error: __thriftError]) return NO;" << endl; + + out << indent() << " break;" << endl; + + scope_down(out); + + // Read field end marker + indent(out) << "if (![inProtocol readFieldEnd: __thriftError]) return NO;" << endl; + + scope_down(out); + + out << indent() << "if (![inProtocol readStructEnd: __thriftError]) return NO;" << endl; + + // performs various checks (e.g. check that all required fields are set) + if (validate_required_) { + out << indent() << "if (![self validate: __thriftError]) return NO;" << endl; + } + + indent(out) << "return YES;" << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +/** + * Generates a function to write all the fields of the struct + * + * @param tstruct The struct definition + */ +void t_cocoa_generator::generate_cocoa_struct_writer(ofstream& out, t_struct* tstruct) { + out << indent() << "- (BOOL) write: (id ) outProtocol error: (NSError *__autoreleasing *)__thriftError {" << endl; + indent_up(); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out << indent() << "if (![outProtocol writeStructBeginWithName: @\"" << name << "\" error: __thriftError]) return NO;" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + out << indent() << "if (_" << (*f_iter)->get_name() << "IsSet) {" << endl; + indent_up(); + bool null_allowed = type_can_be_null((*f_iter)->get_type()); + if (null_allowed) { + out << indent() << "if (_" << (*f_iter)->get_name() << " != nil) {" << endl; + indent_up(); + } + + indent(out) << "if (![outProtocol writeFieldBeginWithName: @\"" << (*f_iter)->get_name() + << "\" type: " << type_to_enum((*f_iter)->get_type()) + << " fieldID: " << (*f_iter)->get_key() << " error: __thriftError]) return NO;" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "_" + (*f_iter)->get_name()); + + // Write field closer + indent(out) << "if (![outProtocol writeFieldEnd: __thriftError]) return NO;" << endl; + + if (null_allowed) { + scope_down(out); + } + scope_down(out); + } + // Write the struct map + out << indent() << "if (![outProtocol writeFieldStop: __thriftError]) return NO;" << endl + << indent() << "if (![outProtocol writeStructEnd: __thriftError]) return NO;" << endl; + + indent(out) << "return YES;" << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +/** + * Generates a function to write all the fields of the struct, which + * is a function result. These fields are only written if they are + * set, and only one of them can be set at a time. + * + * @param tstruct The struct definition + */ +void t_cocoa_generator::generate_cocoa_struct_result_writer(ofstream& out, t_struct* tstruct) { + out << indent() << "- (BOOL) write: (id ) outProtocol error: (NSError *__autoreleasing *)__thriftError {" << endl; + indent_up(); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out << indent() << "if (![outProtocol writeStructBeginWithName: @\"" << name << "\" error: __thriftError]) return NO;" << endl; + + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + out << endl << indent() << "if "; + } else { + out << " else if "; + } + + out << "(_" << (*f_iter)->get_name() << "IsSet) {" << endl; + indent_up(); + + bool null_allowed = type_can_be_null((*f_iter)->get_type()); + if (null_allowed) { + out << indent() << "if (_" << (*f_iter)->get_name() << " != nil) {" << endl; + indent_up(); + } + + indent(out) << "if (![outProtocol writeFieldBeginWithName: @\"" << (*f_iter)->get_name() + << "\" type: " << type_to_enum((*f_iter)->get_type()) + << " fieldID: " << (*f_iter)->get_key() << " error: __thriftError]) return NO;" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "_" + (*f_iter)->get_name()); + + // Write field closer + indent(out) << "if (![outProtocol writeFieldEnd: __thriftError]) return NO;" << endl; + + if (null_allowed) { + indent_down(); + indent(out) << "}" << endl; + } + + indent_down(); + indent(out) << "}"; + } + // Write the struct map + out << endl << indent() << "if (![outProtocol writeFieldStop: __thriftError]) return NO;" + << endl << indent() << "if (![outProtocol writeStructEnd: __thriftError]) return NO;" + << endl; + + indent(out) << "return YES;" << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +/** + * Generates a function to perform various checks + * (e.g. check that all required fields are set) + * + * @param tstruct The struct definition + */ +void t_cocoa_generator::generate_cocoa_struct_validator(ofstream& out, t_struct* tstruct) { + out << indent() << "- (BOOL) validate: (NSError *__autoreleasing *)__thriftError {" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out << indent() << "// check for required fields" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = (*f_iter); + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + out << indent() << "if (!_" << field->get_name() << "IsSet) "; + scope_up(out); + indent(out) << "if (__thriftError) "; + scope_up(out); + out << indent() << "*__thriftError = [NSError errorWithDomain: TProtocolErrorDomain" << endl + << indent() << " code: TProtocolErrorUnknown" << endl + << indent() << " userInfo: @{TProtocolErrorExtendedErrorKey: @(TProtocolExtendedErrorMissingRequiredField)," << endl + << indent() << " TProtocolErrorFieldNameKey: @\"" << (*f_iter)->get_name() << "\"}];" << endl; + scope_down(out); + scope_down(out); + } + } + indent(out) << "return YES;" << endl; + indent_down(); + out << indent() << "}" << endl << endl; +} + +/** + * Generate property accessor methods for all fields in the struct. + * getter, setter, isset getter. + * + * @param tstruct The struct definition + */ +void t_cocoa_generator::generate_cocoa_struct_field_accessor_implementations(ofstream& out, + t_struct* tstruct, + bool is_exception) { + (void)is_exception; + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + t_type* type = get_true_type(field->get_type()); + std::string field_name = field->get_name(); + std::string cap_name = field_name; + cap_name[0] = toupper(cap_name[0]); + + // Simple setter + indent(out) << "- (void) set" << cap_name << ": (" << type_name(type, false, true) << ") " << field_name + << " {" << endl; + indent_up(); + indent(out) << "_" << field_name << " = " << field_name << ";" << endl; + indent(out) << "_" << field_name << "IsSet = YES;" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + + // Unsetter - do we need this? + indent(out) << "- (void) unset" << cap_name << " {" << endl; + indent_up(); + if (type_can_be_null(type)) { + indent(out) << "_" << field_name << " = nil;" << endl; + } + indent(out) << "_" << field_name << "IsSet = NO;" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } +} + +/** + * Generates a description method for the given struct + * + * @param tstruct The struct definition + */ +void t_cocoa_generator::generate_cocoa_struct_description(ofstream& out, t_struct* tstruct) { + + // Allow use of debugDescription so the app can add description via a cateogory/extension + if (debug_descriptions_) { + out << indent() << "- (NSString *) debugDescription {" << endl; + } + else { + out << indent() << "- (NSString *) description {" << endl; + } + indent_up(); + + out << indent() << "NSMutableString * ms = [NSMutableString stringWithString: @\"" + << cocoa_prefix_ << tstruct->get_name() << "(\"];" << endl; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + indent(out) << "[ms appendString: @\"" << (*f_iter)->get_name() << ":\"];" << endl; + } else { + indent(out) << "[ms appendString: @\"," << (*f_iter)->get_name() << ":\"];" << endl; + } + t_type* ttype = (*f_iter)->get_type(); + indent(out) << "[ms appendFormat: @\"" << format_string_for_type(ttype) << "\", " + << format_cast_for_type(ttype) << "_" << (*f_iter)->get_name() << "];" << endl; + } + out << indent() << "[ms appendString: @\")\"];" << endl << indent() + << "return [NSString stringWithString: ms];" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a thrift service. In Objective-C this consists of a + * protocol definition, a client interface and a client implementation. + * + * @param tservice The service definition + */ +void t_cocoa_generator::generate_service(t_service* tservice) { + generate_cocoa_service_protocol(f_header_, tservice); + generate_cocoa_service_client_interface(f_header_, tservice); + generate_cocoa_service_server_interface(f_header_, tservice); + generate_cocoa_service_helpers(tservice); + generate_cocoa_service_client_implementation(f_impl_, tservice); + generate_cocoa_service_server_implementation(f_impl_, tservice); + if (async_clients_) { + generate_cocoa_service_async_protocol(f_header_, tservice); + generate_cocoa_service_client_async_interface(f_header_, tservice); + generate_cocoa_service_client_async_implementation(f_impl_, tservice); + } +} + +/** + * Generates structs for all the service return types + * + * @param tservice The service + */ +void t_cocoa_generator::generate_cocoa_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + + t_struct* ts = (*f_iter)->get_arglist(); + + string qname = function_args_helper_struct_type(tservice, *f_iter); + + t_struct qname_ts = t_struct(ts->get_program(), qname); + + const vector& members = ts->get_members(); + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + qname_ts.append(*m_iter); + } + + generate_cocoa_struct_interface(f_impl_, &qname_ts, false); + generate_cocoa_struct_implementation(f_impl_, &qname_ts, false, false); + generate_function_helpers(tservice, *f_iter); + } +} + +string t_cocoa_generator::function_result_helper_struct_type(t_service *tservice, t_function* tfunction) { + if (tfunction->is_oneway()) { + return tservice->get_name() + "_" + tfunction->get_name(); + } else { + return tservice->get_name() + "_" + tfunction->get_name() + "_result"; + } +} + +string t_cocoa_generator::function_args_helper_struct_type(t_service *tservice, t_function* tfunction) { + return tservice->get_name() + "_" + tfunction->get_name() + "_args"; +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_cocoa_generator::generate_function_helpers(t_service *tservice, t_function* tfunction) { + if (tfunction->is_oneway()) { + return; + } + + // create a result struct with a success field of the return type, + // and a field for each type of exception thrown + t_struct result(program_, function_result_helper_struct_type(tservice, tfunction)); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + // generate the result struct + generate_cocoa_struct_interface(f_impl_, &result, false); + generate_cocoa_struct_implementation(f_impl_, &result, false, true); +} + +/** + * Generates a service protocol definition. + * + * @param tservice The service to generate a protocol definition for + */ +void t_cocoa_generator::generate_cocoa_service_protocol(ofstream& out, t_service* tservice) { + out << "@protocol " << cocoa_prefix_ << tservice->get_name() << " " << endl; + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + out << "- " << function_signature(*f_iter, true) << ";" + << " // throws "; + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + out << type_name((*x_iter)->get_type()) + ", "; + } + out << "TException" << endl; + } + out << "@end" << endl << endl; +} + +/** + * Generates an asynchronous service protocol definition. + * + * @param tservice The service to generate a protocol definition for + */ +void t_cocoa_generator::generate_cocoa_service_async_protocol(ofstream& out, t_service* tservice) { + out << "@protocol " << cocoa_prefix_ << tservice->get_name() << "Async" + << " " << endl; + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + out << "- " << async_function_signature(*f_iter, false) << ";" << endl; + if (promise_kit_) { + out << "- " << promise_function_signature(*f_iter) << ";" << endl; + } + } + out << "@end" << endl << endl; +} + +/** + * Generates a service client interface definition. + * + * @param tservice The service to generate a client interface definition for + */ +void t_cocoa_generator::generate_cocoa_service_client_interface(ofstream& out, + t_service* tservice) { + out << "@interface " << cocoa_prefix_ << tservice->get_name() << "Client : TBaseClient <" + << cocoa_prefix_ << tservice->get_name() << "> " << endl; + + out << "- (id) initWithProtocol: (id ) protocol;" << endl; + out << "- (id) initWithInProtocol: (id ) inProtocol outProtocol: (id ) " + "outProtocol;" << endl; + out << "@end" << endl << endl; +} + +/** + * Generates a service client interface definition. + * + * @param tservice The service to generate a client interface definition for + */ +void t_cocoa_generator::generate_cocoa_service_client_async_interface(ofstream& out, + t_service* tservice) { + out << "@interface " << cocoa_prefix_ << tservice->get_name() << "ClientAsync : TBaseClient <" + << cocoa_prefix_ << tservice->get_name() << "Async> " << endl + << endl; + + out << "- (id) initWithProtocolFactory: (id ) protocolFactory " + << "transportFactory: (id ) transportFactory;" << endl; + out << "@end" << endl << endl; +} + +/** + * Generates a service server interface definition. In other words, the TProcess implementation for + *the + * service definition. + * + * @param tservice The service to generate a client interface definition for + */ +void t_cocoa_generator::generate_cocoa_service_server_interface(ofstream& out, + t_service* tservice) { + out << "@interface " << cocoa_prefix_ << tservice->get_name() + << "Processor : NSObject " << endl; + + out << "- (id) initWith" << tservice->get_name() << ": (id <" << cocoa_prefix_ + << tservice->get_name() << ">) service;" << endl; + out << "- (id<" << cocoa_prefix_ << tservice->get_name() << ">) service;" << endl; + + out << "@end" << endl << endl; +} + +void t_cocoa_generator::generate_cocoa_service_client_send_function_implementation( + ofstream& out, + t_service *tservice, + t_function* tfunction, + bool needs_protocol) { + string funname = tfunction->get_name(); + + t_function send_function(g_type_bool, + string("send_") + tfunction->get_name(), + tfunction->get_arglist()); + + string argsname = function_args_helper_struct_type(tservice, tfunction); + + // Open function + indent(out) << "- (BOOL) send_" << tfunction->get_name() << argument_list(tfunction->get_arglist(), needs_protocol ? "outProtocol" : "", true) << endl; + scope_up(out); + + // Serialize the request + out << indent() << "if (![outProtocol writeMessageBeginWithName: @\"" << funname << "\"" + << (tfunction->is_oneway() ? " type: TMessageTypeONEWAY" : " type: TMessageTypeCALL") + << " sequenceID: 0 error: __thriftError]) return NO;" << endl; + + out << indent() << "if (![outProtocol writeStructBeginWithName: @\"" << argsname + << "\" error: __thriftError]) return NO;" << endl; + + // write out function parameters + t_struct* arg_struct = tfunction->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + string fieldName = (*fld_iter)->get_name(); + if (type_can_be_null((*fld_iter)->get_type())) { + out << indent() << "if (" << fieldName << " != nil)"; + scope_up(out); + } + out << indent() << "if (![outProtocol writeFieldBeginWithName: @\"" << fieldName + << "\"" + " type: " << type_to_enum((*fld_iter)->get_type()) + << " fieldID: " << (*fld_iter)->get_key() << " error: __thriftError]) return NO;" << endl; + + generate_serialize_field(out, *fld_iter, fieldName); + + out << indent() << "if (![outProtocol writeFieldEnd: __thriftError]) return NO;" << endl; + + if (type_can_be_null((*fld_iter)->get_type())) { + indent_down(); + out << indent() << "}" << endl; + } + } + + out << indent() << "if (![outProtocol writeFieldStop: __thriftError]) return NO;" << endl; + out << indent() << "if (![outProtocol writeStructEnd: __thriftError]) return NO;" << endl; + out << indent() << "if (![outProtocol writeMessageEnd: __thriftError]) return NO;" << endl; + out << indent() << "return YES;" << endl; + scope_down(out); + out << endl; +} + +void t_cocoa_generator::generate_cocoa_service_client_recv_function_implementation( + ofstream& out, + t_service* tservice, + t_function* tfunction, + bool needs_protocol) { + + + // Open function + indent(out) << "- (BOOL) recv_" << tfunction->get_name(); + if (!tfunction->get_returntype()->is_void()) { + out << ": (" << type_name(tfunction->get_returntype(), false, true) << " *) result "; + if (needs_protocol) { + out << "protocol"; + } else { + out << "error"; + } + } + if (needs_protocol) { + out << ": (id) inProtocol error"; + } + out << ": (NSError *__autoreleasing *)__thriftError" << endl; + scope_up(out); + + // TODO(mcslee): Message validation here, was the seqid etc ok? + + // check for an exception + out << indent() << "NSError *incomingException = [self checkIncomingMessageException: inProtocol];" << endl + << indent() << "if (incomingException)"; + scope_up(out); + out << indent() << "if (__thriftError)"; + scope_up(out); + out << indent() << "*__thriftError = incomingException;" << endl; + scope_down(out); + out << indent() << "return NO;" << endl; + scope_down(out); + + // FIXME - could optimize here to reduce creation of temporary objects. + string resultname = function_result_helper_struct_type(tservice, tfunction); + out << indent() << cocoa_prefix_ << resultname << " * resulter = [" << cocoa_prefix_ << resultname << " new];" << endl; + indent(out) << "if (![resulter read: inProtocol error: __thriftError]) return NO;" << endl; + indent(out) << "if (![inProtocol readMessageEnd: __thriftError]) return NO;" << endl; + + // Careful, only return _result if not a void function + if (!tfunction->get_returntype()->is_void()) { + out << indent() << "if (resulter.successIsSet)"; + scope_up(out); + out << indent() << "*result = resulter.success;" << endl; + out << indent() << "return YES;" << endl; + scope_down(out); + } + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + out << indent() << "if (resulter." << (*x_iter)->get_name() << "IsSet)"; + scope_up(out); + out << indent() << "if (__thriftError)"; + scope_up(out); + out << indent() << "*__thriftError = [resulter " << (*x_iter)->get_name() << "];" << endl; + scope_down(out); + out << indent() << "return NO;" << endl; + scope_down(out); + } + + // If you get here it's an exception, unless a void function + if (tfunction->get_returntype()->is_void()) { + indent(out) << "return YES;" << endl; + } else { + out << indent() << "if (__thriftError)"; + scope_up(out); + out << indent() << "*__thriftError = [NSError errorWithDomain: TApplicationErrorDomain" << endl + << indent() << " code: TApplicationErrorMissingResult" << endl + << indent() << " userInfo: @{TApplicationErrorMethodKey: @\"" + << tfunction->get_name() << "\"}];" << endl; + scope_down(out); + out << indent() << "return NO;" << endl; + } + + // Close function + scope_down(out); + out << endl; +} + +/** + * Generates an invocation of a given 'send_' function. + * + * @param tfunction The service to generate an implementation for + */ +void t_cocoa_generator::generate_cocoa_service_client_send_function_invocation( + ofstream& out, + t_function* tfunction) { + + t_struct* arg_struct = tfunction->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + out << indent() << "if (![self send_" << tfunction->get_name(); + bool first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + string fieldName = (*fld_iter)->get_name(); + out << " "; + if (first) { + first = false; + out << ": " << fieldName; + } else { + out << fieldName << ": " << fieldName; + } + } + if (!fields.empty()) { + out << " error"; + } + out << ": __thriftError]) " << invalid_return_statement(tfunction) << endl; +} + +/** + * Generates an invocation of a given 'send_' function. + * + * @param tfunction The service to generate an implementation for + */ +void t_cocoa_generator::generate_cocoa_service_client_send_async_function_invocation( + ofstream& out, + t_function* tfunction, + string failureBlockName) { + + t_struct* arg_struct = tfunction->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + out << indent() << "if (![self send_" << tfunction->get_name(); + bool first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + string fieldName = (*fld_iter)->get_name(); + out << " "; + if (first) { + first = false; + out << ": " << fieldName; + } else { + out << fieldName << ": " << fieldName; + } + } + if (!fields.empty()) { + out << " protocol"; + } + out << ": protocol error: &thriftError]) "; + scope_up(out); + out << indent() << failureBlockName << "(thriftError);" << endl + << indent() << "return;" << endl; + scope_down(out); +} + +/** + * Generates a service client implementation. + * + * @param tservice The service to generate an implementation for + */ +void t_cocoa_generator::generate_cocoa_service_client_implementation(ofstream& out, + t_service* tservice) { + + string name = cocoa_prefix_ + tservice->get_name() + "Client"; + + out << "@interface " << name << " () "; + scope_up(out); + out << endl; + out << indent() << "id inProtocol;" << endl; + out << indent() << "id outProtocol;" << endl; + out << endl; + scope_down(out); + out << endl; + out << "@end" << endl << endl; + + out << "@implementation " << name << endl; + + // initializers + out << "- (id) initWithProtocol: (id ) protocol" << endl; + scope_up(out); + out << indent() << "return [self initWithInProtocol: protocol outProtocol: protocol];" << endl; + scope_down(out); + out << endl; + + out << "- (id) initWithInProtocol: (id ) anInProtocol outProtocol: (id ) " + "anOutProtocol" << endl; + scope_up(out); + out << indent() << "self = [super init];" << endl; + out << indent() << "if (self) "; + scope_up(out); + out << indent() << "inProtocol = anInProtocol;" << endl; + out << indent() << "outProtocol = anOutProtocol;" << endl; + scope_down(out); + out << indent() << "return self;" << endl; + scope_down(out); + out << endl; + + // generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + + generate_cocoa_service_client_send_function_implementation(out, tservice, *f_iter, false); + + if (!(*f_iter)->is_oneway()) { + generate_cocoa_service_client_recv_function_implementation(out, tservice, *f_iter, false); + } + + // Open function + indent(out) << "- " << function_signature(*f_iter, true) << endl; + scope_up(out); + generate_cocoa_service_client_send_function_invocation(out, *f_iter); + + out << indent() << "if (![[outProtocol transport] flush: __thriftError]) " << invalid_return_statement(*f_iter) << endl; + if (!(*f_iter)->is_oneway()) { + if ((*f_iter)->get_returntype()->is_void()) { + out << indent() << "if (![self recv_" << (*f_iter)->get_name() << ": __thriftError]) return NO;" << endl; + out << indent() << "return YES;" << endl; + } else { + out << indent() << type_name((*f_iter)->get_returntype(), false, true) << " __result;" << endl + << indent() << "if (![self recv_" << (*f_iter)->get_name() << ": &__result error: __thriftError]) " + << invalid_return_statement(*f_iter) << endl; + if (type_can_be_null((*f_iter)->get_returntype())) { + out << indent() << "return __result;" << endl; + } else { + out << indent() << "return @(__result);" << endl; + } + } + } + else { + out << indent() << "return YES;" << endl; + } + scope_down(out); + out << endl; + } + + out << "@end" << endl << endl; +} + +/** + * Generates a service client implementation for its asynchronous interface. + * + * @param tservice The service to generate an implementation for + */ +void t_cocoa_generator::generate_cocoa_service_client_async_implementation(ofstream& out, + t_service* tservice) { + + string name = cocoa_prefix_ + tservice->get_name() + "ClientAsync"; + + out << "@interface " << name << " () "; + scope_up(out); + out << endl; + out << indent() << "id protocolFactory;" << endl; + out << indent() << "id transportFactory;" << endl; + out << endl; + scope_down(out); + out << endl; + out << "@end" << endl << endl; + + + out << "@implementation " << name << endl + << endl << "- (id) initWithProtocolFactory: (id ) aProtocolFactory " + "transportFactory: (id ) aTransportFactory;" << endl; + + scope_up(out); + out << indent() << "self = [super init];" << endl; + out << indent() << "if (self) {" << endl; + out << indent() << " protocolFactory = aProtocolFactory;" << endl; + out << indent() << " transportFactory = aTransportFactory;" << endl; + out << indent() << "}" << endl; + out << indent() << "return self;" << endl; + scope_down(out); + out << endl; + + // generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + + generate_cocoa_service_client_send_function_implementation(out, tservice, *f_iter, true); + + if (!(*f_iter)->is_oneway()) { + generate_cocoa_service_client_recv_function_implementation(out, tservice, *f_iter, true); + } + + // Open function + indent(out) << "- " << async_function_signature(*f_iter, false) << endl; + scope_up(out); + + out << indent() << "NSError *thriftError;" << endl + << indent() << "id transport = [transportFactory newTransport];" << endl + << indent() << "id protocol = [protocolFactory newProtocolOnTransport:transport];" << endl + << endl; + + generate_cocoa_service_client_send_async_function_invocation(out, *f_iter, "failureBlock"); + + out << indent() << "[transport flushWithCompletion:^{" << endl; + indent_up(); + + if (!(*f_iter)->is_oneway()) { + out << indent() << "NSError *thriftError;" << endl; + + if (!(*f_iter)->get_returntype()->is_void()) { + out << indent() << type_name((*f_iter)->get_returntype()) << " result;" << endl; + } + out << indent() << "if (![self recv_" << (*f_iter)->get_name(); + if (!(*f_iter)->get_returntype()->is_void()) { + out << ": &result protocol"; + } + out << ": protocol error: &thriftError]) "; + scope_up(out); + out << indent() << "failureBlock(thriftError);" << endl + << indent() << "return;" << endl; + scope_down(out); + } + + out << indent() << "responseBlock("; + if (!(*f_iter)->is_oneway() && !(*f_iter)->get_returntype()->is_void()) { + out << "result"; + } + out << ");" << endl; + + indent_down(); + + out << indent() << "} failure:failureBlock];" << endl; + + scope_down(out); + + out << endl; + + // Promise function + if (promise_kit_) { + + indent(out) << "- " << promise_function_signature(*f_iter) << endl; + scope_up(out); + + out << indent() << "return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolver) {" << endl; + indent_up(); + + out << indent() << "NSError *thriftError;" << endl + << indent() << "id transport = [transportFactory newTransport];" << endl + << indent() << "id protocol = [protocolFactory newProtocolOnTransport:transport];" << endl + << endl; + + generate_cocoa_service_client_send_async_function_invocation(out, *f_iter, "resolver"); + + out << indent() << "[transport flushWithCompletion:^{" << endl; + indent_up(); + + if (!(*f_iter)->is_oneway()) { + out << indent() << "NSError *thriftError;" << endl; + + if (!(*f_iter)->get_returntype()->is_void()) { + out << indent() << type_name((*f_iter)->get_returntype()) << " result;" << endl; + } + out << indent() << "if (![self recv_" << (*f_iter)->get_name(); + if (!(*f_iter)->get_returntype()->is_void()) { + out << ": &result protocol"; + } + out << ": protocol error: &thriftError]) "; + scope_up(out); + out << indent() << "resolver(thriftError);" << endl + << indent() << "return;" << endl; + scope_down(out); + } + + out << indent() << "resolver("; + if ((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void()) { + out << "@YES"; + } else if (type_can_be_null((*f_iter)->get_returntype())) { + out << "result"; + } else { + out << "@(result)"; + } + out << ");" << endl; + + indent_down(); + + out << indent() << "} failure:^(NSError *error) {" << endl; + indent_up(); + out << indent() << "resolver(error);" << endl; + indent_down(); + out << indent() << "}];" << endl; + + indent_down(); + out << indent() << "}];" << endl; + + scope_down(out); + + out << endl; + + } + + } + + out << "@end" << endl << endl; +} + +/** + * Generates a service server implementation. In other words the actual TProcessor implementation + * for the service. + * + * @param tservice The service to generate an implementation for + */ +void t_cocoa_generator::generate_cocoa_service_server_implementation(ofstream& out, + t_service* tservice) { + + string name = cocoa_prefix_ + tservice->get_name() + "Processor"; + + out << "@interface " << name << " () "; + + scope_up(out); + out << indent() << "id <" << cocoa_prefix_ << tservice->get_name() << "> service;" << endl; + out << indent() << "NSDictionary * methodMap;" << endl; + scope_down(out); + + out << "@end" << endl << endl; + + out << "@implementation " << name << endl; + + // initializer + out << endl; + out << "- (id) initWith" << tservice->get_name() << ": (id <" << cocoa_prefix_ << tservice->get_name() << ">) aService" << endl; + scope_up(out); + out << indent() << "self = [super init];" << endl; + out << indent() << "if (self) "; + scope_up(out); + out << indent() << "service = aService;" << endl; + out << indent() << "methodMap = [NSMutableDictionary dictionary];" << endl; + + // generate method map for routing incoming calls + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string funname = (*f_iter)->get_name(); + scope_up(out); + out << indent() << "SEL s = @selector(process_" << funname << "_withSequenceID:inProtocol:outProtocol:error:);" << endl; + out << indent() << "NSMethodSignature * sig = [self methodSignatureForSelector: s];" << endl; + out << indent() << "NSInvocation * invocation = [NSInvocation invocationWithMethodSignature: sig];" << endl; + out << indent() << "[invocation setSelector: s];" << endl; + out << indent() << "[invocation retainArguments];" << endl; + out << indent() << "[methodMap setValue: invocation forKey: @\"" << funname << "\"];" << endl; + scope_down(out); + } + scope_down(out); + out << indent() << "return self;" << endl; + scope_down(out); + + // implementation of the 'service' method which returns the service associated with this + // processor + out << endl; + out << indent() << "- (id<" << cocoa_prefix_ << tservice->get_name() << ">) service" << endl; + out << indent() << "{" << endl; + out << indent() << " return service;" << endl; + out << indent() << "}" << endl; + + // implementation of the TProcess method, which dispatches the incoming call using the method map + out << endl; + out << indent() << "- (BOOL) processOnInputProtocol: (id ) inProtocol" << endl; + out << indent() << " outputProtocol: (id ) outProtocol" << endl; + out << indent() << " error: (NSError *__autoreleasing *)__thriftError" << endl; + out << indent() << "{" << endl; + out << indent() << " NSString * messageName;" << endl; + out << indent() << " SInt32 messageType;" << endl; + out << indent() << " SInt32 seqID;" << endl; + out << indent() << " if (![inProtocol readMessageBeginReturningName: &messageName" << endl; + out << indent() << " type: &messageType" << endl; + out << indent() << " sequenceID: &seqID" << endl; + out << indent() << " error: __thriftError]) return NO;" << endl; + out << indent() << " NSInvocation * invocation = [methodMap valueForKey: messageName];" << endl; + out << indent() << " if (invocation == nil) {" << endl; + out << indent() << " if (![TProtocolUtil skipType: TTypeSTRUCT onProtocol: inProtocol error: __thriftError]) return NO;" << endl; + out << indent() << " if (![inProtocol readMessageEnd: __thriftError]) return NO;" << endl; + out << indent() << " NSError * x = [NSError errorWithDomain: TApplicationErrorDomain" << endl; + out << indent() << " code: TApplicationErrorUnknownMethod" << endl; + out << indent() << " userInfo: @{TApplicationErrorMethodKey: messageName}];" << endl; + out << indent() << " if (![outProtocol writeMessageBeginWithName: messageName" << endl; + out << indent() << " type: TMessageTypeEXCEPTION" << endl; + out << indent() << " sequenceID: seqID" << endl; + out << indent() << " error: __thriftError]) return NO;" << endl; + out << indent() << " if (![x write: outProtocol error: __thriftError]) return NO;" << endl; + out << indent() << " if (![outProtocol writeMessageEnd: __thriftError]) return NO;" << endl; + out << indent() << " if (![[outProtocol transport] flush: __thriftError]) return NO;" << endl; + out << indent() << " return YES;" << endl; + out << indent() << " }" << endl; + out << indent() << " // NSInvocation does not conform to NSCopying protocol" << endl; + out << indent() << " NSInvocation * i = [NSInvocation invocationWithMethodSignature: " + "[invocation methodSignature]];" << endl; + out << indent() << " [i setSelector: [invocation selector]];" << endl; + out << indent() << " [i setArgument: &seqID atIndex: 2];" << endl; + out << indent() << " [i setArgument: &inProtocol atIndex: 3];" << endl; + out << indent() << " [i setArgument: &outProtocol atIndex: 4];" << endl; + out << indent() << " [i setArgument: &__thriftError atIndex: 5];" << endl; + out << indent() << " [i setTarget: self];" << endl; + out << indent() << " [i invoke];" << endl; + out << indent() << " return YES;" << endl; + out << indent() << "}" << endl; + + // generate a process_XXXX method for each service function, which reads args, calls the service, + // and writes results + functions = tservice->get_functions(); + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + out << endl; + string funname = (*f_iter)->get_name(); + out << indent() << "- (BOOL) process_" << funname + << "_withSequenceID: (SInt32) seqID inProtocol: (id) inProtocol outProtocol: " + "(id) outProtocol error:(NSError *__autoreleasing *)__thriftError" << endl; + scope_up(out); + string argstype = cocoa_prefix_ + function_args_helper_struct_type(tservice, *f_iter); + out << indent() << argstype << " * args = [" << argstype << " new];" << endl; + out << indent() << "if (![args read: inProtocol error: __thriftError]) return NO;" << endl; + out << indent() << "if (![inProtocol readMessageEnd: __thriftError]) return NO;" << endl; + + // prepare the result if not oneway + if (!(*f_iter)->is_oneway()) { + string resulttype = cocoa_prefix_ + function_result_helper_struct_type(tservice, *f_iter); + out << indent() << resulttype << " * result = [" << resulttype << " new];" << endl; + } + + // make the call to the actual service object + out << indent(); + if ((*f_iter)->get_returntype()->is_void()) { + out << "BOOL"; + } else if (type_can_be_null((*f_iter)->get_returntype())) { + out << type_name((*f_iter)->get_returntype(), false, true); + } else { + out << "NSNumber *"; + } + out << " serviceResult = "; + if ((*f_iter)->get_returntype()->get_true_type()->is_container()) { + out << "(" << type_name((*f_iter)->get_returntype(), false, true) << ")"; + } + out << "[service " << funname; + // supplying arguments + t_struct* arg_struct = (*f_iter)->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + bool first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + string fieldName = (*fld_iter)->get_name(); + if (first) { + first = false; + out << ": [args " << fieldName << "]"; + } else { + out << " " << fieldName << ": [args " << fieldName << "]"; + } + } + if (!fields.empty()) { + out << " error"; + } + out << ": __thriftError];" << endl; + out << indent() << "if (!serviceResult) return NO;" << endl; + if (!(*f_iter)->get_returntype()->is_void()) { + out << indent() << "[result setSuccess: " << unbox((*f_iter)->get_returntype(), "serviceResult") << "];" << endl; + } + + // write out the result if not oneway + if (!(*f_iter)->is_oneway()) { + out << indent() << "if (![outProtocol writeMessageBeginWithName: @\"" << funname << "\"" << endl; + out << indent() << " type: TMessageTypeREPLY" << endl; + out << indent() << " sequenceID: seqID" << endl; + out << indent() << " error: __thriftError]) return NO;" << endl; + out << indent() << "if (![result write: outProtocol error: __thriftError]) return NO;" << endl; + out << indent() << "if (![outProtocol writeMessageEnd: __thriftError]) return NO;" << endl; + out << indent() << "if (![[outProtocol transport] flush: __thriftError]) return NO;" << endl; + } + out << indent() << "return YES;" << endl; + + scope_down(out); + } + + out << "@end" << endl << endl; +} + +/** + * Deserializes a field of any type. + * + * @param tfield The field + * @param fieldName The variable name for this field + */ +void t_cocoa_generator::generate_deserialize_field(ofstream& out, + t_field* tfield, + string fieldName) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + tfield->get_name(); + } + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, fieldName); + } else if (type->is_container()) { + generate_deserialize_container(out, type, fieldName); + } else if (type->is_base_type() || type->is_enum()) { + indent(out) << type_name(type) << " " << fieldName << ";" << endl; + indent(out) << "if (![inProtocol "; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + tfield->get_name(); + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "readBinary:&" << fieldName << " error: __thriftError]"; + } else { + out << "readString:&" << fieldName << " error: __thriftError]"; + } + break; + case t_base_type::TYPE_BOOL: + out << "readBool:&" << fieldName << " error: __thriftError]"; + break; + case t_base_type::TYPE_I8: + out << "readByte:(UInt8 *)&" << fieldName << " error: __thriftError]"; + break; + case t_base_type::TYPE_I16: + out << "readI16:&" << fieldName << " error: __thriftError]"; + break; + case t_base_type::TYPE_I32: + out << "readI32:&" << fieldName << " error: __thriftError]"; + break; + case t_base_type::TYPE_I64: + out << "readI64:&" << fieldName << " error: __thriftError]"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble:&" << fieldName << " error: __thriftError]"; + break; + default: + throw "compiler error: no Objective-C name for base type " + + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "readI32:&" << fieldName << " error: __thriftError]"; + } + out << ") return NO;" << endl; + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +/** + * Generates an unserializer for a struct, allocates the struct and invokes read: + */ +void t_cocoa_generator::generate_deserialize_struct(ofstream& out, + t_struct* tstruct, + string fieldName) { + indent(out) << type_name(tstruct) << fieldName << " = [[" << type_name(tstruct, true) + << " alloc] init];" << endl; + indent(out) << "if (![" << fieldName << " read: inProtocol error: __thriftError]) return NO;" << endl; +} + +/** + * Deserializes a container by reading its size and then iterating + */ +void t_cocoa_generator::generate_deserialize_container(ofstream& out, + t_type* ttype, + string fieldName) { + string size = tmp("_size"); + indent(out) << "SInt32 " << size << ";" << endl; + + // Declare variables, read header + if (ttype->is_map()) { + indent(out) << "if (![inProtocol readMapBeginReturningKeyType: NULL valueType: NULL size: &" << size << " error: __thriftError]) return NO;" << endl; + indent(out) << "NSMutableDictionary * " << fieldName + << " = [[NSMutableDictionary alloc] initWithCapacity: " << size << "];" << endl; + } else if (ttype->is_set()) { + indent(out) << "if (![inProtocol readSetBeginReturningElementType: NULL size: &" << size << " error: __thriftError]) return NO;" + << endl; + indent(out) << "NSMutableSet * " << fieldName + << " = [[NSMutableSet alloc] initWithCapacity: " << size << "];" << endl; + } else if (ttype->is_list()) { + indent(out) << "if (![inProtocol readListBeginReturningElementType: NULL size: &" << size << " error: __thriftError]) return NO;" + << endl; + indent(out) << "NSMutableArray * " << fieldName + << " = [[NSMutableArray alloc] initWithCapacity: " << size << "];" << endl; + } + // FIXME - the code above does not verify that the element types of + // the containers being read match the element types of the + // containers we are reading into. Does that matter? + + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << "int " << i << ";" << endl << indent() << "for (" << i << " = 0; " << i << " < " + << size << "; " + << "++" << i << ")" << endl; + + scope_up(out); + + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, fieldName); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, fieldName); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, fieldName); + } + + scope_down(out); + + // Read container end + if (ttype->is_map()) { + indent(out) << "if (![inProtocol readMapEnd: __thriftError]) return NO;" << endl; + } else if (ttype->is_set()) { + indent(out) << "if (![inProtocol readSetEnd: __thriftError]) return NO;" << endl; + } else if (ttype->is_list()) { + indent(out) << "if (![inProtocol readListEnd: __thriftError]) return NO;" << endl; + } +} + +/** + * Take a variable of a given type and wrap it in code to make it + * suitable for putting into a container, if necessary. Basically, + * wrap scaler primitives in NSNumber objects. + */ +string t_cocoa_generator::box(t_type* ttype, string field_name) { + + ttype = get_true_type(ttype); + if (ttype->is_enum()) { + return "@(" + field_name + ")"; + } else if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "can't box void"; + case t_base_type::TYPE_BOOL: + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + case t_base_type::TYPE_DOUBLE: + return "@(" + field_name + ")"; + default: + break; + } + } + + // do nothing + return field_name; +} + +/** + * Extracts the actual value from a boxed value + */ +string t_cocoa_generator::unbox(t_type* ttype, string field_name) { + ttype = get_true_type(ttype); + if (ttype->is_enum()) { + return "[" + field_name + " intValue]"; + } else if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "can't unbox void"; + case t_base_type::TYPE_BOOL: + return "[" + field_name + " boolValue]"; + case t_base_type::TYPE_I8: + return "((SInt8)[" + field_name + " charValue])"; + case t_base_type::TYPE_I16: + return "((SInt16)[" + field_name + " shortValue])"; + case t_base_type::TYPE_I32: + return "((SInt32)[" + field_name + " longValue])"; + case t_base_type::TYPE_I64: + return "((SInt64)[" + field_name + " longLongValue])"; + case t_base_type::TYPE_DOUBLE: + return "[" + field_name + " doubleValue]"; + default: + break; + } + } + + // do nothing + return field_name; +} + +/** + * Generates code to deserialize a map element + */ +void t_cocoa_generator::generate_deserialize_map_element(ofstream& out, + t_map* tmap, + string fieldName) { + string key = tmp("_key"); + string val = tmp("_val"); + t_type* keyType = tmap->get_key_type(); + t_type* valType = tmap->get_val_type(); + t_field fkey(keyType, key); + t_field fval(valType, val); + + generate_deserialize_field(out, &fkey, key); + generate_deserialize_field(out, &fval, val); + + indent(out) << "[" << fieldName << " setObject: " << box(valType, val) + << " forKey: " << box(keyType, key) << "];" << endl; +} + +/** + * Deserializes a set element + */ +void t_cocoa_generator::generate_deserialize_set_element(ofstream& out, + t_set* tset, + string fieldName) { + string elem = tmp("_elem"); + t_type* type = tset->get_elem_type(); + t_field felem(type, elem); + + generate_deserialize_field(out, &felem, elem); + + indent(out) << "[" << fieldName << " addObject: " << box(type, elem) << "];" << endl; +} + +/** + * Deserializes a list element + */ +void t_cocoa_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string fieldName) { + string elem = tmp("_elem"); + t_type* type = tlist->get_elem_type(); + t_field felem(type, elem); + + generate_deserialize_field(out, &felem, elem); + + indent(out) << "[" << fieldName << " addObject: " << box(type, elem) << "];" << endl; +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param fieldName Name to of the variable holding the field + */ +void t_cocoa_generator::generate_serialize_field(ofstream& out, t_field* tfield, string fieldName) { + t_type* type = get_true_type(tfield->get_type()); + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + tfield->get_name(); + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, fieldName); + } else if (type->is_container()) { + generate_serialize_container(out, type, fieldName); + } else if (type->is_base_type() || type->is_enum()) { + indent(out) << "if (![outProtocol "; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + fieldName; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "writeBinary: " << fieldName << " error: __thriftError]"; + } else { + out << "writeString: " << fieldName << " error: __thriftError]"; + } + break; + case t_base_type::TYPE_BOOL: + out << "writeBool: " << fieldName << " error: __thriftError]"; + break; + case t_base_type::TYPE_I8: + out << "writeByte: (UInt8)" << fieldName << " error: __thriftError]"; + break; + case t_base_type::TYPE_I16: + out << "writeI16: " << fieldName << " error: __thriftError]"; + break; + case t_base_type::TYPE_I32: + out << "writeI32: " << fieldName << " error: __thriftError]"; + break; + case t_base_type::TYPE_I64: + out << "writeI64: " << fieldName << " error: __thriftError]"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble: " << fieldName << " error: __thriftError]"; + break; + default: + throw "compiler error: no Objective-C name for base type " + + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "writeI32: " << fieldName << " error: __thriftError]"; + } + out << ") return NO;" << endl; + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +/** + * Serialize a struct. + * + * @param tstruct The struct to serialize + * @param fieldName Name of variable holding struct + */ +void t_cocoa_generator::generate_serialize_struct(ofstream& out, + t_struct* tstruct, + string fieldName) { + (void)tstruct; + out << indent() << "if (![" << fieldName << " write: outProtocol error: __thriftError]) return NO;" << endl; +} + +/** + * Serializes a container by writing its size then the elements. + * + * @param ttype The type of container + * @param fieldName Name of variable holding container + */ +void t_cocoa_generator::generate_serialize_container(ofstream& out, + t_type* ttype, + string fieldName) { + scope_up(out); + + if (ttype->is_map()) { + indent(out) << "if (![outProtocol writeMapBeginWithKeyType: " + << type_to_enum(((t_map*)ttype)->get_key_type()) + << " valueType: " << type_to_enum(((t_map*)ttype)->get_val_type()) << " size: (SInt32)[" + << fieldName << " count] error: __thriftError]) return NO;" << endl; + } else if (ttype->is_set()) { + indent(out) << "if (![outProtocol writeSetBeginWithElementType: " + << type_to_enum(((t_set*)ttype)->get_elem_type()) << " size: (SInt32)[" << fieldName + << " count] error: __thriftError]) return NO;" << endl; + } else if (ttype->is_list()) { + indent(out) << "if (![outProtocol writeListBeginWithElementType: " + << type_to_enum(((t_list*)ttype)->get_elem_type()) << " size: (SInt32)[" << fieldName + << " count] error: __thriftError]) return NO;" << endl; + } + + string iter = tmp("_iter"); + string key; + if (ttype->is_map()) { + key = tmp("key"); + indent(out) << "NSEnumerator * " << iter << " = [" << fieldName << " keyEnumerator];" << endl; + indent(out) << "id " << key << ";" << endl; + indent(out) << "while ((" << key << " = [" << iter << " nextObject]))" << endl; + } else if (ttype->is_set()) { + key = tmp("obj"); + indent(out) << "NSEnumerator * " << iter << " = [" << fieldName << " objectEnumerator];" + << endl; + indent(out) << "id " << key << ";" << endl; + indent(out) << "while ((" << key << " = [" << iter << " nextObject]))" << endl; + } else if (ttype->is_list()) { + key = tmp("idx"); + indent(out) << "int " << key << ";" << endl; + indent(out) << "for (" << key << " = 0; " << key << " < [" << fieldName << " count]; " << key + << "++)" << endl; + } + + scope_up(out); + + if (ttype->is_map()) { + generate_serialize_map_element(out, (t_map*)ttype, key, fieldName); + } else if (ttype->is_set()) { + generate_serialize_set_element(out, (t_set*)ttype, key); + } else if (ttype->is_list()) { + generate_serialize_list_element(out, (t_list*)ttype, key, fieldName); + } + + scope_down(out); + + if (ttype->is_map()) { + indent(out) << "if (![outProtocol writeMapEnd: __thriftError]) return NO;" << endl; + } else if (ttype->is_set()) { + indent(out) << "if (![outProtocol writeSetEnd: __thriftError]) return NO;" << endl; + } else if (ttype->is_list()) { + indent(out) << "if (![outProtocol writeListEnd: __thriftError]) return NO;" << endl; + } + + scope_down(out); +} + +/** + * Serializes the members of a map. + */ +void t_cocoa_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string key, + string mapName) { + t_field kfield(tmap->get_key_type(), key); + generate_serialize_field(out, &kfield, unbox(kfield.get_type(), key)); + t_field vfield(tmap->get_val_type(), "[" + mapName + " objectForKey: " + key + "]"); + generate_serialize_field(out, &vfield, unbox(vfield.get_type(), vfield.get_name())); +} + +/** + * Serializes the members of a set. + */ +void t_cocoa_generator::generate_serialize_set_element(ofstream& out, + t_set* tset, + string elementName) { + t_field efield(tset->get_elem_type(), elementName); + generate_serialize_field(out, &efield, unbox(efield.get_type(), elementName)); +} + +/** + * Serializes the members of a list. + */ +void t_cocoa_generator::generate_serialize_list_element(ofstream& out, + t_list* tlist, + string index, + string listName) { + t_field efield(tlist->get_elem_type(), "[" + listName + " objectAtIndex: " + index + "]"); + generate_serialize_field(out, &efield, unbox(efield.get_type(), efield.get_name())); +} + +/** + * Returns an Objective-C name + * + * @param ttype The type + * @param class_ref Do we want a Class reference istead of a type reference? + * @return Objective-C type name, i.e. NSDictionary * + */ +string t_cocoa_generator::type_name(t_type* ttype, bool class_ref, bool needs_mutable) { + if (ttype->is_typedef()) { + string name = (needs_mutable && ttype->get_true_type()->is_container()) ? "Mutable" + ttype->get_name() : ttype->get_name(); + t_program* program = ttype->get_program(); + return program ? (program->get_namespace("cocoa") + name) : name; + } + + string result; + if (ttype->is_base_type()) { + return base_type_name((t_base_type*)ttype); + } else if (ttype->is_enum()) { + return cocoa_prefix_ + ttype->get_name(); + } else if (ttype->is_map()) { + t_map *map = (t_map *)ttype; + result = needs_mutable ? "NSMutableDictionary" : "NSDictionary"; + result += "<" + element_type_name(map->get_key_type()) + ", " + element_type_name(map->get_val_type()) + ">"; + } else if (ttype->is_set()) { + t_set *set = (t_set *)ttype; + result = needs_mutable ? "NSMutableSet" : "NSSet"; + result += "<" + element_type_name(set->get_elem_type()) + ">"; + } else if (ttype->is_list()) { + t_list *list = (t_list *)ttype; + result = needs_mutable ? "NSMutableArray" : "NSArray"; + result += "<" + element_type_name(list->get_elem_type()) + ">"; + } else { + // Check for prefix + t_program* program = ttype->get_program(); + if (program != NULL) { + result = program->get_namespace("cocoa") + ttype->get_name(); + } else { + result = ttype->get_name(); + } + } + + if (!class_ref) { + result += " *"; + } + return result; +} + +/** + * Returns an Objective-C type name for container types + * + * @param ttype the type + */ +string t_cocoa_generator::element_type_name(t_type* etype) { + + t_type* ttype = etype->get_true_type(); + + if (etype->is_typedef() && type_can_be_null(ttype)) { + return type_name(etype); + } + + string result; + if (ttype->is_base_type()) { + t_base_type* tbase = (t_base_type*)ttype; + switch (tbase->get_base()) { + case t_base_type::TYPE_STRING: + if (tbase->is_binary()) { + result = "NSData *"; + } + else { + result = "NSString *"; + } + break; + default: + result = "NSNumber *"; + break; + } + } else if (ttype->is_enum()) { + result = "NSNumber *"; + } else if (ttype->is_map()) { + t_map *map = (t_map *)ttype; + result = "NSDictionary<" + element_type_name(map->get_key_type()) + ", " + element_type_name(map->get_val_type()) + "> *"; + } else if (ttype->is_set()) { + t_set *set = (t_set *)ttype; + result = "NSSet<" + element_type_name(set->get_elem_type()) + "> *"; + } else if (ttype->is_list()) { + t_list *list = (t_list *)ttype; + result = "NSArray<" + element_type_name(list->get_elem_type()) + "> *"; + } else if (ttype->is_struct() || ttype->is_xception()) { + result = cocoa_prefix_ + ttype->get_name() + " *"; + } + + return result; +} + +/** + * Returns the Objective-C type that corresponds to the thrift type. + * + * @param tbase The base type + */ +string t_cocoa_generator::base_type_name(t_base_type* type) { + t_base_type::t_base tbase = type->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + return "void"; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + return "NSData *"; + } else { + return "NSString *"; + } + case t_base_type::TYPE_BOOL: + return "BOOL"; + case t_base_type::TYPE_I8: + return "SInt8"; + case t_base_type::TYPE_I16: + return "SInt16"; + case t_base_type::TYPE_I32: + return "SInt32"; + case t_base_type::TYPE_I64: + return "SInt64"; + case t_base_type::TYPE_DOUBLE: + return "double"; + default: + throw "compiler error: no Objective-C name for base type " + t_base_type::t_base_name(tbase); + } +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +void t_cocoa_generator::print_const_value(ostream& out, + string name, + t_type* type, + t_const_value* value, + bool defval) { + type = get_true_type(type); + + if (type->is_base_type()) { + string v2 = render_const_value(out, type, value); + indent(out); + if (defval) + out << type_name(type) << " "; + out << name << " = " << v2 << ";" << endl << endl; + } else if (type->is_enum()) { + indent(out); + if (defval) + out << type_name(type) << " "; + out << name << " = " << render_const_value(out, type, value) << ";" << endl << endl; + } else if (type->is_struct() || type->is_xception()) { + indent(out); + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + if (defval) + out << type_name(type) << " "; + out << name << " = [" << type_name(type, true) << " new];" + << endl; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + string val = render_const_value(out, field_type, v_iter->second); + std::string cap_name = capitalize(v_iter->first->get_string()); + indent(out) << "[" << name << " set" << cap_name << ":" << val << "];" << endl; + } + } else if (type->is_map()) { + ostringstream mapout; + indent(mapout); + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + if (defval) + mapout << type_name(type) << " "; + mapout << name << " = @{"; + for (v_iter = val.begin(); v_iter != val.end();) { + mapout << render_const_value(out, ktype, v_iter->first, true) << ": " + << render_const_value(out, vtype, v_iter->second, true); + if (++v_iter != val.end()) { + mapout << ", "; + } + } + mapout << "}"; + out << mapout.str(); + } else if (type->is_list()) { + ostringstream listout; + indent(listout); + t_type* etype = ((t_list*)type)->get_elem_type(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + if (defval) + listout << type_name(type) << " "; + listout << name << " = @["; + for (v_iter = val.begin(); v_iter != val.end();) { + listout << render_const_value(out, etype, *v_iter, true); + if (++v_iter != val.end()) { + listout << ", "; + } + } + listout << "]"; + out << listout.str(); + } else if (type->is_set()) { + ostringstream setout; + indent(setout); + t_type* etype = ((t_set*)type)->get_elem_type(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + if (defval) + setout << type_name(type) << " "; + setout << name << " = [NSSet setWithArray:@["; + for (v_iter = val.begin(); v_iter != val.end();) { + setout << render_const_value(out, etype, *v_iter, true); + if (++v_iter != val.end()) { + setout << ", "; + } + } + setout << "]]"; + out << setout.str(); + } else { + throw "compiler error: no const of type " + type->get_name(); + } +} + +string t_cocoa_generator::render_const_value(ostream& out, + t_type* type, + t_const_value* value, + bool box_it) { + type = get_true_type(type); + std::ostringstream render; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + // We must handle binary constant but the syntax of IDL defines + // nothing about binary constant. + // if type->is_binary()) + // // binary code + render << "@\"" << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() > 0) ? "YES" : "NO"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + render << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + render << value->get_integer(); + } else { + render << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + render << value->get_integer(); + } else { + string t = tmp("tmp"); + print_const_value(out, t, type, value, true); + out << ";" << endl; + render << t; + } + + if (box_it) { + return box(type, render.str()); + } + return render.str(); +} + +#if 0 +/** +ORIGINAL + * Spit out code that evaluates to the specified constant value. + */ +string t_cocoa_generator::render_const_value(string name, + t_type* type, + t_const_value* value, + bool box_it) { + type = get_true_type(type); + std::ostringstream render; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + render << "@\"" << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() > 0) ? "YES" : "NO"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + render << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + render << value->get_integer(); + } else { + render << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + render << value->get_integer(); + } else if (type->is_struct() || type->is_xception()) { + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + if (val.size() > 0) + render << "[[" << type_name(type, true) << " alloc] initWith"; + else + render << "[[" << type_name(type, true) << " alloc] init"; + bool first = true; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + // FIXME The generated code does not match with initWithXXX + // initializer and causes compile error. + // Try: test/DebugProtoTest.thrift and test/SmallTest.thrift + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + if (first) { + render << capitalize(v_iter->first->get_string()); + first = false; + } else { + render << " " << v_iter->first->get_string(); + } + render << ": " << render_const_value(name, field_type, v_iter->second); + } + render << "]"; + } else if (type->is_map()) { + render << "[[NSDictionary alloc] initWithObjectsAndKeys: "; + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + bool first = true; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string key = render_const_value(name, ktype, v_iter->first, true); + string val = render_const_value(name, vtype, v_iter->second, true); + if (first) { + first = false; + } else { + render << ", "; + } + render << val << ", " << key; + } + if (first) + render << " nil]"; + else + render << ", nil]"; + } else if (type->is_list()) { + render << "[[NSArray alloc] initWithObjects: "; + t_type * etype = ((t_list*)type)->get_elem_type(); + const vector& val = value->get_list(); + bool first = true; + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + if (first) { + first = false; + } else { + render << ", "; + } + render << render_const_value(name, etype, *v_iter, true); + } + if (first) + render << " nil]"; + else + render << ", nil]"; + } else if (type->is_set()) { + render << "[[NSSet alloc] initWithObjects: "; + t_type * etype = ((t_set*)type)->get_elem_type(); + const vector& val = value->get_list(); + bool first = true; + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + if (first) { + first = false; + } else { + render << ", "; + } + render << render_const_value(name, etype, *v_iter, true); + } + if (first) + render << " nil]"; + else + render << ", nil]"; + } else { + throw "don't know how to render constant for type: " + type->get_name(); + } + + if (box_it) { + return box(type, render.str()); + } + + return render.str(); +} +#endif + +/** + * Declares an Objective-C 2.0 property. + * + * @param tfield The field to declare a property for + */ +string t_cocoa_generator::declare_property(t_field* tfield) { + std::ostringstream render; + render << "@property ("; + + if (type_can_be_null(tfield->get_type())) { + render << "strong, "; + } else { + render << "assign, "; + } + + render << "nonatomic) " << type_name(tfield->get_type(), false, true) << " " + << tfield->get_name() << ";"; + + // Check if the property name is an Objective-C return +1 count signal + if ((tfield->get_name().length() >= 3 && tfield->get_name().substr(0,3) == "new") || + (tfield->get_name().length() >= 6 && tfield->get_name().substr(0,6) == "create") || + (tfield->get_name().length() >= 5 && tfield->get_name().substr(0,5) == "alloc")) { + // Let Objective-C know not to return +1 for object pointers + if (type_can_be_null(tfield->get_type())) { + render << endl; + render << "- (" + type_name(tfield->get_type()) + ") " + decapitalize(tfield->get_name()) + " __attribute__((objc_method_family(none)));"; + } + } + + return render.str(); +} + +/** + * Declares an Objective-C 2.0 property. + * + * @param tfield The field to declare a property for + */ +string t_cocoa_generator::declare_property_isset(t_field* tfield) { + return "@property (assign, nonatomic) BOOL " + decapitalize(tfield->get_name()) + "IsSet;"; +} + +/** + * Declares property unset method. + * + * @param tfield The field to declare a property for + */ +string t_cocoa_generator::declare_property_unset(t_field* tfield) { + return "- (void) unset" + capitalize(tfield->get_name()) + ";"; +} + +/** + * Renders the early out return statement + * + * @param tfunction Function definition + * @return String of rendered invalid return statment + */ +string t_cocoa_generator::invalid_return_statement(t_function *tfunction) { + if ((tfunction->get_returntype()->is_void())) { + return "return NO;"; + } + return "return nil;"; +} + +/** + * Renders a function signature + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_cocoa_generator::function_signature(t_function* tfunction, bool include_error) { + t_type* ttype = tfunction->get_returntype(); + string result; + if (ttype->is_void()) { + result = "(BOOL)"; + } + else if (type_can_be_null(ttype)) { + result = "(" + type_name(ttype) + ")"; + } + else { + result = "(NSNumber *)"; + } + result += " " + tfunction->get_name() + argument_list(tfunction->get_arglist(), "", include_error); + return result; +} + +/** + * Renders a function signature that returns asynchronously instead of + * literally returning. + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_cocoa_generator::async_function_signature(t_function* tfunction, bool include_error) { + t_type* ttype = tfunction->get_returntype(); + t_struct* targlist = tfunction->get_arglist(); + string response_param = "void (^)(" + ((ttype->is_void()) ? "" : type_name(ttype)) + ")"; + std::string result = "(void) " + tfunction->get_name() + argument_list(tfunction->get_arglist(), "", include_error) + + (targlist->get_members().size() ? " response" : "") + ": (" + + response_param + ") responseBlock " + + "failure : (TAsyncFailureBlock) failureBlock"; + return result; +} + +/** + * Renders a function signature that returns a promise instead of + * literally returning. + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_cocoa_generator::promise_function_signature(t_function* tfunction) { + return "(AnyPromise *) " + tfunction->get_name() + argument_list(tfunction->get_arglist(), "", false); +} + +/** + * Renders a colon separated list of types and names, suitable for an + * objective-c parameter list + */ +string t_cocoa_generator::argument_list(t_struct* tstruct, string protocol_name, bool include_error) { + string result = ""; + bool include_protocol = !protocol_name.empty(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + string argPrefix = ""; + if (first) { + first = false; + } else { + argPrefix = (*f_iter)->get_name(); + result += " "; + } + result += argPrefix + ": (" + type_name((*f_iter)->get_type()) + ") " + (*f_iter)->get_name(); + } + if (include_protocol) { + if (!first) { + result += " protocol"; + } + result += ": (id) " + protocol_name; + first = false; + } + if (include_error) { + if (!first) { + result += " error"; + } + result += ": (NSError *__autoreleasing *)__thriftError"; + first = false; + } + return result; +} + +/** + * Converts the parse type to an Objective-C enum string for the given type. + */ +string t_cocoa_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "TTypeSTRING"; + case t_base_type::TYPE_BOOL: + return "TTypeBOOL"; + case t_base_type::TYPE_I8: + return "TTypeBYTE"; + case t_base_type::TYPE_I16: + return "TTypeI16"; + case t_base_type::TYPE_I32: + return "TTypeI32"; + case t_base_type::TYPE_I64: + return "TTypeI64"; + case t_base_type::TYPE_DOUBLE: + return "TTypeDOUBLE"; + } + } else if (type->is_enum()) { + return "TTypeI32"; + } else if (type->is_struct() || type->is_xception()) { + return "TTypeSTRUCT"; + } else if (type->is_map()) { + return "TTypeMAP"; + } else if (type->is_set()) { + return "TTypeSET"; + } else if (type->is_list()) { + return "TTypeLIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** + * Returns a format string specifier for the supplied parse type. + */ +string t_cocoa_generator::format_string_for_type(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "\\\"%@\\\""; + case t_base_type::TYPE_BOOL: + return "%i"; + case t_base_type::TYPE_I8: + return "%i"; + case t_base_type::TYPE_I16: + return "%hi"; + case t_base_type::TYPE_I32: + return "%i"; + case t_base_type::TYPE_I64: + return "%qi"; + case t_base_type::TYPE_DOUBLE: + return "%f"; + } + } else if (type->is_enum()) { + return "%i"; + } else if (type->is_struct() || type->is_xception()) { + return "%@"; + } else if (type->is_map()) { + return "%@"; + } else if (type->is_set()) { + return "%@"; + } else if (type->is_list()) { + return "%@"; + } + + throw "INVALID TYPE IN format_string_for_type: " + type->get_name(); +} + +/** + * Returns a format cast for the supplied parse type. + */ +string t_cocoa_generator::format_cast_for_type(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return ""; // "\\\"%@\\\""; + case t_base_type::TYPE_BOOL: + return ""; // "%i"; + case t_base_type::TYPE_I8: + return ""; // "%i"; + case t_base_type::TYPE_I16: + return ""; // "%hi"; + case t_base_type::TYPE_I32: + return "(int)"; // "%i"; + case t_base_type::TYPE_I64: + return ""; // "%qi"; + case t_base_type::TYPE_DOUBLE: + return ""; // "%f"; + } + } else if (type->is_enum()) { + return "(int)"; // "%i"; + } else if (type->is_struct() || type->is_xception()) { + return ""; // "%@"; + } else if (type->is_map()) { + return ""; // "%@"; + } else if (type->is_set()) { + return ""; // "%@"; + } else if (type->is_list()) { + return ""; // "%@"; + } + + throw "INVALID TYPE IN format_cast_for_type: " + type->get_name(); +} + +/** + * Generate a call to a field's setter. + * + * @param tfield Field the setter is being called on + * @param fieldName Name of variable to pass to setter + */ + +string t_cocoa_generator::call_field_setter(t_field* tfield, string fieldName) { + return "self." + tfield->get_name() + " = " + fieldName + ";"; +} + +THRIFT_REGISTER_GENERATOR( + cocoa, + "Cocoa", + " log_unexpected: Log every time an unexpected field ID or type is encountered.\n" + " debug_descriptions:\n" + " Allow use of debugDescription so the app can add description via a cateogory/extension\n" + " validate_required:\n" + " Throws exception if any required field is not set.\n" + " async_clients: Generate clients which invoke asynchronously via block syntax.\n" + " pods: Generate imports in Cocopods framework format.\n" + " promise_kit: Generate clients which invoke asynchronously via promises.\n") diff --git a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc new file mode 100644 index 0000000..1c93957 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc @@ -0,0 +1,4486 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostream; +using std::string; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * C++ code generator. This is legitimacy incarnate. + * + */ +class t_cpp_generator : public t_oop_generator { +public: + t_cpp_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + + gen_pure_enums_ = false; + use_include_prefix_ = false; + gen_cob_style_ = false; + gen_no_client_completion_ = false; + gen_no_default_operators_ = false; + gen_templates_ = false; + gen_templates_only_ = false; + gen_moveable_ = false; + gen_no_ostream_operators_ = false; + gen_no_skeleton_ = false; + + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("pure_enums") == 0) { + gen_pure_enums_ = true; + } else if( iter->first.compare("include_prefix") == 0) { + use_include_prefix_ = true; + } else if( iter->first.compare("cob_style") == 0) { + gen_cob_style_ = true; + } else if( iter->first.compare("no_client_completion") == 0) { + gen_no_client_completion_ = true; + } else if( iter->first.compare("no_default_operators") == 0) { + gen_no_default_operators_ = true; + } else if( iter->first.compare("templates") == 0) { + gen_templates_ = true; + gen_templates_only_ = (iter->second == "only"); + } else if( iter->first.compare("moveable_types") == 0) { + gen_moveable_ = true; + } else if ( iter->first.compare("no_ostream_operators") == 0) { + gen_no_ostream_operators_ = true; + } else if ( iter->first.compare("no_skeleton") == 0) { + gen_no_skeleton_ = true; + } else { + throw "unknown option cpp:" + iter->first; + } + } + + out_dir_base_ = "gen-cpp"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + void generate_consts(std::vector consts); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_enum_ostream_operator_decl(std::ofstream& out, t_enum* tenum); + void generate_enum_ostream_operator(std::ofstream& out, t_enum* tenum); + void generate_forward_declaration(t_struct* tstruct); + void generate_struct(t_struct* tstruct) { generate_cpp_struct(tstruct, false); } + void generate_xception(t_struct* txception) { generate_cpp_struct(txception, true); } + void generate_cpp_struct(t_struct* tstruct, bool is_exception); + + void generate_service(t_service* tservice); + + void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value); + std::string render_const_value(std::ofstream& out, + std::string name, + t_type* type, + t_const_value* value); + + void generate_struct_declaration(std::ofstream& out, + t_struct* tstruct, + bool is_exception = false, + bool pointers = false, + bool read = true, + bool write = true, + bool swap = false, + bool is_user_struct = false); + void generate_struct_definition(std::ofstream& out, + std::ofstream& force_cpp_out, + t_struct* tstruct, + bool setters = true, + bool is_user_struct = false); + void generate_copy_constructor(std::ofstream& out, t_struct* tstruct, bool is_exception); + void generate_move_constructor(std::ofstream& out, t_struct* tstruct, bool is_exception); + void generate_constructor_helper(std::ofstream& out, + t_struct* tstruct, + bool is_excpetion, + bool is_move); + void generate_assignment_operator(std::ofstream& out, t_struct* tstruct); + void generate_move_assignment_operator(std::ofstream& out, t_struct* tstruct); + void generate_assignment_helper(std::ofstream& out, t_struct* tstruct, bool is_move); + void generate_struct_reader(std::ofstream& out, t_struct* tstruct, bool pointers = false); + void generate_struct_writer(std::ofstream& out, t_struct* tstruct, bool pointers = false); + void generate_struct_result_writer(std::ofstream& out, t_struct* tstruct, bool pointers = false); + void generate_struct_swap(std::ofstream& out, t_struct* tstruct); + void generate_struct_print_method(std::ofstream& out, t_struct* tstruct); + void generate_exception_what_method(std::ofstream& out, t_struct* tstruct); + + /** + * Service-level generation functions + */ + + void generate_service_interface(t_service* tservice, string style); + void generate_service_interface_factory(t_service* tservice, string style); + void generate_service_null(t_service* tservice, string style); + void generate_service_multiface(t_service* tservice); + void generate_service_helpers(t_service* tservice); + void generate_service_client(t_service* tservice, string style); + void generate_service_processor(t_service* tservice, string style); + void generate_service_skeleton(t_service* tservice); + void generate_process_function(t_service* tservice, + t_function* tfunction, + string style, + bool specialized = false); + void generate_function_helpers(t_service* tservice, t_function* tfunction); + void generate_service_async_skeleton(t_service* tservice); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, + t_field* tfield, + std::string prefix = "", + std::string suffix = ""); + + void generate_deserialize_struct(std::ofstream& out, + t_struct* tstruct, + std::string prefix = "", + bool pointer = false); + + void generate_deserialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_deserialize_set_element(std::ofstream& out, t_set* tset, std::string prefix = ""); + + void generate_deserialize_map_element(std::ofstream& out, t_map* tmap, std::string prefix = ""); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix, + bool push_back, + std::string index); + + void generate_serialize_field(std::ofstream& out, + t_field* tfield, + std::string prefix = "", + std::string suffix = ""); + + void generate_serialize_struct(std::ofstream& out, + t_struct* tstruct, + std::string prefix = "", + bool pointer = false); + + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_serialize_map_element(std::ofstream& out, t_map* tmap, std::string iter); + + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + + void generate_function_call(ostream& out, + t_function* tfunction, + string target, + string iface, + string arg_prefix); + /* + * Helper rendering functions + */ + + std::string namespace_prefix(std::string ns); + std::string namespace_open(std::string ns); + std::string namespace_close(std::string ns); + std::string type_name(t_type* ttype, bool in_typedef = false, bool arg = false); + std::string base_type_name(t_base_type::t_base tbase); + std::string declare_field(t_field* tfield, + bool init = false, + bool pointer = false, + bool constant = false, + bool reference = false); + std::string function_signature(t_function* tfunction, + std::string style, + std::string prefix = "", + bool name_params = true); + std::string cob_function_signature(t_function* tfunction, + std::string prefix = "", + bool name_params = true); + std::string argument_list(t_struct* tstruct, bool name_params = true, bool start_comma = false); + std::string type_to_enum(t_type* ttype); + + void generate_enum_constant_list(std::ofstream& f, + const vector& constants, + const char* prefix, + const char* suffix, + bool include_values); + + void generate_struct_ostream_operator_decl(std::ofstream& f, t_struct* tstruct); + void generate_struct_ostream_operator(std::ofstream& f, t_struct* tstruct); + void generate_struct_print_method_decl(std::ofstream& f, t_struct* tstruct); + void generate_exception_what_method_decl(std::ofstream& f, + t_struct* tstruct, + bool external = false); + + bool is_reference(t_field* tfield) { return tfield->get_reference(); } + + bool is_complex_type(t_type* ttype) { + ttype = get_true_type(ttype); + + return ttype->is_container() || ttype->is_struct() || ttype->is_xception() + || (ttype->is_base_type() + && (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING)); + } + + void set_use_include_prefix(bool use_include_prefix) { use_include_prefix_ = use_include_prefix; } + + /** + * The compiler option "no_thrift_ostream_impl" can be used to prevent + * the compiler from emitting implementations for operator <<. In this + * case the consuming application must provide any needed to build. + * + * To disable this on a per structure bases, one can alternatively set + * the annotation "cpp.customostream" to prevent thrift from emitting an + * operator << (std::ostream&). + * + * See AnnotationTest for validation of this annotation feature. + */ + bool has_custom_ostream(t_type* ttype) const { + return (gen_no_ostream_operators_) || + (ttype->annotations_.find("cpp.customostream") != ttype->annotations_.end()); + } + +private: + /** + * Returns the include prefix to use for a file generated by program, or the + * empty string if no include prefix should be used. + */ + std::string get_include_prefix(const t_program& program) const; + + /** + * True if we should generate pure enums for Thrift enums, instead of wrapper classes. + */ + bool gen_pure_enums_; + + /** + * True if we should generate templatized reader/writer methods. + */ + bool gen_templates_; + + /** + * True iff we should generate process function pointers for only templatized + * reader/writer methods. + */ + bool gen_templates_only_; + + /** + * True if we should generate move constructors & assignment operators. + */ + bool gen_moveable_; + + /** + * True if we should generate ostream definitions + */ + bool gen_no_ostream_operators_; + + /** + * True iff we should use a path prefix in our #include statements for other + * thrift-generated header files. + */ + bool use_include_prefix_; + + /** + * True if we should generate "Continuation OBject"-style classes as well. + */ + bool gen_cob_style_; + + /** + * True if we should omit calls to completion__() in CobClient class. + */ + bool gen_no_client_completion_; + + /** + * True if we should omit generating the default opeartors ==, != and <. + */ + bool gen_no_default_operators_; + + /** + * True if we should generate skeleton. + */ + bool gen_no_skeleton_; + + /** + * Strings for namespace, computed once up front then used directly + */ + + std::string ns_open_; + std::string ns_close_; + + /** + * File streams, stored here to avoid passing them as parameters to every + * function. + */ + + std::ofstream f_types_; + std::ofstream f_types_impl_; + std::ofstream f_types_tcc_; + std::ofstream f_header_; + std::ofstream f_service_; + std::ofstream f_service_tcc_; + + // The ProcessorGenerator is used to generate parts of the code, + // so it needs access to many of our protected members and methods. + // + // TODO: The code really should be cleaned up so that helper methods for + // writing to the output files are separate from the generator classes + // themselves. + friend class ProcessorGenerator; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + */ +void t_cpp_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + + // Make output file + string f_types_name = get_out_dir() + program_name_ + "_types.h"; + f_types_.open(f_types_name.c_str()); + + string f_types_impl_name = get_out_dir() + program_name_ + "_types.cpp"; + f_types_impl_.open(f_types_impl_name.c_str()); + + if (gen_templates_) { + // If we don't open the stream, it appears to just discard data, + // which is fine. + string f_types_tcc_name = get_out_dir() + program_name_ + "_types.tcc"; + f_types_tcc_.open(f_types_tcc_name.c_str()); + } + + // Print header + f_types_ << autogen_comment(); + f_types_impl_ << autogen_comment(); + f_types_tcc_ << autogen_comment(); + + // Start ifndef + f_types_ << "#ifndef " << program_name_ << "_TYPES_H" << endl << "#define " << program_name_ + << "_TYPES_H" << endl << endl; + f_types_tcc_ << "#ifndef " << program_name_ << "_TYPES_TCC" << endl << "#define " << program_name_ + << "_TYPES_TCC" << endl << endl; + + // Include base types + f_types_ << "#include " << endl + << endl + << "#include " << endl + << "#include " << endl + << "#include " << endl + << "#include " << endl + << "#include " << endl + << endl; + // Include C++xx compatibility header + f_types_ << "#include " << endl; + + // Include other Thrift includes + const vector& includes = program_->get_includes(); + for (size_t i = 0; i < includes.size(); ++i) { + f_types_ << "#include \"" << get_include_prefix(*(includes[i])) << includes[i]->get_name() + << "_types.h\"" << endl; + + // XXX(simpkins): If gen_templates_ is enabled, we currently assume all + // included files were also generated with templates enabled. + f_types_tcc_ << "#include \"" << get_include_prefix(*(includes[i])) << includes[i]->get_name() + << "_types.tcc\"" << endl; + } + f_types_ << endl; + + // Include custom headers + const vector& cpp_includes = program_->get_cpp_includes(); + for (size_t i = 0; i < cpp_includes.size(); ++i) { + if (cpp_includes[i][0] == '<') { + f_types_ << "#include " << cpp_includes[i] << endl; + } else { + f_types_ << "#include \"" << cpp_includes[i] << "\"" << endl; + } + } + f_types_ << endl; + + // Include the types file + f_types_impl_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ + << "_types.h\"" << endl << endl; + f_types_tcc_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ + << "_types.h\"" << endl << endl; + + // The swap() code needs for std::swap() + f_types_impl_ << "#include " << endl; + // for operator<< + f_types_impl_ << "#include " << endl << endl; + f_types_impl_ << "#include " << endl << endl; + + // Open namespace + ns_open_ = namespace_open(program_->get_namespace("cpp")); + ns_close_ = namespace_close(program_->get_namespace("cpp")); + + f_types_ << ns_open_ << endl << endl; + + f_types_impl_ << ns_open_ << endl << endl; + + f_types_tcc_ << ns_open_ << endl << endl; +} + +/** + * Closes the output files. + */ +void t_cpp_generator::close_generator() { + // Close namespace + f_types_ << ns_close_ << endl << endl; + f_types_impl_ << ns_close_ << endl; + f_types_tcc_ << ns_close_ << endl << endl; + + // Include the types.tcc file from the types header file, + // so clients don't have to explicitly include the tcc file. + // TODO(simpkins): Make this a separate option. + if (gen_templates_) { + f_types_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ + << "_types.tcc\"" << endl << endl; + } + + // Close ifndef + f_types_ << "#endif" << endl; + f_types_tcc_ << "#endif" << endl; + + // Close output file + f_types_.close(); + f_types_impl_.close(); + f_types_tcc_.close(); +} + +/** + * Generates a typedef. This is just a simple 1-liner in C++ + * + * @param ttypedef The type definition + */ +void t_cpp_generator::generate_typedef(t_typedef* ttypedef) { + f_types_ << indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " + << ttypedef->get_symbolic() << ";" << endl << endl; +} + +void t_cpp_generator::generate_enum_constant_list(std::ofstream& f, + const vector& constants, + const char* prefix, + const char* suffix, + bool include_values) { + f << " {" << endl; + indent_up(); + + vector::const_iterator c_iter; + bool first = true; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + if (first) { + first = false; + } else { + f << "," << endl; + } + indent(f) << prefix << (*c_iter)->get_name() << suffix; + if (include_values) { + f << " = " << (*c_iter)->get_value(); + } + } + + f << endl; + indent_down(); + indent(f) << "};" << endl; +} + +/** + * Generates code for an enumerated type. In C++, this is essentially the same + * as the thrift definition itself, using the enum keyword in C++. + * + * @param tenum The enumeration + */ +void t_cpp_generator::generate_enum(t_enum* tenum) { + vector constants = tenum->get_constants(); + + std::string enum_name = tenum->get_name(); + if (!gen_pure_enums_) { + enum_name = "type"; + f_types_ << indent() << "struct " << tenum->get_name() << " {" << endl; + indent_up(); + } + f_types_ << indent() << "enum " << enum_name; + + generate_enum_constant_list(f_types_, constants, "", "", true); + + if (!gen_pure_enums_) { + indent_down(); + f_types_ << "};" << endl; + } + + f_types_ << endl; + + /** + Generate a character array of enum names for debugging purposes. + */ + std::string prefix = ""; + if (!gen_pure_enums_) { + prefix = tenum->get_name() + "::"; + } + + f_types_impl_ << indent() << "int _k" << tenum->get_name() << "Values[] ="; + generate_enum_constant_list(f_types_impl_, constants, prefix.c_str(), "", false); + + f_types_impl_ << indent() << "const char* _k" << tenum->get_name() << "Names[] ="; + generate_enum_constant_list(f_types_impl_, constants, "\"", "\"", false); + + f_types_ << indent() << "extern const std::map _" << tenum->get_name() + << "_VALUES_TO_NAMES;" << endl << endl; + + f_types_impl_ << indent() << "const std::map _" << tenum->get_name() + << "_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(" << constants.size() << ", _k" + << tenum->get_name() << "Values" + << ", _k" << tenum->get_name() << "Names), " + << "::apache::thrift::TEnumIterator(-1, NULL, NULL));" << endl << endl; + + generate_enum_ostream_operator_decl(f_types_, tenum); + generate_enum_ostream_operator(f_types_impl_, tenum); +} + +void t_cpp_generator::generate_enum_ostream_operator_decl(std::ofstream& out, t_enum* tenum) { + + out << "std::ostream& operator<<(std::ostream& out, const "; + if (gen_pure_enums_) { + out << tenum->get_name(); + } else { + out << tenum->get_name() << "::type&"; + } + out << " val);" << endl; + out << endl; +} + +void t_cpp_generator::generate_enum_ostream_operator(std::ofstream& out, t_enum* tenum) { + + // If we've been told the consuming application will provide an ostream + // operator definition then we only make a declaration: + + if (!has_custom_ostream(tenum)) { + out << "std::ostream& operator<<(std::ostream& out, const "; + if (gen_pure_enums_) { + out << tenum->get_name(); + } else { + out << tenum->get_name() << "::type&"; + } + out << " val) "; + scope_up(out); + + out << indent() << "std::map::const_iterator it = _" + << tenum->get_name() << "_VALUES_TO_NAMES.find(val);" << endl; + out << indent() << "if (it != _" << tenum->get_name() << "_VALUES_TO_NAMES.end()) {" << endl; + indent_up(); + out << indent() << "out << it->second;" << endl; + indent_down(); + out << indent() << "} else {" << endl; + indent_up(); + out << indent() << "out << static_cast(val);" << endl; + indent_down(); + out << indent() << "}" << endl; + + out << indent() << "return out;" << endl; + scope_down(out); + out << endl; + } +} + +/** + * Generates a class that holds all the constants. + */ +void t_cpp_generator::generate_consts(std::vector consts) { + string f_consts_name = get_out_dir() + program_name_ + "_constants.h"; + ofstream f_consts; + f_consts.open(f_consts_name.c_str()); + + string f_consts_impl_name = get_out_dir() + program_name_ + "_constants.cpp"; + ofstream f_consts_impl; + f_consts_impl.open(f_consts_impl_name.c_str()); + + // Print header + f_consts << autogen_comment(); + f_consts_impl << autogen_comment(); + + // Start ifndef + f_consts << "#ifndef " << program_name_ << "_CONSTANTS_H" << endl << "#define " << program_name_ + << "_CONSTANTS_H" << endl << endl << "#include \"" << get_include_prefix(*get_program()) + << program_name_ << "_types.h\"" << endl << endl << ns_open_ << endl << endl; + + f_consts_impl << "#include \"" << get_include_prefix(*get_program()) << program_name_ + << "_constants.h\"" << endl << endl << ns_open_ << endl << endl; + + f_consts << "class " << program_name_ << "Constants {" << endl << " public:" << endl << " " + << program_name_ << "Constants();" << endl << endl; + indent_up(); + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + string name = (*c_iter)->get_name(); + t_type* type = (*c_iter)->get_type(); + f_consts << indent() << type_name(type) << " " << name << ";" << endl; + } + indent_down(); + f_consts << "};" << endl; + + f_consts_impl << "const " << program_name_ << "Constants g_" << program_name_ << "_constants;" + << endl << endl << program_name_ << "Constants::" << program_name_ + << "Constants() {" << endl; + indent_up(); + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + print_const_value(f_consts_impl, + (*c_iter)->get_name(), + (*c_iter)->get_type(), + (*c_iter)->get_value()); + } + indent_down(); + indent(f_consts_impl) << "}" << endl; + + f_consts << endl << "extern const " << program_name_ << "Constants g_" << program_name_ + << "_constants;" << endl << endl << ns_close_ << endl << endl << "#endif" << endl; + f_consts.close(); + + f_consts_impl << endl << ns_close_ << endl << endl; +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +void t_cpp_generator::print_const_value(ofstream& out, + string name, + t_type* type, + t_const_value* value) { + type = get_true_type(type); + if (type->is_base_type()) { + string v2 = render_const_value(out, name, type, value); + indent(out) << name << " = " << v2 << ";" << endl << endl; + } else if (type->is_enum()) { + indent(out) << name << " = (" << type_name(type) << ")" << value->get_integer() << ";" << endl + << endl; + } else if (type->is_struct() || type->is_xception()) { + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + bool is_nonrequired_field = false; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + is_nonrequired_field = false; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + is_nonrequired_field = (*f_iter)->get_req() != t_field::T_REQUIRED; + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + string val = render_const_value(out, name, field_type, v_iter->second); + indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl; + if (is_nonrequired_field) { + indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl; + } + } + out << endl; + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string key = render_const_value(out, name, ktype, v_iter->first); + string val = render_const_value(out, name, vtype, v_iter->second); + indent(out) << name << ".insert(std::make_pair(" << key << ", " << val << "));" << endl; + } + out << endl; + } else if (type->is_list()) { + t_type* etype = ((t_list*)type)->get_elem_type(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(out, name, etype, *v_iter); + indent(out) << name << ".push_back(" << val << ");" << endl; + } + out << endl; + } else if (type->is_set()) { + t_type* etype = ((t_set*)type)->get_elem_type(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(out, name, etype, *v_iter); + indent(out) << name << ".insert(" << val << ");" << endl; + } + out << endl; + } else { + throw "INVALID TYPE IN print_const_value: " + type->get_name(); + } +} + +/** + * + */ +string t_cpp_generator::render_const_value(ofstream& out, + string name, + t_type* type, + t_const_value* value) { + (void)name; + std::ostringstream render; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + render << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() > 0) ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + render << value->get_integer(); + break; + case t_base_type::TYPE_I64: + render << value->get_integer() << "LL"; + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + render << value->get_integer(); + } else { + render << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + render << "(" << type_name(type) << ")" << value->get_integer(); + } else { + string t = tmp("tmp"); + indent(out) << type_name(type) << " " << t << ";" << endl; + print_const_value(out, t, type, value); + render << t; + } + + return render.str(); +} + +void t_cpp_generator::generate_forward_declaration(t_struct* tstruct) { + // Forward declare struct def + f_types_ << indent() << "class " << tstruct->get_name() << ";" << endl << endl; +} + +/** + * Generates a struct definition for a thrift data type. This is a class + * with data members and a read/write() function, plus a mirroring isset + * inner class. + * + * @param tstruct The struct definition + */ +void t_cpp_generator::generate_cpp_struct(t_struct* tstruct, bool is_exception) { + generate_struct_declaration(f_types_, tstruct, is_exception, false, true, true, true, true); + generate_struct_definition(f_types_impl_, f_types_impl_, tstruct, true, true); + + std::ofstream& out = (gen_templates_ ? f_types_tcc_ : f_types_impl_); + generate_struct_reader(out, tstruct); + generate_struct_writer(out, tstruct); + generate_struct_swap(f_types_impl_, tstruct); + generate_copy_constructor(f_types_impl_, tstruct, is_exception); + if (gen_moveable_) { + generate_move_constructor(f_types_impl_, tstruct, is_exception); + } + generate_assignment_operator(f_types_impl_, tstruct); + if (gen_moveable_) { + generate_move_assignment_operator(f_types_impl_, tstruct); + } + + if (!has_custom_ostream(tstruct)) { + generate_struct_print_method(f_types_impl_, tstruct); + } + + if (is_exception) { + generate_exception_what_method(f_types_impl_, tstruct); + } +} + +void t_cpp_generator::generate_copy_constructor(ofstream& out, + t_struct* tstruct, + bool is_exception) { + generate_constructor_helper(out, tstruct, is_exception, /*is_move=*/false); +} + +void t_cpp_generator::generate_move_constructor(ofstream& out, + t_struct* tstruct, + bool is_exception) { + generate_constructor_helper(out, tstruct, is_exception, /*is_move=*/true); +} + +namespace { +// Helper to convert a variable to rvalue, if move is enabled +std::string maybeMove(std::string const& other, bool move) { + if (move) { + return "std::move(" + other + ")"; + } + return other; +} +} + +void t_cpp_generator::generate_constructor_helper(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool is_move) { + + std::string tmp_name = tmp("other"); + + indent(out) << tstruct->get_name() << "::" << tstruct->get_name(); + + if (is_move) { + out << "( " << tstruct->get_name() << "&& "; + } else { + out << "(const " << tstruct->get_name() << "& "; + } + out << tmp_name << ") "; + if (is_exception) + out << ": TException() "; + out << "{" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + + // eliminate compiler unused warning + if (members.empty()) + indent(out) << "(void) " << tmp_name << ";" << endl; + + vector::const_iterator f_iter; + bool has_nonrequired_fields = false; + for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) { + if ((*f_iter)->get_req() != t_field::T_REQUIRED) + has_nonrequired_fields = true; + indent(out) << (*f_iter)->get_name() << " = " + << maybeMove(tmp_name + "." + (*f_iter)->get_name(), is_move) << ";" << endl; + } + + if (has_nonrequired_fields) { + indent(out) << "__isset = " << maybeMove(tmp_name + ".__isset", is_move) << ";" << endl; + } + + indent_down(); + indent(out) << "}" << endl; +} + +void t_cpp_generator::generate_assignment_operator(ofstream& out, t_struct* tstruct) { + generate_assignment_helper(out, tstruct, /*is_move=*/false); +} + +void t_cpp_generator::generate_move_assignment_operator(ofstream& out, t_struct* tstruct) { + generate_assignment_helper(out, tstruct, /*is_move=*/true); +} + +void t_cpp_generator::generate_assignment_helper(ofstream& out, t_struct* tstruct, bool is_move) { + std::string tmp_name = tmp("other"); + + indent(out) << tstruct->get_name() << "& " << tstruct->get_name() << "::operator=("; + + if (is_move) { + out << tstruct->get_name() << "&& "; + } else { + out << "const " << tstruct->get_name() << "& "; + } + out << tmp_name << ") {" << endl; + + indent_up(); + + const vector& members = tstruct->get_members(); + + // eliminate compiler unused warning + if (members.empty()) + indent(out) << "(void) " << tmp_name << ";" << endl; + + vector::const_iterator f_iter; + bool has_nonrequired_fields = false; + for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) { + if ((*f_iter)->get_req() != t_field::T_REQUIRED) + has_nonrequired_fields = true; + indent(out) << (*f_iter)->get_name() << " = " + << maybeMove(tmp_name + "." + (*f_iter)->get_name(), is_move) << ";" << endl; + } + if (has_nonrequired_fields) { + indent(out) << "__isset = " << maybeMove(tmp_name + ".__isset", is_move) << ";" << endl; + } + + indent(out) << "return *this;" << endl; + indent_down(); + indent(out) << "}" << endl; +} + +/** + * Writes the struct declaration into the header file + * + * @param out Output stream + * @param tstruct The struct + */ +void t_cpp_generator::generate_struct_declaration(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool pointers, + bool read, + bool write, + bool swap, + bool is_user_struct) { + string extends = ""; + if (is_exception) { + extends = " : public ::apache::thrift::TException"; + } else { + if (is_user_struct && !gen_templates_) { + extends = " : public virtual ::apache::thrift::TBase"; + } + } + + // Get members + vector::const_iterator m_iter; + const vector& members = tstruct->get_members(); + + // Write the isset structure declaration outside the class. This makes + // the generated code amenable to processing by SWIG. + // We only declare the struct if it gets used in the class. + + // Isset struct has boolean fields, but only for non-required fields. + bool has_nonrequired_fields = false; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() != t_field::T_REQUIRED) + has_nonrequired_fields = true; + } + + if (has_nonrequired_fields && (!pointers || read)) { + + out << indent() << "typedef struct _" << tstruct->get_name() << "__isset {" << endl; + indent_up(); + + indent(out) << "_" << tstruct->get_name() << "__isset() "; + bool first = true; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() == t_field::T_REQUIRED) { + continue; + } + string isSet = ((*m_iter)->get_value() != NULL) ? "true" : "false"; + if (first) { + first = false; + out << ": " << (*m_iter)->get_name() << "(" << isSet << ")"; + } else { + out << ", " << (*m_iter)->get_name() << "(" << isSet << ")"; + } + } + out << " {}" << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() != t_field::T_REQUIRED) { + indent(out) << "bool " << (*m_iter)->get_name() << " :1;" << endl; + } + } + + indent_down(); + indent(out) << "} _" << tstruct->get_name() << "__isset;" << endl; + } + + out << endl; + + // Open struct def + out << indent() << "class " << tstruct->get_name() << extends << " {" << endl << indent() + << " public:" << endl << endl; + indent_up(); + + if (!pointers) { + // Copy constructor + indent(out) << tstruct->get_name() << "(const " << tstruct->get_name() << "&);" << endl; + + // Move constructor + if (gen_moveable_) { + indent(out) << tstruct->get_name() << "(" << tstruct->get_name() << "&&);" << endl; + } + + // Assignment Operator + indent(out) << tstruct->get_name() << "& operator=(const " << tstruct->get_name() << "&);" + << endl; + + // Move assignment operator + if (gen_moveable_) { + indent(out) << tstruct->get_name() << "& operator=(" << tstruct->get_name() << "&&);" << endl; + } + + // Default constructor + indent(out) << tstruct->get_name() << "()"; + + bool init_ctor = false; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if (t->is_base_type() || t->is_enum() || is_reference(*m_iter)) { + string dval; + if (t->is_enum()) { + dval += "(" + type_name(t) + ")"; + } + dval += (t->is_string() || is_reference(*m_iter)) ? "" : "0"; + t_const_value* cv = (*m_iter)->get_value(); + if (cv != NULL) { + dval = render_const_value(out, (*m_iter)->get_name(), t, cv); + } + if (!init_ctor) { + init_ctor = true; + out << " : "; + out << (*m_iter)->get_name() << "(" << dval << ")"; + } else { + out << ", " << (*m_iter)->get_name() << "(" << dval << ")"; + } + } + } + out << " {" << endl; + indent_up(); + // TODO(dreiss): When everything else in Thrift is perfect, + // do more of these in the initializer list. + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + + if (!t->is_base_type()) { + t_const_value* cv = (*m_iter)->get_value(); + if (cv != NULL) { + print_const_value(out, (*m_iter)->get_name(), t, cv); + } + } + } + scope_down(out); + } + + if (tstruct->annotations_.find("final") == tstruct->annotations_.end()) { + out << endl << indent() << "virtual ~" << tstruct->get_name() << "() throw();" << endl; + } + + // Declare all fields + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << declare_field(*m_iter, + false, + (pointers && !(*m_iter)->get_type()->is_xception()), + !read) << endl; + } + + // Add the __isset data member if we need it, using the definition from above + if (has_nonrequired_fields && (!pointers || read)) { + out << endl << indent() << "_" << tstruct->get_name() << "__isset __isset;" << endl; + } + + // Create a setter function for each field + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (pointers) { + continue; + } + if (is_reference((*m_iter))) { + out << endl << indent() << "void __set_" << (*m_iter)->get_name() << "(::apache::thrift::stdcxx::shared_ptr<" + << type_name((*m_iter)->get_type(), false, false) << ">"; + out << " val);" << endl; + } else { + out << endl << indent() << "void __set_" << (*m_iter)->get_name() << "(" + << type_name((*m_iter)->get_type(), false, true); + out << " val);" << endl; + } + } + out << endl; + + if (!pointers) { + // Should we generate default operators? + if (!gen_no_default_operators_) { + // Generate an equality testing operator. Make it inline since the compiler + // will do a better job than we would when deciding whether to inline it. + out << indent() << "bool operator == (const " << tstruct->get_name() << " & " + << (members.size() > 0 ? "rhs" : "/* rhs */") << ") const" << endl; + scope_up(out); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + // Most existing Thrift code does not use isset or optional/required, + // so we treat "default" fields as required. + if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { + out << indent() << "if (!(" << (*m_iter)->get_name() << " == rhs." + << (*m_iter)->get_name() << "))" << endl << indent() << " return false;" << endl; + } else { + out << indent() << "if (__isset." << (*m_iter)->get_name() << " != rhs.__isset." + << (*m_iter)->get_name() << ")" << endl << indent() << " return false;" << endl + << indent() << "else if (__isset." << (*m_iter)->get_name() << " && !(" + << (*m_iter)->get_name() << " == rhs." << (*m_iter)->get_name() << "))" << endl + << indent() << " return false;" << endl; + } + } + indent(out) << "return true;" << endl; + scope_down(out); + out << indent() << "bool operator != (const " << tstruct->get_name() << " &rhs) const {" + << endl << indent() << " return !(*this == rhs);" << endl << indent() << "}" << endl + << endl; + + // Generate the declaration of a less-than operator. This must be + // implemented by the application developer if they wish to use it. (They + // will get a link error if they try to use it without an implementation.) + out << indent() << "bool operator < (const " << tstruct->get_name() << " & ) const;" << endl + << endl; + } + } + + if (read) { + if (gen_templates_) { + out << indent() << "template " << endl << indent() + << "uint32_t read(Protocol_* iprot);" << endl; + } else { + out << indent() << "uint32_t read(" + << "::apache::thrift::protocol::TProtocol* iprot);" << endl; + } + } + if (write) { + if (gen_templates_) { + out << indent() << "template " << endl << indent() + << "uint32_t write(Protocol_* oprot) const;" << endl; + } else { + out << indent() << "uint32_t write(" + << "::apache::thrift::protocol::TProtocol* oprot) const;" << endl; + } + } + out << endl; + + if (is_user_struct && !has_custom_ostream(tstruct)) { + out << indent() << "virtual "; + generate_struct_print_method_decl(out, NULL); + out << ";" << endl; + } + + // std::exception::what() + if (is_exception) { + out << indent() << "mutable std::string thriftTExceptionMessageHolder_;" << endl; + out << indent(); + generate_exception_what_method_decl(out, tstruct, false); + out << ";" << endl; + } + + indent_down(); + indent(out) << "};" << endl << endl; + + if (swap) { + // Generate a namespace-scope swap() function + out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name() + << " &b);" << endl << endl; + } + + if (is_user_struct) { + generate_struct_ostream_operator_decl(out, tstruct); + } +} + +void t_cpp_generator::generate_struct_definition(ofstream& out, + ofstream& force_cpp_out, + t_struct* tstruct, + bool setters, + bool is_user_struct) { + // Get members + vector::const_iterator m_iter; + const vector& members = tstruct->get_members(); + + // Destructor + if (tstruct->annotations_.find("final") == tstruct->annotations_.end()) { + force_cpp_out << endl << indent() << tstruct->get_name() << "::~" << tstruct->get_name() + << "() throw() {" << endl; + indent_up(); + + indent_down(); + force_cpp_out << indent() << "}" << endl << endl; + } + + // Create a setter function for each field + if (setters) { + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (is_reference((*m_iter))) { + std::string type = type_name((*m_iter)->get_type()); + out << endl << indent() << "void " << tstruct->get_name() << "::__set_" + << (*m_iter)->get_name() << "(::apache::thrift::stdcxx::shared_ptr<" + << type_name((*m_iter)->get_type(), false, false) << ">"; + out << " val) {" << endl; + } else { + out << endl << indent() << "void " << tstruct->get_name() << "::__set_" + << (*m_iter)->get_name() << "(" << type_name((*m_iter)->get_type(), false, true); + out << " val) {" << endl; + } + indent_up(); + out << indent() << "this->" << (*m_iter)->get_name() << " = val;" << endl; + indent_down(); + + // assume all fields are required except optional fields. + // for optional fields change __isset.name to true + bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL; + if (is_optional) { + out << indent() << indent() << "__isset." << (*m_iter)->get_name() << " = true;" << endl; + } + out << indent() << "}" << endl; + } + } + if (is_user_struct) { + generate_struct_ostream_operator(out, tstruct); + } + out << endl; +} + +/** + * Makes a helper function to gen a struct reader. + * + * @param out Stream to write to + * @param tstruct The struct + */ +void t_cpp_generator::generate_struct_reader(ofstream& out, t_struct* tstruct, bool pointers) { + if (gen_templates_) { + out << indent() << "template " << endl << indent() << "uint32_t " + << tstruct->get_name() << "::read(Protocol_* iprot) {" << endl; + } else { + indent(out) << "uint32_t " << tstruct->get_name() + << "::read(::apache::thrift::protocol::TProtocol* iprot) {" << endl; + } + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Declare stack tmp variables + out << endl + << indent() << "::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot);" << endl + << indent() << "uint32_t xfer = 0;" << endl + << indent() << "std::string fname;" << endl + << indent() << "::apache::thrift::protocol::TType ftype;" << endl + << indent() << "int16_t fid;" << endl + << endl + << indent() << "xfer += iprot->readStructBegin(fname);" << endl + << endl + << indent() << "using ::apache::thrift::protocol::TProtocolException;" << endl + << endl; + + // Required variables aren't in __isset, so we need tmp vars to check them. + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) + indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl; + } + out << endl; + + // Loop over reading in fields + indent(out) << "while (true)" << endl; + scope_up(out); + + // Read beginning field marker + indent(out) << "xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl; + + // Check for field STOP marker + out << indent() << "if (ftype == ::apache::thrift::protocol::T_STOP) {" << endl << indent() + << " break;" << endl << indent() << "}" << endl; + + if (fields.empty()) { + out << indent() << "xfer += iprot->skip(ftype);" << endl; + } else { + // Switch statement on the field we are reading + indent(out) << "switch (fid)" << endl; + + scope_up(out); + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << "case " << (*f_iter)->get_key() << ":" << endl; + indent_up(); + indent(out) << "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; + indent_up(); + + const char* isset_prefix = ((*f_iter)->get_req() != t_field::T_REQUIRED) ? "this->__isset." + : "isset_"; + +#if 0 + // This code throws an exception if the same field is encountered twice. + // We've decided to leave it out for performance reasons. + // TODO(dreiss): Generate this code and "if" it out to make it easier + // for people recompiling thrift to include it. + out << + indent() << "if (" << isset_prefix << (*f_iter)->get_name() << ")" << endl << + indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl; +#endif + + if (pointers && !(*f_iter)->get_type()->is_xception()) { + generate_deserialize_field(out, *f_iter, "(*(this->", "))"); + } else { + generate_deserialize_field(out, *f_iter, "this->"); + } + out << indent() << isset_prefix << (*f_iter)->get_name() << " = true;" << endl; + indent_down(); + out << indent() << "} else {" << endl << indent() << " xfer += iprot->skip(ftype);" << endl + << + // TODO(dreiss): Make this an option when thrift structs + // have a common base class. + // indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl << + indent() << "}" << endl << indent() << "break;" << endl; + indent_down(); + } + + // In the default case we skip the field + out << indent() << "default:" << endl << indent() << " xfer += iprot->skip(ftype);" << endl + << indent() << " break;" << endl; + + scope_down(out); + } //!fields.empty() + // Read field end marker + indent(out) << "xfer += iprot->readFieldEnd();" << endl; + + scope_down(out); + + out << endl << indent() << "xfer += iprot->readStructEnd();" << endl; + + // Throw if any required fields are missing. + // We do this after reading the struct end so that + // there might possibly be a chance of continuing. + out << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) + out << indent() << "if (!isset_" << (*f_iter)->get_name() << ')' << endl << indent() + << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl; + } + + indent(out) << "return xfer;" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates the write function. + * + * @param out Stream to write to + * @param tstruct The struct + */ +void t_cpp_generator::generate_struct_writer(ofstream& out, t_struct* tstruct, bool pointers) { + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + if (gen_templates_) { + out << indent() << "template " << endl << indent() << "uint32_t " + << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl; + } else { + indent(out) << "uint32_t " << tstruct->get_name() + << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl; + } + indent_up(); + + out << indent() << "uint32_t xfer = 0;" << endl; + + indent(out) << "::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot);" << endl; + indent(out) << "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool check_if_set = (*f_iter)->get_req() == t_field::T_OPTIONAL + || (*f_iter)->get_type()->is_xception(); + if (check_if_set) { + out << endl << indent() << "if (this->__isset." << (*f_iter)->get_name() << ") {" << endl; + indent_up(); + } else { + out << endl; + } + + // Write field header + out << indent() << "xfer += oprot->writeFieldBegin(" + << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", " + << (*f_iter)->get_key() << ");" << endl; + // Write field contents + if (pointers && !(*f_iter)->get_type()->is_xception()) { + generate_serialize_field(out, *f_iter, "(*(this->", "))"); + } else { + generate_serialize_field(out, *f_iter, "this->"); + } + // Write field closer + indent(out) << "xfer += oprot->writeFieldEnd();" << endl; + if (check_if_set) { + indent_down(); + indent(out) << '}'; + } + } + + out << endl; + + // Write the struct map + out << indent() << "xfer += oprot->writeFieldStop();" << endl << indent() + << "xfer += oprot->writeStructEnd();" << endl << indent() + << "return xfer;" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Struct writer for result of a function, which can have only one of its + * fields set and does a conditional if else look up into the __isset field + * of the struct. + * + * @param out Output stream + * @param tstruct The result struct + */ +void t_cpp_generator::generate_struct_result_writer(ofstream& out, + t_struct* tstruct, + bool pointers) { + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + if (gen_templates_) { + out << indent() << "template " << endl << indent() << "uint32_t " + << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl; + } else { + indent(out) << "uint32_t " << tstruct->get_name() + << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl; + } + indent_up(); + + out << endl << indent() << "uint32_t xfer = 0;" << endl << endl; + + indent(out) << "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl; + + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + out << endl << indent() << "if "; + } else { + out << " else if "; + } + + out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl; + + indent_up(); + + // Write field header + out << indent() << "xfer += oprot->writeFieldBegin(" + << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", " + << (*f_iter)->get_key() << ");" << endl; + // Write field contents + if (pointers) { + generate_serialize_field(out, *f_iter, "(*(this->", "))"); + } else { + generate_serialize_field(out, *f_iter, "this->"); + } + // Write field closer + indent(out) << "xfer += oprot->writeFieldEnd();" << endl; + + indent_down(); + indent(out) << "}"; + } + + // Write the struct map + out << endl << indent() << "xfer += oprot->writeFieldStop();" << endl << indent() + << "xfer += oprot->writeStructEnd();" << endl << indent() << "return xfer;" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates the swap function. + * + * @param out Stream to write to + * @param tstruct The struct + */ +void t_cpp_generator::generate_struct_swap(ofstream& out, t_struct* tstruct) { + out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name() + << " &b) {" << endl; + indent_up(); + + // Let argument-dependent name lookup find the correct swap() function to + // use based on the argument types. If none is found in the arguments' + // namespaces, fall back to ::std::swap(). + out << indent() << "using ::std::swap;" << endl; + + bool has_nonrequired_fields = false; + const vector& fields = tstruct->get_members(); + for (vector::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* tfield = *f_iter; + + if (tfield->get_req() != t_field::T_REQUIRED) { + has_nonrequired_fields = true; + } + + out << indent() << "swap(a." << tfield->get_name() << ", b." << tfield->get_name() << ");" + << endl; + } + + if (has_nonrequired_fields) { + out << indent() << "swap(a.__isset, b.__isset);" << endl; + } + + // handle empty structs + if (fields.size() == 0) { + out << indent() << "(void) a;" << endl; + out << indent() << "(void) b;" << endl; + } + + scope_down(out); + out << endl; +} + +void t_cpp_generator::generate_struct_ostream_operator_decl(std::ofstream& out, t_struct* tstruct) { + out << "std::ostream& operator<<(std::ostream& out, const " + << tstruct->get_name() + << "& obj);" << endl; + out << endl; +} + +void t_cpp_generator::generate_struct_ostream_operator(std::ofstream& out, t_struct* tstruct) { + if (!has_custom_ostream(tstruct)) { + // thrift defines this behavior + out << "std::ostream& operator<<(std::ostream& out, const " + << tstruct->get_name() + << "& obj)" << endl; + scope_up(out); + out << indent() << "obj.printTo(out);" << endl + << indent() << "return out;" << endl; + scope_down(out); + out << endl; + } +} + +void t_cpp_generator::generate_struct_print_method_decl(std::ofstream& out, t_struct* tstruct) { + out << "void "; + if (tstruct) { + out << tstruct->get_name() << "::"; + } + out << "printTo(std::ostream& out) const"; +} + +void t_cpp_generator::generate_exception_what_method_decl(std::ofstream& out, + t_struct* tstruct, + bool external) { + out << "const char* "; + if (external) { + out << tstruct->get_name() << "::"; + } + out << "what() const throw()"; +} + +namespace struct_ostream_operator_generator { +void generate_required_field_value(std::ofstream& out, const t_field* field) { + out << " << to_string(" << field->get_name() << ")"; +} + +void generate_optional_field_value(std::ofstream& out, const t_field* field) { + out << "; (__isset." << field->get_name() << " ? (out"; + generate_required_field_value(out, field); + out << ") : (out << \"\"))"; +} + +void generate_field_value(std::ofstream& out, const t_field* field) { + if (field->get_req() == t_field::T_OPTIONAL) + generate_optional_field_value(out, field); + else + generate_required_field_value(out, field); +} + +void generate_field_name(std::ofstream& out, const t_field* field) { + out << "\"" << field->get_name() << "=\""; +} + +void generate_field(std::ofstream& out, const t_field* field) { + generate_field_name(out, field); + generate_field_value(out, field); +} + +void generate_fields(std::ofstream& out, + const vector& fields, + const std::string& indent) { + const vector::const_iterator beg = fields.begin(); + const vector::const_iterator end = fields.end(); + + for (vector::const_iterator it = beg; it != end; ++it) { + out << indent << "out << "; + + if (it != beg) { + out << "\", \" << "; + } + + generate_field(out, *it); + out << ";" << endl; + } +} +} + +/** + * Generates operator<< + */ +void t_cpp_generator::generate_struct_print_method(std::ofstream& out, t_struct* tstruct) { + out << indent(); + generate_struct_print_method_decl(out, tstruct); + out << " {" << endl; + + indent_up(); + + out << indent() << "using ::apache::thrift::to_string;" << endl; + out << indent() << "out << \"" << tstruct->get_name() << "(\";" << endl; + struct_ostream_operator_generator::generate_fields(out, tstruct->get_members(), indent()); + out << indent() << "out << \")\";" << endl; + + indent_down(); + out << "}" << endl << endl; +} + +/** + * Generates what() method for exceptions + */ +void t_cpp_generator::generate_exception_what_method(std::ofstream& out, t_struct* tstruct) { + out << indent(); + generate_exception_what_method_decl(out, tstruct, true); + out << " {" << endl; + + indent_up(); + out << indent() << "try {" << endl; + + indent_up(); + out << indent() << "std::stringstream ss;" << endl; + out << indent() << "ss << \"TException - service has thrown: \" << *this;" << endl; + out << indent() << "this->thriftTExceptionMessageHolder_ = ss.str();" << endl; + out << indent() << "return this->thriftTExceptionMessageHolder_.c_str();" << endl; + indent_down(); + + out << indent() << "} catch (const std::exception&) {" << endl; + + indent_up(); + out << indent() << "return \"TException - service has thrown: " << tstruct->get_name() << "\";" + << endl; + indent_down(); + + out << indent() << "}" << endl; + + indent_down(); + out << "}" << endl << endl; +} + +/** + * Generates a thrift service. In C++, this comprises an entirely separate + * header and source file. The header file defines the methods and includes + * the data types defined in the main header file, and the implementation + * file contains implementations of the basic printer and default interfaces. + * + * @param tservice The service definition + */ +void t_cpp_generator::generate_service(t_service* tservice) { + string svcname = tservice->get_name(); + + // Make output files + string f_header_name = get_out_dir() + svcname + ".h"; + f_header_.open(f_header_name.c_str()); + + // Print header file includes + f_header_ << autogen_comment(); + f_header_ << "#ifndef " << svcname << "_H" << endl << "#define " << svcname << "_H" << endl + << endl; + if (gen_cob_style_) { + f_header_ << "#include " << endl << // TMemoryBuffer + "#include " << endl + << "namespace apache { namespace thrift { namespace async {" << endl + << "class TAsyncChannel;" << endl << "}}}" << endl; + } + f_header_ << "#include " << endl; + if (gen_cob_style_) { + f_header_ << "#include " << endl; + } + f_header_ << "#include " << endl; + f_header_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ << "_types.h\"" + << endl; + + t_service* extends_service = tservice->get_extends(); + if (extends_service != NULL) { + f_header_ << "#include \"" << get_include_prefix(*(extends_service->get_program())) + << extends_service->get_name() << ".h\"" << endl; + } + + f_header_ << endl << ns_open_ << endl << endl; + + f_header_ << "#ifdef _MSC_VER\n" + " #pragma warning( push )\n" + " #pragma warning (disable : 4250 ) //inheriting methods via dominance \n" + "#endif\n\n"; + + // Service implementation file includes + string f_service_name = get_out_dir() + svcname + ".cpp"; + f_service_.open(f_service_name.c_str()); + f_service_ << autogen_comment(); + f_service_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl; + if (gen_cob_style_) { + f_service_ << "#include \"thrift/async/TAsyncChannel.h\"" << endl; + } + if (gen_templates_) { + f_service_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".tcc\"" + << endl; + + string f_service_tcc_name = get_out_dir() + svcname + ".tcc"; + f_service_tcc_.open(f_service_tcc_name.c_str()); + f_service_tcc_ << autogen_comment(); + f_service_tcc_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" + << endl; + + f_service_tcc_ << "#ifndef " << svcname << "_TCC" << endl << "#define " << svcname << "_TCC" + << endl << endl; + + if (gen_cob_style_) { + f_service_tcc_ << "#include \"thrift/async/TAsyncChannel.h\"" << endl; + } + } + + f_service_ << endl << ns_open_ << endl << endl; + f_service_tcc_ << endl << ns_open_ << endl << endl; + + // Generate all the components + generate_service_interface(tservice, ""); + generate_service_interface_factory(tservice, ""); + generate_service_null(tservice, ""); + generate_service_helpers(tservice); + generate_service_client(tservice, ""); + generate_service_processor(tservice, ""); + generate_service_multiface(tservice); + generate_service_client(tservice, "Concurrent"); + + // Generate skeleton + if (!gen_no_skeleton_) { + generate_service_skeleton(tservice); + } + + // Generate all the cob components + if (gen_cob_style_) { + generate_service_interface(tservice, "CobCl"); + generate_service_interface(tservice, "CobSv"); + generate_service_interface_factory(tservice, "CobSv"); + generate_service_null(tservice, "CobSv"); + generate_service_client(tservice, "Cob"); + generate_service_processor(tservice, "Cob"); + + if (!gen_no_skeleton_) { + generate_service_async_skeleton(tservice); + } + + } + + f_header_ << "#ifdef _MSC_VER\n" + " #pragma warning( pop )\n" + "#endif\n\n"; + + // Close the namespace + f_service_ << ns_close_ << endl << endl; + f_service_tcc_ << ns_close_ << endl << endl; + f_header_ << ns_close_ << endl << endl; + + // TODO(simpkins): Make this a separate option + if (gen_templates_) { + f_header_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".tcc\"" << endl + << "#include \"" << get_include_prefix(*get_program()) << program_name_ + << "_types.tcc\"" << endl << endl; + } + + f_header_ << "#endif" << endl; + f_service_tcc_ << "#endif" << endl; + + // Close the files + f_service_tcc_.close(); + f_service_.close(); + f_header_.close(); +} + +/** + * Generates helper functions for a service. Basically, this generates types + * for all the arguments and results to functions. + * + * @param tservice The service to generate a header definition for + */ +void t_cpp_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_); + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + string name_orig = ts->get_name(); + + // TODO(dreiss): Why is this stuff not in generate_function_helpers? + ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_args"); + generate_struct_declaration(f_header_, ts, false); + generate_struct_definition(out, f_service_, ts, false); + generate_struct_reader(out, ts); + generate_struct_writer(out, ts); + ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs"); + generate_struct_declaration(f_header_, ts, false, true, false, true); + generate_struct_definition(out, f_service_, ts, false); + generate_struct_writer(out, ts, true); + ts->set_name(name_orig); + + generate_function_helpers(tservice, *f_iter); + } +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_cpp_generator::generate_service_interface(t_service* tservice, string style) { + + string service_if_name = service_name_ + style + "If"; + if (style == "CobCl") { + // Forward declare the client. + string client_name = service_name_ + "CobClient"; + if (gen_templates_) { + client_name += "T"; + service_if_name += "T"; + indent(f_header_) << "template " << endl; + } + indent(f_header_) << "class " << client_name << ";" << endl << endl; + } + + string extends = ""; + if (tservice->get_extends() != NULL) { + extends = " : virtual public " + type_name(tservice->get_extends()) + style + "If"; + if (style == "CobCl" && gen_templates_) { + // TODO(simpkins): If gen_templates_ is enabled, we currently assume all + // parent services were also generated with templates enabled. + extends += "T"; + } + } + + if (style == "CobCl" && gen_templates_) { + f_header_ << "template " << endl; + } + f_header_ << "class " << service_if_name << extends << " {" << endl << " public:" << endl; + indent_up(); + f_header_ << indent() << "virtual ~" << service_if_name << "() {}" << endl; + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + if ((*f_iter)->has_doc()) + f_header_ << endl; + generate_java_doc(f_header_, *f_iter); + f_header_ << indent() << "virtual " << function_signature(*f_iter, style) << " = 0;" << endl; + } + indent_down(); + f_header_ << "};" << endl << endl; + + if (style == "CobCl" && gen_templates_) { + // generate a backwards-compatible typedef for clients that do not + // know about the new template-style code + f_header_ << "typedef " << service_if_name << "< ::apache::thrift::protocol::TProtocol> " + << service_name_ << style << "If;" << endl << endl; + } +} + +/** + * Generates a service interface factory. + * + * @param tservice The service to generate an interface factory for. + */ +void t_cpp_generator::generate_service_interface_factory(t_service* tservice, string style) { + string service_if_name = service_name_ + style + "If"; + + // Figure out the name of the upper-most parent class. + // Getting everything to work out properly with inheritance is annoying. + // Here's what we're doing for now: + // + // - All handlers implement getHandler(), but subclasses use covariant return + // types to return their specific service interface class type. We have to + // use raw pointers because of this; shared_ptr<> can't be used for + // covariant return types. + // + // - Since we're not using shared_ptr<>, we also provide a releaseHandler() + // function that must be called to release a pointer to a handler obtained + // via getHandler(). + // + // releaseHandler() always accepts a pointer to the upper-most parent class + // type. This is necessary since the parent versions of releaseHandler() + // may accept any of the parent types, not just the most specific subclass + // type. Implementations can use dynamic_cast to cast the pointer to the + // subclass type if desired. + t_service* base_service = tservice; + while (base_service->get_extends() != NULL) { + base_service = base_service->get_extends(); + } + string base_if_name = type_name(base_service) + style + "If"; + + // Generate the abstract factory class + string factory_name = service_if_name + "Factory"; + string extends; + if (tservice->get_extends() != NULL) { + extends = " : virtual public " + type_name(tservice->get_extends()) + style + "IfFactory"; + } + + f_header_ << "class " << factory_name << extends << " {" << endl << " public:" << endl; + indent_up(); + f_header_ << indent() << "typedef " << service_if_name << " Handler;" << endl << endl << indent() + << "virtual ~" << factory_name << "() {}" << endl << endl << indent() << "virtual " + << service_if_name << "* getHandler(" + << "const ::apache::thrift::TConnectionInfo& connInfo) = 0;" << endl << indent() + << "virtual void releaseHandler(" << base_if_name << "* /* handler */) = 0;" << endl; + + indent_down(); + f_header_ << "};" << endl << endl; + + // Generate the singleton factory class + string singleton_factory_name = service_if_name + "SingletonFactory"; + f_header_ << "class " << singleton_factory_name << " : virtual public " << factory_name << " {" + << endl << " public:" << endl; + indent_up(); + f_header_ << indent() << singleton_factory_name << "(const ::apache::thrift::stdcxx::shared_ptr<" << service_if_name + << ">& iface) : iface_(iface) {}" << endl << indent() << "virtual ~" + << singleton_factory_name << "() {}" << endl << endl << indent() << "virtual " + << service_if_name << "* getHandler(" + << "const ::apache::thrift::TConnectionInfo&) {" << endl << indent() + << " return iface_.get();" << endl << indent() << "}" << endl << indent() + << "virtual void releaseHandler(" << base_if_name << "* /* handler */) {}" << endl; + + f_header_ << endl << " protected:" << endl << indent() << "::apache::thrift::stdcxx::shared_ptr<" << service_if_name + << "> iface_;" << endl; + + indent_down(); + f_header_ << "};" << endl << endl; +} + +/** + * Generates a null implementation of the service. + * + * @param tservice The service to generate a header definition for + */ +void t_cpp_generator::generate_service_null(t_service* tservice, string style) { + string extends = ""; + if (tservice->get_extends() != NULL) { + extends = " , virtual public " + type_name(tservice->get_extends()) + style + "Null"; + } + f_header_ << "class " << service_name_ << style << "Null : virtual public " << service_name_ + << style << "If" << extends << " {" << endl << " public:" << endl; + indent_up(); + f_header_ << indent() << "virtual ~" << service_name_ << style << "Null() {}" << endl; + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_header_ << indent() << function_signature(*f_iter, style, "", false) << " {" << endl; + indent_up(); + + t_type* returntype = (*f_iter)->get_returntype(); + t_field returnfield(returntype, "_return"); + + if (style == "") { + if (returntype->is_void() || is_complex_type(returntype)) { + f_header_ << indent() << "return;" << endl; + } else { + f_header_ << indent() << declare_field(&returnfield, true) << endl << indent() + << "return _return;" << endl; + } + } else if (style == "CobSv") { + if (returntype->is_void()) { + f_header_ << indent() << "return cob();" << endl; + } else { + t_field returnfield(returntype, "_return"); + f_header_ << indent() << declare_field(&returnfield, true) << endl << indent() + << "return cob(_return);" << endl; + } + + } else { + throw "UNKNOWN STYLE"; + } + + indent_down(); + f_header_ << indent() << "}" << endl; + } + indent_down(); + f_header_ << "};" << endl << endl; +} + +void t_cpp_generator::generate_function_call(ostream& out, + t_function* tfunction, + string target, + string iface, + string arg_prefix) { + bool first = true; + t_type* ret_type = get_true_type(tfunction->get_returntype()); + out << indent(); + if (!tfunction->is_oneway() && !ret_type->is_void()) { + if (is_complex_type(ret_type)) { + first = false; + out << iface << "->" << tfunction->get_name() << "(" << target; + } else { + out << target << " = " << iface << "->" << tfunction->get_name() << "("; + } + } else { + out << iface << "->" << tfunction->get_name() << "("; + } + const std::vector& fields = tfunction->get_arglist()->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + out << ", "; + } + out << arg_prefix << (*f_iter)->get_name(); + } + out << ");" << endl; +} + +void t_cpp_generator::generate_service_async_skeleton(t_service* tservice) { + string svcname = tservice->get_name(); + + // Service implementation file includes + string f_skeleton_name = get_out_dir() + svcname + "_async_server.skeleton.cpp"; + + string ns = namespace_prefix(tservice->get_program()->get_namespace("cpp")); + + ofstream f_skeleton; + f_skeleton.open(f_skeleton_name.c_str()); + f_skeleton << "// This autogenerated skeleton file illustrates one way to adapt a synchronous" + << endl << "// interface into an asynchronous interface. You should copy it to another" + << endl + << "// filename to avoid overwriting it and rewrite as asynchronous any functions" + << endl << "// that would otherwise introduce unwanted latency." << endl << endl + << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl + << "#include " << endl << endl + << "using namespace ::apache::thrift;" << endl + << "using namespace ::apache::thrift::protocol;" << endl + << "using namespace ::apache::thrift::transport;" << endl + << "using namespace ::apache::thrift::async;" << endl << endl; + + // the following code would not compile: + // using namespace ; + // using namespace ::; + if ((!ns.empty()) && (ns.compare(" ::") != 0)) { + f_skeleton << "using namespace " << string(ns, 0, ns.size() - 2) << ";" << endl << endl; + } + + f_skeleton << "class " << svcname << "AsyncHandler : " + << "public " << svcname << "CobSvIf {" << endl << " public:" << endl; + indent_up(); + f_skeleton << indent() << svcname << "AsyncHandler() {" << endl << indent() + << " syncHandler_ = std::auto_ptr<" << svcname << "Handler>(new " << svcname + << "Handler);" << endl << indent() << " // Your initialization goes here" << endl + << indent() << "}" << endl; + f_skeleton << indent() << "virtual ~" << service_name_ << "AsyncHandler();" << endl; + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_skeleton << endl << indent() << function_signature(*f_iter, "CobSv", "", true) << " {" + << endl; + indent_up(); + + t_type* returntype = (*f_iter)->get_returntype(); + t_field returnfield(returntype, "_return"); + + string target = returntype->is_void() ? "" : "_return"; + if (!returntype->is_void()) { + f_skeleton << indent() << declare_field(&returnfield, true) << endl; + } + generate_function_call(f_skeleton, *f_iter, target, "syncHandler_", ""); + f_skeleton << indent() << "return cob(" << target << ");" << endl; + + scope_down(f_skeleton); + } + f_skeleton << endl << " protected:" << endl << indent() << "std::auto_ptr<" << svcname + << "Handler> syncHandler_;" << endl; + indent_down(); + f_skeleton << "};" << endl << endl; +} + +/** + * Generates a multiface, which is a single server that just takes a set + * of objects implementing the interface and calls them all, returning the + * value of the last one to be called. + * + * @param tservice The service to generate a multiserver for. + */ +void t_cpp_generator::generate_service_multiface(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + string extends = ""; + string extends_multiface = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_multiface = ", public " + extends + "Multiface"; + } + + string list_type = string("std::vector >"; + + // Generate the header portion + f_header_ << "class " << service_name_ << "Multiface : " + << "virtual public " << service_name_ << "If" << extends_multiface << " {" << endl + << " public:" << endl; + indent_up(); + f_header_ << indent() << service_name_ << "Multiface(" << list_type + << "& ifaces) : ifaces_(ifaces) {" << endl; + if (!extends.empty()) { + f_header_ << indent() + << " std::vector >::iterator iter;" + << endl << indent() << " for (iter = ifaces.begin(); iter != ifaces.end(); ++iter) {" + << endl << indent() << " " << extends << "Multiface::add(*iter);" << endl + << indent() << " }" << endl; + } + f_header_ << indent() << "}" << endl << indent() << "virtual ~" << service_name_ + << "Multiface() {}" << endl; + indent_down(); + + // Protected data members + f_header_ << " protected:" << endl; + indent_up(); + f_header_ << indent() << list_type << " ifaces_;" << endl << indent() << service_name_ + << "Multiface() {}" << endl << indent() << "void add(::apache::thrift::stdcxx::shared_ptr<" + << service_name_ << "If> iface) {" << endl; + if (!extends.empty()) { + f_header_ << indent() << " " << extends << "Multiface::add(iface);" << endl; + } + f_header_ << indent() << " ifaces_.push_back(iface);" << endl << indent() << "}" << endl; + indent_down(); + + f_header_ << indent() << " public:" << endl; + indent_up(); + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* arglist = (*f_iter)->get_arglist(); + const vector& args = arglist->get_members(); + vector::const_iterator a_iter; + + string call = string("ifaces_[i]->") + (*f_iter)->get_name() + "("; + bool first = true; + if (is_complex_type((*f_iter)->get_returntype())) { + call += "_return"; + first = false; + } + for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) { + if (first) { + first = false; + } else { + call += ", "; + } + call += (*a_iter)->get_name(); + } + call += ")"; + + f_header_ << indent() << function_signature(*f_iter, "") << " {" << endl; + indent_up(); + f_header_ << indent() << "size_t sz = ifaces_.size();" << endl << indent() << "size_t i = 0;" + << endl << indent() << "for (; i < (sz - 1); ++i) {" << endl; + indent_up(); + f_header_ << indent() << call << ";" << endl; + indent_down(); + f_header_ << indent() << "}" << endl; + + if (!(*f_iter)->get_returntype()->is_void()) { + if (is_complex_type((*f_iter)->get_returntype())) { + f_header_ << indent() << call << ";" << endl << indent() << "return;" << endl; + } else { + f_header_ << indent() << "return " << call << ";" << endl; + } + } else { + f_header_ << indent() << call << ";" << endl; + } + + indent_down(); + f_header_ << indent() << "}" << endl << endl; + } + + indent_down(); + f_header_ << indent() << "};" << endl << endl; +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_cpp_generator::generate_service_client(t_service* tservice, string style) { + string ifstyle; + if (style == "Cob") { + ifstyle = "CobCl"; + } + + std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_); + string template_header, template_suffix, short_suffix, protocol_type, _this; + string const prot_factory_type = "::apache::thrift::protocol::TProtocolFactory"; + if (gen_templates_) { + template_header = "template \n"; + short_suffix = "T"; + template_suffix = "T"; + protocol_type = "Protocol_"; + _this = "this->"; + } else { + protocol_type = "::apache::thrift::protocol::TProtocol"; + } + string prot_ptr = "apache::thrift::stdcxx::shared_ptr< " + protocol_type + ">"; + string client_suffix = "Client" + template_suffix; + string if_suffix = "If"; + if (style == "Cob") { + if_suffix += template_suffix; + } + + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() != NULL) { + // TODO(simpkins): If gen_templates_ is enabled, we currently assume all + // parent services were also generated with templates enabled. + extends = type_name(tservice->get_extends()); + extends_client = ", public " + extends + style + client_suffix; + } + + // Generate the header portion + if (style == "Concurrent") { + f_header_ << "// The \'concurrent\' client is a thread safe client that correctly handles\n" + "// out of order responses. It is slower than the regular client, so should\n" + "// only be used when you need to share a connection among multiple threads\n"; + } + f_header_ << template_header << "class " << service_name_ << style << "Client" << short_suffix + << " : " + << "virtual public " << service_name_ << ifstyle << if_suffix << extends_client << " {" + << endl << " public:" << endl; + + indent_up(); + if (style != "Cob") { + f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" << prot_ptr + << " prot) "; + + if (extends.empty()) { + f_header_ << "{" << endl; + f_header_ << indent() << " setProtocol" << short_suffix << "(prot);" << endl << indent() + << "}" << endl; + } else { + f_header_ << ":" << endl; + f_header_ << indent() << " " << extends << style << client_suffix << "(prot, prot) {}" + << endl; + } + + f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" << prot_ptr + << " iprot, " << prot_ptr << " oprot) "; + if (extends.empty()) { + f_header_ << "{" << endl; + f_header_ << indent() << " setProtocol" << short_suffix << "(iprot,oprot);" << endl + << indent() << "}" << endl; + } else { + f_header_ << ":" << indent() << " " << extends << style << client_suffix + << "(iprot, oprot) {}" << endl; + } + + // create the setProtocol methods + if (extends.empty()) { + f_header_ << " private:" << endl; + // 1: one parameter + f_header_ << indent() << "void setProtocol" << short_suffix << "(" << prot_ptr << " prot) {" + << endl; + f_header_ << indent() << "setProtocol" << short_suffix << "(prot,prot);" << endl; + f_header_ << indent() << "}" << endl; + // 2: two parameter + f_header_ << indent() << "void setProtocol" << short_suffix << "(" << prot_ptr << " iprot, " + << prot_ptr << " oprot) {" << endl; + + f_header_ << indent() << " piprot_=iprot;" << endl << indent() << " poprot_=oprot;" << endl + << indent() << " iprot_ = iprot.get();" << endl << indent() + << " oprot_ = oprot.get();" << endl; + + f_header_ << indent() << "}" << endl; + f_header_ << " public:" << endl; + } + + // Generate getters for the protocols. + // Note that these are not currently templated for simplicity. + // TODO(simpkins): should they be templated? + f_header_ << indent() + << "apache::thrift::stdcxx::shared_ptr< ::apache::thrift::protocol::TProtocol> getInputProtocol() {" + << endl << indent() << " return " << _this << "piprot_;" << endl << indent() << "}" + << endl; + + f_header_ << indent() + << "apache::thrift::stdcxx::shared_ptr< ::apache::thrift::protocol::TProtocol> getOutputProtocol() {" + << endl << indent() << " return " << _this << "poprot_;" << endl << indent() << "}" + << endl; + + } else /* if (style == "Cob") */ { + f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" + << "apache::thrift::stdcxx::shared_ptr< ::apache::thrift::async::TAsyncChannel> channel, " + << "::apache::thrift::protocol::TProtocolFactory* protocolFactory) :" << endl; + if (extends.empty()) { + f_header_ << indent() << " channel_(channel)," << endl << indent() + << " itrans_(new ::apache::thrift::transport::TMemoryBuffer())," << endl + << indent() << " otrans_(new ::apache::thrift::transport::TMemoryBuffer())," + << endl; + if (gen_templates_) { + // TProtocolFactory classes return generic TProtocol pointers. + // We have to dynamic cast to the Protocol_ type we are expecting. + f_header_ << indent() << " piprot_(::apache::thrift::stdcxx::dynamic_pointer_cast(" + << "protocolFactory->getProtocol(itrans_)))," << endl << indent() + << " poprot_(::apache::thrift::stdcxx::dynamic_pointer_cast(" + << "protocolFactory->getProtocol(otrans_))) {" << endl; + // Throw a TException if either dynamic cast failed. + f_header_ << indent() << " if (!piprot_ || !poprot_) {" << endl << indent() + << " throw ::apache::thrift::TException(\"" + << "TProtocolFactory returned unexpected protocol type in " << service_name_ + << style << "Client" << short_suffix << " constructor\");" << endl << indent() + << " }" << endl; + } else { + f_header_ << indent() << " piprot_(protocolFactory->getProtocol(itrans_))," << endl + << indent() << " poprot_(protocolFactory->getProtocol(otrans_)) {" << endl; + } + f_header_ << indent() << " iprot_ = piprot_.get();" << endl << indent() + << " oprot_ = poprot_.get();" << endl << indent() << "}" << endl; + } else { + f_header_ << indent() << " " << extends << style << client_suffix + << "(channel, protocolFactory) {}" << endl; + } + } + + if (style == "Cob") { + f_header_ << indent() + << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::async::TAsyncChannel> getChannel() {" << endl + << indent() << " return " << _this << "channel_;" << endl << indent() << "}" << endl; + if (!gen_no_client_completion_) { + f_header_ << indent() << "virtual void completed__(bool /* success */) {}" << endl; + } + } + + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + indent(f_header_) << function_signature(*f_iter, ifstyle) << ";" << endl; + // TODO(dreiss): Use private inheritance to avoid generating thise in cob-style. + if (style == "Concurrent" && !(*f_iter)->is_oneway()) { + // concurrent clients need to move the seqid from the send function to the + // recv function. Oneway methods don't have a recv function, so we don't need to + // move the seqid for them. Attempting to do so would result in a seqid leak. + t_function send_function(g_type_i32, /*returning seqid*/ + string("send_") + (*f_iter)->get_name(), + (*f_iter)->get_arglist()); + indent(f_header_) << function_signature(&send_function, "") << ";" << endl; + } else { + t_function send_function(g_type_void, + string("send_") + (*f_iter)->get_name(), + (*f_iter)->get_arglist()); + indent(f_header_) << function_signature(&send_function, "") << ";" << endl; + } + if (!(*f_iter)->is_oneway()) { + if (style == "Concurrent") { + t_field seqIdArg(g_type_i32, "seqid"); + t_struct seqIdArgStruct(program_); + seqIdArgStruct.append(&seqIdArg); + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + &seqIdArgStruct); + indent(f_header_) << function_signature(&recv_function, "") << ";" << endl; + } else { + t_struct noargs(program_); + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + &noargs); + indent(f_header_) << function_signature(&recv_function, "") << ";" << endl; + } + } + } + indent_down(); + + if (extends.empty()) { + f_header_ << " protected:" << endl; + indent_up(); + + if (style == "Cob") { + f_header_ << indent() + << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::async::TAsyncChannel> channel_;" << endl + << indent() + << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::transport::TMemoryBuffer> itrans_;" << endl + << indent() + << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::transport::TMemoryBuffer> otrans_;" + << endl; + } + f_header_ << + indent() << prot_ptr << " piprot_;" << endl << + indent() << prot_ptr << " poprot_;" << endl << + indent() << protocol_type << "* iprot_;" << endl << + indent() << protocol_type << "* oprot_;" << endl; + + if (style == "Concurrent") { + f_header_ << + indent() << "::apache::thrift::async::TConcurrentClientSyncInfo sync_;"< " << service_name_ << style + << "Client;" << endl << endl; + } + + string scope = service_name_ + style + client_suffix + "::"; + + // Generate client method implementations + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string seqIdCapture; + string seqIdUse; + string seqIdCommaUse; + if (style == "Concurrent" && !(*f_iter)->is_oneway()) { + seqIdCapture = "int32_t seqid = "; + seqIdUse = "seqid"; + seqIdCommaUse = ", seqid"; + } + + string funname = (*f_iter)->get_name(); + + // Open function + if (gen_templates_) { + indent(out) << template_header; + } + indent(out) << function_signature(*f_iter, ifstyle, scope) << endl; + scope_up(out); + indent(out) << seqIdCapture << "send_" << funname << "("; + + // Get the struct of function call params + t_struct* arg_struct = (*f_iter)->get_arglist(); + + // Declare the function arguments + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + bool first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + if (first) { + first = false; + } else { + out << ", "; + } + out << (*fld_iter)->get_name(); + } + out << ");" << endl; + + if (style != "Cob") { + if (!(*f_iter)->is_oneway()) { + out << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + if (is_complex_type((*f_iter)->get_returntype())) { + out << "recv_" << funname << "(_return" << seqIdCommaUse << ");" << endl; + } else { + out << "return recv_" << funname << "(" << seqIdUse << ");" << endl; + } + } else { + out << "recv_" << funname << "(" << seqIdUse << ");" << endl; + } + } + } else { + if (!(*f_iter)->is_oneway()) { + out << indent() << _this << "channel_->sendAndRecvMessage(" + << "::apache::thrift::stdcxx::bind(cob, this), " << _this << "otrans_.get(), " << _this << "itrans_.get());" + << endl; + } else { + out << indent() << _this << "channel_->sendMessage(" + << "::apache::thrift::stdcxx::bind(cob, this), " << _this << "otrans_.get());" << endl; + } + } + scope_down(out); + out << endl; + + // if (style != "Cob") // TODO(dreiss): Libify the client and don't generate this for cob-style + if (true) { + t_type* send_func_return_type = g_type_void; + if (style == "Concurrent" && !(*f_iter)->is_oneway()) { + send_func_return_type = g_type_i32; + } + // Function for sending + t_function send_function(send_func_return_type, + string("send_") + (*f_iter)->get_name(), + (*f_iter)->get_arglist()); + + // Open the send function + if (gen_templates_) { + indent(out) << template_header; + } + indent(out) << function_signature(&send_function, "", scope) << endl; + scope_up(out); + + // Function arguments and results + string argsname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs"; + string resultname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_presult"; + + string cseqidVal = "0"; + if (style == "Concurrent") { + if (!(*f_iter)->is_oneway()) { + cseqidVal = "this->sync_.generateSeqId()"; + } + } + // Serialize the request + out << + indent() << "int32_t cseqid = " << cseqidVal << ";" << endl; + if(style == "Concurrent") { + out << + indent() << "::apache::thrift::async::TConcurrentSendSentry sentry(&this->sync_);" << endl; + } + if (style == "Cob") { + out << + indent() << _this << "otrans_->resetBuffer();" << endl; + } + out << + indent() << _this << "oprot_->writeMessageBegin(\"" << + (*f_iter)->get_name() << + "\", ::apache::thrift::protocol::" << ((*f_iter)->is_oneway() ? "T_ONEWAY" : "T_CALL") << + ", cseqid);" << endl << endl << + indent() << argsname << " args;" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + out << indent() << "args." << (*fld_iter)->get_name() << " = &" << (*fld_iter)->get_name() + << ";" << endl; + } + + out << indent() << "args.write(" << _this << "oprot_);" << endl << endl << indent() << _this + << "oprot_->writeMessageEnd();" << endl << indent() << _this + << "oprot_->getTransport()->writeEnd();" << endl << indent() << _this + << "oprot_->getTransport()->flush();" << endl; + + if (style == "Concurrent") { + out << endl << indent() << "sentry.commit();" << endl; + + if (!(*f_iter)->is_oneway()) { + out << indent() << "return cseqid;" << endl; + } + } + scope_down(out); + out << endl; + + // Generate recv function only if not an oneway function + if (!(*f_iter)->is_oneway()) { + t_struct noargs(program_); + + t_field seqIdArg(g_type_i32, "seqid"); + t_struct seqIdArgStruct(program_); + seqIdArgStruct.append(&seqIdArg); + + t_struct* recv_function_args = &noargs; + if (style == "Concurrent") { + recv_function_args = &seqIdArgStruct; + } + + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + recv_function_args); + // Open the recv function + if (gen_templates_) { + indent(out) << template_header; + } + indent(out) << function_signature(&recv_function, "", scope) << endl; + scope_up(out); + + out << endl << + indent() << "int32_t rseqid = 0;" << endl << + indent() << "std::string fname;" << endl << + indent() << "::apache::thrift::protocol::TMessageType mtype;" << endl; + if(style == "Concurrent") { + out << + endl << + indent() << "// the read mutex gets dropped and reacquired as part of waitForWork()" << endl << + indent() << "// The destructor of this sentry wakes up other clients" << endl << + indent() << "::apache::thrift::async::TConcurrentRecvSentry sentry(&this->sync_, seqid);" << endl; + } + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << "bool completed = false;" << endl << endl << indent() << "try {"; + indent_up(); + } + out << endl; + if (style == "Concurrent") { + out << + indent() << "while(true) {" << endl << + indent() << " if(!this->sync_.getPending(fname, mtype, rseqid)) {" << endl; + indent_up(); + indent_up(); + } + out << + indent() << _this << "iprot_->readMessageBegin(fname, mtype, rseqid);" << endl; + if (style == "Concurrent") { + scope_down(out); + out << indent() << "if(seqid == rseqid) {" << endl; + indent_up(); + } + out << + indent() << "if (mtype == ::apache::thrift::protocol::T_EXCEPTION) {" << endl << + indent() << " ::apache::thrift::TApplicationException x;" << endl << + indent() << " x.read(" << _this << "iprot_);" << endl << + indent() << " " << _this << "iprot_->readMessageEnd();" << endl << + indent() << " " << _this << "iprot_->getTransport()->readEnd();" << endl; + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << " completed = true;" << endl << indent() << " completed__(true);" + << endl; + } + if (style == "Concurrent") { + out << indent() << " sentry.commit();" << endl; + } + out << + indent() << " throw x;" << endl << + indent() << "}" << endl << + indent() << "if (mtype != ::apache::thrift::protocol::T_REPLY) {" << endl << + indent() << " " << _this << "iprot_->skip(" << "::apache::thrift::protocol::T_STRUCT);" << endl << + indent() << " " << _this << "iprot_->readMessageEnd();" << endl << + indent() << " " << _this << "iprot_->getTransport()->readEnd();" << endl; + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << " completed = true;" << endl << indent() << " completed__(false);" + << endl; + } + out << + indent() << "}" << endl << + indent() << "if (fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl << + indent() << " " << _this << "iprot_->skip(" << "::apache::thrift::protocol::T_STRUCT);" << endl << + indent() << " " << _this << "iprot_->readMessageEnd();" << endl << + indent() << " " << _this << "iprot_->getTransport()->readEnd();" << endl; + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << " completed = true;" << endl << indent() << " completed__(false);" + << endl; + } + if (style == "Concurrent") { + out << endl << + indent() << " // in a bad state, don't commit" << endl << + indent() << " using ::apache::thrift::protocol::TProtocolException;" << endl << + indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl; + } + out << indent() << "}" << endl; + + if (!(*f_iter)->get_returntype()->is_void() + && !is_complex_type((*f_iter)->get_returntype())) { + t_field returnfield((*f_iter)->get_returntype(), "_return"); + out << indent() << declare_field(&returnfield) << endl; + } + + out << indent() << resultname << " result;" << endl; + + if (!(*f_iter)->get_returntype()->is_void()) { + out << indent() << "result.success = &_return;" << endl; + } + + out << indent() << "result.read(" << _this << "iprot_);" << endl << indent() << _this + << "iprot_->readMessageEnd();" << endl << indent() << _this + << "iprot_->getTransport()->readEnd();" << endl << endl; + + // Careful, only look for _result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + if (is_complex_type((*f_iter)->get_returntype())) { + out << + indent() << "if (result.__isset.success) {" << endl; + out << + indent() << " // _return pointer has now been filled" << endl; + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << " completed = true;" << endl << indent() << " completed__(true);" + << endl; + } + if (style == "Concurrent") { + out << indent() << " sentry.commit();" << endl; + } + out << + indent() << " return;" << endl << + indent() << "}" << endl; + } else { + out << indent() << "if (result.__isset.success) {" << endl; + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << " completed = true;" << endl << indent() << " completed__(true);" + << endl; + } + if (style == "Concurrent") { + out << indent() << " sentry.commit();" << endl; + } + out << indent() << " return _return;" << endl << indent() << "}" << endl; + } + } + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + out << indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl; + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << " completed = true;" << endl << indent() << " completed__(true);" + << endl; + } + if (style == "Concurrent") { + out << indent() << " sentry.commit();" << endl; + } + out << indent() << " throw result." << (*x_iter)->get_name() << ";" << endl << indent() + << "}" << endl; + } + + // We only get here if we are a void function + if ((*f_iter)->get_returntype()->is_void()) { + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << "completed = true;" << endl << indent() << "completed__(true);" + << endl; + } + if (style == "Concurrent") { + out << indent() << "sentry.commit();" << endl; + } + indent(out) << "return;" << endl; + } else { + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << "completed = true;" << endl << indent() << "completed__(true);" + << endl; + } + if (style == "Concurrent") { + out << indent() << "// in a bad state, don't commit" << endl; + } + out << indent() << "throw " + "::apache::thrift::TApplicationException(::apache::thrift::" + "TApplicationException::MISSING_RESULT, \"" << (*f_iter)->get_name() + << " failed: unknown result\");" << endl; + } + if (style == "Concurrent") { + indent_down(); + indent_down(); + out << + indent() << " }" << endl << + indent() << " // seqid != rseqid" << endl << + indent() << " this->sync_.updatePending(fname, mtype, rseqid);" << endl << + endl << + indent() << " // this will temporarily unlock the readMutex, and let other clients get work done" << endl << + indent() << " this->sync_.waitForWork(seqid);" << endl << + indent() << "} // end while(true)" << endl; + } + if (style == "Cob" && !gen_no_client_completion_) { + indent_down(); + out << indent() << "} catch (...) {" << endl << indent() << " if (!completed) {" << endl + << indent() << " completed__(false);" << endl << indent() << " }" << endl + << indent() << " throw;" << endl << indent() << "}" << endl; + } + // Close function + scope_down(out); + out << endl; + } + } + } +} + +class ProcessorGenerator { +public: + ProcessorGenerator(t_cpp_generator* generator, t_service* service, const string& style); + + void run() { + generate_class_definition(); + + // Generate the dispatchCall() function + generate_dispatch_call(false); + if (generator_->gen_templates_) { + generate_dispatch_call(true); + } + + // Generate all of the process subfunctions + generate_process_functions(); + + generate_factory(); + } + + void generate_class_definition(); + void generate_dispatch_call(bool template_protocol); + void generate_process_functions(); + void generate_factory(); + +protected: + std::string type_name(t_type* ttype, bool in_typedef = false, bool arg = false) { + return generator_->type_name(ttype, in_typedef, arg); + } + + std::string indent() { return generator_->indent(); } + std::ostream& indent(std::ostream& os) { return generator_->indent(os); } + + void indent_up() { generator_->indent_up(); } + void indent_down() { generator_->indent_down(); } + + t_cpp_generator* generator_; + t_service* service_; + std::ofstream& f_header_; + std::ofstream& f_out_; + string service_name_; + string style_; + string pstyle_; + string class_name_; + string if_name_; + string factory_class_name_; + string finish_cob_; + string finish_cob_decl_; + string ret_type_; + string call_context_; + string cob_arg_; + string call_context_arg_; + string call_context_decl_; + string template_header_; + string template_suffix_; + string typename_str_; + string class_suffix_; + string extends_; +}; + +ProcessorGenerator::ProcessorGenerator(t_cpp_generator* generator, + t_service* service, + const string& style) + : generator_(generator), + service_(service), + f_header_(generator->f_header_), + f_out_(generator->gen_templates_ ? generator->f_service_tcc_ : generator->f_service_), + service_name_(generator->service_name_), + style_(style) { + if (style_ == "Cob") { + pstyle_ = "Async"; + class_name_ = service_name_ + pstyle_ + "Processor"; + if_name_ = service_name_ + "CobSvIf"; + + finish_cob_ = "::apache::thrift::stdcxx::function cob, "; + finish_cob_decl_ = "::apache::thrift::stdcxx::function, "; + cob_arg_ = "cob, "; + ret_type_ = "void "; + } else { + class_name_ = service_name_ + "Processor"; + if_name_ = service_name_ + "If"; + + ret_type_ = "bool "; + // TODO(edhall) callContext should eventually be added to TAsyncProcessor + call_context_ = ", void* callContext"; + call_context_arg_ = ", callContext"; + call_context_decl_ = ", void*"; + } + + factory_class_name_ = class_name_ + "Factory"; + + if (generator->gen_templates_) { + template_header_ = "template \n"; + template_suffix_ = ""; + typename_str_ = "typename "; + class_name_ += "T"; + factory_class_name_ += "T"; + } + + if (service_->get_extends() != NULL) { + extends_ = type_name(service_->get_extends()) + pstyle_ + "Processor"; + if (generator_->gen_templates_) { + // TODO(simpkins): If gen_templates_ is enabled, we currently assume all + // parent services were also generated with templates enabled. + extends_ += "T"; + } + } +} + +void ProcessorGenerator::generate_class_definition() { + // Generate the dispatch methods + vector functions = service_->get_functions(); + vector::iterator f_iter; + + string parent_class; + if (service_->get_extends() != NULL) { + parent_class = extends_; + } else { + if (style_ == "Cob") { + parent_class = "::apache::thrift::async::TAsyncDispatchProcessor"; + } else { + parent_class = "::apache::thrift::TDispatchProcessor"; + } + + if (generator_->gen_templates_) { + parent_class += "T"; + } + } + + // Generate the header portion + f_header_ << template_header_ << "class " << class_name_ << " : public " << parent_class << " {" + << endl; + + // Protected data members + f_header_ << " protected:" << endl; + indent_up(); + f_header_ << indent() << "::apache::thrift::stdcxx::shared_ptr<" << if_name_ << "> iface_;" << endl; + f_header_ << indent() << "virtual " << ret_type_ << "dispatchCall(" << finish_cob_ + << "::apache::thrift::protocol::TProtocol* iprot, " + << "::apache::thrift::protocol::TProtocol* oprot, " + << "const std::string& fname, int32_t seqid" << call_context_ << ");" << endl; + if (generator_->gen_templates_) { + f_header_ << indent() << "virtual " << ret_type_ << "dispatchCallTemplated(" << finish_cob_ + << "Protocol_* iprot, Protocol_* oprot, " + << "const std::string& fname, int32_t seqid" << call_context_ << ");" << endl; + } + indent_down(); + + // Process function declarations + f_header_ << " private:" << endl; + indent_up(); + + // Declare processMap_ + f_header_ << indent() << "typedef void (" << class_name_ << "::*" + << "ProcessFunction)(" << finish_cob_decl_ << "int32_t, " + << "::apache::thrift::protocol::TProtocol*, " + << "::apache::thrift::protocol::TProtocol*" << call_context_decl_ << ");" << endl; + if (generator_->gen_templates_) { + f_header_ << indent() << "typedef void (" << class_name_ << "::*" + << "SpecializedProcessFunction)(" << finish_cob_decl_ << "int32_t, " + << "Protocol_*, Protocol_*" << call_context_decl_ << ");" << endl << indent() + << "struct ProcessFunctions {" << endl << indent() << " ProcessFunction generic;" + << endl << indent() << " SpecializedProcessFunction specialized;" << endl << indent() + << " ProcessFunctions(ProcessFunction g, " + << "SpecializedProcessFunction s) :" << endl << indent() << " generic(g)," << endl + << indent() << " specialized(s) {}" << endl << indent() + << " ProcessFunctions() : generic(NULL), specialized(NULL) " + << "{}" << endl << indent() << "};" << endl << indent() + << "typedef std::map " + << "ProcessMap;" << endl; + } else { + f_header_ << indent() << "typedef std::map " + << "ProcessMap;" << endl; + } + f_header_ << indent() << "ProcessMap processMap_;" << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + indent(f_header_) << "void process_" << (*f_iter)->get_name() << "(" << finish_cob_ + << "int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, " + "::apache::thrift::protocol::TProtocol* oprot" << call_context_ << ");" + << endl; + if (generator_->gen_templates_) { + indent(f_header_) << "void process_" << (*f_iter)->get_name() << "(" << finish_cob_ + << "int32_t seqid, Protocol_* iprot, Protocol_* oprot" << call_context_ + << ");" << endl; + } + if (style_ == "Cob") { + // XXX Factor this out, even if it is a pain. + string ret_arg = ((*f_iter)->get_returntype()->is_void() + ? "" + : ", const " + type_name((*f_iter)->get_returntype()) + "& _return"); + f_header_ << indent() << "void return_" << (*f_iter)->get_name() + << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << "::apache::thrift::protocol::TProtocol* oprot, " + << "void* ctx" << ret_arg << ");" << endl; + if (generator_->gen_templates_) { + f_header_ << indent() << "void return_" << (*f_iter)->get_name() + << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << "Protocol_* oprot, void* ctx" << ret_arg << ");" << endl; + } + // XXX Don't declare throw if it doesn't exist + f_header_ << indent() << "void throw_" << (*f_iter)->get_name() + << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << "::apache::thrift::protocol::TProtocol* oprot, void* ctx, " + << "::apache::thrift::TDelayedException* _throw);" << endl; + if (generator_->gen_templates_) { + f_header_ << indent() << "void throw_" << (*f_iter)->get_name() + << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << "Protocol_* oprot, void* ctx, " + << "::apache::thrift::TDelayedException* _throw);" << endl; + } + } + } + + f_header_ << " public:" << endl << indent() << class_name_ << "(::apache::thrift::stdcxx::shared_ptr<" << if_name_ + << "> iface) :" << endl; + if (!extends_.empty()) { + f_header_ << indent() << " " << extends_ << "(iface)," << endl; + } + f_header_ << indent() << " iface_(iface) {" << endl; + indent_up(); + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_header_ << indent() << "processMap_[\"" << (*f_iter)->get_name() << "\"] = "; + if (generator_->gen_templates_) { + f_header_ << "ProcessFunctions(" << endl; + if (generator_->gen_templates_only_) { + indent(f_header_) << " NULL," << endl; + } else { + indent(f_header_) << " &" << class_name_ << "::process_" << (*f_iter)->get_name() << "," + << endl; + } + indent(f_header_) << " &" << class_name_ << "::process_" << (*f_iter)->get_name() << ")"; + } else { + f_header_ << "&" << class_name_ << "::process_" << (*f_iter)->get_name(); + } + f_header_ << ";" << endl; + } + + indent_down(); + f_header_ << indent() << "}" << endl << endl << indent() << "virtual ~" << class_name_ << "() {}" + << endl; + indent_down(); + f_header_ << "};" << endl << endl; + + if (generator_->gen_templates_) { + // Generate a backwards compatible typedef, for callers who don't know + // about the new template-style code. + // + // We can't use TProtocol as the template parameter, since ProcessorT + // provides overloaded versions of most methods, one of which accepts + // TProtocol pointers, and one which accepts Protocol_ pointers. This + // results in a compile error if instantiated with Protocol_ == TProtocol. + // Therefore, we define TDummyProtocol solely so we can use it as the + // template parameter here. + f_header_ << "typedef " << class_name_ << "< ::apache::thrift::protocol::TDummyProtocol > " + << service_name_ << pstyle_ << "Processor;" << endl << endl; + } +} + +void ProcessorGenerator::generate_dispatch_call(bool template_protocol) { + string protocol = "::apache::thrift::protocol::TProtocol"; + string function_suffix; + if (template_protocol) { + protocol = "Protocol_"; + // We call the generic version dispatchCall(), and the specialized + // version dispatchCallTemplated(). We can't call them both + // dispatchCall(), since this will cause the compiler to issue a warning if + // a service that doesn't use templates inherits from a service that does + // use templates: the compiler complains that the subclass only implements + // the generic version of dispatchCall(), and hides the templated version. + // Using different names for the two functions prevents this. + function_suffix = "Templated"; + } + + f_out_ << template_header_ << ret_type_ << class_name_ << template_suffix_ << "::dispatchCall" + << function_suffix << "(" << finish_cob_ << protocol << "* iprot, " << protocol + << "* oprot, " + << "const std::string& fname, int32_t seqid" << call_context_ << ") {" << endl; + indent_up(); + + // HOT: member function pointer map + f_out_ << indent() << typename_str_ << "ProcessMap::iterator pfn;" << endl << indent() + << "pfn = processMap_.find(fname);" << endl << indent() + << "if (pfn == processMap_.end()) {" << endl; + if (extends_.empty()) { + f_out_ << indent() << " iprot->skip(::apache::thrift::protocol::T_STRUCT);" << endl << indent() + << " iprot->readMessageEnd();" << endl << indent() + << " iprot->getTransport()->readEnd();" << endl << indent() + << " ::apache::thrift::TApplicationException " + "x(::apache::thrift::TApplicationException::UNKNOWN_METHOD, \"Invalid method name: " + "'\"+fname+\"'\");" << endl << indent() + << " oprot->writeMessageBegin(fname, ::apache::thrift::protocol::T_EXCEPTION, seqid);" + << endl << indent() << " x.write(oprot);" << endl << indent() + << " oprot->writeMessageEnd();" << endl << indent() + << " oprot->getTransport()->writeEnd();" << endl << indent() + << " oprot->getTransport()->flush();" << endl << indent() + << (style_ == "Cob" ? " return cob(true);" : " return true;") << endl; + } else { + f_out_ << indent() << " return " << extends_ << "::dispatchCall(" + << (style_ == "Cob" ? "cob, " : "") << "iprot, oprot, fname, seqid" << call_context_arg_ + << ");" << endl; + } + f_out_ << indent() << "}" << endl; + if (template_protocol) { + f_out_ << indent() << "(this->*(pfn->second.specialized))"; + } else { + if (generator_->gen_templates_only_) { + // TODO: This is a null pointer, so nothing good will come from calling + // it. Throw an exception instead. + f_out_ << indent() << "(this->*(pfn->second.generic))"; + } else if (generator_->gen_templates_) { + f_out_ << indent() << "(this->*(pfn->second.generic))"; + } else { + f_out_ << indent() << "(this->*(pfn->second))"; + } + } + f_out_ << "(" << cob_arg_ << "seqid, iprot, oprot" << call_context_arg_ << ");" << endl; + + // TODO(dreiss): return pfn ret? + if (style_ == "Cob") { + f_out_ << indent() << "return;" << endl; + } else { + f_out_ << indent() << "return true;" << endl; + } + + indent_down(); + f_out_ << "}" << endl << endl; +} + +void ProcessorGenerator::generate_process_functions() { + vector functions = service_->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + if (generator_->gen_templates_) { + generator_->generate_process_function(service_, *f_iter, style_, false); + generator_->generate_process_function(service_, *f_iter, style_, true); + } else { + generator_->generate_process_function(service_, *f_iter, style_, false); + } + } +} + +void ProcessorGenerator::generate_factory() { + string if_factory_name = if_name_ + "Factory"; + + // Generate the factory class definition + f_header_ << template_header_ << "class " << factory_class_name_ << " : public ::apache::thrift::" + << (style_ == "Cob" ? "async::TAsyncProcessorFactory" : "TProcessorFactory") << " {" + << endl << " public:" << endl; + indent_up(); + + f_header_ << indent() << factory_class_name_ << "(const ::apache::thrift::stdcxx::shared_ptr< " << if_factory_name + << " >& handlerFactory) :" << endl << indent() + << " handlerFactory_(handlerFactory) {}" << endl << endl << indent() + << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::" + << (style_ == "Cob" ? "async::TAsyncProcessor" : "TProcessor") << " > " + << "getProcessor(const ::apache::thrift::TConnectionInfo& connInfo);" << endl; + + f_header_ << endl << " protected:" << endl << indent() << "::apache::thrift::stdcxx::shared_ptr< " + << if_factory_name << " > handlerFactory_;" << endl; + + indent_down(); + f_header_ << "};" << endl << endl; + + // If we are generating templates, output a typedef for the plain + // factory name. + if (generator_->gen_templates_) { + f_header_ << "typedef " << factory_class_name_ + << "< ::apache::thrift::protocol::TDummyProtocol > " << service_name_ << pstyle_ + << "ProcessorFactory;" << endl << endl; + } + + // Generate the getProcessor() method + f_out_ << template_header_ << indent() << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::" + << (style_ == "Cob" ? "async::TAsyncProcessor" : "TProcessor") << " > " + << factory_class_name_ << template_suffix_ << "::getProcessor(" + << "const ::apache::thrift::TConnectionInfo& connInfo) {" << endl; + indent_up(); + + f_out_ << indent() << "::apache::thrift::ReleaseHandler< " << if_factory_name + << " > cleanup(handlerFactory_);" << endl << indent() << "::apache::thrift::stdcxx::shared_ptr< " + << if_name_ << " > handler(" + << "handlerFactory_->getHandler(connInfo), cleanup);" << endl << indent() + << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::" + << (style_ == "Cob" ? "async::TAsyncProcessor" : "TProcessor") << " > " + << "processor(new " << class_name_ << template_suffix_ << "(handler));" << endl << indent() + << "return processor;" << endl; + + indent_down(); + f_out_ << indent() << "}" << endl << endl; +} + +/** + * Generates a service processor definition. + * + * @param tservice The service to generate a processor for. + */ +void t_cpp_generator::generate_service_processor(t_service* tservice, string style) { + ProcessorGenerator generator(this, tservice, style); + generator.run(); +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_cpp_generator::generate_function_helpers(t_service* tservice, t_function* tfunction) { + if (tfunction->is_oneway()) { + return; + } + + std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_); + + t_struct result(program_, tservice->get_name() + "_" + tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + generate_struct_declaration(f_header_, &result, false); + generate_struct_definition(out, f_service_, &result, false); + generate_struct_reader(out, &result); + generate_struct_result_writer(out, &result); + + result.set_name(tservice->get_name() + "_" + tfunction->get_name() + "_presult"); + generate_struct_declaration(f_header_, &result, false, true, true, gen_cob_style_); + generate_struct_definition(out, f_service_, &result, false); + generate_struct_reader(out, &result, true); + if (gen_cob_style_) { + generate_struct_writer(out, &result, true); + } +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_cpp_generator::generate_process_function(t_service* tservice, + t_function* tfunction, + string style, + bool specialized) { + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + string service_func_name = "\"" + tservice->get_name() + "." + tfunction->get_name() + "\""; + + std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_); + + string prot_type = (specialized ? "Protocol_" : "::apache::thrift::protocol::TProtocol"); + string class_suffix; + if (gen_templates_) { + class_suffix = "T"; + } + + // I tried to do this as one function. I really did. But it was too hard. + if (style != "Cob") { + // Open function + if (gen_templates_) { + out << indent() << "template " << endl; + } + const bool unnamed_oprot_seqid = tfunction->is_oneway() && !(gen_templates_ && !specialized); + out << "void " << tservice->get_name() << "Processor" << class_suffix << "::" + << "process_" << tfunction->get_name() << "(" + << "int32_t" << (unnamed_oprot_seqid ? ", " : " seqid, ") << prot_type << "* iprot, " + << prot_type << "*" << (unnamed_oprot_seqid ? ", " : " oprot, ") << "void* callContext)" + << endl; + scope_up(out); + + string argsname = tservice->get_name() + "_" + tfunction->get_name() + "_args"; + string resultname = tservice->get_name() + "_" + tfunction->get_name() + "_result"; + + if (tfunction->is_oneway() && !unnamed_oprot_seqid) { + out << indent() << "(void) seqid;" << endl << indent() << "(void) oprot;" << endl; + } + + out << indent() << "void* ctx = NULL;" << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " ctx = this->eventHandler_->getContext(" << service_func_name << ", callContext);" + << endl << indent() << "}" << endl << indent() + << "::apache::thrift::TProcessorContextFreer freer(" + << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl + << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->preRead(ctx, " << service_func_name << ");" << endl << indent() + << "}" << endl << endl << indent() << argsname << " args;" << endl << indent() + << "args.read(iprot);" << endl << indent() << "iprot->readMessageEnd();" << endl << indent() + << "uint32_t bytes = iprot->getTransport()->readEnd();" << endl << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->postRead(ctx, " << service_func_name << ", bytes);" << endl + << indent() << "}" << endl << endl; + + // Declare result + if (!tfunction->is_oneway()) { + out << indent() << resultname << " result;" << endl; + } + + // Try block for functions with exceptions + out << indent() << "try {" << endl; + indent_up(); + + // Generate the function call + bool first = true; + out << indent(); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + if (is_complex_type(tfunction->get_returntype())) { + first = false; + out << "iface_->" << tfunction->get_name() << "(result.success"; + } else { + out << "result.success = iface_->" << tfunction->get_name() << "("; + } + } else { + out << "iface_->" << tfunction->get_name() << "("; + } + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + out << ", "; + } + out << "args." << (*f_iter)->get_name(); + } + out << ");" << endl; + + // Set isset on success field + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + out << indent() << "result.__isset.success = true;" << endl; + } + + indent_down(); + out << indent() << "}"; + + if (!tfunction->is_oneway()) { + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + out << " catch (" << type_name((*x_iter)->get_type()) << " &" << (*x_iter)->get_name() + << ") {" << endl; + if (!tfunction->is_oneway()) { + indent_up(); + out << indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() + << ";" << endl << indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" + << endl; + indent_down(); + out << indent() << "}"; + } else { + out << "}"; + } + } + } + + if (!tfunction->is_oneway()) { + out << " catch (const std::exception& e) {" << endl; + } else { + out << " catch (const std::exception&) {" << endl; + } + + indent_up(); + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->handlerError(ctx, " << service_func_name << ");" << endl + << indent() << "}" << endl; + + if (!tfunction->is_oneway()) { + out << endl << indent() << "::apache::thrift::TApplicationException x(e.what());" << endl + << indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() + << "\", ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl << indent() + << "x.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl + << indent() << "oprot->getTransport()->writeEnd();" << endl << indent() + << "oprot->getTransport()->flush();" << endl; + } + out << indent() << "return;" << endl; + indent_down(); + out << indent() << "}" << endl << endl; + + // Shortcut out here for oneway functions + if (tfunction->is_oneway()) { + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->asyncComplete(ctx, " << service_func_name << ");" << endl + << indent() << "}" << endl << endl << indent() << "return;" << endl; + indent_down(); + out << "}" << endl << endl; + return; + } + + // Serialize the result into a struct + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->preWrite(ctx, " << service_func_name << ");" << endl << indent() + << "}" << endl << endl << indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() + << "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl << indent() + << "result.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl + << indent() << "bytes = oprot->getTransport()->writeEnd();" << endl << indent() + << "oprot->getTransport()->flush();" << endl << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->postWrite(ctx, " << service_func_name << ", bytes);" << endl + << indent() << "}" << endl; + + // Close function + scope_down(out); + out << endl; + } + + // Cob style. + else { + // Processor entry point. + // TODO(edhall) update for callContext when TEventServer is ready + if (gen_templates_) { + out << indent() << "template " << endl; + } + out << "void " << tservice->get_name() << "AsyncProcessor" << class_suffix << "::process_" + << tfunction->get_name() << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << prot_type << "* iprot, " << prot_type << "* oprot)" << endl; + scope_up(out); + + // TODO(simpkins): we could try to consoldate this + // with the non-cob code above + if (gen_templates_ && !specialized) { + // If these are instances of Protocol_, instead of any old TProtocol, + // use the specialized process function instead. + out << indent() << "Protocol_* _iprot = dynamic_cast(iprot);" << endl << indent() + << "Protocol_* _oprot = dynamic_cast(oprot);" << endl << indent() + << "if (_iprot && _oprot) {" << endl << indent() << " return process_" + << tfunction->get_name() << "(cob, seqid, _iprot, _oprot);" << endl << indent() << "}" + << endl << indent() << "T_GENERIC_PROTOCOL(this, iprot, _iprot);" << endl << indent() + << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" << endl << endl; + } + + if (tfunction->is_oneway()) { + out << indent() << "(void) seqid;" << endl << indent() << "(void) oprot;" << endl; + } + + out << indent() << tservice->get_name() + "_" + tfunction->get_name() << "_args args;" << endl + << indent() << "void* ctx = NULL;" << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " ctx = this->eventHandler_->getContext(" << service_func_name << ", NULL);" << endl + << indent() << "}" << endl << indent() << "::apache::thrift::TProcessorContextFreer freer(" + << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl + << indent() << "try {" << endl; + indent_up(); + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->preRead(ctx, " << service_func_name << ");" << endl << indent() + << "}" << endl << indent() << "args.read(iprot);" << endl << indent() + << "iprot->readMessageEnd();" << endl << indent() + << "uint32_t bytes = iprot->getTransport()->readEnd();" << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->postRead(ctx, " << service_func_name << ", bytes);" << endl + << indent() << "}" << endl; + scope_down(out); + + // TODO(dreiss): Handle TExceptions? Expose to server? + out << indent() << "catch (const std::exception&) {" << endl << indent() + << " if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->handlerError(ctx, " << service_func_name << ");" << endl + << indent() << " }" << endl << indent() << " return cob(false);" << endl << indent() + << "}" << endl; + + if (tfunction->is_oneway()) { + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->asyncComplete(ctx, " << service_func_name << ");" << endl + << indent() << "}" << endl; + } + // TODO(dreiss): Figure out a strategy for exceptions in async handlers. + out << indent() << "freer.unregister();" << endl; + if (tfunction->is_oneway()) { + // No return. Just hand off our cob. + // TODO(dreiss): Call the cob immediately? + out << indent() << "iface_->" << tfunction->get_name() << "(" + << "::apache::thrift::stdcxx::bind(cob, true)" << endl; + indent_up(); + indent_up(); + } else { + string ret_arg, ret_placeholder; + if (!tfunction->get_returntype()->is_void()) { + ret_arg = ", const " + type_name(tfunction->get_returntype()) + "& _return"; + ret_placeholder = ", ::apache::thrift::stdcxx::placeholders::_1"; + } + + // When gen_templates_ is true, the return_ and throw_ functions are + // overloaded. We have to declare pointers to them so that the compiler + // can resolve the correct overloaded version. + out << indent() << "void (" << tservice->get_name() << "AsyncProcessor" << class_suffix + << "::*return_fn)(::apache::thrift::stdcxx::function " + << "cob, int32_t seqid, " << prot_type << "* oprot, void* ctx" << ret_arg + << ") =" << endl; + out << indent() << " &" << tservice->get_name() << "AsyncProcessor" << class_suffix + << "::return_" << tfunction->get_name() << ";" << endl; + if (!xceptions.empty()) { + out << indent() << "void (" << tservice->get_name() << "AsyncProcessor" << class_suffix + << "::*throw_fn)(::apache::thrift::stdcxx::function " + << "cob, int32_t seqid, " << prot_type << "* oprot, void* ctx, " + << "::apache::thrift::TDelayedException* _throw) =" << endl; + out << indent() << " &" << tservice->get_name() << "AsyncProcessor" << class_suffix + << "::throw_" << tfunction->get_name() << ";" << endl; + } + + out << indent() << "iface_->" << tfunction->get_name() << "(" << endl; + indent_up(); + indent_up(); + out << indent() << "::apache::thrift::stdcxx::bind(return_fn, this, cob, seqid, oprot, ctx" << ret_placeholder + << ")"; + if (!xceptions.empty()) { + out << ',' << endl << indent() << "::apache::thrift::stdcxx::bind(throw_fn, this, cob, seqid, oprot, " + << "ctx, ::apache::thrift::stdcxx::placeholders::_1)"; + } + } + + // XXX Whitespace cleanup. + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + out << ',' << endl << indent() << "args." << (*f_iter)->get_name(); + } + out << ");" << endl; + indent_down(); + indent_down(); + scope_down(out); + out << endl; + + // Normal return. + if (!tfunction->is_oneway()) { + string ret_arg_decl, ret_arg_name; + if (!tfunction->get_returntype()->is_void()) { + ret_arg_decl = ", const " + type_name(tfunction->get_returntype()) + "& _return"; + ret_arg_name = ", _return"; + } + if (gen_templates_) { + out << indent() << "template " << endl; + } + out << "void " << tservice->get_name() << "AsyncProcessor" << class_suffix << "::return_" + << tfunction->get_name() << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << prot_type << "* oprot, void* ctx" << ret_arg_decl << ')' << endl; + scope_up(out); + + if (gen_templates_ && !specialized) { + // If oprot is a Protocol_ instance, + // use the specialized return function instead. + out << indent() << "Protocol_* _oprot = dynamic_cast(oprot);" << endl + << indent() << "if (_oprot) {" << endl << indent() << " return return_" + << tfunction->get_name() << "(cob, seqid, _oprot, ctx" << ret_arg_name << ");" << endl + << indent() << "}" << endl << indent() << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" + << endl << endl; + } + + out << indent() << tservice->get_name() << "_" << tfunction->get_name() << "_presult result;" + << endl; + if (!tfunction->get_returntype()->is_void()) { + // The const_cast here is unfortunate, but it would be a pain to avoid, + // and we only do a write with this struct, which is const-safe. + out << indent() << "result.success = const_cast<" << type_name(tfunction->get_returntype()) + << "*>(&_return);" << endl << indent() << "result.__isset.success = true;" << endl; + } + // Serialize the result into a struct + out << endl << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " ctx = this->eventHandler_->getContext(" << service_func_name << ", NULL);" << endl + << indent() << "}" << endl << indent() + << "::apache::thrift::TProcessorContextFreer freer(" + << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl + << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->preWrite(ctx, " << service_func_name << ");" << endl + << indent() << "}" << endl << endl << indent() << "oprot->writeMessageBegin(\"" + << tfunction->get_name() << "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl + << indent() << "result.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" + << endl << indent() << "uint32_t bytes = oprot->getTransport()->writeEnd();" << endl + << indent() << "oprot->getTransport()->flush();" << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->postWrite(ctx, " << service_func_name << ", bytes);" << endl + << indent() << "}" << endl << indent() << "return cob(true);" << endl; + scope_down(out); + out << endl; + } + + // Exception return. + if (!tfunction->is_oneway() && !xceptions.empty()) { + if (gen_templates_) { + out << indent() << "template " << endl; + } + out << "void " << tservice->get_name() << "AsyncProcessor" << class_suffix << "::throw_" + << tfunction->get_name() << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << prot_type << "* oprot, void* ctx, " + << "::apache::thrift::TDelayedException* _throw)" << endl; + scope_up(out); + + if (gen_templates_ && !specialized) { + // If oprot is a Protocol_ instance, + // use the specialized throw function instead. + out << indent() << "Protocol_* _oprot = dynamic_cast(oprot);" << endl + << indent() << "if (_oprot) {" << endl << indent() << " return throw_" + << tfunction->get_name() << "(cob, seqid, _oprot, ctx, _throw);" << endl << indent() + << "}" << endl << indent() << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" << endl + << endl; + } + + // Get the event handler context + out << endl << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " ctx = this->eventHandler_->getContext(" << service_func_name << ", NULL);" << endl + << indent() << "}" << endl << indent() + << "::apache::thrift::TProcessorContextFreer freer(" + << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl; + + // Throw the TDelayedException, and catch the result + out << indent() << tservice->get_name() << "_" << tfunction->get_name() << "_result result;" + << endl << endl << indent() << "try {" << endl; + indent_up(); + out << indent() << "_throw->throw_it();" << endl << indent() << "return cob(false);" + << endl; // Is this possible? TBD. + indent_down(); + out << indent() << '}'; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + out << " catch (" << type_name((*x_iter)->get_type()) << " &" << (*x_iter)->get_name() + << ") {" << endl; + indent_up(); + out << indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() + << ";" << endl << indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" + << endl; + scope_down(out); + } + + // Handle the case where an undeclared exception is thrown + out << " catch (std::exception& e) {" << endl; + indent_up(); + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->handlerError(ctx, " << service_func_name << ");" << endl + << indent() << "}" << endl << endl << indent() + << "::apache::thrift::TApplicationException x(e.what());" << endl << indent() + << "oprot->writeMessageBegin(\"" << tfunction->get_name() + << "\", ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl << indent() + << "x.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl + << indent() << "oprot->getTransport()->writeEnd();" << endl << indent() + << "oprot->getTransport()->flush();" << endl << + // We pass true to the cob here, since we did successfully write a + // response, even though it is an exception response. + // It looks like the argument is currently ignored, anyway. + indent() << "return cob(true);" << endl; + scope_down(out); + + // Serialize the result into a struct + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->preWrite(ctx, " << service_func_name << ");" << endl + << indent() << "}" << endl << endl << indent() << "oprot->writeMessageBegin(\"" + << tfunction->get_name() << "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl + << indent() << "result.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" + << endl << indent() << "uint32_t bytes = oprot->getTransport()->writeEnd();" << endl + << indent() << "oprot->getTransport()->flush();" << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->postWrite(ctx, " << service_func_name << ", bytes);" << endl + << indent() << "}" << endl << indent() << "return cob(true);" << endl; + scope_down(out); + out << endl; + } // for each function + } // cob style +} + +/** + * Generates a skeleton file of a server + * + * @param tservice The service to generate a server for. + */ +void t_cpp_generator::generate_service_skeleton(t_service* tservice) { + string svcname = tservice->get_name(); + + // Service implementation file includes + string f_skeleton_name = get_out_dir() + svcname + "_server.skeleton.cpp"; + + string ns = namespace_prefix(tservice->get_program()->get_namespace("cpp")); + + ofstream f_skeleton; + f_skeleton.open(f_skeleton_name.c_str()); + f_skeleton << "// This autogenerated skeleton file illustrates how to build a server." << endl + << "// You should copy it to another filename to avoid overwriting it." << endl << endl + << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl + << "#include " << endl + << "#include " << endl + << "#include " << endl + << "#include " << endl << endl + << "using namespace ::apache::thrift;" << endl + << "using namespace ::apache::thrift::protocol;" << endl + << "using namespace ::apache::thrift::transport;" << endl + << "using namespace ::apache::thrift::server;" << endl << endl; + + // the following code would not compile: + // using namespace ; + // using namespace ::; + if ((!ns.empty()) && (ns.compare(" ::") != 0)) { + f_skeleton << "using namespace " << string(ns, 0, ns.size() - 2) << ";" << endl << endl; + } + + f_skeleton << "class " << svcname << "Handler : virtual public " << svcname << "If {" << endl + << " public:" << endl; + indent_up(); + f_skeleton << indent() << svcname << "Handler() {" << endl << indent() + << " // Your initialization goes here" << endl << indent() << "}" << endl << endl; + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_java_doc(f_skeleton, *f_iter); + f_skeleton << indent() << function_signature(*f_iter, "") << " {" << endl << indent() + << " // Your implementation goes here" << endl << indent() << " printf(\"" + << (*f_iter)->get_name() << "\\n\");" << endl << indent() << "}" << endl << endl; + } + + indent_down(); + f_skeleton << "};" << endl << endl; + + f_skeleton << indent() << "int main(int argc, char **argv) {" << endl; + indent_up(); + f_skeleton + << indent() << "int port = 9090;" << endl << indent() << "::apache::thrift::stdcxx::shared_ptr<" << svcname + << "Handler> handler(new " << svcname << "Handler());" << endl << indent() + << "::apache::thrift::stdcxx::shared_ptr processor(new " << svcname << "Processor(handler));" << endl + << indent() << "::apache::thrift::stdcxx::shared_ptr serverTransport(new TServerSocket(port));" + << endl << indent() + << "::apache::thrift::stdcxx::shared_ptr transportFactory(new TBufferedTransportFactory());" << endl + << indent() << "::apache::thrift::stdcxx::shared_ptr protocolFactory(new TBinaryProtocolFactory());" + << endl << endl << indent() + << "TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);" + << endl << indent() << "server.serve();" << endl << indent() << "return 0;" << endl; + indent_down(); + f_skeleton << "}" << endl << endl; + + // Close the files + f_skeleton.close(); +} + +/** + * Deserializes a field of any type. + */ +void t_cpp_generator::generate_deserialize_field(ofstream& out, + t_field* tfield, + string prefix, + string suffix) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = prefix + tfield->get_name() + suffix; + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name, is_reference(tfield)); + } else if (type->is_container()) { + generate_deserialize_container(out, type, name); + } else if (type->is_base_type()) { + indent(out) << "xfer += iprot->"; + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "readBinary(" << name << ");"; + } else { + out << "readString(" << name << ");"; + } + break; + case t_base_type::TYPE_BOOL: + out << "readBool(" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "readByte(" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "readI16(" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "readI32(" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "readI64(" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble(" << name << ");"; + break; + default: + throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + name; + } + out << endl; + } else if (type->is_enum()) { + string t = tmp("ecast"); + out << indent() << "int32_t " << t << ";" << endl << indent() << "xfer += iprot->readI32(" << t + << ");" << endl << indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl; + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +/** + * Generates an unserializer for a variable. This makes two key assumptions, + * first that there is a const char* variable named data that points to the + * buffer for deserialization, and that there is a variable protocol which + * is a reference to a TProtocol serialization object. + */ +void t_cpp_generator::generate_deserialize_struct(ofstream& out, + t_struct* tstruct, + string prefix, + bool pointer) { + if (pointer) { + indent(out) << "if (!" << prefix << ") { " << endl; + indent(out) << " " << prefix << " = ::apache::thrift::stdcxx::shared_ptr<" << type_name(tstruct) << ">(new " + << type_name(tstruct) << ");" << endl; + indent(out) << "}" << endl; + indent(out) << "xfer += " << prefix << "->read(iprot);" << endl; + indent(out) << "bool wasSet = false;" << endl; + const vector& members = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) { + + indent(out) << "if (" << prefix << "->__isset." << (*f_iter)->get_name() + << ") { wasSet = true; }" << endl; + } + indent(out) << "if (!wasSet) { " << prefix << ".reset(); }" << endl; + } else { + indent(out) << "xfer += " << prefix << ".read(iprot);" << endl; + } +} + +void t_cpp_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) { + scope_up(out); + + string size = tmp("_size"); + string ktype = tmp("_ktype"); + string vtype = tmp("_vtype"); + string etype = tmp("_etype"); + + t_container* tcontainer = (t_container*)ttype; + bool use_push = tcontainer->has_cpp_name(); + + indent(out) << prefix << ".clear();" << endl << indent() << "uint32_t " << size << ";" << endl; + + // Declare variables, read header + if (ttype->is_map()) { + out << indent() << "::apache::thrift::protocol::TType " << ktype << ";" << endl << indent() + << "::apache::thrift::protocol::TType " << vtype << ";" << endl << indent() + << "xfer += iprot->readMapBegin(" << ktype << ", " << vtype << ", " << size << ");" << endl; + } else if (ttype->is_set()) { + out << indent() << "::apache::thrift::protocol::TType " << etype << ";" << endl << indent() + << "xfer += iprot->readSetBegin(" << etype << ", " << size << ");" << endl; + } else if (ttype->is_list()) { + out << indent() << "::apache::thrift::protocol::TType " << etype << ";" << endl << indent() + << "xfer += iprot->readListBegin(" << etype << ", " << size << ");" << endl; + if (!use_push) { + indent(out) << prefix << ".resize(" << size << ");" << endl; + } + } + + // For loop iterates over elements + string i = tmp("_i"); + out << indent() << "uint32_t " << i << ";" << endl << indent() << "for (" << i << " = 0; " << i + << " < " << size << "; ++" << i << ")" << endl; + + scope_up(out); + + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, prefix); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, prefix); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, prefix, use_push, i); + } + + scope_down(out); + + // Read container end + if (ttype->is_map()) { + indent(out) << "xfer += iprot->readMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "xfer += iprot->readSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "xfer += iprot->readListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Generates code to deserialize a map + */ +void t_cpp_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) { + string key = tmp("_key"); + string val = tmp("_val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + out << indent() << declare_field(&fkey) << endl; + + generate_deserialize_field(out, &fkey); + indent(out) << declare_field(&fval, false, false, false, true) << " = " << prefix << "[" << key + << "];" << endl; + + generate_deserialize_field(out, &fval); +} + +void t_cpp_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) { + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); + + indent(out) << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".insert(" << elem << ");" << endl; +} + +void t_cpp_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix, + bool use_push, + string index) { + if (use_push) { + string elem = tmp("_elem"); + t_field felem(tlist->get_elem_type(), elem); + indent(out) << declare_field(&felem) << endl; + generate_deserialize_field(out, &felem); + indent(out) << prefix << ".push_back(" << elem << ");" << endl; + } else { + t_field felem(tlist->get_elem_type(), prefix + "[" + index + "]"); + generate_deserialize_field(out, &felem); + } +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_cpp_generator::generate_serialize_field(ofstream& out, + t_field* tfield, + string prefix, + string suffix) { + t_type* type = get_true_type(tfield->get_type()); + + string name = prefix + tfield->get_name() + suffix; + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name; + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, name, is_reference(tfield)); + } else if (type->is_container()) { + generate_serialize_container(out, type, name); + } else if (type->is_base_type() || type->is_enum()) { + + indent(out) << "xfer += oprot->"; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "writeBinary(" << name << ");"; + } else { + out << "writeString(" << name << ");"; + } + break; + case t_base_type::TYPE_BOOL: + out << "writeBool(" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "writeByte(" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "writeI16(" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "writeI32(" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "writeI64(" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble(" << name << ");"; + break; + default: + throw "compiler error: no C++ writer for base type " + t_base_type::t_base_name(tbase) + + name; + } + } else if (type->is_enum()) { + out << "writeI32((int32_t)" << name << ");"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n", + name.c_str(), + type_name(type).c_str()); + } +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_cpp_generator::generate_serialize_struct(ofstream& out, + t_struct* tstruct, + string prefix, + bool pointer) { + if (pointer) { + indent(out) << "if (" << prefix << ") {" << endl; + indent(out) << " xfer += " << prefix << "->write(oprot); " << endl; + indent(out) << "} else {" + << "oprot->writeStructBegin(\"" << tstruct->get_name() << "\"); " << endl; + indent(out) << " oprot->writeStructEnd();" << endl; + indent(out) << " oprot->writeFieldStop();" << endl; + indent(out) << "}" << endl; + } else { + indent(out) << "xfer += " << prefix << ".write(oprot);" << endl; + } +} + +void t_cpp_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + scope_up(out); + + if (ttype->is_map()) { + indent(out) << "xfer += oprot->writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) + << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " + << "static_cast(" << prefix << ".size()));" << endl; + } else if (ttype->is_set()) { + indent(out) << "xfer += oprot->writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) + << ", " + << "static_cast(" << prefix << ".size()));" << endl; + } else if (ttype->is_list()) { + indent(out) << "xfer += oprot->writeListBegin(" + << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " + << "static_cast(" << prefix << ".size()));" << endl; + } + + string iter = tmp("_iter"); + out << indent() << type_name(ttype) << "::const_iterator " << iter << ";" << endl << indent() + << "for (" << iter << " = " << prefix << ".begin(); " << iter << " != " << prefix + << ".end(); ++" << iter << ")" << endl; + scope_up(out); + if (ttype->is_map()) { + generate_serialize_map_element(out, (t_map*)ttype, iter); + } else if (ttype->is_set()) { + generate_serialize_set_element(out, (t_set*)ttype, iter); + } else if (ttype->is_list()) { + generate_serialize_list_element(out, (t_list*)ttype, iter); + } + scope_down(out); + + if (ttype->is_map()) { + indent(out) << "xfer += oprot->writeMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "xfer += oprot->writeSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "xfer += oprot->writeListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Serializes the members of a map. + * + */ +void t_cpp_generator::generate_serialize_map_element(ofstream& out, t_map* tmap, string iter) { + t_field kfield(tmap->get_key_type(), iter + "->first"); + generate_serialize_field(out, &kfield, ""); + + t_field vfield(tmap->get_val_type(), iter + "->second"); + generate_serialize_field(out, &vfield, ""); +} + +/** + * Serializes the members of a set. + */ +void t_cpp_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) { + t_field efield(tset->get_elem_type(), "(*" + iter + ")"); + generate_serialize_field(out, &efield, ""); +} + +/** + * Serializes the members of a list. + */ +void t_cpp_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) { + t_field efield(tlist->get_elem_type(), "(*" + iter + ")"); + generate_serialize_field(out, &efield, ""); +} + +/** + * Makes a :: prefix for a namespace + * + * @param ns The namespace, w/ periods in it + * @return Namespaces + */ +string t_cpp_generator::namespace_prefix(string ns) { + // Always start with "::", to avoid possible name collisions with + // other names in one of the current namespaces. + // + // We also need a leading space, in case the name is used inside of a + // template parameter. "MyTemplate<::foo::Bar>" is not valid C++, + // since "<:" is an alternative token for "[". + string result = " ::"; + + if (ns.size() == 0) { + return result; + } + string::size_type loc; + while ((loc = ns.find(".")) != string::npos) { + result += ns.substr(0, loc); + result += "::"; + ns = ns.substr(loc + 1); + } + if (ns.size() > 0) { + result += ns + "::"; + } + return result; +} + +/** + * Opens namespace. + * + * @param ns The namespace, w/ periods in it + * @return Namespaces + */ +string t_cpp_generator::namespace_open(string ns) { + if (ns.size() == 0) { + return ""; + } + string result = ""; + string separator = ""; + string::size_type loc; + while ((loc = ns.find(".")) != string::npos) { + result += separator; + result += "namespace "; + result += ns.substr(0, loc); + result += " {"; + separator = " "; + ns = ns.substr(loc + 1); + } + if (ns.size() > 0) { + result += separator + "namespace " + ns + " {"; + } + return result; +} + +/** + * Closes namespace. + * + * @param ns The namespace, w/ periods in it + * @return Namespaces + */ +string t_cpp_generator::namespace_close(string ns) { + if (ns.size() == 0) { + return ""; + } + string result = "}"; + string::size_type loc; + while ((loc = ns.find(".")) != string::npos) { + result += "}"; + ns = ns.substr(loc + 1); + } + result += " // namespace"; + return result; +} + +/** + * Returns a C++ type name + * + * @param ttype The type + * @return String of the type name, i.e. std::set + */ +string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) { + if (ttype->is_base_type()) { + string bname = base_type_name(((t_base_type*)ttype)->get_base()); + std::map::iterator it = ttype->annotations_.find("cpp.type"); + if (it != ttype->annotations_.end()) { + bname = it->second; + } + + if (!arg) { + return bname; + } + + if (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING) { + return "const " + bname + "&"; + } else { + return "const " + bname; + } + } + + // Check for a custom overloaded C++ name + if (ttype->is_container()) { + string cname; + + t_container* tcontainer = (t_container*)ttype; + if (tcontainer->has_cpp_name()) { + cname = tcontainer->get_cpp_name(); + } else if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + cname = "std::map<" + type_name(tmap->get_key_type(), in_typedef) + ", " + + type_name(tmap->get_val_type(), in_typedef) + "> "; + } else if (ttype->is_set()) { + t_set* tset = (t_set*)ttype; + cname = "std::set<" + type_name(tset->get_elem_type(), in_typedef) + "> "; + } else if (ttype->is_list()) { + t_list* tlist = (t_list*)ttype; + cname = "std::vector<" + type_name(tlist->get_elem_type(), in_typedef) + "> "; + } + + if (arg) { + return "const " + cname + "&"; + } else { + return cname; + } + } + + string class_prefix; + if (in_typedef && (ttype->is_struct() || ttype->is_xception())) { + class_prefix = "class "; + } + + // Check if it needs to be namespaced + string pname; + t_program* program = ttype->get_program(); + if (program != NULL && program != program_) { + pname = class_prefix + namespace_prefix(program->get_namespace("cpp")) + ttype->get_name(); + } else { + pname = class_prefix + ttype->get_name(); + } + + if (ttype->is_enum() && !gen_pure_enums_) { + pname += "::type"; + } + + if (arg) { + if (is_complex_type(ttype)) { + return "const " + pname + "&"; + } else { + return "const " + pname; + } + } else { + return pname; + } +} + +/** + * Returns the C++ type that corresponds to the thrift type. + * + * @param tbase The base type + * @return Explicit C++ type, i.e. "int32_t" + */ +string t_cpp_generator::base_type_name(t_base_type::t_base tbase) { + switch (tbase) { + case t_base_type::TYPE_VOID: + return "void"; + case t_base_type::TYPE_STRING: + return "std::string"; + case t_base_type::TYPE_BOOL: + return "bool"; + case t_base_type::TYPE_I8: + return "int8_t"; + case t_base_type::TYPE_I16: + return "int16_t"; + case t_base_type::TYPE_I32: + return "int32_t"; + case t_base_type::TYPE_I64: + return "int64_t"; + case t_base_type::TYPE_DOUBLE: + return "double"; + default: + throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase); + } +} + +/** + * Declares a field, which may include initialization as necessary. + * + * @param ttype The type + * @return Field declaration, i.e. int x = 0; + */ +string t_cpp_generator::declare_field(t_field* tfield, + bool init, + bool pointer, + bool constant, + bool reference) { + // TODO(mcslee): do we ever need to initialize the field? + string result = ""; + if (constant) { + result += "const "; + } + result += type_name(tfield->get_type()); + if (is_reference(tfield)) { + result = "::apache::thrift::stdcxx::shared_ptr<" + result + ">"; + } + if (pointer) { + result += "*"; + } + if (reference) { + result += "&"; + } + result += " " + tfield->get_name(); + if (init) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + case t_base_type::TYPE_STRING: + break; + case t_base_type::TYPE_BOOL: + result += " = false"; + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + result += " = 0"; + break; + case t_base_type::TYPE_DOUBLE: + result += " = (double)0"; + break; + default: + throw "compiler error: no C++ initializer for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + result += " = (" + type_name(type) + ")0"; + } + } + if (!reference) { + result += ";"; + } + return result; +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_cpp_generator::function_signature(t_function* tfunction, + string style, + string prefix, + bool name_params) { + t_type* ttype = tfunction->get_returntype(); + t_struct* arglist = tfunction->get_arglist(); + bool has_xceptions = !tfunction->get_xceptions()->get_members().empty(); + + if (style == "") { + if (is_complex_type(ttype)) { + return "void " + prefix + tfunction->get_name() + "(" + type_name(ttype) + + (name_params ? "& _return" : "& /* _return */") + + argument_list(arglist, name_params, true) + ")"; + } else { + return type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + + argument_list(arglist, name_params) + ")"; + } + } else if (style.substr(0, 3) == "Cob") { + string cob_type; + string exn_cob; + if (style == "CobCl") { + cob_type = "(" + service_name_ + "CobClient"; + if (gen_templates_) { + cob_type += "T"; + } + cob_type += "* client)"; + } else if (style == "CobSv") { + cob_type = (ttype->is_void() ? "()" : ("(" + type_name(ttype) + " const& _return)")); + if (has_xceptions) { + exn_cob + = ", ::apache::thrift::stdcxx::function /* exn_cob */"; + } + } else { + throw "UNKNOWN STYLE"; + } + + return "void " + prefix + tfunction->get_name() + "(::apache::thrift::stdcxx::function cob" + + exn_cob + argument_list(arglist, name_params, true) + ")"; + } else { + throw "UNKNOWN STYLE"; + } +} + +/** + * Renders a field list + * + * @param tstruct The struct definition + * @return Comma sepearated list of all field names in that struct + */ +string t_cpp_generator::argument_list(t_struct* tstruct, bool name_params, bool start_comma) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = !start_comma; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + result += type_name((*f_iter)->get_type(), false, true) + " " + + (name_params ? (*f_iter)->get_name() : "/* " + (*f_iter)->get_name() + " */"); + } + return result; +} + +/** + * Converts the parse type to a C++ enum string for the given type. + * + * @param type Thrift Type + * @return String of C++ code to definition of that type constant + */ +string t_cpp_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "::apache::thrift::protocol::T_STRING"; + case t_base_type::TYPE_BOOL: + return "::apache::thrift::protocol::T_BOOL"; + case t_base_type::TYPE_I8: + return "::apache::thrift::protocol::T_BYTE"; + case t_base_type::TYPE_I16: + return "::apache::thrift::protocol::T_I16"; + case t_base_type::TYPE_I32: + return "::apache::thrift::protocol::T_I32"; + case t_base_type::TYPE_I64: + return "::apache::thrift::protocol::T_I64"; + case t_base_type::TYPE_DOUBLE: + return "::apache::thrift::protocol::T_DOUBLE"; + } + } else if (type->is_enum()) { + return "::apache::thrift::protocol::T_I32"; + } else if (type->is_struct()) { + return "::apache::thrift::protocol::T_STRUCT"; + } else if (type->is_xception()) { + return "::apache::thrift::protocol::T_STRUCT"; + } else if (type->is_map()) { + return "::apache::thrift::protocol::T_MAP"; + } else if (type->is_set()) { + return "::apache::thrift::protocol::T_SET"; + } else if (type->is_list()) { + return "::apache::thrift::protocol::T_LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +string t_cpp_generator::get_include_prefix(const t_program& program) const { + string include_prefix = program.get_include_prefix(); + if (!use_include_prefix_ || (include_prefix.size() > 0 && include_prefix[0] == '/')) { + // if flag is turned off or this is absolute path, return empty prefix + return ""; + } + + string::size_type last_slash = string::npos; + if ((last_slash = include_prefix.rfind("/")) != string::npos) { + return include_prefix.substr(0, last_slash) + + (get_program()->is_out_path_absolute() ? "/" : "/" + out_dir_base_ + "/"); + } + + return ""; +} + +THRIFT_REGISTER_GENERATOR( + cpp, + "C++", + " cob_style: Generate \"Continuation OBject\"-style classes.\n" + " no_client_completion:\n" + " Omit calls to completion__() in CobClient class.\n" + " no_default_operators:\n" + " Omits generation of default operators ==, != and <\n" + " templates: Generate templatized reader/writer methods.\n" + " pure_enums: Generate pure enums instead of wrapper classes.\n" + " include_prefix: Use full include paths in generated files.\n" + " moveable_types: Generate move constructors and assignment operators.\n" + " no_ostream_operators:\n" + " Omit generation of ostream definitions.\n" + " no_skeleton: Omits generation of skeleton.\n") diff --git a/compiler/cpp/src/thrift/generate/t_csharp_generator.cc b/compiler/cpp/src/thrift/generate/t_csharp_generator.cc new file mode 100644 index 0000000..a6cb09d --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_csharp_generator.cc @@ -0,0 +1,3224 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +struct member_mapping_scope { + void* scope_member; + std::map mapping_table; +}; + +class t_csharp_generator : public t_oop_generator { +public: + t_csharp_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + + std::map::const_iterator iter; + + async_ = false; + nullable_ = false; + hashcode_ = false; + union_ = false; + serialize_ = false; + wcf_ = false; + wcf_namespace_.clear(); + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("async") == 0) { + async_ = true; + } else if( iter->first.compare("nullable") == 0) { + nullable_ = true; + } else if( iter->first.compare("hashcode") == 0) { + hashcode_ = true; + } else if( iter->first.compare("union") == 0) { + union_ = true; + } else if( iter->first.compare("serial") == 0) { + serialize_ = true; + wcf_namespace_ = iter->second; // since there can be only one namespace + } else if( iter->first.compare("wcf") == 0) { + wcf_ = true; + wcf_namespace_ = iter->second; + } else { + throw "unknown option csharp:" + iter->first; + } + } + + out_dir_base_ = "gen-csharp"; + } + void init_generator(); + void close_generator(); + + void generate_consts(std::vector consts); + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_struct(t_struct* tstruct); + void generate_union(t_struct* tunion); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + void generate_property(ofstream& out, t_field* tfield, bool isPublic, bool generateIsset); + void generate_csharp_property(ofstream& out, + t_field* tfield, + bool isPublic, + bool includeIsset = true, + std::string fieldPrefix = ""); + bool print_const_value(std::ofstream& out, + std::string name, + t_type* type, + t_const_value* value, + bool in_static, + bool defval = false, + bool needtype = false); + std::string render_const_value(std::ofstream& out, + std::string name, + t_type* type, + t_const_value* value); + void print_const_constructor(std::ofstream& out, std::vector consts); + void print_const_def_value(std::ofstream& out, + std::string name, + t_type* type, + t_const_value* value); + + void generate_csharp_struct(t_struct* tstruct, bool is_exception); + void generate_csharp_union(t_struct* tunion); + void generate_csharp_struct_definition(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false, + bool in_class = false, + bool is_result = false); + void generate_csharp_union_definition(std::ofstream& out, t_struct* tunion); + void generate_csharp_union_class(std::ofstream& out, t_struct* tunion, t_field* tfield); + void generate_csharp_wcffault(std::ofstream& out, t_struct* tstruct); + void generate_csharp_struct_reader(std::ofstream& out, t_struct* tstruct); + void generate_csharp_struct_result_writer(std::ofstream& out, t_struct* tstruct); + void generate_csharp_struct_writer(std::ofstream& out, t_struct* tstruct); + void generate_csharp_struct_tostring(std::ofstream& out, t_struct* tstruct); + void generate_csharp_struct_equals(std::ofstream& out, t_struct* tstruct); + void generate_csharp_struct_hashcode(std::ofstream& out, t_struct* tstruct); + void generate_csharp_union_reader(std::ofstream& out, t_struct* tunion); + + void generate_function_helpers(t_function* tfunction); + void generate_service_interface(t_service* tservice); + void generate_separate_service_interfaces(t_service* tservice); + void generate_sync_service_interface(t_service* tservice); + void generate_async_service_interface(t_service* tservice); + void generate_combined_service_interface(t_service* tservice); + void generate_silverlight_async_methods(t_service* tservice); + void generate_service_helpers(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_service_server_sync(t_service* tservice); + void generate_service_server_async(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* function); + void generate_process_function_async(t_service* tservice, t_function* function); + + void generate_deserialize_field(std::ofstream& out, + t_field* tfield, + std::string prefix = "", + bool is_propertyless = false); + void generate_deserialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + void generate_deserialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + void generate_deserialize_set_element(std::ofstream& out, t_set* tset, std::string prefix = ""); + void generate_deserialize_map_element(std::ofstream& out, t_map* tmap, std::string prefix = ""); + void generate_deserialize_list_element(std::ofstream& out, t_list* list, std::string prefix = ""); + void generate_serialize_field(std::ofstream& out, + t_field* tfield, + std::string prefix = "", + bool is_element = false, + bool is_propertyless = false); + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string iter, + std::string map); + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + + void generate_csharp_doc(std::ofstream& out, t_field* field); + void generate_csharp_doc(std::ofstream& out, t_doc* tdoc); + void generate_csharp_doc(std::ofstream& out, t_function* tdoc); + void generate_csharp_docstring_comment(std::ofstream& out, string contents); + + void start_csharp_namespace(std::ofstream& out); + void end_csharp_namespace(std::ofstream& out); + + std::string csharp_type_usings(); + std::string csharp_thrift_usings(); + + std::string type_name(t_type* ttype, + bool in_countainer = false, + bool in_init = false, + bool in_param = false, + bool is_required = false); + std::string base_type_name(t_base_type* tbase, + bool in_container = false, + bool in_param = false, + bool is_required = false); + std::string declare_field(t_field* tfield, bool init = false, std::string prefix = ""); + std::string function_signature_async_begin(t_function* tfunction, std::string prefix = ""); + std::string function_signature_async_end(t_function* tfunction, std::string prefix = ""); + std::string function_signature_async(t_function* tfunction, std::string prefix = ""); + std::string function_signature(t_function* tfunction, std::string prefix = ""); + std::string argument_list(t_struct* tstruct); + std::string type_to_enum(t_type* ttype); + std::string prop_name(t_field* tfield, bool suppress_mapping = false); + std::string get_enum_class_name(t_type* type); + + bool field_has_default(t_field* tfield) { return tfield->get_value() != NULL; } + + bool field_is_required(t_field* tfield) { return tfield->get_req() == t_field::T_REQUIRED; } + + bool type_can_be_null(t_type* ttype) { + while (ttype->is_typedef()) { + ttype = ((t_typedef*)ttype)->get_type(); + } + + return ttype->is_container() || ttype->is_struct() || ttype->is_xception() + || ttype->is_string(); + } + +private: + std::string namespace_name_; + std::ofstream f_service_; + std::string namespace_dir_; + bool async_; + bool nullable_; + bool union_; + bool hashcode_; + bool serialize_; + bool wcf_; + std::string wcf_namespace_; + + std::map csharp_keywords; + std::vector member_mapping_scopes; + + void init_keywords(); + std::string normalize_name(std::string name); + std::string make_valid_csharp_identifier(std::string const& fromName); + void prepare_member_name_mapping(t_struct* tstruct); + void prepare_member_name_mapping(void* scope, + const vector& members, + const string& structname); + void cleanup_member_name_mapping(void* scope); + string get_mapped_member_name(string oldname); +}; + +void t_csharp_generator::init_generator() { + MKDIR(get_out_dir().c_str()); + namespace_name_ = program_->get_namespace("csharp"); + + string dir = namespace_name_; + string subdir = get_out_dir().c_str(); + string::size_type loc; + + while ((loc = dir.find(".")) != string::npos) { + subdir = subdir + "/" + dir.substr(0, loc); + MKDIR(subdir.c_str()); + dir = dir.substr(loc + 1); + } + if (dir.size() > 0) { + subdir = subdir + "/" + dir; + MKDIR(subdir.c_str()); + } + + namespace_dir_ = subdir; + init_keywords(); + + while( ! member_mapping_scopes.empty()) { + cleanup_member_name_mapping( member_mapping_scopes.back().scope_member); + } + + pverbose("C# options:\n"); + pverbose("- async ...... %s\n", (async_ ? "ON" : "off")); + pverbose("- nullable ... %s\n", (nullable_ ? "ON" : "off")); + pverbose("- union ...... %s\n", (union_ ? "ON" : "off")); + pverbose("- hashcode ... %s\n", (hashcode_ ? "ON" : "off")); + pverbose("- serialize .. %s\n", (serialize_ ? "ON" : "off")); + pverbose("- wcf ........ %s\n", (wcf_ ? "ON" : "off")); +} + +std::string t_csharp_generator::normalize_name(std::string name) { + string tmp(name); + std::transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast(std::tolower)); + + // un-conflict keywords by prefixing with "@" + if (csharp_keywords.find(tmp) != csharp_keywords.end()) { + return "@" + name; + } + + // no changes necessary + return name; +} + +void t_csharp_generator::init_keywords() { + csharp_keywords.clear(); + + // C# keywords + csharp_keywords["abstract"] = 1; + csharp_keywords["as"] = 1; + csharp_keywords["base"] = 1; + csharp_keywords["bool"] = 1; + csharp_keywords["break"] = 1; + csharp_keywords["byte"] = 1; + csharp_keywords["case"] = 1; + csharp_keywords["catch"] = 1; + csharp_keywords["char"] = 1; + csharp_keywords["checked"] = 1; + csharp_keywords["class"] = 1; + csharp_keywords["const"] = 1; + csharp_keywords["continue"] = 1; + csharp_keywords["decimal"] = 1; + csharp_keywords["default"] = 1; + csharp_keywords["delegate"] = 1; + csharp_keywords["do"] = 1; + csharp_keywords["double"] = 1; + csharp_keywords["else"] = 1; + csharp_keywords["enum"] = 1; + csharp_keywords["event"] = 1; + csharp_keywords["explicit"] = 1; + csharp_keywords["extern"] = 1; + csharp_keywords["false"] = 1; + csharp_keywords["finally"] = 1; + csharp_keywords["fixed"] = 1; + csharp_keywords["float"] = 1; + csharp_keywords["for"] = 1; + csharp_keywords["foreach"] = 1; + csharp_keywords["goto"] = 1; + csharp_keywords["if"] = 1; + csharp_keywords["implicit"] = 1; + csharp_keywords["in"] = 1; + csharp_keywords["int"] = 1; + csharp_keywords["interface"] = 1; + csharp_keywords["internal"] = 1; + csharp_keywords["is"] = 1; + csharp_keywords["lock"] = 1; + csharp_keywords["long"] = 1; + csharp_keywords["namespace"] = 1; + csharp_keywords["new"] = 1; + csharp_keywords["null"] = 1; + csharp_keywords["object"] = 1; + csharp_keywords["operator"] = 1; + csharp_keywords["out"] = 1; + csharp_keywords["override"] = 1; + csharp_keywords["params"] = 1; + csharp_keywords["private"] = 1; + csharp_keywords["protected"] = 1; + csharp_keywords["public"] = 1; + csharp_keywords["readonly"] = 1; + csharp_keywords["ref"] = 1; + csharp_keywords["return"] = 1; + csharp_keywords["sbyte"] = 1; + csharp_keywords["sealed"] = 1; + csharp_keywords["short"] = 1; + csharp_keywords["sizeof"] = 1; + csharp_keywords["stackalloc"] = 1; + csharp_keywords["static"] = 1; + csharp_keywords["string"] = 1; + csharp_keywords["struct"] = 1; + csharp_keywords["switch"] = 1; + csharp_keywords["this"] = 1; + csharp_keywords["throw"] = 1; + csharp_keywords["true"] = 1; + csharp_keywords["try"] = 1; + csharp_keywords["typeof"] = 1; + csharp_keywords["uint"] = 1; + csharp_keywords["ulong"] = 1; + csharp_keywords["unchecked"] = 1; + csharp_keywords["unsafe"] = 1; + csharp_keywords["ushort"] = 1; + csharp_keywords["using"] = 1; + csharp_keywords["virtual"] = 1; + csharp_keywords["void"] = 1; + csharp_keywords["volatile"] = 1; + csharp_keywords["while"] = 1; + + // C# contextual keywords + csharp_keywords["add"] = 1; + csharp_keywords["alias"] = 1; + csharp_keywords["ascending"] = 1; + csharp_keywords["async"] = 1; + csharp_keywords["await"] = 1; + csharp_keywords["descending"] = 1; + csharp_keywords["dynamic"] = 1; + csharp_keywords["from"] = 1; + csharp_keywords["get"] = 1; + csharp_keywords["global"] = 1; + csharp_keywords["group"] = 1; + csharp_keywords["into"] = 1; + csharp_keywords["join"] = 1; + csharp_keywords["let"] = 1; + csharp_keywords["orderby"] = 1; + csharp_keywords["partial"] = 1; + csharp_keywords["remove"] = 1; + csharp_keywords["select"] = 1; + csharp_keywords["set"] = 1; + csharp_keywords["value"] = 1; + csharp_keywords["var"] = 1; + csharp_keywords["where"] = 1; + csharp_keywords["yield"] = 1; +} + +void t_csharp_generator::start_csharp_namespace(ofstream& out) { + if (!namespace_name_.empty()) { + out << "namespace " << namespace_name_ << "\n"; + scope_up(out); + } +} + +void t_csharp_generator::end_csharp_namespace(ofstream& out) { + if (!namespace_name_.empty()) { + scope_down(out); + } +} + +string t_csharp_generator::csharp_type_usings() { + return string() + "using System;\n" + "using System.Collections;\n" + + "using System.Collections.Generic;\n" + "using System.Text;\n" + "using System.IO;\n" + + ((async_) ? "using System.Threading.Tasks;\n" : "") + "using Thrift;\n" + + "using Thrift.Collections;\n" + ((serialize_ || wcf_) ? "#if !SILVERLIGHT\n" : "") + + ((serialize_ || wcf_) ? "using System.Xml.Serialization;\n" : "") + + ((serialize_ || wcf_) ? "#endif\n" : "") + (wcf_ ? "//using System.ServiceModel;\n" : "") + + "using System.Runtime.Serialization;\n"; +} + +string t_csharp_generator::csharp_thrift_usings() { + return string() + "using Thrift.Protocol;\n" + "using Thrift.Transport;\n"; +} + +void t_csharp_generator::close_generator() { +} +void t_csharp_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + +void t_csharp_generator::generate_enum(t_enum* tenum) { + string f_enum_name = namespace_dir_ + "/" + (tenum->get_name()) + ".cs"; + ofstream f_enum; + f_enum.open(f_enum_name.c_str()); + + f_enum << autogen_comment() << endl; + + start_csharp_namespace(f_enum); + + generate_csharp_doc(f_enum, tenum); + + indent(f_enum) << "public enum " << tenum->get_name() << "\n"; + scope_up(f_enum); + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + generate_csharp_doc(f_enum, *c_iter); + + int value = (*c_iter)->get_value(); + indent(f_enum) << (*c_iter)->get_name() << " = " << value << "," << endl; + } + + scope_down(f_enum); + + end_csharp_namespace(f_enum); + + f_enum.close(); +} + +void t_csharp_generator::generate_consts(std::vector consts) { + if (consts.empty()) { + return; + } + string f_consts_name = namespace_dir_ + '/' + program_name_ + ".Constants.cs"; + ofstream f_consts; + f_consts.open(f_consts_name.c_str()); + + f_consts << autogen_comment() << csharp_type_usings() << endl; + + start_csharp_namespace(f_consts); + + indent(f_consts) << "public static class " << make_valid_csharp_identifier(program_name_) + << "Constants" << endl; + scope_up(f_consts); + + vector::iterator c_iter; + bool need_static_constructor = false; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + generate_csharp_doc(f_consts, (*c_iter)); + if (print_const_value(f_consts, + (*c_iter)->get_name(), + (*c_iter)->get_type(), + (*c_iter)->get_value(), + false)) { + need_static_constructor = true; + } + } + + if (need_static_constructor) { + print_const_constructor(f_consts, consts); + } + + scope_down(f_consts); + end_csharp_namespace(f_consts); + f_consts.close(); +} + +void t_csharp_generator::print_const_def_value(std::ofstream& out, + string name, + t_type* type, + t_const_value* value) { + if (type->is_struct() || type->is_xception()) { + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + prepare_member_name_mapping((t_struct*)type); + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_field* field = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field = (*f_iter); + } + } + if (field == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + t_type* field_type = field->get_type(); + string val = render_const_value(out, name, field_type, v_iter->second); + indent(out) << name << "." << prop_name(field) << " = " << val << ";" << endl; + } + cleanup_member_name_mapping((t_struct*)type); + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string key = render_const_value(out, name, ktype, v_iter->first); + string val = render_const_value(out, name, vtype, v_iter->second); + indent(out) << name << "[" << key << "]" + << " = " << val << ";" << endl; + } + } else if (type->is_list() || type->is_set()) { + t_type* etype; + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(out, name, etype, *v_iter); + indent(out) << name << ".Add(" << val << ");" << endl; + } + } +} + +void t_csharp_generator::print_const_constructor(std::ofstream& out, std::vector consts) { + indent(out) << "static " << make_valid_csharp_identifier(program_name_).c_str() << "Constants()" + << endl; + scope_up(out); + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + string name = (*c_iter)->get_name(); + t_type* type = (*c_iter)->get_type(); + t_const_value* value = (*c_iter)->get_value(); + + print_const_def_value(out, name, type, value); + } + scope_down(out); +} + +// it seems like all that methods that call this are using in_static to be the opposite of what it +// would imply +bool t_csharp_generator::print_const_value(std::ofstream& out, + string name, + t_type* type, + t_const_value* value, + bool in_static, + bool defval, + bool needtype) { + indent(out); + bool need_static_construction = !in_static; + while (type->is_typedef()) { + type = ((t_typedef*)type)->get_type(); + } + + if (!defval || needtype) { + out << (in_static ? "" : type->is_base_type() ? "public const " : "public static ") + << type_name(type) << " "; + } + if (type->is_base_type()) { + string v2 = render_const_value(out, name, type, value); + out << name << " = " << v2 << ";" << endl; + need_static_construction = false; + } else if (type->is_enum()) { + out << name << " = " << type_name(type, false, true) << "." << value->get_identifier_name() + << ";" << endl; + need_static_construction = false; + } else if (type->is_struct() || type->is_xception()) { + out << name << " = new " << type_name(type) << "();" << endl; + } else if (type->is_map()) { + out << name << " = new " << type_name(type, true, true) << "();" << endl; + } else if (type->is_list() || type->is_set()) { + out << name << " = new " << type_name(type) << "();" << endl; + } + + if (defval && !type->is_base_type() && !type->is_enum()) { + print_const_def_value(out, name, type, value); + } + + return need_static_construction; +} + +std::string t_csharp_generator::render_const_value(ofstream& out, + string name, + t_type* type, + t_const_value* value) { + (void)name; + std::ostringstream render; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + render << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() > 0) ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + render << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + render << value->get_integer(); + } else { + render << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + render << type->get_name() << "." << value->get_identifier_name(); + } else { + string t = tmp("tmp"); + print_const_value(out, t, type, value, true, true, true); + render << t; + } + + return render.str(); +} + +void t_csharp_generator::generate_struct(t_struct* tstruct) { + if (union_ && tstruct->is_union()) { + generate_csharp_union(tstruct); + } else { + generate_csharp_struct(tstruct, false); + } +} + +void t_csharp_generator::generate_xception(t_struct* txception) { + generate_csharp_struct(txception, true); +} + +void t_csharp_generator::generate_csharp_struct(t_struct* tstruct, bool is_exception) { + string f_struct_name = namespace_dir_ + "/" + (tstruct->get_name()) + ".cs"; + ofstream f_struct; + + f_struct.open(f_struct_name.c_str()); + + f_struct << autogen_comment() << csharp_type_usings() << csharp_thrift_usings() << endl; + + generate_csharp_struct_definition(f_struct, tstruct, is_exception); + + f_struct.close(); +} + +void t_csharp_generator::generate_csharp_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool in_class, + bool is_result) { + + if (!in_class) { + start_csharp_namespace(out); + } + + out << endl; + + generate_csharp_doc(out, tstruct); + prepare_member_name_mapping(tstruct); + + indent(out) << "#if !SILVERLIGHT" << endl; + indent(out) << "[Serializable]" << endl; + indent(out) << "#endif" << endl; + if ((serialize_ || wcf_) && !is_exception) { + indent(out) << "[DataContract(Namespace=\"" << wcf_namespace_ << "\")]" + << endl; // do not make exception classes directly WCF serializable, we provide a + // separate "fault" for that + } + bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); + + indent(out) << "public " << (is_final ? "sealed " : "") << "partial class " + << normalize_name(tstruct->get_name()) << " : "; + + if (is_exception) { + out << "TException, "; + } + out << "TBase"; + + out << endl; + + scope_up(out); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + // make private members with public Properties + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + // if the field is requied, then we use auto-properties + if (!field_is_required((*m_iter)) && (!nullable_ || field_has_default((*m_iter)))) { + indent(out) << "private " << declare_field(*m_iter, false, "_") << endl; + } + } + out << endl; + + bool has_non_required_fields = false; + bool has_non_required_default_value_fields = false; + bool has_required_fields = false; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + generate_csharp_doc(out, *m_iter); + generate_property(out, *m_iter, true, true); + bool is_required = field_is_required((*m_iter)); + bool has_default = field_has_default((*m_iter)); + if (is_required) { + has_required_fields = true; + } else { + if (has_default) { + has_non_required_default_value_fields = true; + } + has_non_required_fields = true; + } + } + + bool generate_isset = (nullable_ && has_non_required_default_value_fields) + || (!nullable_ && has_non_required_fields); + if (generate_isset) { + out << endl; + if (serialize_ || wcf_) { + out << indent() << "[XmlIgnore] // XmlSerializer" << endl << indent() + << "[DataMember(Order = 1)] // XmlObjectSerializer, DataContractJsonSerializer, etc." + << endl; + } + out << indent() << "public Isset __isset;" << endl << indent() << "#if !SILVERLIGHT" << endl + << indent() << "[Serializable]" << endl << indent() << "#endif" << endl; + if (serialize_ || wcf_) { + indent(out) << "[DataContract]" << endl; + } + indent(out) << "public struct Isset {" << endl; + indent_up(); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + bool is_required = field_is_required((*m_iter)); + bool has_default = field_has_default((*m_iter)); + // if it is required, don't need Isset for that variable + // if it is not required, if it has a default value, we need to generate Isset + // if we are not nullable, then we generate Isset + if (!is_required && (!nullable_ || has_default)) { + if (serialize_ || wcf_) { + indent(out) << "[DataMember]" << endl; + } + indent(out) << "public bool " << normalize_name((*m_iter)->get_name()) << ";" << endl; + } + } + + indent_down(); + indent(out) << "}" << endl << endl; + + if (generate_isset && (serialize_ || wcf_)) { + indent(out) << "#region XmlSerializer support" << endl << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + bool is_required = field_is_required((*m_iter)); + bool has_default = field_has_default((*m_iter)); + // if it is required, don't need Isset for that variable + // if it is not required, if it has a default value, we need to generate Isset + // if we are not nullable, then we generate Isset + if (!is_required && (!nullable_ || has_default)) { + indent(out) << "public bool ShouldSerialize" << prop_name((*m_iter)) << "()" << endl; + indent(out) << "{" << endl; + indent_up(); + indent(out) << "return __isset." << normalize_name((*m_iter)->get_name()) << ";" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } + } + + indent(out) << "#endregion XmlSerializer support" << endl << endl; + } + } + + // We always want a default, no argument constructor for Reading + indent(out) << "public " << normalize_name(tstruct->get_name()) << "() {" << endl; + indent_up(); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = (*m_iter)->get_type(); + while (t->is_typedef()) { + t = ((t_typedef*)t)->get_type(); + } + if ((*m_iter)->get_value() != NULL) { + if (field_is_required((*m_iter))) { + print_const_value(out, "this." + prop_name(*m_iter), t, (*m_iter)->get_value(), true, true); + } else { + print_const_value(out, + "this._" + (*m_iter)->get_name(), + t, + (*m_iter)->get_value(), + true, + true); + // Optionals with defaults are marked set + indent(out) << "this.__isset." << normalize_name((*m_iter)->get_name()) << " = true;" + << endl; + } + } + } + indent_down(); + indent(out) << "}" << endl << endl; + + if (has_required_fields) { + indent(out) << "public " << tstruct->get_name() << "("; + bool first = true; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (field_is_required((*m_iter))) { + if (first) { + first = false; + } else { + out << ", "; + } + out << type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name(); + } + } + out << ") : this() {" << endl; + indent_up(); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (field_is_required((*m_iter))) { + indent(out) << "this." << prop_name((*m_iter)) << " = " << (*m_iter)->get_name() << ";" + << endl; + } + } + + indent_down(); + indent(out) << "}" << endl << endl; + } + + generate_csharp_struct_reader(out, tstruct); + if (is_result) { + generate_csharp_struct_result_writer(out, tstruct); + } else { + generate_csharp_struct_writer(out, tstruct); + } + if (hashcode_) { + generate_csharp_struct_equals(out, tstruct); + generate_csharp_struct_hashcode(out, tstruct); + } + generate_csharp_struct_tostring(out, tstruct); + scope_down(out); + out << endl; + + // generate a corresponding WCF fault to wrap the exception + if ((serialize_ || wcf_) && is_exception) { + generate_csharp_wcffault(out, tstruct); + } + + cleanup_member_name_mapping(tstruct); + if (!in_class) { + end_csharp_namespace(out); + } +} + +void t_csharp_generator::generate_csharp_wcffault(ofstream& out, t_struct* tstruct) { + out << endl; + indent(out) << "#if !SILVERLIGHT" << endl; + indent(out) << "[Serializable]" << endl; + indent(out) << "#endif" << endl; + indent(out) << "[DataContract]" << endl; + bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); + + indent(out) << "public " << (is_final ? "sealed " : "") << "partial class " << tstruct->get_name() + << "Fault" << endl; + + scope_up(out); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + // make private members with public Properties + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << "private " << declare_field(*m_iter, false, "_") << endl; + } + out << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + generate_property(out, *m_iter, true, false); + } + + scope_down(out); + out << endl; +} + +void t_csharp_generator::generate_csharp_struct_reader(ofstream& out, t_struct* tstruct) { + indent(out) << "public void Read (TProtocol iprot)" << endl; + scope_up(out); + + out << indent() << "iprot.IncrementRecursionDepth();" << endl; + out << indent() << "try" << endl; + scope_up(out); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Required variables aren't in __isset, so we need tmp vars to check them + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (field_is_required((*f_iter))) { + indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl; + } + } + + indent(out) << "TField field;" << endl << indent() << "iprot.ReadStructBegin();" << endl; + + indent(out) << "while (true)" << endl; + scope_up(out); + + indent(out) << "field = iprot.ReadFieldBegin();" << endl; + + indent(out) << "if (field.Type == TType.Stop) { " << endl; + indent_up(); + indent(out) << "break;" << endl; + indent_down(); + indent(out) << "}" << endl; + + indent(out) << "switch (field.ID)" << endl; + + scope_up(out); + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool is_required = field_is_required((*f_iter)); + indent(out) << "case " << (*f_iter)->get_key() << ":" << endl; + indent_up(); + indent(out) << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; + indent_up(); + + generate_deserialize_field(out, *f_iter); + if (is_required) { + indent(out) << "isset_" << (*f_iter)->get_name() << " = true;" << endl; + } + + indent_down(); + out << indent() << "} else { " << endl << indent() << " TProtocolUtil.Skip(iprot, field.Type);" + << endl << indent() << "}" << endl << indent() << "break;" << endl; + indent_down(); + } + + indent(out) << "default: " << endl; + indent_up(); + indent(out) << "TProtocolUtil.Skip(iprot, field.Type);" << endl; + indent(out) << "break;" << endl; + indent_down(); + + scope_down(out); + + indent(out) << "iprot.ReadFieldEnd();" << endl; + + scope_down(out); + + indent(out) << "iprot.ReadStructEnd();" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (field_is_required((*f_iter))) { + indent(out) << "if (!isset_" << (*f_iter)->get_name() << ")" << endl; + indent_up(); + out << indent() + << "throw new TProtocolException(TProtocolException.INVALID_DATA, " + << "\"required field " << prop_name((*f_iter)) << " not set\");" + << endl; + indent_down(); + } + } + + scope_down(out); + out << indent() << "finally" << endl; + scope_up(out); + out << indent() << "iprot.DecrementRecursionDepth();" << endl; + scope_down(out); + + indent_down(); + + indent(out) << "}" << endl << endl; +} + +void t_csharp_generator::generate_csharp_struct_writer(ofstream& out, t_struct* tstruct) { + out << indent() << "public void Write(TProtocol oprot) {" << endl; + indent_up(); + + out << indent() << "oprot.IncrementRecursionDepth();" << endl; + out << indent() << "try" << endl; + scope_up(out); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + indent(out) << "TStruct struc = new TStruct(\"" << name << "\");" << endl; + indent(out) << "oprot.WriteStructBegin(struc);" << endl; + + if (fields.size() > 0) { + indent(out) << "TField field = new TField();" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool is_required = field_is_required((*f_iter)); + bool has_default = field_has_default((*f_iter)); + bool null_allowed = type_can_be_null((*f_iter)->get_type()); + + if (is_required) + { + if (null_allowed) { + indent(out) << "if (" << prop_name((*f_iter)) << " == null)" << endl; + indent_up(); + out << indent() + << "throw new TProtocolException(TProtocolException.INVALID_DATA, " + << "\"required field " << prop_name((*f_iter)) << " not set\");" + << endl; + indent_down(); + } + } + else + { + if (nullable_ && !has_default) { + indent(out) << "if (" << prop_name((*f_iter)) << " != null) {" << endl; + } + else if (null_allowed) { + out << indent() + << "if (" << prop_name((*f_iter)) << " != null && __isset." + << normalize_name((*f_iter)->get_name()) << ") {" + << endl; + } + else { + indent(out) << "if (__isset." << normalize_name((*f_iter)->get_name()) << ") {" << endl; + } + indent_up(); + } + indent(out) << "field.Name = \"" << (*f_iter)->get_name() << "\";" << endl; + indent(out) << "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl; + indent(out) << "field.ID = " << (*f_iter)->get_key() << ";" << endl; + indent(out) << "oprot.WriteFieldBegin(field);" << endl; + + generate_serialize_field(out, *f_iter); + + indent(out) << "oprot.WriteFieldEnd();" << endl; + if (!is_required) { + indent_down(); + indent(out) << "}" << endl; + } + } + } + + indent(out) << "oprot.WriteFieldStop();" << endl; + indent(out) << "oprot.WriteStructEnd();" << endl; + + scope_down(out); + out << indent() << "finally" << endl; + scope_up(out); + out << indent() << "oprot.DecrementRecursionDepth();" << endl; + scope_down(out); + + indent_down(); + + indent(out) << "}" << endl << endl; +} + +void t_csharp_generator::generate_csharp_struct_result_writer(ofstream& out, t_struct* tstruct) { + indent(out) << "public void Write(TProtocol oprot) {" << endl; + indent_up(); + + out << indent() << "oprot.IncrementRecursionDepth();" << endl; + out << indent() << "try" << endl; + scope_up(out); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + indent(out) << "TStruct struc = new TStruct(\"" << name << "\");" << endl; + indent(out) << "oprot.WriteStructBegin(struc);" << endl; + + if (fields.size() > 0) { + indent(out) << "TField field = new TField();" << endl; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + out << endl << indent() << "if "; + } else { + out << " else if "; + } + + if (nullable_) { + out << "(this." << prop_name((*f_iter)) << " != null) {" << endl; + } else { + out << "(this.__isset." << normalize_name((*f_iter)->get_name()) << ") {" << endl; + } + indent_up(); + + bool null_allowed = !nullable_ && type_can_be_null((*f_iter)->get_type()); + if (null_allowed) { + indent(out) << "if (" << prop_name(*f_iter) << " != null) {" << endl; + indent_up(); + } + + indent(out) << "field.Name = \"" << prop_name(*f_iter) << "\";" << endl; + indent(out) << "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl; + indent(out) << "field.ID = " << (*f_iter)->get_key() << ";" << endl; + indent(out) << "oprot.WriteFieldBegin(field);" << endl; + + generate_serialize_field(out, *f_iter); + + indent(out) << "oprot.WriteFieldEnd();" << endl; + + if (null_allowed) { + indent_down(); + indent(out) << "}" << endl; + } + + indent_down(); + indent(out) << "}"; + } + } + + out << endl << indent() << "oprot.WriteFieldStop();" << endl << indent() + << "oprot.WriteStructEnd();" << endl; + + scope_down(out); + out << indent() << "finally" << endl; + scope_up(out); + out << indent() << "oprot.DecrementRecursionDepth();" << endl; + scope_down(out); + + indent_down(); + + indent(out) << "}" << endl << endl; +} + +void t_csharp_generator::generate_csharp_struct_tostring(ofstream& out, t_struct* tstruct) { + indent(out) << "public override string ToString() {" << endl; + indent_up(); + + indent(out) << "StringBuilder __sb = new StringBuilder(\"" << tstruct->get_name() << "(\");" + << endl; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + bool useFirstFlag = false; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (!field_is_required((*f_iter))) { + indent(out) << "bool __first = true;" << endl; + useFirstFlag = true; + } + break; + } + + bool had_required = false; // set to true after first required field has been processed + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool is_required = field_is_required((*f_iter)); + bool has_default = field_has_default((*f_iter)); + if (nullable_ && !has_default && !is_required) { + indent(out) << "if (" << prop_name((*f_iter)) << " != null) {" << endl; + indent_up(); + } else if (!is_required) { + bool null_allowed = type_can_be_null((*f_iter)->get_type()); + if (null_allowed) { + indent(out) << "if (" << prop_name((*f_iter)) << " != null && __isset." + << normalize_name((*f_iter)->get_name()) << ") {" << endl; + indent_up(); + } else { + indent(out) << "if (__isset." << normalize_name((*f_iter)->get_name()) << ") {" << endl; + indent_up(); + } + } + + if (useFirstFlag && (!had_required)) { + indent(out) << "if(!__first) { __sb.Append(\", \"); }" << endl; + if (!is_required) { + indent(out) << "__first = false;" << endl; + } + indent(out) << "__sb.Append(\"" << prop_name((*f_iter)) << ": \");" << endl; + } else { + indent(out) << "__sb.Append(\", " << prop_name((*f_iter)) << ": \");" << endl; + } + + t_type* ttype = (*f_iter)->get_type(); + if (ttype->is_xception() || ttype->is_struct()) { + indent(out) << "__sb.Append(" << prop_name((*f_iter)) + << "== null ? \"\" : " << prop_name((*f_iter)) << ".ToString());" << endl; + } else { + indent(out) << "__sb.Append(" << prop_name((*f_iter)) << ");" << endl; + } + + if (!is_required) { + indent_down(); + indent(out) << "}" << endl; + } else { + had_required = true; // now __first must be false, so we don't need to check it anymore + } + } + + indent(out) << "__sb.Append(\")\");" << endl; + indent(out) << "return __sb.ToString();" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +void t_csharp_generator::generate_csharp_union(t_struct* tunion) { + string f_union_name = namespace_dir_ + "/" + (tunion->get_name()) + ".cs"; + ofstream f_union; + + f_union.open(f_union_name.c_str()); + + f_union << autogen_comment() << csharp_type_usings() << csharp_thrift_usings() << endl; + + generate_csharp_union_definition(f_union, tunion); + + f_union.close(); +} + +void t_csharp_generator::generate_csharp_union_definition(std::ofstream& out, t_struct* tunion) { + // Let's define the class first + start_csharp_namespace(out); + + indent(out) << "public abstract partial class " << tunion->get_name() << " : TAbstractBase {" + << endl; + + indent_up(); + + indent(out) << "public abstract void Write(TProtocol protocol);" << endl; + indent(out) << "public readonly bool Isset;" << endl; + indent(out) << "public abstract object Data { get; }" << endl; + + indent(out) << "protected " << tunion->get_name() << "(bool isset) {" << endl; + indent_up(); + indent(out) << "Isset = isset;" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + + indent(out) << "public class ___undefined : " << tunion->get_name() << " {" << endl; + indent_up(); + + indent(out) << "public override object Data { get { return null; } }" << endl; + + indent(out) << "public ___undefined() : base(false) {}" << endl << endl; + + indent(out) << "public override void Write(TProtocol protocol) {" << endl; + indent_up(); + indent(out) << "throw new TProtocolException( TProtocolException.INVALID_DATA, \"Cannot persist " + "an union type which is not set.\");" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + + indent_down(); + indent(out) << "}" << endl << endl; + + const vector& fields = tunion->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + generate_csharp_union_class(out, tunion, (*f_iter)); + } + + generate_csharp_union_reader(out, tunion); + + indent_down(); + indent(out) << "}" << endl << endl; + + end_csharp_namespace(out); +} + +void t_csharp_generator::generate_csharp_union_class(std::ofstream& out, + t_struct* tunion, + t_field* tfield) { + indent(out) << "public class " << tfield->get_name() << " : " << tunion->get_name() << " {" + << endl; + indent_up(); + indent(out) << "private " << type_name(tfield->get_type()) << " _data;" << endl; + indent(out) << "public override object Data { get { return _data; } }" << endl; + indent(out) << "public " << tfield->get_name() << "(" << type_name(tfield->get_type()) + << " data) : base(true) {" << endl; + indent_up(); + indent(out) << "this._data = data;" << endl; + indent_down(); + indent(out) << "}" << endl; + indent(out) << "public override void Write(TProtocol oprot) {" << endl; + indent_up(); + + out << indent() << "oprot.IncrementRecursionDepth();" << endl; + out << indent() << "try" << endl; + scope_up(out); + + indent(out) << "TStruct struc = new TStruct(\"" << tunion->get_name() << "\");" << endl; + indent(out) << "oprot.WriteStructBegin(struc);" << endl; + + indent(out) << "TField field = new TField();" << endl; + indent(out) << "field.Name = \"" << tfield->get_name() << "\";" << endl; + indent(out) << "field.Type = " << type_to_enum(tfield->get_type()) << ";" << endl; + indent(out) << "field.ID = " << tfield->get_key() << ";" << endl; + indent(out) << "oprot.WriteFieldBegin(field);" << endl; + + generate_serialize_field(out, tfield, "_data", true, true); + + indent(out) << "oprot.WriteFieldEnd();" << endl; + indent(out) << "oprot.WriteFieldStop();" << endl; + indent(out) << "oprot.WriteStructEnd();" << endl; + indent_down(); + + scope_down(out); + out << indent() << "finally" << endl; + scope_up(out); + out << indent() << "oprot.DecrementRecursionDepth();" << endl; + scope_down(out); + + indent(out) << "}" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +void t_csharp_generator::generate_csharp_struct_equals(ofstream& out, t_struct* tstruct) { + indent(out) << "public override bool Equals(object that) {" << endl; + indent_up(); + + indent(out) << "var other = that as " << type_name(tstruct) << ";" << endl; + indent(out) << "if (other == null) return false;" << endl; + indent(out) << "if (ReferenceEquals(this, other)) return true;" << endl; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + bool first = true; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + indent(out) << "return "; + indent_up(); + } else { + out << endl; + indent(out) << "&& "; + } + if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) { + out << "((__isset." << normalize_name((*f_iter)->get_name()) << " == other.__isset." + << normalize_name((*f_iter)->get_name()) << ") && ((!__isset." + << normalize_name((*f_iter)->get_name()) << ") || ("; + } + t_type* ttype = (*f_iter)->get_type(); + if (ttype->is_container() || ttype->is_binary()) { + out << "TCollections.Equals("; + } else { + out << "System.Object.Equals("; + } + out << prop_name((*f_iter)) << ", other." << prop_name((*f_iter)) << ")"; + if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) { + out << ")))"; + } + } + if (first) { + indent(out) << "return true;" << endl; + } else { + out << ";" << endl; + indent_down(); + } + + indent_down(); + indent(out) << "}" << endl << endl; +} + +void t_csharp_generator::generate_csharp_struct_hashcode(ofstream& out, t_struct* tstruct) { + indent(out) << "public override int GetHashCode() {" << endl; + indent_up(); + + indent(out) << "int hashcode = 0;" << endl; + indent(out) << "unchecked {" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_type* ttype = (*f_iter)->get_type(); + indent(out) << "hashcode = (hashcode * 397) ^ "; + if (field_is_required((*f_iter))) { + out << "("; + } else if (nullable_) { + out << "(" << prop_name((*f_iter)) << " == null ? 0 : "; + } else { + out << "(!__isset." << normalize_name((*f_iter)->get_name()) << " ? 0 : "; + } + if (ttype->is_container()) { + out << "(TCollections.GetHashCode(" << prop_name((*f_iter)) << "))"; + } else { + out << "(" << prop_name((*f_iter)) << ".GetHashCode())"; + } + out << ");" << endl; + } + + indent_down(); + indent(out) << "}" << endl; + indent(out) << "return hashcode;" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +void t_csharp_generator::generate_service(t_service* tservice) { + string f_service_name = namespace_dir_ + "/" + service_name_ + ".cs"; + f_service_.open(f_service_name.c_str()); + + f_service_ << autogen_comment() << csharp_type_usings() << csharp_thrift_usings() << endl; + + start_csharp_namespace(f_service_); + + indent(f_service_) << "public partial class " << normalize_name(service_name_) << " {" << endl; + indent_up(); + + generate_service_interface(tservice); + generate_service_client(tservice); + generate_service_server(tservice); + generate_service_helpers(tservice); + + indent_down(); + + indent(f_service_) << "}" << endl; + end_csharp_namespace(f_service_); + f_service_.close(); +} + +void t_csharp_generator::generate_service_interface(t_service* tservice) { + generate_separate_service_interfaces(tservice); +} + +void t_csharp_generator::generate_separate_service_interfaces(t_service* tservice) { + generate_sync_service_interface(tservice); + + if (async_) { + generate_async_service_interface(tservice); + } + + generate_combined_service_interface(tservice); +} + +void t_csharp_generator::generate_sync_service_interface(t_service* tservice) { + string extends = ""; + string extends_iface = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_iface = " : " + extends + ".ISync"; + } + + generate_csharp_doc(f_service_, tservice); + + if (wcf_) { + indent(f_service_) << "[ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl; + } + indent(f_service_) << "public interface ISync" << extends_iface << " {" << endl; + + indent_up(); + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_csharp_doc(f_service_, *f_iter); + + // if we're using WCF, add the corresponding attributes + if (wcf_) { + indent(f_service_) << "[OperationContract]" << endl; + + const std::vector& xceptions = (*f_iter)->get_xceptions()->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + indent(f_service_) << "[FaultContract(typeof(" + + type_name((*x_iter)->get_type(), false, false) + "Fault))]" << endl; + } + } + + indent(f_service_) << function_signature(*f_iter) << ";" << endl; + } + indent_down(); + f_service_ << indent() << "}" << endl << endl; +} + +void t_csharp_generator::generate_async_service_interface(t_service* tservice) { + string extends = ""; + string extends_iface = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_iface = " : " + extends + ".IAsync"; + } + + generate_csharp_doc(f_service_, tservice); + + if (wcf_) { + indent(f_service_) << "[ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl; + } + indent(f_service_) << "public interface IAsync" << extends_iface << " {" << endl; + + indent_up(); + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_csharp_doc(f_service_, *f_iter); + + // if we're using WCF, add the corresponding attributes + if (wcf_) { + indent(f_service_) << "[OperationContract]" << endl; + + const std::vector& xceptions = (*f_iter)->get_xceptions()->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + indent(f_service_) << "[FaultContract(typeof(" + + type_name((*x_iter)->get_type(), false, false) + "Fault))]" << endl; + } + } + + indent(f_service_) << function_signature_async(*f_iter) << ";" << endl; + } + indent_down(); + f_service_ << indent() << "}" << endl << endl; +} + +void t_csharp_generator::generate_combined_service_interface(t_service* tservice) { + string extends_iface = " : ISync"; + + if (async_) { + extends_iface += ", IAsync"; + } + + generate_csharp_doc(f_service_, tservice); + + if (wcf_) { + indent(f_service_) << "[ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl; + } + + indent(f_service_) << "public interface Iface" << extends_iface << " {" << endl; + + indent_up(); + + // We need to generate extra old style async methods for silverlight. Since + // this isn't something you'd want to implement server-side, just put them into + // the main Iface interface. + generate_silverlight_async_methods(tservice); + + indent_down(); + + f_service_ << indent() << "}" << endl << endl; +} + +void t_csharp_generator::generate_silverlight_async_methods(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_csharp_doc(f_service_, *f_iter); + + // For backwards compatibility, include the Begin_, End_ methods if we're generating + // with the async flag. I'm not sure this is necessary, so someone with more knowledge + // can maybe remove these checks if they know it's safe. + if (!async_) { + indent(f_service_) << "#if SILVERLIGHT" << endl; + } + + indent(f_service_) << function_signature_async_begin(*f_iter, "Begin_") << ";" << endl; + indent(f_service_) << function_signature_async_end(*f_iter, "End_") << ";" << endl; + + if (!async_) { + indent(f_service_) << "#endif" << endl; + } + } +} + +void t_csharp_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_csharp_struct_definition(f_service_, ts, false, true); + generate_function_helpers(*f_iter); + } +} + +void t_csharp_generator::generate_service_client(t_service* tservice) { + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_client = extends + ".Client, "; + } else { + extends_client = "IDisposable, "; + } + + generate_csharp_doc(f_service_, tservice); + + indent(f_service_) << "public class Client : " << extends_client << "Iface {" << endl; + indent_up(); + indent(f_service_) << "public Client(TProtocol prot) : this(prot, prot)" << endl; + scope_up(f_service_); + scope_down(f_service_); + f_service_ << endl; + + indent(f_service_) << "public Client(TProtocol iprot, TProtocol oprot)"; + if (!extends.empty()) { + f_service_ << " : base(iprot, oprot)"; + } + f_service_ << endl; + + scope_up(f_service_); + if (extends.empty()) { + f_service_ << indent() << "iprot_ = iprot;" << endl << indent() << "oprot_ = oprot;" << endl; + } + scope_down(f_service_); + + f_service_ << endl; + + if (extends.empty()) { + f_service_ << indent() << "protected TProtocol iprot_;" << endl << indent() + << "protected TProtocol oprot_;" << endl << indent() << "protected int seqid_;" + << endl << endl; + + f_service_ << indent() << "public TProtocol InputProtocol" << endl; + scope_up(f_service_); + indent(f_service_) << "get { return iprot_; }" << endl; + scope_down(f_service_); + + f_service_ << indent() << "public TProtocol OutputProtocol" << endl; + scope_up(f_service_); + indent(f_service_) << "get { return oprot_; }" << endl; + scope_down(f_service_); + f_service_ << endl << endl; + + indent(f_service_) << "#region \" IDisposable Support \"" << endl; + indent(f_service_) << "private bool _IsDisposed;" << endl << endl; + indent(f_service_) << "// IDisposable" << endl; + indent(f_service_) << "public void Dispose()" << endl; + scope_up(f_service_); + indent(f_service_) << "Dispose(true);" << endl; + scope_down(f_service_); + indent(f_service_) << endl << endl; + indent(f_service_) << "protected virtual void Dispose(bool disposing)" << endl; + scope_up(f_service_); + indent(f_service_) << "if (!_IsDisposed)" << endl; + scope_up(f_service_); + indent(f_service_) << "if (disposing)" << endl; + scope_up(f_service_); + indent(f_service_) << "if (iprot_ != null)" << endl; + scope_up(f_service_); + indent(f_service_) << "((IDisposable)iprot_).Dispose();" << endl; + scope_down(f_service_); + indent(f_service_) << "if (oprot_ != null)" << endl; + scope_up(f_service_); + indent(f_service_) << "((IDisposable)oprot_).Dispose();" << endl; + scope_down(f_service_); + scope_down(f_service_); + scope_down(f_service_); + indent(f_service_) << "_IsDisposed = true;" << endl; + scope_down(f_service_); + indent(f_service_) << "#endregion" << endl; + f_service_ << endl << endl; + } + + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string funname = (*f_iter)->get_name(); + + indent(f_service_) << endl; + + if (!async_) { + indent(f_service_) << "#if SILVERLIGHT" << endl; + } + // Begin_ + indent(f_service_) << "public " << function_signature_async_begin(*f_iter, "Begin_") << endl; + scope_up(f_service_); + indent(f_service_) << "return " + << "send_" << funname << "(callback, state"; + + t_struct* arg_struct = (*f_iter)->get_arglist(); + prepare_member_name_mapping(arg_struct); + + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << ", "; + f_service_ << normalize_name((*fld_iter)->get_name()); + } + f_service_ << ");" << endl; + scope_down(f_service_); + f_service_ << endl; + + // End + indent(f_service_) << "public " << function_signature_async_end(*f_iter, "End_") << endl; + scope_up(f_service_); + indent(f_service_) << "oprot_.Transport.EndFlush(asyncResult);" << endl; + if (!(*f_iter)->is_oneway()) { + f_service_ << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << "return "; + } + f_service_ << "recv_" << funname << "();" << endl; + } + scope_down(f_service_); + f_service_ << endl; + + // async + bool first; + if (async_) { + indent(f_service_) << "public async " << function_signature_async(*f_iter, "") << endl; + scope_up(f_service_); + + if (!(*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << type_name((*f_iter)->get_returntype()) << " retval;" << endl; + indent(f_service_) << "retval = "; + } else { + indent(f_service_); + } + f_service_ << "await Task.Run(() =>" << endl; + scope_up(f_service_); + indent(f_service_); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << "return "; + } + f_service_ << funname << "("; + first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << (*fld_iter)->get_name(); + } + f_service_ << ");" << endl; + indent_down(); + indent(f_service_) << "});" << endl; + if (!(*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << "return retval;" << endl; + } + scope_down(f_service_); + f_service_ << endl; + } + + if (!async_) { + indent(f_service_) << "#endif" << endl << endl; + } + + // "Normal" Synchronous invoke + generate_csharp_doc(f_service_, *f_iter); + indent(f_service_) << "public " << function_signature(*f_iter) << endl; + scope_up(f_service_); + + if (!async_) { + indent(f_service_) << "#if !SILVERLIGHT" << endl; + indent(f_service_) << "send_" << funname << "("; + + first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << normalize_name((*fld_iter)->get_name()); + } + f_service_ << ");" << endl; + + if (!(*f_iter)->is_oneway()) { + f_service_ << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << "return "; + } + f_service_ << "recv_" << funname << "();" << endl; + } + f_service_ << endl; + + indent(f_service_) << "#else" << endl; + } + + // Silverlight synchronous invoke + indent(f_service_) << "var asyncResult = Begin_" << funname << "(null, null"; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << ", " << normalize_name((*fld_iter)->get_name()); + } + f_service_ << ");" << endl; + + if (!(*f_iter)->is_oneway()) { + f_service_ << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << "return "; + } + f_service_ << "End_" << funname << "(asyncResult);" << endl; + } + f_service_ << endl; + + if (!async_) { + indent(f_service_) << "#endif" << endl; + } + scope_down(f_service_); + + // Send + t_function send_function(g_type_void, + string("send_") + (*f_iter)->get_name(), + (*f_iter)->get_arglist()); + + string argsname = (*f_iter)->get_name() + "_args"; + + if (!async_) { + indent(f_service_) << "#if SILVERLIGHT" << endl; + } + indent(f_service_) << "public " << function_signature_async_begin(&send_function) << endl; + if (!async_) { + indent(f_service_) << "#else" << endl; + indent(f_service_) << "public " << function_signature(&send_function) << endl; + indent(f_service_) << "#endif" << endl; + } + scope_up(f_service_); + + f_service_ << indent() << "oprot_.WriteMessageBegin(new TMessage(\"" << funname << "\", " + << ((*f_iter)->is_oneway() ? "TMessageType.Oneway" : "TMessageType.Call") + << ", seqid_));" << endl << indent() << argsname << " args = new " << argsname + << "();" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << indent() << "args." << prop_name(*fld_iter) << " = " + << normalize_name((*fld_iter)->get_name()) << ";" << endl; + } + + f_service_ << indent() << "args.Write(oprot_);" << endl << indent() + << "oprot_.WriteMessageEnd();" << endl; + ; + + if (!async_) { + indent(f_service_) << "#if SILVERLIGHT" << endl; + } + indent(f_service_) << "return oprot_.Transport.BeginFlush(callback, state);" << endl; + if (!async_) { + indent(f_service_) << "#else" << endl; + indent(f_service_) << "oprot_.Transport.Flush();" << endl; + indent(f_service_) << "#endif" << endl; + } + + cleanup_member_name_mapping(arg_struct); + scope_down(f_service_); + f_service_ << endl; + + if (!(*f_iter)->is_oneway()) { + string resultname = (*f_iter)->get_name() + "_result"; + + t_struct noargs(program_); + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + &noargs, + (*f_iter)->get_xceptions()); + indent(f_service_) << "public " << function_signature(&recv_function) << endl; + scope_up(f_service_); + + t_struct* xs = (*f_iter)->get_xceptions(); + prepare_member_name_mapping(xs, xs->get_members(), resultname); + + f_service_ << indent() << "TMessage msg = iprot_.ReadMessageBegin();" << endl << indent() + << "if (msg.Type == TMessageType.Exception) {" << endl; + indent_up(); + f_service_ << indent() << "TApplicationException x = TApplicationException.Read(iprot_);" + << endl << indent() << "iprot_.ReadMessageEnd();" << endl << indent() << "throw x;" + << endl; + indent_down(); + f_service_ << indent() << "}" << endl << indent() << resultname << " result = new " + << resultname << "();" << endl << indent() << "result.Read(iprot_);" << endl + << indent() << "iprot_.ReadMessageEnd();" << endl; + + if (!(*f_iter)->get_returntype()->is_void()) { + if (nullable_) { + if (type_can_be_null((*f_iter)->get_returntype())) { + f_service_ << indent() << "if (result.Success != null) {" << endl << indent() + << " return result.Success;" << endl << indent() << "}" << endl; + } else { + f_service_ << indent() << "if (result.Success.HasValue) {" << endl << indent() + << " return result.Success.Value;" << endl << indent() << "}" << endl; + } + } else { + f_service_ << indent() << "if (result.__isset.success) {" << endl << indent() + << " return result.Success;" << endl << indent() << "}" << endl; + } + } + + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + if (nullable_) { + f_service_ << indent() << "if (result." << prop_name(*x_iter) << " != null) {" << endl + << indent() << " throw result." << prop_name(*x_iter) << ";" << endl + << indent() << "}" << endl; + } else { + f_service_ << indent() << "if (result.__isset." << normalize_name((*x_iter)->get_name()) + << ") {" << endl << indent() << " throw result." << prop_name(*x_iter) << ";" + << endl << indent() << "}" << endl; + } + } + + if ((*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << "return;" << endl; + } else { + f_service_ << indent() + << "throw new " + "TApplicationException(TApplicationException.ExceptionType.MissingResult, \"" + << (*f_iter)->get_name() << " failed: unknown result\");" << endl; + } + + cleanup_member_name_mapping((*f_iter)->get_xceptions()); + scope_down(f_service_); + f_service_ << endl; + } + } + + indent_down(); + indent(f_service_) << "}" << endl; +} + +void t_csharp_generator::generate_service_server(t_service* tservice) { + if (async_) { + generate_service_server_async(tservice); + generate_service_server_sync(tservice); + } + else { + generate_service_server_sync(tservice); + } +} + +void t_csharp_generator::generate_service_server_sync(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_processor = extends + ".Processor, "; + } + + indent(f_service_) << "public class Processor : " << extends_processor << "TProcessor {" << endl; + indent_up(); + + indent(f_service_) << "public Processor(ISync iface)"; + + if (!extends.empty()) { + f_service_ << " : base(iface)"; + } + f_service_ << endl; + scope_up(f_service_); + f_service_ << indent() << "iface_ = iface;" << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << indent() << "processMap_[\"" << (*f_iter)->get_name() + << "\"] = " << (*f_iter)->get_name() << "_Process;" << endl; + } + + scope_down(f_service_); + f_service_ << endl; + + if (extends.empty()) { + f_service_ + << indent() + << "protected delegate void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);" + << endl; + } + + f_service_ << indent() << "private ISync iface_;" << endl; + + if (extends.empty()) { + f_service_ << indent() << "protected Dictionary processMap_ = new " + "Dictionary();" << endl; + } + + f_service_ << endl; + + if (extends.empty()) { + indent(f_service_) << "public bool Process(TProtocol iprot, TProtocol oprot)" << endl; + } + else { + indent(f_service_) << "public new bool Process(TProtocol iprot, TProtocol oprot)" << endl; + } + scope_up(f_service_); + + f_service_ << indent() << "try" << endl; + scope_up(f_service_); + + f_service_ << indent() << "TMessage msg = iprot.ReadMessageBegin();" << endl; + + f_service_ + << indent() << "ProcessFunction fn;" << endl << indent() + << "processMap_.TryGetValue(msg.Name, out fn);" << endl << indent() << "if (fn == null) {" + << endl << indent() << " TProtocolUtil.Skip(iprot, TType.Struct);" << endl << indent() + << " iprot.ReadMessageEnd();" << endl << indent() + << " TApplicationException x = new TApplicationException " + "(TApplicationException.ExceptionType.UnknownMethod, \"Invalid method name: '\" + " + "msg.Name + \"'\");" << endl << indent() + << " oprot.WriteMessageBegin(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID));" + << endl << indent() << " x.Write(oprot);" << endl << indent() << " oprot.WriteMessageEnd();" + << endl << indent() << " oprot.Transport.Flush();" << endl << indent() << " return true;" + << endl << indent() << "}" << endl << indent() << "fn(msg.SeqID, iprot, oprot);" << endl; + + scope_down(f_service_); + + f_service_ << indent() << "catch (IOException)" << endl; + scope_up(f_service_); + f_service_ << indent() << "return false;" << endl; + scope_down(f_service_); + + f_service_ << indent() << "return true;" << endl; + + scope_down(f_service_); + f_service_ << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(tservice, *f_iter); + } + + indent_down(); + indent(f_service_) << "}" << endl << endl; +} + +void t_csharp_generator::generate_service_server_async(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_processor = extends + ".Processor, "; + } + + indent(f_service_) << "public class AsyncProcessor : " << extends_processor << "TAsyncProcessor {" << endl; + indent_up(); + + indent(f_service_) << "public AsyncProcessor(IAsync iface)"; + if (!extends.empty()) { + f_service_ << " : base(iface)"; + } + f_service_ << endl; + scope_up(f_service_); + f_service_ << indent() << "iface_ = iface;" << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << indent() << "processMap_[\"" << (*f_iter)->get_name() + << "\"] = " << (*f_iter)->get_name() << "_ProcessAsync;" << endl; + } + + scope_down(f_service_); + f_service_ << endl; + + if (extends.empty()) { + f_service_ + << indent() + << "protected delegate Task ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);" + << endl; + } + + f_service_ << indent() << "private IAsync iface_;" << endl; + + if (extends.empty()) { + f_service_ << indent() << "protected Dictionary processMap_ = new " + "Dictionary();" << endl; + } + + f_service_ << endl; + + if (extends.empty()) { + indent(f_service_) << "public async Task ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl; + } + else { + indent(f_service_) << "public new async Task ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl; + } + scope_up(f_service_); + + f_service_ << indent() << "try" << endl; + scope_up(f_service_); + + f_service_ << indent() << "TMessage msg = iprot.ReadMessageBegin();" << endl; + + f_service_ + << indent() << "ProcessFunction fn;" << endl << indent() + << "processMap_.TryGetValue(msg.Name, out fn);" << endl << indent() << "if (fn == null) {" + << endl << indent() << " TProtocolUtil.Skip(iprot, TType.Struct);" << endl << indent() + << " iprot.ReadMessageEnd();" << endl << indent() + << " TApplicationException x = new TApplicationException " + "(TApplicationException.ExceptionType.UnknownMethod, \"Invalid method name: '\" + " + "msg.Name + \"'\");" << endl << indent() + << " oprot.WriteMessageBegin(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID));" + << endl << indent() << " x.Write(oprot);" << endl << indent() << " oprot.WriteMessageEnd();" + << endl << indent() << " oprot.Transport.Flush();" << endl << indent() << " return true;" + << endl << indent() << "}" << endl << indent() << "await fn(msg.SeqID, iprot, oprot);" << endl; + + scope_down(f_service_); + + f_service_ << indent() << "catch (IOException)" << endl; + scope_up(f_service_); + f_service_ << indent() << "return false;" << endl; + scope_down(f_service_); + + f_service_ << indent() << "return true;" << endl; + + scope_down(f_service_); + f_service_ << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function_async(tservice, *f_iter); + } + + indent_down(); + indent(f_service_) << "}" << endl << endl; +} + +void t_csharp_generator::generate_function_helpers(t_function* tfunction) { + if (tfunction->is_oneway()) { + return; + } + + t_struct result(program_, tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + generate_csharp_struct_definition(f_service_, &result, false, true, true); +} + +void t_csharp_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + (void)tservice; + indent(f_service_) << "public void " << tfunction->get_name() + << "_Process(int seqid, TProtocol iprot, TProtocol oprot)" << endl; + scope_up(f_service_); + + string argsname = tfunction->get_name() + "_args"; + string resultname = tfunction->get_name() + "_result"; + + f_service_ << indent() << argsname << " args = new " << argsname << "();" << endl + << indent() << "args.Read(iprot);" << endl + << indent() << "iprot.ReadMessageEnd();" << endl; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + if (!tfunction->is_oneway()) { + f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl; + } + + f_service_ << indent() << "try" << endl + << indent() << "{" << endl; + indent_up(); + + if (xceptions.size() > 0) { + f_service_ << indent() << "try" << endl + << indent() << "{" << endl; + indent_up(); + } + + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + f_service_ << indent(); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + f_service_ << "result.Success = "; + } + f_service_ << "iface_." << normalize_name(tfunction->get_name()) << "("; + bool first = true; + prepare_member_name_mapping(arg_struct); + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "args." << prop_name(*f_iter); + if (nullable_ && !type_can_be_null((*f_iter)->get_type())) { + f_service_ << ".Value"; + } + } + cleanup_member_name_mapping(arg_struct); + f_service_ << ");" << endl; + + prepare_member_name_mapping(xs, xs->get_members(), resultname); + if (xceptions.size() > 0) { + indent_down(); + f_service_ << indent() << "}" << endl; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << indent() << "catch (" << type_name((*x_iter)->get_type(), false, false) << " " + << (*x_iter)->get_name() << ")" << endl + << indent() << "{" << endl; + if (!tfunction->is_oneway()) { + indent_up(); + f_service_ << indent() << "result." << prop_name(*x_iter) << " = " << (*x_iter)->get_name() + << ";" << endl; + indent_down(); + } + f_service_ << indent() << "}" << endl; + } + } + if (!tfunction->is_oneway()) { + f_service_ << indent() << "oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name() + << "\", TMessageType.Reply, seqid)); " << endl; + f_service_ << indent() << "result.Write(oprot);" << endl; + } + indent_down(); + + cleanup_member_name_mapping(xs); + + f_service_ << indent() << "}" << endl + << indent() << "catch (TTransportException)" << endl + << indent() << "{" << endl + << indent() << " throw;" << endl + << indent() << "}" << endl + << indent() << "catch (Exception ex)" << endl + << indent() << "{" << endl + << indent() << " Console.Error.WriteLine(\"Error occurred in processor:\");" << endl + << indent() << " Console.Error.WriteLine(ex.ToString());" << endl; + + if (tfunction->is_oneway()) { + f_service_ << indent() << "}" << endl; + } else { + f_service_ << indent() << " TApplicationException x = new TApplicationException" << indent() + << "(TApplicationException.ExceptionType.InternalError,\" Internal error.\");" + << endl + << indent() << " oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name() + << "\", TMessageType.Exception, seqid));" << endl + << indent() << " x.Write(oprot);" << endl + << indent() << "}" << endl; + f_service_ << indent() << "oprot.WriteMessageEnd();" << endl + << indent() << "oprot.Transport.Flush();" << endl; + } + + scope_down(f_service_); + + f_service_ << endl; +} + +void t_csharp_generator::generate_process_function_async(t_service* tservice, t_function* tfunction) { + (void)tservice; + indent(f_service_) << "public async Task " << tfunction->get_name() + << "_ProcessAsync(int seqid, TProtocol iprot, TProtocol oprot)" << endl; + scope_up(f_service_); + + string argsname = tfunction->get_name() + "_args"; + string resultname = tfunction->get_name() + "_result"; + + f_service_ << indent() << argsname << " args = new " << argsname << "();" << endl + << indent() << "args.Read(iprot);" << endl + << indent() << "iprot.ReadMessageEnd();" << endl; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + if (!tfunction->is_oneway()) { + f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl; + } + + f_service_ << indent() << "try" << endl + << indent() << "{" << endl; + indent_up(); + + if (xceptions.size() > 0) { + f_service_ << indent() << "try" << endl + << indent() << "{" << endl; + indent_up(); + } + + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + f_service_ << indent(); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + f_service_ << "result.Success = "; + } + f_service_ << "await iface_." << normalize_name(tfunction->get_name()) << "Async("; + bool first = true; + prepare_member_name_mapping(arg_struct); + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } + else { + f_service_ << ", "; + } + f_service_ << "args." << prop_name(*f_iter); + if (nullable_ && !type_can_be_null((*f_iter)->get_type())) { + f_service_ << ".Value"; + } + } + cleanup_member_name_mapping(arg_struct); + f_service_ << ");" << endl; + + prepare_member_name_mapping(xs, xs->get_members(), resultname); + if (xceptions.size() > 0) { + indent_down(); + f_service_ << indent() << "}" << endl; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << indent() << "catch (" << type_name((*x_iter)->get_type(), false, false) << " " + << (*x_iter)->get_name() << ")" << endl + << indent() << "{" << endl; + if (!tfunction->is_oneway()) { + indent_up(); + f_service_ << indent() << "result." << prop_name(*x_iter) << " = " << (*x_iter)->get_name() + << ";" << endl; + indent_down(); + } + f_service_ << indent() << "}" << endl; + } + } + if (!tfunction->is_oneway()) { + f_service_ << indent() << "oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name() + << "\", TMessageType.Reply, seqid)); " << endl; + f_service_ << indent() << "result.Write(oprot);" << endl; + } + indent_down(); + + cleanup_member_name_mapping(xs); + + f_service_ << indent() << "}" << endl + << indent() << "catch (TTransportException)" << endl + << indent() << "{" << endl + << indent() << " throw;" << endl + << indent() << "}" << endl + << indent() << "catch (Exception ex)" << endl + << indent() << "{" << endl + << indent() << " Console.Error.WriteLine(\"Error occurred in processor:\");" << endl + << indent() << " Console.Error.WriteLine(ex.ToString());" << endl; + + if (tfunction->is_oneway()) { + f_service_ << indent() << "}" << endl; + } + else { + f_service_ << indent() << " TApplicationException x = new TApplicationException" << indent() + << "(TApplicationException.ExceptionType.InternalError,\" Internal error.\");" + << endl + << indent() << " oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name() + << "\", TMessageType.Exception, seqid));" << endl + << indent() << " x.Write(oprot);" << endl + << indent() << "}" << endl; + f_service_ << indent() << "oprot.WriteMessageEnd();" << endl + << indent() << "oprot.Transport.Flush();" << endl; + } + + scope_down(f_service_); + + f_service_ << endl; +} + +void t_csharp_generator::generate_csharp_union_reader(std::ofstream& out, t_struct* tunion) { + // Thanks to THRIFT-1768, we don't need to check for required fields in the union + const vector& fields = tunion->get_members(); + vector::const_iterator f_iter; + + indent(out) << "public static " << tunion->get_name() << " Read(TProtocol iprot)" << endl; + scope_up(out); + + out << indent() << "iprot.IncrementRecursionDepth();" << endl; + out << indent() << "try" << endl; + scope_up(out); + + indent(out) << tunion->get_name() << " retval;" << endl; + indent(out) << "iprot.ReadStructBegin();" << endl; + indent(out) << "TField field = iprot.ReadFieldBegin();" << endl; + // we cannot have the first field be a stop -- we must have a single field defined + indent(out) << "if (field.Type == TType.Stop)" << endl; + scope_up(out); + indent(out) << "iprot.ReadFieldEnd();" << endl; + indent(out) << "retval = new ___undefined();" << endl; + scope_down(out); + indent(out) << "else" << endl; + scope_up(out); + indent(out) << "switch (field.ID)" << endl; + scope_up(out); + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << "case " << (*f_iter)->get_key() << ":" << endl; + indent_up(); + indent(out) << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; + indent_up(); + + indent(out) << type_name((*f_iter)->get_type()) << " temp;" << endl; + generate_deserialize_field(out, (*f_iter), "temp", true); + indent(out) << "retval = new " << (*f_iter)->get_name() << "(temp);" << endl; + + indent_down(); + out << indent() << "} else { " << endl << indent() << " TProtocolUtil.Skip(iprot, field.Type);" + << endl << indent() << " retval = new ___undefined();" << endl << indent() << "}" << endl + << indent() << "break;" << endl; + indent_down(); + } + + indent(out) << "default: " << endl; + indent_up(); + indent(out) << "TProtocolUtil.Skip(iprot, field.Type);" << endl << indent() + << "retval = new ___undefined();" << endl; + indent(out) << "break;" << endl; + indent_down(); + + scope_down(out); + + indent(out) << "iprot.ReadFieldEnd();" << endl; + + indent(out) << "if (iprot.ReadFieldBegin().Type != TType.Stop)" << endl; + scope_up(out); + indent(out) << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl; + scope_down(out); + + // end of else for TStop + scope_down(out); + indent(out) << "iprot.ReadStructEnd();" << endl; + indent(out) << "return retval;" << endl; + indent_down(); + + scope_down(out); + out << indent() << "finally" << endl; + scope_up(out); + out << indent() << "iprot.DecrementRecursionDepth();" << endl; + scope_down(out); + + indent(out) << "}" << endl << endl; +} + +void t_csharp_generator::generate_deserialize_field(ofstream& out, + t_field* tfield, + string prefix, + bool is_propertyless) { + t_type* type = tfield->get_type(); + while (type->is_typedef()) { + type = ((t_typedef*)type)->get_type(); + } + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = prefix + (is_propertyless ? "" : prop_name(tfield)); + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name); + } else if (type->is_container()) { + generate_deserialize_container(out, type, name); + } else if (type->is_base_type() || type->is_enum()) { + indent(out) << name << " = "; + + if (type->is_enum()) { + out << "(" << type_name(type, false, true) << ")"; + } + + out << "iprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "ReadBinary();"; + } else { + out << "ReadString();"; + } + break; + case t_base_type::TYPE_BOOL: + out << "ReadBool();"; + break; + case t_base_type::TYPE_I8: + out << "ReadByte();"; + break; + case t_base_type::TYPE_I16: + out << "ReadI16();"; + break; + case t_base_type::TYPE_I32: + out << "ReadI32();"; + break; + case t_base_type::TYPE_I64: + out << "ReadI64();"; + break; + case t_base_type::TYPE_DOUBLE: + out << "ReadDouble();"; + break; + default: + throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "ReadI32();"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +void t_csharp_generator::generate_deserialize_struct(ofstream& out, + t_struct* tstruct, + string prefix) { + if (union_ && tstruct->is_union()) { + out << indent() << prefix << " = " << type_name(tstruct) << ".Read(iprot);" << endl; + } else { + out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl << indent() + << prefix << ".Read(iprot);" << endl; + } +} + +void t_csharp_generator::generate_deserialize_container(ofstream& out, + t_type* ttype, + string prefix) { + scope_up(out); + + string obj; + + if (ttype->is_map()) { + obj = tmp("_map"); + } else if (ttype->is_set()) { + obj = tmp("_set"); + } else if (ttype->is_list()) { + obj = tmp("_list"); + } + + indent(out) << prefix << " = new " << type_name(ttype, false, true) << "();" << endl; + if (ttype->is_map()) { + out << indent() << "TMap " << obj << " = iprot.ReadMapBegin();" << endl; + } else if (ttype->is_set()) { + out << indent() << "TSet " << obj << " = iprot.ReadSetBegin();" << endl; + } else if (ttype->is_list()) { + out << indent() << "TList " << obj << " = iprot.ReadListBegin();" << endl; + } + + string i = tmp("_i"); + indent(out) << "for( int " << i << " = 0; " << i << " < " << obj << ".Count" + << "; " + << "++" << i << ")" << endl; + scope_up(out); + + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, prefix); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, prefix); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, prefix); + } + + scope_down(out); + + if (ttype->is_map()) { + indent(out) << "iprot.ReadMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "iprot.ReadSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "iprot.ReadListEnd();" << endl; + } + + scope_down(out); +} + +void t_csharp_generator::generate_deserialize_map_element(ofstream& out, + t_map* tmap, + string prefix) { + string key = tmp("_key"); + string val = tmp("_val"); + + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + indent(out) << declare_field(&fkey) << endl; + indent(out) << declare_field(&fval) << endl; + + generate_deserialize_field(out, &fkey); + generate_deserialize_field(out, &fval); + + indent(out) << prefix << "[" << key << "] = " << val << ";" << endl; +} + +void t_csharp_generator::generate_deserialize_set_element(ofstream& out, + t_set* tset, + string prefix) { + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); + + indent(out) << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".Add(" << elem << ");" << endl; +} + +void t_csharp_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix) { + string elem = tmp("_elem"); + t_field felem(tlist->get_elem_type(), elem); + + indent(out) << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".Add(" << elem << ");" << endl; +} + +void t_csharp_generator::generate_serialize_field(ofstream& out, + t_field* tfield, + string prefix, + bool is_element, + bool is_propertyless) { + t_type* type = tfield->get_type(); + while (type->is_typedef()) { + type = ((t_typedef*)type)->get_type(); + } + + string name = prefix + (is_propertyless ? "" : prop_name(tfield)); + + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name; + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, name); + } else if (type->is_container()) { + generate_serialize_container(out, type, name); + } else if (type->is_base_type() || type->is_enum()) { + indent(out) << "oprot."; + + string nullable_name = nullable_ && !is_element && !field_is_required(tfield) ? name + ".Value" + : name; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "WriteBinary("; + } else { + out << "WriteString("; + } + out << name << ");"; + break; + case t_base_type::TYPE_BOOL: + out << "WriteBool(" << nullable_name << ");"; + break; + case t_base_type::TYPE_I8: + out << "WriteByte(" << nullable_name << ");"; + break; + case t_base_type::TYPE_I16: + out << "WriteI16(" << nullable_name << ");"; + break; + case t_base_type::TYPE_I32: + out << "WriteI32(" << nullable_name << ");"; + break; + case t_base_type::TYPE_I64: + out << "WriteI64(" << nullable_name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "WriteDouble(" << nullable_name << ");"; + break; + default: + throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "WriteI32((int)" << nullable_name << ");"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n", + prefix.c_str(), + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +void t_csharp_generator::generate_serialize_struct(ofstream& out, + t_struct* tstruct, + string prefix) { + (void)tstruct; + out << indent() << prefix << ".Write(oprot);" << endl; +} + +void t_csharp_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + scope_up(out); + + if (ttype->is_map()) { + indent(out) << "oprot.WriteMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type()) + << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix + << ".Count));" << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.WriteSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type()) + << ", " << prefix << ".Count));" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.WriteListBegin(new TList(" + << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".Count));" + << endl; + } + + string iter = tmp("_iter"); + if (ttype->is_map()) { + indent(out) << "foreach (" << type_name(((t_map*)ttype)->get_key_type()) << " " << iter + << " in " << prefix << ".Keys)"; + } else if (ttype->is_set()) { + indent(out) << "foreach (" << type_name(((t_set*)ttype)->get_elem_type()) << " " << iter + << " in " << prefix << ")"; + } else if (ttype->is_list()) { + indent(out) << "foreach (" << type_name(((t_list*)ttype)->get_elem_type()) << " " << iter + << " in " << prefix << ")"; + } + + out << endl; + scope_up(out); + + if (ttype->is_map()) { + generate_serialize_map_element(out, (t_map*)ttype, iter, prefix); + } else if (ttype->is_set()) { + generate_serialize_set_element(out, (t_set*)ttype, iter); + } else if (ttype->is_list()) { + generate_serialize_list_element(out, (t_list*)ttype, iter); + } + + scope_down(out); + + if (ttype->is_map()) { + indent(out) << "oprot.WriteMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.WriteSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.WriteListEnd();" << endl; + } + + scope_down(out); +} + +void t_csharp_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string iter, + string map) { + t_field kfield(tmap->get_key_type(), iter); + generate_serialize_field(out, &kfield, "", true); + t_field vfield(tmap->get_val_type(), map + "[" + iter + "]"); + generate_serialize_field(out, &vfield, "", true); +} + +void t_csharp_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) { + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, &efield, "", true); +} + +void t_csharp_generator::generate_serialize_list_element(ofstream& out, + t_list* tlist, + string iter) { + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, &efield, "", true); +} + +void t_csharp_generator::generate_property(ofstream& out, + t_field* tfield, + bool isPublic, + bool generateIsset) { + generate_csharp_property(out, tfield, isPublic, generateIsset, "_"); +} +void t_csharp_generator::generate_csharp_property(ofstream& out, + t_field* tfield, + bool isPublic, + bool generateIsset, + std::string fieldPrefix) { + if ((serialize_ || wcf_) && isPublic) { + indent(out) << "[DataMember(Order = 0)]" << endl; + } + bool has_default = field_has_default(tfield); + bool is_required = field_is_required(tfield); + if ((nullable_ && !has_default) || (is_required)) { + indent(out) << (isPublic ? "public " : "private ") + << type_name(tfield->get_type(), false, false, true, is_required) << " " + << prop_name(tfield) << " { get; set; }" << endl; + } else { + indent(out) << (isPublic ? "public " : "private ") + << type_name(tfield->get_type(), false, false, true) << " " << prop_name(tfield) + << endl; + scope_up(out); + indent(out) << "get" << endl; + scope_up(out); + bool use_nullable = false; + if (nullable_) { + t_type* ttype = tfield->get_type(); + while (ttype->is_typedef()) { + ttype = ((t_typedef*)ttype)->get_type(); + } + if (ttype->is_base_type()) { + use_nullable = ((t_base_type*)ttype)->get_base() != t_base_type::TYPE_STRING; + } else if (ttype->is_enum()) { + use_nullable = true; + } + } + indent(out) << "return " << fieldPrefix + tfield->get_name() << ";" << endl; + scope_down(out); + indent(out) << "set" << endl; + scope_up(out); + if (use_nullable) { + if (generateIsset) { + indent(out) << "__isset." << normalize_name(tfield->get_name()) << " = value.HasValue;" + << endl; + } + indent(out) << "if (value.HasValue) this." << fieldPrefix + tfield->get_name() + << " = value.Value;" << endl; + } else { + if (generateIsset) { + indent(out) << "__isset." << normalize_name(tfield->get_name()) << " = true;" << endl; + } + indent(out) << "this." << fieldPrefix + tfield->get_name() << " = value;" << endl; + } + scope_down(out); + scope_down(out); + } + out << endl; +} + +std::string t_csharp_generator::make_valid_csharp_identifier(std::string const& fromName) { + std::string str = fromName; + if (str.empty()) { + return str; + } + + // tests rely on this + assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9')); + + // if the first letter is a number, we add an additional underscore in front of it + char c = str.at(0); + if (('0' <= c) && (c <= '9')) { + str = "_" + str; + } + + // following chars: letter, number or underscore + for (size_t i = 0; i < str.size(); ++i) { + c = str.at(i); + if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9')) + && ('_' != c)) { + str.replace(i, 1, "_"); + } + } + + return str; +} + +void t_csharp_generator::cleanup_member_name_mapping(void* scope) { + if( member_mapping_scopes.empty()) { + throw "internal error: cleanup_member_name_mapping() no scope active"; + } + + member_mapping_scope& active = member_mapping_scopes.back(); + if (active.scope_member != scope) { + throw "internal error: cleanup_member_name_mapping() called for wrong struct"; + } + + member_mapping_scopes.pop_back(); +} + +string t_csharp_generator::get_mapped_member_name(string name) { + if( ! member_mapping_scopes.empty()) { + member_mapping_scope& active = member_mapping_scopes.back(); + map::iterator iter = active.mapping_table.find(name); + if (active.mapping_table.end() != iter) { + return iter->second; + } + } + + pverbose("no mapping for member %s\n", name.c_str()); + return name; +} + +void t_csharp_generator::prepare_member_name_mapping(t_struct* tstruct) { + prepare_member_name_mapping(tstruct, tstruct->get_members(), tstruct->get_name()); +} + +void t_csharp_generator::prepare_member_name_mapping(void* scope, + const vector& members, + const string& structname) { + // begin new scope + member_mapping_scope dummy; + dummy.scope_member = 0; + member_mapping_scopes.push_back(dummy); + member_mapping_scope& active = member_mapping_scopes.back(); + active.scope_member = scope; + + // current C# generator policy: + // - prop names are always rendered with an Uppercase first letter + // - struct names are used as given + std::set used_member_names; + vector::const_iterator iter; + + // prevent name conflicts with struct (CS0542 error) + used_member_names.insert(structname); + + // prevent name conflicts with known methods (THRIFT-2942) + used_member_names.insert("Read"); + used_member_names.insert("Write"); + + for (iter = members.begin(); iter != members.end(); ++iter) { + string oldname = (*iter)->get_name(); + string newname = prop_name(*iter, true); + while (true) { + + // new name conflicts with another member + if (used_member_names.find(newname) != used_member_names.end()) { + pverbose("struct %s: member %s conflicts with another member\n", + structname.c_str(), + newname.c_str()); + newname += '_'; + continue; + } + + // add always, this helps us to detect edge cases like + // different spellings ("foo" and "Foo") within the same struct + pverbose("struct %s: member mapping %s => %s\n", + structname.c_str(), + oldname.c_str(), + newname.c_str()); + active.mapping_table[oldname] = newname; + used_member_names.insert(newname); + break; + } + } +} + +std::string t_csharp_generator::prop_name(t_field* tfield, bool suppress_mapping) { + string name(tfield->get_name()); + if (suppress_mapping) { + name[0] = toupper(name[0]); + } else { + name = get_mapped_member_name(name); + } + return name; +} + +string t_csharp_generator::type_name(t_type* ttype, + bool in_container, + bool in_init, + bool in_param, + bool is_required) { + (void)in_init; + while (ttype->is_typedef()) { + ttype = ((t_typedef*)ttype)->get_type(); + } + + if (ttype->is_base_type()) { + return base_type_name((t_base_type*)ttype, in_container, in_param, is_required); + } else if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + return "Dictionary<" + type_name(tmap->get_key_type(), true) + ", " + + type_name(tmap->get_val_type(), true) + ">"; + } else if (ttype->is_set()) { + t_set* tset = (t_set*)ttype; + return "THashSet<" + type_name(tset->get_elem_type(), true) + ">"; + } else if (ttype->is_list()) { + t_list* tlist = (t_list*)ttype; + return "List<" + type_name(tlist->get_elem_type(), true) + ">"; + } + + t_program* program = ttype->get_program(); + string postfix = (!is_required && nullable_ && in_param && ttype->is_enum()) ? "?" : ""; + if (program != NULL && program != program_) { + string ns = program->get_namespace("csharp"); + if (!ns.empty()) { + return ns + "." + normalize_name(ttype->get_name()) + postfix; + } + } + + return normalize_name(ttype->get_name()) + postfix; +} + +string t_csharp_generator::base_type_name(t_base_type* tbase, + bool in_container, + bool in_param, + bool is_required) { + (void)in_container; + string postfix = (!is_required && nullable_ && in_param) ? "?" : ""; + switch (tbase->get_base()) { + case t_base_type::TYPE_VOID: + return "void"; + case t_base_type::TYPE_STRING: + if (tbase->is_binary()) { + return "byte[]"; + } else { + return "string"; + } + case t_base_type::TYPE_BOOL: + return "bool" + postfix; + case t_base_type::TYPE_I8: + return "sbyte" + postfix; + case t_base_type::TYPE_I16: + return "short" + postfix; + case t_base_type::TYPE_I32: + return "int" + postfix; + case t_base_type::TYPE_I64: + return "long" + postfix; + case t_base_type::TYPE_DOUBLE: + return "double" + postfix; + default: + throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase->get_base()); + } +} + +string t_csharp_generator::declare_field(t_field* tfield, bool init, std::string prefix) { + string result = type_name(tfield->get_type()) + " " + prefix + tfield->get_name(); + if (init) { + t_type* ttype = tfield->get_type(); + while (ttype->is_typedef()) { + ttype = ((t_typedef*)ttype)->get_type(); + } + if (ttype->is_base_type() && field_has_default(tfield)) { + ofstream dummy; + result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value()); + } else if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + result += " = null"; + break; + case t_base_type::TYPE_BOOL: + result += " = false"; + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + result += " = 0"; + break; + case t_base_type::TYPE_DOUBLE: + result += " = (double)0"; + break; + } + } else if (ttype->is_enum()) { + result += " = (" + type_name(ttype, false, true) + ")0"; + } else if (ttype->is_container()) { + result += " = new " + type_name(ttype, false, true) + "()"; + } else { + result += " = new " + type_name(ttype, false, true) + "()"; + } + } + return result + ";"; +} + +string t_csharp_generator::function_signature(t_function* tfunction, string prefix) { + t_type* ttype = tfunction->get_returntype(); + return type_name(ttype) + " " + normalize_name(prefix + tfunction->get_name()) + "(" + + argument_list(tfunction->get_arglist()) + ")"; +} + +string t_csharp_generator::function_signature_async_begin(t_function* tfunction, string prefix) { + string comma = (tfunction->get_arglist()->get_members().size() > 0 ? ", " : ""); + return "IAsyncResult " + normalize_name(prefix + tfunction->get_name()) + + "(AsyncCallback callback, object state" + comma + argument_list(tfunction->get_arglist()) + + ")"; +} + +string t_csharp_generator::function_signature_async_end(t_function* tfunction, string prefix) { + t_type* ttype = tfunction->get_returntype(); + return type_name(ttype) + " " + normalize_name(prefix + tfunction->get_name()) + + "(IAsyncResult asyncResult)"; +} + +string t_csharp_generator::function_signature_async(t_function* tfunction, string prefix) { + t_type* ttype = tfunction->get_returntype(); + string task = "Task"; + if (!ttype->is_void()) + task += "<" + type_name(ttype) + ">"; + return task + " " + normalize_name(prefix + tfunction->get_name()) + "Async(" + + argument_list(tfunction->get_arglist()) + ")"; +} + +string t_csharp_generator::argument_list(t_struct* tstruct) { + string result = ""; + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + result += type_name((*f_iter)->get_type()) + " " + normalize_name((*f_iter)->get_name()); + } + return result; +} + +string t_csharp_generator::type_to_enum(t_type* type) { + while (type->is_typedef()) { + type = ((t_typedef*)type)->get_type(); + } + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "TType.String"; + case t_base_type::TYPE_BOOL: + return "TType.Bool"; + case t_base_type::TYPE_I8: + return "TType.Byte"; + case t_base_type::TYPE_I16: + return "TType.I16"; + case t_base_type::TYPE_I32: + return "TType.I32"; + case t_base_type::TYPE_I64: + return "TType.I64"; + case t_base_type::TYPE_DOUBLE: + return "TType.Double"; + } + } else if (type->is_enum()) { + return "TType.I32"; + } else if (type->is_struct() || type->is_xception()) { + return "TType.Struct"; + } else if (type->is_map()) { + return "TType.Map"; + } else if (type->is_set()) { + return "TType.Set"; + } else if (type->is_list()) { + return "TType.List"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +void t_csharp_generator::generate_csharp_docstring_comment(ofstream& out, string contents) { + generate_docstring_comment(out, "/// \n", "/// ", contents, "/// \n"); +} + +void t_csharp_generator::generate_csharp_doc(ofstream& out, t_field* field) { + if (field->get_type()->is_enum()) { + string combined_message = field->get_doc() + "\nget_type()) + "\"/>"; + generate_csharp_docstring_comment(out, combined_message); + } else { + generate_csharp_doc(out, (t_doc*)field); + } +} + +void t_csharp_generator::generate_csharp_doc(ofstream& out, t_doc* tdoc) { + if (tdoc->has_doc()) { + generate_csharp_docstring_comment(out, tdoc->get_doc()); + } +} + +void t_csharp_generator::generate_csharp_doc(ofstream& out, t_function* tfunction) { + if (tfunction->has_doc()) { + stringstream ps; + const vector& fields = tfunction->get_arglist()->get_members(); + vector::const_iterator p_iter; + for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { + t_field* p = *p_iter; + ps << "\nget_name() << "\">"; + if (p->has_doc()) { + std::string str = p->get_doc(); + str.erase(std::remove(str.begin(), str.end(), '\n'), + str.end()); // remove the newlines that appear from the parser + ps << str; + } + ps << ""; + } + generate_docstring_comment(out, + "", + "/// ", + "\n" + tfunction->get_doc() + "" + ps.str(), + ""); + } +} + +std::string t_csharp_generator::get_enum_class_name(t_type* type) { + string package = ""; + t_program* program = type->get_program(); + if (program != NULL && program != program_) { + package = program->get_namespace("csharp") + "."; + } + return package + type->get_name(); +} + + +THRIFT_REGISTER_GENERATOR( + csharp, + "C#", + " async: Adds Async support using Task.Run.\n" + " wcf: Adds bindings for WCF to generated classes.\n" + " serial: Add serialization support to generated classes.\n" + " nullable: Use nullable types for properties.\n" + " hashcode: Generate a hashcode and equals implementation for classes.\n" + " union: Use new union typing, which includes a static read function for union " + "types.\n") diff --git a/compiler/cpp/src/thrift/generate/t_d_generator.cc b/compiler/cpp/src/thrift/generate/t_d_generator.cc new file mode 100644 index 0000000..35f611d --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_d_generator.cc @@ -0,0 +1,742 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostream; +using std::ostringstream; +using std::set; +using std::string; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * D code generator. + * + * generate_*() functions are called by the base class to emit code for the + * given entity, print_*() functions write a piece of code to the passed + * stream, and render_*() return a string containing the D representation of + * the passed entity. + */ +class t_d_generator : public t_oop_generator { +public: + t_d_generator(t_program* program, + const std::map& parsed_options, + const string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + /* no options yet */ + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + throw "unknown option d:" + iter->first; + } + + out_dir_base_ = "gen-d"; + } + +protected: + virtual void init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + + string dir = program_->get_namespace("d"); + string subdir = get_out_dir(); + string::size_type loc; + while ((loc = dir.find(".")) != string::npos) { + subdir = subdir + "/" + dir.substr(0, loc); + MKDIR(subdir.c_str()); + dir = dir.substr(loc + 1); + } + if (!dir.empty()) { + subdir = subdir + "/" + dir; + MKDIR(subdir.c_str()); + } + + package_dir_ = subdir + "/"; + + // Make output file + string f_types_name = package_dir_ + program_name_ + "_types.d"; + f_types_.open(f_types_name.c_str()); + + // Print header + f_types_ << autogen_comment() << "module " << render_package(*program_) << program_name_ + << "_types;" << endl << endl; + + print_default_imports(f_types_); + + // Include type modules from other imported programs. + const vector& includes = program_->get_includes(); + for (size_t i = 0; i < includes.size(); ++i) { + f_types_ << "public import " << render_package(*(includes[i])) << includes[i]->get_name() + << "_types;" << endl; + } + if (!includes.empty()) + f_types_ << endl; + } + + virtual void close_generator() { + // Close output file + f_types_.close(); + } + + virtual void generate_consts(std::vector consts) { + if (!consts.empty()) { + string f_consts_name = package_dir_ + program_name_ + "_constants.d"; + ofstream f_consts; + f_consts.open(f_consts_name.c_str()); + + f_consts << autogen_comment() << "module " << render_package(*program_) << program_name_ + << "_constants;" << endl << endl; + + print_default_imports(f_consts); + + f_consts << "import " << render_package(*get_program()) << program_name_ << "_types;" << endl + << endl; + + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + this->emit_doc(*c_iter, f_consts); + string name = (*c_iter)->get_name(); + t_type* type = (*c_iter)->get_type(); + indent(f_consts) << "immutable(" << render_type_name(type) << ") " << name << ";" << endl; + } + + f_consts << endl << "static this() {" << endl; + indent_up(); + + bool first = true; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + if (first) { + first = false; + } else { + f_consts << endl; + } + t_type* type = (*c_iter)->get_type(); + indent(f_consts) << (*c_iter)->get_name() << " = "; + if (!is_immutable_type(type)) { + f_consts << "cast(immutable(" << render_type_name(type) << ")) "; + } + f_consts << render_const_value(type, (*c_iter)->get_value()) << ";" << endl; + } + indent_down(); + indent(f_consts) << "}" << endl; + } + } + + virtual void generate_typedef(t_typedef* ttypedef) { + this->emit_doc(ttypedef, f_types_); + f_types_ << indent() << "alias " << render_type_name(ttypedef->get_type()) << " " + << ttypedef->get_symbolic() << ";" << endl << endl; + } + + virtual void generate_enum(t_enum* tenum) { + vector constants = tenum->get_constants(); + + this->emit_doc(tenum, f_types_); + string enum_name = tenum->get_name(); + f_types_ << indent() << "enum " << enum_name << " {" << endl; + + indent_up(); + + vector::const_iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + this->emit_doc(*c_iter, f_types_); + indent(f_types_) << (*c_iter)->get_name(); + f_types_ << " = " << (*c_iter)->get_value() << ","; + } + + f_types_ << endl; + indent_down(); + indent(f_types_) << "}" << endl; + + f_types_ << endl; + } + + virtual void generate_struct(t_struct* tstruct) { + print_struct_definition(f_types_, tstruct, false); + } + + virtual void generate_xception(t_struct* txception) { + print_struct_definition(f_types_, txception, true); + } + + virtual void generate_service(t_service* tservice) { + string svc_name = tservice->get_name(); + + // Service implementation file includes + string f_servicename = package_dir_ + svc_name + ".d"; + std::ofstream f_service; + f_service.open(f_servicename.c_str()); + f_service << autogen_comment() << "module " << render_package(*program_) << svc_name << ";" + << endl << endl; + + print_default_imports(f_service); + + f_service << "import " << render_package(*get_program()) << program_name_ << "_types;" << endl; + + t_service* extends_service = tservice->get_extends(); + if (extends_service != NULL) { + f_service << "import " << render_package(*(extends_service->get_program())) + << extends_service->get_name() << ";" << endl; + } + + f_service << endl; + + string extends = ""; + if (tservice->get_extends() != NULL) { + extends = " : " + render_type_name(tservice->get_extends()); + } + + this->emit_doc(tservice, f_service); + f_service << indent() << "interface " << svc_name << extends << " {" << endl; + indent_up(); + + // Collect all the exception types service methods can throw so we can + // emit the necessary aliases later. + set exception_types; + + // Print the method signatures. + vector functions = tservice->get_functions(); + vector::iterator fn_iter; + for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) { + this->emit_doc(*fn_iter, f_service); + f_service << indent(); + print_function_signature(f_service, *fn_iter); + f_service << ";" << endl; + + const vector& exceptions = (*fn_iter)->get_xceptions()->get_members(); + vector::const_iterator ex_iter; + for (ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter) { + exception_types.insert((*ex_iter)->get_type()); + } + } + + // Alias the exception types into the current scope. + if (!exception_types.empty()) + f_service << endl; + set::const_iterator et_iter; + for (et_iter = exception_types.begin(); et_iter != exception_types.end(); ++et_iter) { + indent(f_service) << "alias " << render_package(*(*et_iter)->get_program()) + << (*et_iter)->get_program()->get_name() << "_types" + << "." << (*et_iter)->get_name() << " " << (*et_iter)->get_name() << ";" + << endl; + } + + // Write the method metadata. + ostringstream meta; + indent_up(); + bool first = true; + for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) { + if ((*fn_iter)->get_arglist()->get_members().empty() + && (*fn_iter)->get_xceptions()->get_members().empty() && !(*fn_iter)->is_oneway()) { + continue; + } + + if (first) { + first = false; + } else { + meta << ","; + } + + meta << endl << indent() << "TMethodMeta(`" << (*fn_iter)->get_name() << "`, " << endl; + indent_up(); + indent(meta) << "["; + + bool first = true; + const vector& params = (*fn_iter)->get_arglist()->get_members(); + vector::const_iterator p_iter; + for (p_iter = params.begin(); p_iter != params.end(); ++p_iter) { + if (first) { + first = false; + } else { + meta << ", "; + } + + meta << "TParamMeta(`" << (*p_iter)->get_name() << "`, " << (*p_iter)->get_key(); + + t_const_value* cv = (*p_iter)->get_value(); + if (cv != NULL) { + meta << ", q{" << render_const_value((*p_iter)->get_type(), cv) << "}"; + } + meta << ")"; + } + + meta << "]"; + + if (!(*fn_iter)->get_xceptions()->get_members().empty() || (*fn_iter)->is_oneway()) { + meta << "," << endl << indent() << "["; + + bool first = true; + const vector& exceptions = (*fn_iter)->get_xceptions()->get_members(); + vector::const_iterator ex_iter; + for (ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter) { + if (first) { + first = false; + } else { + meta << ", "; + } + + meta << "TExceptionMeta(`" << (*ex_iter)->get_name() << "`, " << (*ex_iter)->get_key() + << ", `" << (*ex_iter)->get_type()->get_name() << "`)"; + } + + meta << "]"; + } + + if ((*fn_iter)->is_oneway()) { + meta << "," << endl << indent() << "TMethodType.ONEWAY"; + } + + indent_down(); + meta << endl << indent() << ")"; + } + indent_down(); + + string meta_str(meta.str()); + if (!meta_str.empty()) { + f_service << endl << indent() << "enum methodMeta = [" << meta_str << endl << indent() << "];" + << endl; + } + + indent_down(); + indent(f_service) << "}" << endl; + + // Server skeleton generation. + string f_skeletonname = package_dir_ + svc_name + "_server.skeleton.d"; + std::ofstream f_skeleton; + f_skeleton.open(f_skeletonname.c_str()); + print_server_skeleton(f_skeleton, tservice); + f_skeleton.close(); + } + + void emit_doc(t_doc *doc, std::ofstream& out) { + if (!doc->has_doc()) { + return; + } + indent(out) << "/**" << std::endl; + indent_up(); + // No endl -- comments reliably have a newline at the end. + // This is true even for stuff like: + // /** method infos */ void foo(/** huh?*/ 1: i64 stuff) + indent(out) << doc->get_doc(); + indent_down(); + indent(out) << "*/" << std::endl; + } + +private: + /** + * Writes a server skeleton for the passed service to out. + */ + void print_server_skeleton(ostream& out, t_service* tservice) { + string svc_name = tservice->get_name(); + + out << "/*" << endl + << " * This auto-generated skeleton file illustrates how to build a server. If you" << endl + << " * intend to customize it, you should edit a copy with another file name to " << endl + << " * avoid overwriting it when running the generator again." << endl << " */" << endl + << "module " << render_package(*tservice->get_program()) << svc_name << "_server;" << endl + << endl << "import std.stdio;" << endl << "import thrift.codegen.processor;" << endl + << "import thrift.protocol.binary;" << endl << "import thrift.server.simple;" << endl + << "import thrift.server.transport.socket;" << endl << "import thrift.transport.buffered;" + << endl << "import thrift.util.hashset;" << endl << endl << "import " + << render_package(*tservice->get_program()) << svc_name << ";" << endl << "import " + << render_package(*get_program()) << program_name_ << "_types;" << endl << endl << endl + << "class " << svc_name << "Handler : " << svc_name << " {" << endl; + + indent_up(); + out << indent() << "this() {" << endl << indent() << " // Your initialization goes here." + << endl << indent() << "}" << endl << endl; + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + out << indent(); + print_function_signature(out, *f_iter); + out << " {" << endl; + + indent_up(); + + out << indent() << "// Your implementation goes here." << endl << indent() << "writeln(\"" + << (*f_iter)->get_name() << " called\");" << endl; + + t_type* rt = (*f_iter)->get_returntype(); + if (!rt->is_void()) { + indent(out) << "return typeof(return).init;" << endl; + } + + indent_down(); + + out << indent() << "}" << endl << endl; + } + + indent_down(); + out << "}" << endl << endl; + + out << indent() << "void main() {" << endl; + indent_up(); + out << indent() << "auto protocolFactory = new TBinaryProtocolFactory!();" << endl << indent() + << "auto processor = new TServiceProcessor!" << svc_name << "(new " << svc_name + << "Handler);" << endl << indent() << "auto serverTransport = new TServerSocket(9090);" + << endl << indent() << "auto transportFactory = new TBufferedTransportFactory;" << endl + << indent() << "auto server = new TSimpleServer(" << endl << indent() + << " processor, serverTransport, transportFactory, protocolFactory);" << endl << indent() + << "server.serve();" << endl; + indent_down(); + out << "}" << endl; + } + + /** + * Writes the definition of a struct or an exception type to out. + */ + void print_struct_definition(ostream& out, t_struct* tstruct, bool is_exception) { + const vector& members = tstruct->get_members(); + + if (is_exception) { + indent(out) << "class " << tstruct->get_name() << " : TException {" << endl; + } else { + indent(out) << "struct " << tstruct->get_name() << " {" << endl; + } + indent_up(); + + // Declare all fields. + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << render_type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name() << ";" + << endl; + } + + if (!members.empty()) + indent(out) << endl; + indent(out) << "mixin TStructHelpers!("; + + if (!members.empty()) { + // If there are any fields, construct the TFieldMeta array to pass to + // TStructHelpers. We can't just pass an empty array if not because [] + // doesn't pass the TFieldMeta[] constraint. + out << "["; + indent_up(); + + bool first = true; + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (first) { + first = false; + } else { + out << ","; + } + out << endl; + + indent(out) << "TFieldMeta(`" << (*m_iter)->get_name() << "`, " << (*m_iter)->get_key(); + + t_const_value* cv = (*m_iter)->get_value(); + t_field::e_req req = (*m_iter)->get_req(); + out << ", " << render_req(req); + if (cv != NULL) { + out << ", q{" << render_const_value((*m_iter)->get_type(), cv) << "}"; + } + out << ")"; + } + + indent_down(); + out << endl << indent() << "]"; + } + + out << ");" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; + } + + /** + * Prints the D function signature (including return type) for the given + * method. + */ + void print_function_signature(ostream& out, t_function* fn) { + out << render_type_name(fn->get_returntype()) << " " << fn->get_name() << "("; + + const vector& fields = fn->get_arglist()->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + out << ", "; + } + out << render_type_name((*f_iter)->get_type(), true) << " " << (*f_iter)->get_name(); + } + + out << ")"; + } + + /** + * Returns the D representation of value. The result is guaranteed to be a + * single expression; for complex types, immediately called delegate + * literals are used to achieve this. + */ + string render_const_value(t_type* type, t_const_value* value) { + // Resolve any typedefs. + type = get_true_type(type); + + ostringstream out; + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + out << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + out << ((value->get_integer() > 0) ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + out << "cast(" << render_type_name(type) << ")" << value->get_integer(); + break; + case t_base_type::TYPE_I32: + out << value->get_integer(); + break; + case t_base_type::TYPE_I64: + out << value->get_integer() << "L"; + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + out << value->get_integer(); + } else { + out << value->get_double(); + } + break; + default: + throw "Compiler error: No const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "cast(" << render_type_name(type) << ")" << value->get_integer(); + } else { + out << "{" << endl; + indent_up(); + + indent(out) << render_type_name(type) << " v;" << endl; + if (type->is_struct() || type->is_xception()) { + indent(out) << "v = " << (type->is_xception() ? "new " : "") << render_type_name(type) + << "();" << endl; + + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "Type error: " + type->get_name() + " has no field " + + v_iter->first->get_string(); + } + string val = render_const_value(field_type, v_iter->second); + indent(out) << "v.set!`" << v_iter->first->get_string() << "`(" << val << ");" << endl; + } + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string key = render_const_value(ktype, v_iter->first); + string val = render_const_value(vtype, v_iter->second); + indent(out) << "v["; + if (!is_immutable_type(ktype)) { + out << "cast(immutable(" << render_type_name(ktype) << "))"; + } + out << key << "] = " << val << ";" << endl; + } + } else if (type->is_list()) { + t_type* etype = ((t_list*)type)->get_elem_type(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(etype, *v_iter); + indent(out) << "v ~= " << val << ";" << endl; + } + } else if (type->is_set()) { + t_type* etype = ((t_set*)type)->get_elem_type(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(etype, *v_iter); + indent(out) << "v ~= " << val << ";" << endl; + } + } else { + throw "Compiler error: Invalid type in render_const_value: " + type->get_name(); + } + indent(out) << "return v;" << endl; + + indent_down(); + indent(out) << "}()"; + } + + return out.str(); + } + + /** + * Returns the D package to which modules for program are written (with a + * trailing dot, if not empty). + */ + string render_package(const t_program& program) const { + string package = program.get_namespace("d"); + if (package.size() == 0) + return ""; + return package + "."; + } + + /** + * Returns the name of the D repesentation of ttype. + * + * If isArg is true, a const reference to the type will be returned for + * structs. + */ + string render_type_name(const t_type* ttype, bool isArg = false) const { + if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + return "void"; + case t_base_type::TYPE_STRING: + return "string"; + case t_base_type::TYPE_BOOL: + return "bool"; + case t_base_type::TYPE_I8: + return "byte"; + case t_base_type::TYPE_I16: + return "short"; + case t_base_type::TYPE_I32: + return "int"; + case t_base_type::TYPE_I64: + return "long"; + case t_base_type::TYPE_DOUBLE: + return "double"; + default: + throw "Compiler error: No D type name for base type " + t_base_type::t_base_name(tbase); + } + } + + if (ttype->is_container()) { + t_container* tcontainer = (t_container*)ttype; + if (tcontainer->has_cpp_name()) { + return tcontainer->get_cpp_name(); + } else if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + t_type* ktype = tmap->get_key_type(); + + string name = render_type_name(tmap->get_val_type()) + "["; + if (!is_immutable_type(ktype)) { + name += "immutable("; + } + name += render_type_name(ktype); + if (!is_immutable_type(ktype)) { + name += ")"; + } + name += "]"; + return name; + } else if (ttype->is_set()) { + t_set* tset = (t_set*)ttype; + return "HashSet!(" + render_type_name(tset->get_elem_type()) + ")"; + } else if (ttype->is_list()) { + t_list* tlist = (t_list*)ttype; + return render_type_name(tlist->get_elem_type()) + "[]"; + } + } + + if (ttype->is_struct() && isArg) { + return "ref const(" + ttype->get_name() + ")"; + } else { + return ttype->get_name(); + } + } + + /** + * Returns the D TReq enum member corresponding to req. + */ + string render_req(t_field::e_req req) const { + switch (req) { + case t_field::T_OPT_IN_REQ_OUT: + return "TReq.OPT_IN_REQ_OUT"; + case t_field::T_OPTIONAL: + return "TReq.OPTIONAL"; + case t_field::T_REQUIRED: + return "TReq.REQUIRED"; + default: { + std::stringstream ss; + ss << "Compiler error: Invalid requirement level " << req; + throw ss.str(); + } + } + } + + /** + * Writes the default list of imports (which are written to every generated + * module) to f. + */ + void print_default_imports(ostream& out) { + indent(out) << "import thrift.base;" << endl << "import thrift.codegen.base;" << endl + << "import thrift.util.hashset;" << endl << endl; + } + + /** + * Returns whether type is »intrinsically immutable«, in the sense that + * a value of that type is implicitly castable to immutable(type), and it is + * allowed for AA keys without an immutable() qualifier. + */ + bool is_immutable_type(t_type* type) const { + t_type* ttype = get_true_type(type); + return ttype->is_base_type() || ttype->is_enum(); + } + + /* + * File streams, stored here to avoid passing them as parameters to every + * function. + */ + ofstream f_types_; + ofstream f_header_; + + string package_dir_; +}; + +THRIFT_REGISTER_GENERATOR(d, "D", "") diff --git a/compiler/cpp/src/thrift/generate/t_dart_generator.cc b/compiler/cpp/src/thrift/generate/t_dart_generator.cc new file mode 100644 index 0000000..f7bd1c2 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_dart_generator.cc @@ -0,0 +1,2516 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes +static const string endl2 = "\n\n"; + +/** + * Use the current Thrift version for static libraries. When releasing, update + * the version in these files. + * - lib/dart/pubspec.yaml + * - test/dart/test_client/pubspec.yaml + * - tutorial/dart/client/pubspec.yaml + * - tutorial/dart/console_client/pubspec.yaml + * - tutorial/dart/server/pubspec.yaml + * See https://thrift.apache.org/docs/committers/HowToVersion + */ +static const string dart_thrift_version = THRIFT_VERSION; + +/* forward declarations */ +string initial_caps_to_underscores(string name); + +/** + * Dart code generator + * + */ +class t_dart_generator : public t_oop_generator { +public: + t_dart_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + library_name_ = ""; + library_prefix_ = ""; + package_prefix_ = ""; + pubspec_lib_ = ""; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("library_name") == 0) { + library_name_ = (iter->second); + } else if( iter->first.compare("library_prefix") == 0) { + library_prefix_ = (iter->second) + "."; + package_prefix_ = replace_all(library_prefix_, ".", "/"); + } else if( iter->first.compare("pubspec_lib") == 0) { + pubspec_lib_ = (iter->second); + } else { + throw "unknown option dart:" + iter->first; + } + } + + out_dir_base_ = "gen-dart"; + } + + void scope_up(std::ostream& out, std::string prefix=" ") { + out << prefix << "{" << endl; + indent_up(); + } + + void scope_down(std::ostream& out, std::string postfix=endl) { + indent_down(); + indent(out) << "}" << postfix; + } + + string replace_all(string contents, string search, string repl) { + string str(contents); + + size_t slen = search.length(); + size_t rlen = repl.length(); + size_t incr = (rlen > 0) ? rlen : 1; + + if (slen > 0) { + size_t found = str.find(search); + while ((found != string::npos) && (found < str.length())) { + str.replace(found, slen, repl); + found = str.find(search, found + incr); + } + } + + return str; + } + + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + void export_class_to_library(string file_name, string class_name); + + void generate_dart_library(); + void generate_dart_pubspec(); + + void generate_consts(std::vector consts); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + void print_const_value(std::ofstream& out, + std::string name, + t_type* type, + t_const_value* value, + bool in_static, + bool defval = false); + std::string render_const_value(ofstream& out, + std::string name, + t_type* type, + t_const_value* value); + + /** + * Service-level generation functions + */ + + void generate_dart_struct(t_struct* tstruct, bool is_exception); + + void generate_dart_struct_definition(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false, + bool is_result = false, + string export_file_name = ""); + void generate_dart_struct_reader(std::ofstream& out, t_struct* tstruct); + void generate_dart_validator(std::ofstream& out, t_struct* tstruct); + void generate_dart_struct_result_writer(std::ofstream& out, t_struct* tstruct); + void generate_dart_struct_writer(std::ofstream& out, t_struct* tstruct); + void generate_dart_struct_tostring(std::ofstream& out, t_struct* tstruct); + std::string get_dart_type_string(t_type* type); + void generate_generic_field_getters(std::ofstream& out, t_struct* tstruct); + void generate_generic_field_setters(std::ofstream& out, t_struct* tstruct); + void generate_generic_isset_method(std::ofstream& out, t_struct* tstruct); + void generate_dart_bean_boilerplate(std::ofstream& out, t_struct* tstruct); + + void generate_function_helpers(t_function* tfunction); + std::string init_value(t_field* tfield); + std::string get_cap_name(std::string name); + std::string get_member_name(std::string name); + std::string get_args_class_name(std::string name); + std::string get_result_class_name(std::string name); + std::string get_file_name(std::string name); + std::string get_constants_class_name(std::string name); + std::string generate_isset_check(t_field* field); + std::string generate_isset_check(std::string field); + void generate_isset_set(ofstream& out, t_field* field); + + void generate_service_interface(t_service* tservice); + void generate_service_helpers(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* tfunction); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + + void generate_deserialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_deserialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_deserialize_set_element(std::ofstream& out, t_set* tset, std::string prefix = ""); + + void generate_deserialize_map_element(std::ofstream& out, t_map* tmap, std::string prefix = ""); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix = ""); + + void generate_serialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string iter, + std::string map); + + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + + void generate_dart_doc(std::ofstream& out, t_doc* tdoc); + + void generate_dart_doc(std::ofstream& out, t_function* tdoc); + + /** + * Helper rendering functions + */ + + std::string find_library_name(t_program* program); + std::string dart_library(string file_name); + std::string service_imports(); + std::string dart_thrift_imports(); + std::string type_name(t_type* ttype); + std::string base_type_name(t_base_type* tbase); + std::string declare_field(t_field* tfield, bool init = false); + std::string function_signature(t_function* tfunction); + std::string argument_list(t_struct* tstruct); + std::string type_to_enum(t_type* ttype); + std::string get_ttype_class_name(t_type* ttype); + + bool type_can_be_null(t_type* ttype) { + ttype = get_true_type(ttype); + + return ttype->is_container() || ttype->is_struct() || ttype->is_xception() + || ttype->is_string(); + } + + vector split(const string& s, char delim) { + vector elems; + stringstream ss(s); + string item; + while (getline(ss, item, delim)) { + elems.push_back(item); + } + return elems; + } + + std::string constant_name(std::string name); + +private: + std::ofstream f_service_; + + std::string library_name_; + std::string library_prefix_; + std::string package_prefix_; + std::string pubspec_lib_; + + std::string base_dir_; + std::string src_dir_; + std::string library_exports_; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_dart_generator::init_generator() { + MKDIR(get_out_dir().c_str()); + + if (library_name_.empty()) { + library_name_ = find_library_name(program_); + } + + string subdir = get_out_dir() + "/" + library_name_; + MKDIR(subdir.c_str()); + base_dir_ = subdir; + + if (library_prefix_.empty()) { + subdir += "/lib"; + MKDIR(subdir.c_str()); + subdir += "/src"; + MKDIR(subdir.c_str()); + src_dir_ = subdir; + } else { + src_dir_ = base_dir_; + } +} + +string t_dart_generator::find_library_name(t_program* program) { + string name = program->get_namespace("dart"); + if (name.empty()) { + name = program->get_name(); + } + name = replace_all(name, ".", "_"); + name = replace_all(name, "-", "_"); + return name; +} + +/** + * The Dart library + * + * @return String of the library, e.g. "library myservice;" + */ +string t_dart_generator::dart_library(string file_name) { + string out = "library " + library_prefix_ + library_name_; + if (!file_name.empty()) { + if (library_prefix_.empty()) { + out += ".src." + file_name; + } else { + out += "." + file_name; + } + } + return out + ";\n"; +} + +/** + * Prints imports for services + * + * @return List of imports for services + */ +string t_dart_generator::service_imports() { + return "import 'dart:async';" + endl; +} + +/** + * Prints standard dart imports + * + * @return List of imports necessary for thrift + */ +string t_dart_generator::dart_thrift_imports() { + string imports = "import 'dart:typed_data' show Uint8List;" + endl + + "import 'package:thrift/thrift.dart';" + endl; + + // add import for this library + if (package_prefix_.empty()) { + imports += "import 'package:" + library_name_ + "/" + library_name_ + ".dart';" + endl; + } else { + imports += "import 'package:" + package_prefix_ + library_name_ + ".dart';" + endl; + } + + // add imports for included thrift files + const vector& includes = program_->get_includes(); + for (size_t i = 0; i < includes.size(); ++i) { + string include_name = find_library_name(includes[i]); + string named_import = "t_" + include_name; + if (package_prefix_.empty()) { + imports += "import 'package:" + include_name + "/" + include_name + ".dart' as " + named_import + ";" + endl; + } else { + imports += "import 'package:" + package_prefix_ + include_name + ".dart' as " + named_import + ";" + endl; + } + } + + return imports; +} + +/** + * Not used + */ +void t_dart_generator::close_generator() { + generate_dart_library(); + + if (library_prefix_.empty()) { + generate_dart_pubspec(); + } +} + +void t_dart_generator::generate_dart_library() { + string f_library_name; + if (library_prefix_.empty()) { + f_library_name = base_dir_ + "/lib/" + library_name_ + ".dart"; + } else { + f_library_name = get_out_dir() + "/" + library_name_ + ".dart"; + } + + ofstream f_library; + f_library.open(f_library_name.c_str()); + + f_library << autogen_comment() << endl; + f_library << "library " << library_prefix_ << library_name_ << ";" << endl2; + f_library << library_exports_; + + f_library.close(); +} + +void t_dart_generator::export_class_to_library(string file_name, string class_name) { + string subdir; + if (library_prefix_.empty()) { + subdir = "src"; + } else { + subdir = library_name_; + } + library_exports_ += "export '" + subdir + "/" + file_name + ".dart' show " + class_name + ";" + endl; +} + +void t_dart_generator::generate_dart_pubspec() { + string f_pubspec_name = base_dir_ + "/pubspec.yaml"; + ofstream f_pubspec; + f_pubspec.open(f_pubspec_name.c_str()); + + indent(f_pubspec) << "name: " << library_name_ << endl; + indent(f_pubspec) << "version: 0.0.1" << endl; + indent(f_pubspec) << "description: Autogenerated by Thrift Compiler" << endl; + f_pubspec << endl; + + indent(f_pubspec) << "environment:" << endl; + indent_up(); + indent(f_pubspec) << "sdk: ^1.12.0" << endl; + indent_down(); + f_pubspec << endl; + + indent(f_pubspec) << "dependencies:" << endl; + indent_up(); + + if (pubspec_lib_.empty()) { + // default to relative path within working directory, which works for tests + indent(f_pubspec) << "thrift: # ^" << dart_thrift_version << endl; + indent_up(); + indent(f_pubspec) << "path: ../../../../lib/dart" << endl; + indent_down(); + } else { + const vector lines = split(pubspec_lib_, '|'); + for (size_t line_index = 0; line_index < lines.size(); line_index++) { + indent(f_pubspec) << lines[line_index] << endl; + } + } + + // add included thrift files as dependencies + const vector& includes = program_->get_includes(); + for (size_t i = 0; i < includes.size(); ++i) { + string include_name = find_library_name(includes[i]); + indent(f_pubspec) << include_name << ":" << endl; + indent_up(); + indent(f_pubspec) << "path: ../" << include_name << endl; + indent_down(); + } + + indent_down(); + f_pubspec << endl; + + f_pubspec.close(); +} + +/** + * Not used + * + * @param ttypedef The type definition + */ +void t_dart_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + +/** + * Enums are a class with a set of static constants. + * + * @param tenum The enumeration + */ +void t_dart_generator::generate_enum(t_enum* tenum) { + // Make output file + string file_name = get_file_name(tenum->get_name()); + + string f_enum_name = src_dir_ + "/" + file_name + ".dart"; + ofstream f_enum; + f_enum.open(f_enum_name.c_str()); + + // Comment and add library + f_enum << autogen_comment() << dart_library(file_name) << endl; + + string class_name = tenum->get_name(); + export_class_to_library(file_name, class_name); + f_enum << "class " << class_name; + scope_up(f_enum); + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + indent(f_enum) << "static const int " << (*c_iter)->get_name() << " = " << value << ";" + << endl; + } + + // Create a static Set with all valid values for this enum + f_enum << endl; + + indent(f_enum) << "static final Set VALID_VALUES = new Set.from([" << endl; + indent_up(); + bool firstValue = true; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + // populate set + indent(f_enum) << (firstValue ? "" : ", "); + f_enum << (*c_iter)->get_name() << endl; + firstValue = false; + } + indent_down(); + indent(f_enum) << "]);" << endl; + + indent(f_enum) << "static final Map VALUES_TO_NAMES = {" << endl; + indent_up(); + firstValue = true; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + indent(f_enum) << (firstValue ? "" : ", "); + f_enum << (*c_iter)->get_name() << ": '" << (*c_iter)->get_name() << "'" << endl; + firstValue = false; + } + indent_down(); + indent(f_enum) << "};" << endl; + + scope_down(f_enum); // end class + + f_enum.close(); +} + +/** + * Generates a class that holds all the constants. + */ +void t_dart_generator::generate_consts(std::vector consts) { + if (consts.empty()) { + return; + } + + string class_name = get_constants_class_name(program_name_); + string file_name = get_file_name(class_name); + + string f_consts_name = src_dir_ + "/" + file_name + ".dart"; + ofstream f_consts; + f_consts.open(f_consts_name.c_str()); + + // Print header + f_consts << autogen_comment() << dart_library(file_name) << endl; + f_consts << dart_thrift_imports() << endl; + + export_class_to_library(file_name, class_name); + indent(f_consts) << "class " << class_name; + scope_up(f_consts); + + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + print_const_value(f_consts, + (*c_iter)->get_name(), + (*c_iter)->get_type(), + (*c_iter)->get_value(), + false); + f_consts << endl; + } + + scope_down(f_consts); + + f_consts.close(); +} + +void t_dart_generator::print_const_value(std::ofstream& out, + string name, + t_type* type, + t_const_value* value, + bool in_static, + bool defval) { + type = get_true_type(type); + + indent(out); + if (!defval) { + out << (in_static ? "var " : "static final "); + } + if (type->is_base_type()) { + if (!defval) { + out << type_name(type) << " "; + } + string v2 = render_const_value(out, name, type, value); + out << name; + out << " = " << v2 << ";" << endl << endl; + } else if (type->is_enum()) { + if (!defval) { + out << type_name(type) << " "; + } + out << name; + out << " = " << value->get_integer() << ";" << endl << endl; + } else if (type->is_struct() || type->is_xception()) { + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + out << type_name(type) << " " << name << " = new " << type_name(type) << "()"; + indent_up(); + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + string val = render_const_value(out, name, field_type, v_iter->second); + out << endl; + indent(out) << ".." << v_iter->first->get_string() << " = " << val; + } + indent_down(); + out << ";" << endl; + } else if (type->is_map()) { + if (!defval) { + out << type_name(type) << " "; + } + out << name << " ="; + scope_up(out); + + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string key = render_const_value(out, name, ktype, v_iter->first); + string val = render_const_value(out, name, vtype, v_iter->second); + indent(out) << key << ": " << val << "," << endl; + } + scope_down(out, ";" + endl); + + out << endl; + } else if (type->is_list() || type->is_set()) { + if (!defval) { + out << type_name(type) << " "; + } + out << name << " = "; + t_type* etype; + if (type->is_list()) { + out << "[" << endl; + etype = ((t_list*)type)->get_elem_type(); + } else { + out << "new " << type_name(type) << ".from([" << endl; + etype = ((t_set*)type)->get_elem_type(); + } + const vector& val = value->get_list(); + vector::const_iterator v_iter; + + indent_up(); + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(out, name, etype, *v_iter); + indent(out) << val << "," << endl; + } + indent_down(); + + if (type->is_list()) { + indent(out) << "];" << endl; + } else { + indent(out) << "]);" << endl; + } + + } else { + throw "compiler error: no const of type " + type->get_name(); + } +} + +string t_dart_generator::render_const_value(ofstream& out, + string name, + t_type* type, + t_const_value* value) { + (void)name; + type = get_true_type(type); + std::ostringstream render; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + render << "'" << get_escaped_string(value) << "'"; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() > 0) ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + render << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + render << value->get_integer(); + } else { + render << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + render << value->get_integer(); + } else { + string t = tmp("tmp"); + print_const_value(out, t, type, value, true); + out << endl; + render << t; + } + + return render.str(); +} + +/** + * Generates a struct definition for a thrift data type. This is a class + * with data members, read(), write(), and an inner Isset class. + * + * @param tstruct The struct definition + */ +void t_dart_generator::generate_struct(t_struct* tstruct) { + generate_dart_struct(tstruct, false); +} + +/** + * Exceptions are structs, but they inherit from Exception + * + * @param tstruct The struct definition + */ +void t_dart_generator::generate_xception(t_struct* txception) { + generate_dart_struct(txception, true); +} + +/** + * Dart struct definition. + * + * @param tstruct The struct definition + */ +void t_dart_generator::generate_dart_struct(t_struct* tstruct, bool is_exception) { + string file_name = get_file_name(tstruct->get_name()); + string f_struct_name = src_dir_ + "/" + file_name + ".dart"; + ofstream f_struct; + f_struct.open(f_struct_name.c_str()); + + f_struct << autogen_comment() << dart_library(file_name) << endl; + + string imports; + + f_struct << dart_thrift_imports() << endl; + + generate_dart_struct_definition(f_struct, tstruct, is_exception, false, file_name); + + f_struct.close(); +} + +/** + * Dart struct definition. This has various parameters, as it could be + * generated standalone or inside another class as a helper. If it + * is a helper than it is a static class. + * + * @param tstruct The struct definition + * @param is_exception Is this an exception? + * @param in_class If inside a class, needs to be static class + * @param is_result If this is a result it needs a different writer + */ +void t_dart_generator::generate_dart_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool is_result, + string export_file_name) { + generate_dart_doc(out, tstruct); + + string class_name = tstruct->get_name(); + if (!export_file_name.empty()) { + export_class_to_library(export_file_name, class_name); + } + indent(out) << "class " << class_name << " "; + + if (is_exception) { + out << "extends Error "; + } + out << "implements TBase"; + scope_up(out); + + indent(out) << "static final TStruct _STRUCT_DESC = new TStruct(\"" << class_name + << "\");" << endl; + + // Members are public for -dart, private for -dartbean + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << "static final TField _" << constant_name((*m_iter)->get_name()) + << "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", " + << type_to_enum((*m_iter)->get_type()) << ", " << (*m_iter)->get_key() << ");" + << endl; + } + + out << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + generate_dart_doc(out, *m_iter); + indent(out) << type_name((*m_iter)->get_type()) + " _" + << get_member_name((*m_iter)->get_name()) << init_value(*m_iter) << ";" << endl; + + indent(out) << "static const int " << upcase_string((*m_iter)->get_name()) + << " = " << (*m_iter)->get_key() << ";" << endl; + } + + out << endl; + + // Inner Isset class + if (members.size() > 0) { + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (!type_can_be_null((*m_iter)->get_type())) { + string field_name = get_member_name((*m_iter)->get_name()); + indent(out) << "bool __isset_" << field_name << " = false;" << endl; + } + } + } + + out << endl; + + // Default constructor + indent(out) << tstruct->get_name() << "()"; + scope_up(out); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if ((*m_iter)->get_value() != NULL) { + print_const_value(out, + "this." + get_member_name((*m_iter)->get_name()), + t, + (*m_iter)->get_value(), + true, + true); + } + } + scope_down(out); + out << endl; + + generate_dart_bean_boilerplate(out, tstruct); + generate_generic_field_getters(out, tstruct); + generate_generic_field_setters(out, tstruct); + generate_generic_isset_method(out, tstruct); + + generate_dart_struct_reader(out, tstruct); + if (is_result) { + generate_dart_struct_result_writer(out, tstruct); + } else { + generate_dart_struct_writer(out, tstruct); + } + generate_dart_struct_tostring(out, tstruct); + generate_dart_validator(out, tstruct); + scope_down(out); + out << endl; +} + +/** + * Generates a function to read all the fields of the struct. + * + * @param tstruct The struct definition + */ +void t_dart_generator::generate_dart_struct_reader(ofstream& out, t_struct* tstruct) { + indent(out) << "read(TProtocol iprot)"; + scope_up(out); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Declare stack tmp variables and read struct header + indent(out) << "TField field;" << endl; + indent(out) << "iprot.readStructBegin();" << endl; + + // Loop over reading in fields + indent(out) << "while (true)"; + scope_up(out); + + // Read beginning field marker + indent(out) << "field = iprot.readFieldBegin();" << endl; + + // Check for field STOP marker and break + indent(out) << "if (field.type == TType.STOP)"; + scope_up(out); + indent(out) << "break;" << endl; + scope_down(out); + + // Switch statement on the field we are reading + indent(out) << "switch (field.id)"; + scope_up(out); + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << "case " << upcase_string((*f_iter)->get_name()) << ":" << endl; + indent_up(); + + indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ")"; + scope_up(out); + + generate_deserialize_field(out, *f_iter, "this."); + generate_isset_set(out, *f_iter); + + scope_down(out, " else"); + scope_up(out); + indent(out) << "TProtocolUtil.skip(iprot, field.type);" << endl; + scope_down(out); + + indent(out) << "break;" << endl; + indent_down(); + } + + // In the default case we skip the field + indent(out) << "default:" << endl; + indent_up(); + indent(out) << "TProtocolUtil.skip(iprot, field.type);" << endl; + indent(out) << "break;" << endl; + indent_down(); + + scope_down(out); + + // Read field end marker + indent(out) << "iprot.readFieldEnd();" << endl; + + scope_down(out); + + indent(out) << "iprot.readStructEnd();" << endl2; + + // in non-beans style, check for required fields of primitive type + // (which can be checked here but not in the general validate method) + indent(out) << "// check for required fields of primitive type, which can't be " + "checked in the validate method" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) { + string field_name = get_member_name((*f_iter)->get_name()); + indent(out) << "if (!__isset_" << field_name << ")"; + scope_up(out); + indent(out) << " throw new TProtocolError(TProtocolErrorType.UNKNOWN, \"Required field '" + << field_name + << "' was not found in serialized data! Struct: \" + toString());" << endl; + scope_down(out, endl2); + } + } + + // performs various checks (e.g. check that all required fields are set) + indent(out) << "validate();" << endl; + + scope_down(out, endl2); +} + +// generates dart method to perform various checks +// (e.g. check that all required fields are set) +void t_dart_generator::generate_dart_validator(ofstream& out, t_struct* tstruct) { + indent(out) << "validate()"; + scope_up(out); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + indent(out) << "// check for required fields" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + string field_name = get_member_name((*f_iter)->get_name()); + if (type_can_be_null((*f_iter)->get_type())) { + indent(out) << "if (" << field_name << " == null)"; + scope_up(out); + indent(out) << "throw new TProtocolError(TProtocolErrorType.UNKNOWN, \"Required field '" + << field_name << "' was not present! Struct: \" + toString());" + << endl; + scope_down(out); + } else { + indent(out) << "// alas, we cannot check '" << field_name + << "' because it's a primitive and you chose the non-beans generator." << endl; + } + } + } + + // check that fields of type enum have valid values + indent(out) << "// check that fields of type enum have valid values" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = (*f_iter); + t_type* type = field->get_type(); + // if field is an enum, check that its value is valid + if (type->is_enum()) { + string field_name = get_member_name(field->get_name()); + indent(out) << "if (" << generate_isset_check(field) << " && !" << get_ttype_class_name(type) + << ".VALID_VALUES.contains(" << field_name << "))"; + scope_up(out); + indent(out) << "throw new TProtocolError(TProtocolErrorType.UNKNOWN, \"The field '" + << field_name << "' has been assigned the invalid value " + << "$" << field_name << "\");" << endl; + scope_down(out); + } + } + + scope_down(out, endl2); +} + +/** + * Generates a function to write all the fields of the struct + * + * @param tstruct The struct definition + */ +void t_dart_generator::generate_dart_struct_writer(ofstream& out, t_struct* tstruct) { + out << indent() << "write(TProtocol oprot)"; + scope_up(out); + + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + // performs various checks (e.g. check that all required fields are set) + indent(out) << "validate();" << endl2; + + indent(out) << "oprot.writeStructBegin(_STRUCT_DESC);" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + string field_name = get_member_name((*f_iter)->get_name()); + bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; + if (could_be_unset) { + indent(out) << "if (" << generate_isset_check(*f_iter) << ")"; + scope_up(out); + } + bool null_allowed = type_can_be_null((*f_iter)->get_type()); + if (null_allowed) { + indent(out) << "if (this." << field_name << " != null)"; + scope_up(out); + } + + indent(out) << "oprot.writeFieldBegin(_" << constant_name((*f_iter)->get_name()) + << "_FIELD_DESC);" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "this."); + + // Write field closer + indent(out) << "oprot.writeFieldEnd();" << endl; + + if (null_allowed) { + scope_down(out); + } + if (could_be_unset) { + scope_down(out); + } + } + // Write the struct map + indent(out) << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();" + << endl; + + scope_down(out, endl2); +} + +/** + * Generates a function to write all the fields of the struct, + * which is a function result. These fields are only written + * if they are set in the Isset array, and only one of them + * can be set at a time. + * + * @param tstruct The struct definition + */ +void t_dart_generator::generate_dart_struct_result_writer(ofstream& out, t_struct* tstruct) { + indent(out) << "write(TProtocol oprot)"; + scope_up(out); + + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + indent(out) << "oprot.writeStructBegin(_STRUCT_DESC);" << endl2; + + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + indent(out) << "if "; + } else { + out << " else if "; + } + + out << "(this." << generate_isset_check(*f_iter) << ")"; + scope_up(out); + + indent(out) << "oprot.writeFieldBegin(_" << constant_name((*f_iter)->get_name()) + << "_FIELD_DESC);" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "this."); + + // Write field closer + indent(out) << "oprot.writeFieldEnd();" << endl; + + scope_down(out, ""); + } + out << endl; + + // Write the struct map + indent(out) << "oprot.writeFieldStop();" << endl << indent() + << "oprot.writeStructEnd();" << endl; + + scope_down(out, endl2); +} + +void t_dart_generator::generate_generic_field_getters(std::ofstream& out, + t_struct* tstruct) { + // create the getter + indent(out) << "getFieldValue(int fieldID)"; + scope_up(out); + + indent(out) << "switch (fieldID)"; + scope_up(out); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + std::string field_name = get_member_name(field->get_name()); + + indent(out) << "case " << upcase_string(field_name) << ":" << endl; + indent_up(); + indent(out) << "return this." << field_name << ";" << endl; + indent_down(); + } + + indent(out) << "default:" << endl; + indent_up(); + indent(out) << "throw new ArgumentError(\"Field $fieldID doesn't exist!\");" << endl; + indent_down(); + + scope_down(out); // switch + scope_down(out, endl2); // method +} + +void t_dart_generator::generate_generic_field_setters(std::ofstream& out, + t_struct* tstruct) { + + // create the setter + indent(out) << "setFieldValue(int fieldID, Object value)"; + scope_up(out); + + indent(out) << "switch (fieldID)"; + scope_up(out); + + // build up the bodies of both the getter and setter at once + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + std::string field_name = get_member_name(field->get_name()); + + indent(out) << "case " << upcase_string(field_name) << ":" << endl; + indent_up(); + + indent(out) << "if (value == null)"; + scope_up(out); + indent(out) << "unset" << get_cap_name(field_name) << "();" << endl; + + scope_down(out, " else"); + scope_up(out); + indent(out) << "this." << field_name << " = value;" << endl; + scope_down(out); + + indent(out) << "break;" << endl; + + indent_down(); + out << endl; + } + + indent(out) << "default:" << endl; + indent_up(); + indent(out) << "throw new ArgumentError(\"Field $fieldID doesn't exist!\");" << endl; + indent_down(); + + scope_down(out); // switch + scope_down(out, endl2); // method +} + +// Creates a generic isSet method that takes the field number as argument +void t_dart_generator::generate_generic_isset_method(std::ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // create the isSet method + indent(out) << "// Returns true if field corresponding to fieldID is set (has been assigned a " + "value) and false otherwise" << endl; + indent(out) << "bool isSet(int fieldID)"; + scope_up(out); + + indent(out) << "switch (fieldID)"; + scope_up(out); + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl; + indent_up(); + indent(out) << "return " << generate_isset_check(field) << ";" << endl; + indent_down(); + } + + indent(out) << "default:" << endl; + indent_up(); + indent(out) << "throw new ArgumentError(\"Field $fieldID doesn't exist!\");" << endl; + indent_down(); + + scope_down(out); // switch + scope_down(out, endl2); // method +} + +/** + * Generates a set of Dart Bean boilerplate functions (setters, getters, etc.) + * for the given struct. + * + * @param tstruct The struct definition + */ +void t_dart_generator::generate_dart_bean_boilerplate(ofstream& out, + t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + t_type* type = get_true_type(field->get_type()); + std::string field_name = get_member_name(field->get_name()); + std::string cap_name = get_cap_name(field_name); + + indent(out) << "// " << field_name << endl; + + // Simple getter + generate_dart_doc(out, field); + indent(out) << type_name(type) << " get " << field_name << " => this._" << field_name << ";" << endl2; + + // Simple setter + generate_dart_doc(out, field); + indent(out) << "set " << field_name << "(" << type_name(type) << " " << field_name << ")"; + scope_up(out); + indent(out) << "this._" << field_name << " = " << field_name << ";" << endl; + generate_isset_set(out, field); + scope_down(out, endl2); + + // isSet method + indent(out) << "bool is" << get_cap_name("set") << cap_name << "()"; + if (type_can_be_null(type)) { + out << " => this." << field_name << " != null;" << endl2; + } else { + out << " => this.__isset_" << field_name << ";" << endl2; + } + + // Unsetter + indent(out) << "unset" << cap_name << "()"; + scope_up(out); + if (type_can_be_null(type)) { + indent(out) << "this." << field_name << " = null;" << endl; + } else { + indent(out) << "this.__isset_" << field_name << " = false;" << endl; + } + scope_down(out, endl2); + } +} + +/** + * Generates a toString() method for the given struct + * + * @param tstruct The struct definition + */ +void t_dart_generator::generate_dart_struct_tostring(ofstream& out, + t_struct* tstruct) { + indent(out) << "String toString()"; + scope_up(out); + + indent(out) << "StringBuffer ret = new StringBuffer(\"" + << tstruct->get_name() << "(\");" << endl2; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; + if (could_be_unset) { + indent(out) << "if (" << generate_isset_check(*f_iter) << ")"; + scope_up(out); + } + + t_field* field = (*f_iter); + std::string field_name = get_member_name(field->get_name()); + + if (!first) { + indent(out) << "ret.write(\", \");" << endl; + } + indent(out) << "ret.write(\"" << field_name << ":\");" << endl; + bool can_be_null = type_can_be_null(field->get_type()); + if (can_be_null) { + indent(out) << "if (this." << field_name << " == null)"; + scope_up(out); + indent(out) << "ret.write(\"null\");" << endl; + scope_down(out, " else"); + scope_up(out); + } + + if (field->get_type()->is_binary()) { + indent(out) << "ret.write(\"BINARY\");" << endl; + } else if (field->get_type()->is_enum()) { + indent(out) << "String " << field_name << "_name = " + << get_ttype_class_name(field->get_type()) + << ".VALUES_TO_NAMES[this." << field_name << "];" << endl; + indent(out) << "if (" << field_name << "_name != null)"; + scope_up(out); + indent(out) << "ret.write(" << field_name << "_name);" << endl; + indent(out) << "ret.write(\" (\");" << endl; + scope_down(out); + indent(out) << "ret.write(this." << field_name << ");" << endl; + indent(out) << "if (" << field_name << "_name != null)"; + scope_up(out); + indent(out) << "ret.write(\")\");" << endl; + scope_down(out); + } else { + indent(out) << "ret.write(this." << field_name << ");" << endl; + } + + if (can_be_null) { + scope_down(out); + } + if (could_be_unset) { + scope_down(out); + } + + out << endl; + first = false; + } + + indent(out) << "ret.write(\")\");" << endl2; + + indent(out) << "return ret.toString();" << endl; + + scope_down(out, endl2); +} + +/** + * Returns a string with the dart representation of the given thrift type + * (e.g. for the type struct it returns "TType.STRUCT") + */ +std::string t_dart_generator::get_dart_type_string(t_type* type) { + if (type->is_list()) { + return "TType.LIST"; + } else if (type->is_map()) { + return "TType.MAP"; + } else if (type->is_set()) { + return "TType.SET"; + } else if (type->is_struct() || type->is_xception()) { + return "TType.STRUCT"; + } else if (type->is_enum()) { + return "TType.I32"; + } else if (type->is_typedef()) { + return get_dart_type_string(((t_typedef*)type)->get_type()); + } else if (type->is_base_type()) { + switch (((t_base_type*)type)->get_base()) { + case t_base_type::TYPE_VOID: + return "TType.VOID"; + break; + case t_base_type::TYPE_STRING: + return "TType.STRING"; + break; + case t_base_type::TYPE_BOOL: + return "TType.BOOL"; + break; + case t_base_type::TYPE_I8: + return "TType.BYTE"; + break; + case t_base_type::TYPE_I16: + return "TType.I16"; + break; + case t_base_type::TYPE_I32: + return "TType.I32"; + break; + case t_base_type::TYPE_I64: + return "TType.I64"; + break; + case t_base_type::TYPE_DOUBLE: + return "TType.DOUBLE"; + break; + default: + throw std::runtime_error("Unknown thrift type \"" + type->get_name() + + "\" passed to t_dart_generator::get_dart_type_string!"); + break; // This should never happen! + } + } else { + throw std::runtime_error( + "Unknown thrift type \"" + type->get_name() + + "\" passed to t_dart_generator::get_dart_type_string!"); // This should never happen! + } +} + +void t_dart_generator::generate_service(t_service* tservice) { + string file_name = get_file_name(service_name_); + string f_service_name = src_dir_ + "/" + file_name + ".dart"; + f_service_.open(f_service_name.c_str()); + + f_service_ << autogen_comment() << dart_library(file_name) << endl; + f_service_ << service_imports() << dart_thrift_imports() << endl; + f_service_ << endl; + + generate_service_interface(tservice); + generate_service_client(tservice); + generate_service_server(tservice); + generate_service_helpers(tservice); + + f_service_.close(); +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_dart_generator::generate_service_interface(t_service* tservice) { + string extends_iface = ""; + if (tservice->get_extends() != NULL) { + extends_iface = " extends " + get_ttype_class_name(tservice->get_extends()); + } + + generate_dart_doc(f_service_, tservice); + + string class_name = service_name_; + export_class_to_library(get_file_name(service_name_), class_name); + indent(f_service_) << "abstract class " << class_name << extends_iface; + scope_up(f_service_); + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << endl; + generate_dart_doc(f_service_, *f_iter); + indent(f_service_) << function_signature(*f_iter) << ";" << endl; + } + + scope_down(f_service_, endl2); +} + +/** + * Generates structs for all the service args and return types + * + * @param tservice The service + */ +void t_dart_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_dart_struct_definition(f_service_, ts, false, false); + generate_function_helpers(*f_iter); + } +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_dart_generator::generate_service_client(t_service* tservice) { + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() != NULL) { + extends = get_ttype_class_name(tservice->get_extends()); + extends_client = " extends " + extends + "Client"; + } + + string class_name = service_name_ + "Client"; + export_class_to_library(get_file_name(service_name_), class_name); + indent(f_service_) << "class " << class_name << extends_client + << " implements " << service_name_; + scope_up(f_service_); + f_service_ << endl; + + indent(f_service_) << class_name << "(TProtocol iprot, [TProtocol oprot = null])"; + + if (!extends.empty()) { + indent_up(); + f_service_ << endl; + indent(f_service_) << ": super(iprot, oprot);" << endl; + indent_down(); + } else { + scope_up(f_service_); + indent(f_service_) << "_iprot = iprot;" << endl; + indent(f_service_) << "_oprot = (oprot == null) ? iprot : oprot;" << endl; + scope_down(f_service_); + } + f_service_ << endl; + + if (extends.empty()) { + indent(f_service_) << "TProtocol _iprot;" << endl2; + indent(f_service_) << "TProtocol get iprot => _iprot;" << endl2; + indent(f_service_) << "TProtocol _oprot;" << endl2; + indent(f_service_) << "TProtocol get oprot => _oprot;" << endl2; + indent(f_service_) << "int _seqid = 0;" << endl2; + indent(f_service_) << "int get seqid => _seqid;" << endl2; + indent(f_service_) << "int nextSeqid() => ++_seqid;" << endl2; + } + + // Generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + // Open function + indent(f_service_) << function_signature(*f_iter) << " async"; + scope_up(f_service_); + + // Get the struct of function call params + t_struct* arg_struct = (*f_iter)->get_arglist(); + + string argsname = get_args_class_name((*f_iter)->get_name()); + vector::const_iterator fld_iter; + const vector& fields = arg_struct->get_members(); + + // Serialize the request + indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << (*f_iter)->get_name() << "\", " + << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL") + << ", nextSeqid()));" << endl; + indent(f_service_) << argsname << " args = new " << argsname << "();" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + string arg_field_name = get_member_name((*fld_iter)->get_name()); + indent(f_service_) << "args." << arg_field_name << " = " + << arg_field_name << ";" << endl; + } + + indent(f_service_) << "args.write(oprot);" << endl; + indent(f_service_) << "oprot.writeMessageEnd();" << endl2; + + indent(f_service_) << "await oprot.transport.flush();" << endl2; + + if (!(*f_iter)->is_oneway()) { + indent(f_service_) << "TMessage msg = iprot.readMessageBegin();" << endl; + indent(f_service_) << "if (msg.type == TMessageType.EXCEPTION)"; + scope_up(f_service_); + indent(f_service_) << "TApplicationError error = TApplicationError.read(iprot);" << endl; + indent(f_service_) << "iprot.readMessageEnd();" << endl; + indent(f_service_) << "throw error;" << endl; + scope_down(f_service_, endl2); + + string result_class = get_result_class_name((*f_iter)->get_name()); + indent(f_service_) << result_class << " result = new " << result_class << "();" << endl; + indent(f_service_) << "result.read(iprot);" << endl; + indent(f_service_) << "iprot.readMessageEnd();" << endl; + + // Careful, only return _result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << "if (result." << generate_isset_check("success") << ")"; + scope_up(f_service_); + indent(f_service_) << "return result.success;" << endl; + scope_down(f_service_, endl2); + } + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + string result_field_name = get_member_name((*x_iter)->get_name()); + indent(f_service_) << "if (result." << result_field_name << " != null)"; + scope_up(f_service_); + indent(f_service_) << "throw result." << result_field_name << ";" << endl; + scope_down(f_service_); + } + + // If you get here it's an exception, unless a void function + if ((*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << "return;" << endl; + } else { + indent(f_service_) << "throw new TApplicationError(TApplicationErrorType.MISSING_RESULT, \"" + << (*f_iter)->get_name() << " failed: unknown result\");" << endl; + } + } + + scope_down(f_service_, endl2); + } + + scope_down(f_service_, endl2); +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_dart_generator::generate_service_server(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + // typedef + indent(f_service_) << "typedef void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);" << endl2; + + // Extends stuff + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() != NULL) { + extends = get_ttype_class_name(tservice->get_extends()); + extends_processor = " extends " + extends + "Processor"; + } + + // Generate the header portion + string class_name = service_name_ + "Processor"; + export_class_to_library(get_file_name(service_name_), class_name); + indent(f_service_) << "class " << class_name << extends_processor << " implements TProcessor"; + scope_up(f_service_); + + indent(f_service_) << class_name << "(" << service_name_ << " iface)"; + if (!extends.empty()) { + indent_up(); + f_service_ << endl; + indent(f_service_) << ": super(iface)"; + indent_down(); + } + scope_up(f_service_); + + if (extends.empty()) { + indent(f_service_) << "iface_ = iface;" << endl; + } + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + indent(f_service_) << "PROCESS_MAP[\"" << (*f_iter)->get_name() + << "\"] = " << get_member_name((*f_iter)->get_name()) << ";" << endl; + } + scope_down(f_service_, endl2); + + indent(f_service_) << service_name_ << " iface_;" << endl; + + if (extends.empty()) { + indent(f_service_) << "final Map PROCESS_MAP = {};" << endl; + } + + f_service_ << endl; + + // Generate the server implementation + indent(f_service_) << "bool process(TProtocol iprot, TProtocol oprot)"; + scope_up(f_service_); + indent(f_service_) << "TMessage msg = iprot.readMessageBegin();" << endl; + indent(f_service_) << "ProcessFunction fn = PROCESS_MAP[msg.name];" << endl; + indent(f_service_) << "if (fn == null)"; + scope_up(f_service_); + indent(f_service_) << "TProtocolUtil.skip(iprot, TType.STRUCT);" << endl; + indent(f_service_) << "iprot.readMessageEnd();" << endl; + indent(f_service_) << "TApplicationError x = new TApplicationError(TApplicationErrorType.UNKNOWN_METHOD, " + "\"Invalid method name: '\"+msg.name+\"'\");" << endl; + indent(f_service_) << "oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" << endl; + indent(f_service_) << "x.write(oprot);" << endl; + indent(f_service_) << "oprot.writeMessageEnd();" << endl; + indent(f_service_) << "oprot.transport.flush();" << endl; + indent(f_service_) << "return true;" << endl; + scope_down(f_service_); + indent(f_service_) << "fn(msg.seqid, iprot, oprot);" << endl; + indent(f_service_) << "return true;" << endl; + scope_down(f_service_, endl2); // process function + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(tservice, *f_iter); + } + + scope_down(f_service_, endl2); // class +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_dart_generator::generate_function_helpers(t_function* tfunction) { + if (tfunction->is_oneway()) { + return; + } + + t_struct result(program_, get_result_class_name(tfunction->get_name())); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + generate_dart_struct_definition(f_service_, &result, false, true); +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_dart_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + (void)tservice; + + bool await_result = (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()); + + indent(f_service_) << get_member_name(tfunction->get_name()) << "(int seqid, TProtocol iprot, TProtocol oprot)"; + if (await_result) { + f_service_ << " async"; + } + scope_up(f_service_); + + string argsname = get_args_class_name(tfunction->get_name()); + string resultname = get_result_class_name(tfunction->get_name()); + + indent(f_service_) << argsname << " args = new " << argsname << "();" << endl; + indent(f_service_) << "args.read(iprot);" << endl; + indent(f_service_) << "iprot.readMessageEnd();" << endl; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + if (!tfunction->is_oneway()) { + indent(f_service_) << resultname << " result = new " << resultname << "();" << endl; + } + + if (!tfunction->is_oneway() && xceptions.size() > 0) { + indent(f_service_) << "try"; + scope_up(f_service_); + } + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + f_service_ << indent(); + if (await_result) { + f_service_ << "result.success = await "; + } + f_service_ << "iface_." << get_member_name(tfunction->get_name()) << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "args." << get_member_name((*f_iter)->get_name()); + } + f_service_ << ");" << endl; + + if (!tfunction->is_oneway() && xceptions.size() > 0) { + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + string result_field_name = get_member_name((*x_iter)->get_name()); + scope_down(f_service_, ""); + f_service_ << " on " << type_name((*x_iter)->get_type()) + << " catch(" << result_field_name << ")"; + scope_up(f_service_); + if (!tfunction->is_oneway()) { + indent(f_service_) << "result." << result_field_name << " = " + << result_field_name << ";" << endl; + } + } + scope_down(f_service_, " "); + f_service_ << "catch (th)"; + scope_up(f_service_); + indent(f_service_) << "// Internal error" << endl; + indent(f_service_) << "TApplicationError x = new " + "TApplicationError(TApplicationErrorType.INTERNAL_ERROR, \"Internal error processing " + << tfunction->get_name() << "\");" << endl; + indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() + << "\", TMessageType.EXCEPTION, seqid));" << endl; + indent(f_service_) << "x.write(oprot);" << endl; + indent(f_service_) << "oprot.writeMessageEnd();" << endl; + indent(f_service_) << "oprot.transport.flush();" << endl; + indent(f_service_) << "return;" << endl; + scope_down(f_service_); + } + + if (tfunction->is_oneway()) { + indent(f_service_) << "return;" << endl; + } else { + indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() + << "\", TMessageType.REPLY, seqid));" << endl; + indent(f_service_) << "result.write(oprot);" << endl; + indent(f_service_) << "oprot.writeMessageEnd();" << endl; + indent(f_service_) << "oprot.transport.flush();" << endl; + } + + scope_down(f_service_, endl2); +} + +/** + * Deserializes a field of any type. + * + * @param tfield The field + * @param prefix The variable name or container for this field + */ +void t_dart_generator::generate_deserialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = get_true_type(tfield->get_type()); + string field_name = get_member_name(tfield->get_name()); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + field_name; + } + + string name = prefix + field_name; + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name); + } else if (type->is_container()) { + generate_deserialize_container(out, type, name); + } else if (type->is_base_type() || type->is_enum()) { + + indent(out) << name << " = iprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "readBinary();"; + } else { + out << "readString();"; + } + break; + case t_base_type::TYPE_BOOL: + out << "readBool();"; + break; + case t_base_type::TYPE_I8: + out << "readByte();"; + break; + case t_base_type::TYPE_I16: + out << "readI16();"; + break; + case t_base_type::TYPE_I32: + out << "readI32();"; + break; + case t_base_type::TYPE_I64: + out << "readI64();"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble();"; + break; + default: + throw "compiler error: no Dart name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "readI32();"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + field_name.c_str(), + type_name(type).c_str()); + } +} + +/** + * Generates an unserializer for a struct, invokes read() + */ +void t_dart_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + indent(out) << prefix << " = new " << type_name(tstruct) << "();" << endl; + indent(out) << prefix << ".read(iprot);" << endl; +} + +/** + * Deserializes a container by reading its size and then iterating + */ +void t_dart_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) { + indent(out); + scope_up(out, ""); + + string obj; + + if (ttype->is_map()) { + obj = tmp("_map"); + } else if (ttype->is_set()) { + obj = tmp("_set"); + } else if (ttype->is_list()) { + obj = tmp("_list"); + } + + // Declare variables, read header + if (ttype->is_map()) { + indent(out) << "TMap " << obj << " = iprot.readMapBegin();" << endl; + } else if (ttype->is_set()) { + indent(out) << "TSet " << obj << " = iprot.readSetBegin();" << endl; + } else if (ttype->is_list()) { + indent(out) << "TList " << obj << " = iprot.readListBegin();" << endl; + } + + indent(out) << prefix << " = new " << type_name(ttype) << "();" << endl; + + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".length" + << "; " + << "++" << i << ")"; + scope_up(out); + + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, prefix); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, prefix); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, prefix); + } + + scope_down(out); + + // Read container end + if (ttype->is_map()) { + indent(out) << "iprot.readMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "iprot.readSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "iprot.readListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Generates code to deserialize a map + */ +void t_dart_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) { + string key = tmp("_key"); + string val = tmp("_val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + indent(out) << declare_field(&fkey) << endl; + indent(out) << declare_field(&fval) << endl; + + generate_deserialize_field(out, &fkey); + generate_deserialize_field(out, &fval); + + indent(out) << prefix << "[" << key << "] = " << val << ";" << endl; +} + +/** + * Deserializes a set element + */ +void t_dart_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) { + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); + + indent(out) << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".add(" << elem << ");" << endl; +} + +/** + * Deserializes a list element + */ +void t_dart_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix) { + string elem = tmp("_elem"); + t_field felem(tlist->get_elem_type(), elem); + + indent(out) << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".add(" << elem << ");" << endl; +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_dart_generator::generate_serialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = get_true_type(tfield->get_type()); + string field_name = get_member_name(tfield->get_name()); + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + field_name; + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, prefix + field_name); + } else if (type->is_container()) { + generate_serialize_container(out, type, prefix + field_name); + } else if (type->is_base_type() || type->is_enum()) { + + string name = prefix + field_name; + indent(out) << "oprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "writeBinary(" << name << ");"; + } else { + out << "writeString(" << name << ");"; + } + break; + case t_base_type::TYPE_BOOL: + out << "writeBool(" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "writeByte(" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "writeI16(" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "writeI32(" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "writeI64(" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble(" << name << ");"; + break; + default: + throw "compiler error: no Dart name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "writeI32(" << name << ");"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", + prefix.c_str(), + field_name.c_str(), + type_name(type).c_str()); + } +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_dart_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + (void)tstruct; + indent(out) << prefix << ".write(oprot);" << endl; +} + +/** + * Serializes a container by writing its size then the elements. + * + * @param ttype The type of container + * @param prefix String prefix for fields + */ +void t_dart_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + indent(out); + scope_up(out, ""); + + if (ttype->is_map()) { + string iter = tmp("_key"); + indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type()) + << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix << ".length));" + << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type()) + << ", " << prefix << ".length));" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.writeListBegin(new TList(" + << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".length));" + << endl; + } + + string iter = tmp("elem"); + if (ttype->is_map()) { + indent(out) << "for (var " << iter << " in " << prefix << ".keys)"; + } else if (ttype->is_set() || ttype->is_list()) { + indent(out) << "for (var " << iter << " in " << prefix << ")"; + } + + scope_up(out); + + if (ttype->is_map()) { + generate_serialize_map_element(out, (t_map*)ttype, iter, prefix); + } else if (ttype->is_set()) { + generate_serialize_set_element(out, (t_set*)ttype, iter); + } else if (ttype->is_list()) { + generate_serialize_list_element(out, (t_list*)ttype, iter); + } + + scope_down(out); + + if (ttype->is_map()) { + indent(out) << "oprot.writeMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.writeSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.writeListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Serializes the members of a map. + */ +void t_dart_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string iter, + string map) { + t_field kfield(tmap->get_key_type(), iter); + generate_serialize_field(out, &kfield, ""); + t_field vfield(tmap->get_val_type(), map + "[" + iter + "]"); + generate_serialize_field(out, &vfield, ""); +} + +/** + * Serializes the members of a set. + */ +void t_dart_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) { + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +/** + * Serializes the members of a list. + */ +void t_dart_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) { + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +/** + * Returns a Dart type name + * + * @param ttype The type + * @return Dart type name, i.e. Map + */ +string t_dart_generator::type_name(t_type* ttype) { + ttype = get_true_type(ttype); + + if (ttype->is_base_type()) { + return base_type_name((t_base_type*)ttype); + } else if (ttype->is_enum()) { + return "int"; + } else if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + return "Map<" + type_name(tmap->get_key_type()) + ", " + + type_name(tmap->get_val_type()) + ">"; + } else if (ttype->is_set()) { + t_set* tset = (t_set*)ttype; + return "Set<" + type_name(tset->get_elem_type()) + ">"; + } else if (ttype->is_list()) { + t_list* tlist = (t_list*)ttype; + return "List<" + type_name(tlist->get_elem_type()) + ">"; + } + + return get_ttype_class_name(ttype); +} + +/** + * Returns the Dart type that corresponds to the thrift type. + * + * @param tbase The base type + */ +string t_dart_generator::base_type_name(t_base_type* type) { + t_base_type::t_base tbase = type->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + return "void"; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + return "Uint8List"; + } else { + return "String"; + } + case t_base_type::TYPE_BOOL: + return "bool"; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + return "int"; + case t_base_type::TYPE_DOUBLE: + return "double"; + default: + throw "compiler error: no Dart name for base type " + t_base_type::t_base_name(tbase); + } +} + +/** + * Declares a field, which may include initialization as necessary. + * + * @param ttype The type + */ +string t_dart_generator::declare_field(t_field* tfield, bool init) { + string field_name = get_member_name(tfield->get_name()); + string result = type_name(tfield->get_type()) + " " + field_name; + if (init) { + t_type* ttype = get_true_type(tfield->get_type()); + if (ttype->is_base_type() && tfield->get_value() != NULL) { + ofstream dummy; + result += " = " + render_const_value(dummy, field_name, ttype, tfield->get_value()); + } else if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + result += " = null"; + break; + case t_base_type::TYPE_BOOL: + result += " = false"; + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + result += " = 0"; + break; + case t_base_type::TYPE_DOUBLE: + result += " = 0.0"; + break; + } + + } else if (ttype->is_enum()) { + result += " = 0"; + } else if (ttype->is_container()) { + result += " = new " + type_name(ttype) + "()"; + } else { + result += " = new " + type_name(ttype) + "()"; + ; + } + } + return result + ";"; +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_dart_generator::function_signature(t_function* tfunction) { + std::string arguments = argument_list(tfunction->get_arglist()); + + std::string returntype; + if (tfunction->get_returntype()->is_void()) { + returntype = "Future"; + } else { + returntype = "Future<" + type_name(tfunction->get_returntype()) + ">"; + } + + std::string result = returntype + " " + get_member_name(tfunction->get_name()) + + "(" + arguments + ")"; + return result; +} + +/** + * Renders a comma separated field list, with type names + */ +string t_dart_generator::argument_list(t_struct* tstruct) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + string field_name = get_member_name((*f_iter)->get_name()); + result += type_name((*f_iter)->get_type()) + " " + field_name; + } + return result; +} + +/** + * Converts the parse type to a C++ enum string for the given type. + */ +string t_dart_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "TType.STRING"; + case t_base_type::TYPE_BOOL: + return "TType.BOOL"; + case t_base_type::TYPE_I8: + return "TType.BYTE"; + case t_base_type::TYPE_I16: + return "TType.I16"; + case t_base_type::TYPE_I32: + return "TType.I32"; + case t_base_type::TYPE_I64: + return "TType.I64"; + case t_base_type::TYPE_DOUBLE: + return "TType.DOUBLE"; + } + } else if (type->is_enum()) { + return "TType.I32"; + } else if (type->is_struct() || type->is_xception()) { + return "TType.STRUCT"; + } else if (type->is_map()) { + return "TType.MAP"; + } else if (type->is_set()) { + return "TType.SET"; + } else if (type->is_list()) { + return "TType.LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +std::string t_dart_generator::init_value(t_field* field) { + // Do not initialize optional fields + if (field->get_req() == t_field::T_OPTIONAL) { + return ""; + } + + t_type* ttype = field->get_type(); + + // Get the actual type for a typedef + if (ttype->is_typedef()) { + ttype = ((t_typedef*)ttype)->get_type(); + } + + // Only consider base types for default initialization + if (!ttype->is_base_type()) { + return ""; + } + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + + // Initialize bools, ints, and doubles with sane defaults + string result; + switch (tbase) { + case t_base_type::TYPE_BOOL: + result = " = false"; + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + result = " = 0"; + break; + case t_base_type::TYPE_DOUBLE: + result = " = 0.0"; + break; + case t_base_type::TYPE_VOID: + case t_base_type::TYPE_STRING: + result = ""; + break; + } + + return result; +} + +std::string t_dart_generator::get_cap_name(std::string name) { + name[0] = toupper(name[0]); + return name; +} + +std::string t_dart_generator::get_member_name(std::string name) { + name[0] = tolower(name[0]); + return name; +} + +std::string t_dart_generator::get_args_class_name(std::string name) { + return name + "_args"; +} + +std::string t_dart_generator::get_result_class_name(std::string name) { + return name + "_result"; +} + +std::string t_dart_generator::get_file_name(std::string name) { + // e.g. change APIForFileIO to api_for_file_io + + string ret; + const char* tmp = name.c_str(); + bool is_prev_lc = true; + bool is_current_lc = tmp[0] == tolower(tmp[0]); + bool is_next_lc = false; + + for (unsigned int i = 0; i < name.length(); i++) { + char lc = tolower(tmp[i]); + + if (i == name.length() - 1) { + is_next_lc = false; + } else { + is_next_lc = (tmp[i+1] == tolower(tmp[i+1])); + } + + if (i != 0 && !is_current_lc && (is_prev_lc || is_next_lc)) { + ret += "_"; + } + ret += lc; + + is_prev_lc = is_current_lc; + is_current_lc = is_next_lc; + } + + return ret; +} + +std::string t_dart_generator::get_constants_class_name(std::string name) { + // e.g. change my_great_model to MyGreatModelConstants + string ret; + const char* tmp = name.c_str(); + bool is_prev_underscore = true; + + for (unsigned int i = 0; i < name.length(); i++) { + if (tmp[i] == '_') { + is_prev_underscore = true; + } else { + if (is_prev_underscore) { + ret += toupper(tmp[i]); + } else { + ret += tmp[i]; + } + + is_prev_underscore = false; + } + } + + return ret + "Constants"; +} + +string t_dart_generator::constant_name(string name) { + string constant_name; + + bool is_first = true; + bool was_previous_char_upper = false; + for (string::iterator iter = name.begin(); iter != name.end(); ++iter) { + string::value_type character = (*iter); + + bool is_upper = isupper(character); + + if (is_upper && !is_first && !was_previous_char_upper) { + constant_name += '_'; + } + constant_name += toupper(character); + + is_first = false; + was_previous_char_upper = is_upper; + } + + return constant_name; +} + +/** + * Emits a doc comment if the provided object has a doc in Thrift + */ +void t_dart_generator::generate_dart_doc(ofstream& out, t_doc* tdoc) { + if (tdoc->has_doc()) { + generate_docstring_comment(out, "", "/// ", tdoc->get_doc(), ""); + } +} + +/** + * Emits a doc comment if the provided function object has a doc in Thrift + */ +void t_dart_generator::generate_dart_doc(ofstream& out, t_function* tfunction) { + if (tfunction->has_doc()) { + stringstream ss; + ss << tfunction->get_doc(); + const vector& fields = tfunction->get_arglist()->get_members(); + vector::const_iterator p_iter; + for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { + t_field* p = *p_iter; + string field_name = get_member_name(p->get_name()); + ss << "\n@param " << field_name; + if (p->has_doc()) { + ss << " " << p->get_doc(); + } + } + generate_docstring_comment(out, "", "/// ", ss.str(), ""); + } +} + +std::string t_dart_generator::generate_isset_check(t_field* field) { + string field_name = get_member_name(field->get_name()); + return generate_isset_check(field_name); +} + +std::string t_dart_generator::generate_isset_check(std::string field_name) { + return "is" + get_cap_name("set") + get_cap_name(field_name) + "()"; +} + +void t_dart_generator::generate_isset_set(ofstream& out, t_field* field) { + if (!type_can_be_null(field->get_type())) { + string field_name = get_member_name(field->get_name()); + indent(out) << "this.__isset_" << field_name << " = true;" << endl; + } +} + +std::string t_dart_generator::get_ttype_class_name(t_type* ttype) { + if (program_ == ttype->get_program()) { + return ttype->get_name(); + } else { + string named_import = "t_" + find_library_name(ttype->get_program()); + return named_import + "." + ttype->get_name(); + } +} + +THRIFT_REGISTER_GENERATOR( + dart, + "Dart", + " library_name: Optional override for library name.\n" + " library_prefix: Generate code that can be used within an existing library.\n" + " Use a dot-separated string, e.g. \"my_parent_lib.src.gen\"\n" + " pubspec_lib: Optional override for thrift lib dependency in pubspec.yaml,\n" + " e.g. \"thrift: 0.x.x\". Use a pipe delimiter to separate lines,\n" + " e.g. \"thrift:| git:| url: git@foo.com\"\n" +) diff --git a/compiler/cpp/src/thrift/generate/t_delphi_generator.cc b/compiler/cpp/src/thrift/generate/t_delphi_generator.cc new file mode 100644 index 0000000..1894fe8 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_delphi_generator.cc @@ -0,0 +1,3920 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +class t_delphi_generator : public t_oop_generator { +public: + t_delphi_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + indent_impl_ = 0; + has_forward = false; + has_enum = false; + has_const = false; + std::map::const_iterator iter; + + ansistr_binary_ = false; + register_types_ = false; + constprefix_ = false; + events_ = false; + xmldoc_ = false; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("ansistr_binary") == 0) { + ansistr_binary_ = true; + } else if( iter->first.compare("register_types") == 0) { + register_types_ = true; + } else if( iter->first.compare("constprefix") == 0) { + constprefix_ = true; + } else if( iter->first.compare("events") == 0) { + events_ = true; + } else if( iter->first.compare("xmldoc") == 0) { + xmldoc_ = true; + } else { + throw "unknown option delphi:" + iter->first; + } + } + + out_dir_base_ = "gen-delphi"; + escape_.clear(); + escape_['\''] = "''"; + } + + void init_generator(); + void close_generator(); + + void generate_consts(std::vector consts); + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_forward_declaration(t_struct* tstruct); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + void generate_property(ostream& out, t_field* tfield, bool isPublic, bool is_xception); + void generate_property_writer_(ostream& out, t_field* tfield, bool isPublic); + + void generate_delphi_property(ostream& out, + bool struct_is_exception, + t_field* tfield, + bool isPublic, + std::string fieldPrefix = ""); + void generate_delphi_isset_reader_definition(ostream& out, t_field* tfield, bool is_xception); + void generate_delphi_property_reader_definition(ostream& out, + t_field* tfield, + bool is_xception_class); + void generate_delphi_property_writer_definition(ostream& out, + t_field* tfield, + bool is_xception_class); + void generate_delphi_property_reader_impl(ostream& out, + std::string cls_prefix, + std::string name, + t_type* type, + t_field* tfield, + std::string fieldPrefix, + bool is_xception_class); + void generate_delphi_property_writer_impl(ostream& out, + std::string cls_prefix, + std::string name, + t_type* type, + t_field* tfield, + std::string fieldPrefix, + bool is_xception_class, + bool is_union, + bool is_xception_factory, + std::string xception_factroy_name); + void generate_delphi_clear_union_value(ostream& out, + std::string cls_prefix, + std::string name, + t_type* type, + t_field* tfield, + std::string fieldPrefix, + bool is_xception_class, + bool is_union, + bool is_xception_factory, + std::string xception_factroy_name); + void generate_delphi_isset_reader_impl(ostream& out, + std::string cls_prefix, + std::string name, + t_type* type, + t_field* tfield, + std::string fieldPrefix, + bool is_xception); + void generate_delphi_struct_writer_impl(ostream& out, + std::string cls_prefix, + t_struct* tstruct, + bool is_exception); + void generate_delphi_struct_result_writer_impl(ostream& out, + std::string cls_prefix, + t_struct* tstruct, + bool is_exception); + + void generate_delphi_struct_tostring_impl(ostream& out, + std::string cls_prefix, + t_struct* tstruct, + bool is_exception, + bool is_x_factory); + + void add_delphi_uses_list(string unitname); + + void generate_delphi_struct_reader_impl(ostream& out, + std::string cls_prefix, + t_struct* tstruct, + bool is_exception); + void generate_delphi_create_exception_impl(ostream& out, + string cls_prefix, + t_struct* tstruct, + bool is_exception); + + bool const_needs_var(t_type* type); + void print_const_prop(std::ostream& out, string name, t_type* type, t_const_value* value); + void print_private_field(std::ostream& out, string name, t_type* type, t_const_value* value); + void print_const_value(std::ostream& vars, + std::ostream& out, + std::string name, + t_type* type, + t_const_value* value); + void initialize_field(std::ostream& vars, + std::ostream& out, + std::string name, + t_type* type, + t_const_value* value); + void finalize_field(std::ostream& out, + std::string name, + t_type* type, + t_const_value* value, + std::string cls_nm = ""); + std::string render_const_value(std::ostream& local_vars, + std::ostream& out, + std::string name, + t_type* type, + t_const_value* value); + void print_const_def_value(std::ostream& vars, + std::ostream& out, + std::string name, + t_type* type, + t_const_value* value, + std::string cls_nm = ""); + std::string make_constants_classname(); + + void generate_delphi_struct(t_struct* tstruct, bool is_exception); + void generate_delphi_struct_impl(ostream& out, + std::string cls_prefix, + t_struct* tstruct, + bool is_exception, + bool is_result = false, + bool is_x_factory = false); + void print_delphi_struct_type_factory_func(ostream& out, t_struct* tstruct); + void generate_delphi_struct_type_factory(ostream& out, + std::string cls_prefix, + t_struct* tstruct, + bool is_exception, + bool is_result = false, + bool is_x_factory = false); + void generate_delphi_struct_type_factory_registration(ostream& out, + std::string cls_prefix, + t_struct* tstruct, + bool is_exception, + bool is_result = false, + bool is_x_factory = false); + void generate_delphi_struct_definition(std::ostream& out, + t_struct* tstruct, + bool is_xception = false, + bool in_class = false, + bool is_result = false, + bool is_x_factory = false); + void generate_delphi_struct_reader(std::ostream& out, t_struct* tstruct); + void generate_delphi_struct_result_writer(std::ostream& out, t_struct* tstruct); + void generate_delphi_struct_writer(std::ostream& out, t_struct* tstruct); + void generate_delphi_struct_tostring(std::ostream& out, t_struct* tstruct); + + void generate_function_helpers(t_function* tfunction); + void generate_service_interface(t_service* tservice); + void generate_service_helpers(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* function); + + void generate_deserialize_field(std::ostream& out, + bool is_xception, + t_field* tfield, + std::string prefix, + std::ostream& local_vars); + void generate_deserialize_struct(std::ostream& out, + t_struct* tstruct, + std::string name, + std::string prefix); + void generate_deserialize_container(ostream& out, + bool is_xception, + t_type* ttype, + string name, + std::ostream& local_vars); + + void generate_deserialize_set_element(std::ostream& out, + bool is_xception, + t_set* tset, + std::string prefix, + std::ostream& local_vars); + void generate_deserialize_map_element(std::ostream& out, + bool is_xception, + t_map* tmap, + std::string prefix, + std::ostream& local_vars); + void generate_deserialize_list_element(std::ostream& out, + bool is_xception, + t_list* list, + std::string prefix, + std::ostream& local_vars); + + void generate_serialize_field(std::ostream& out, + bool is_xception, + t_field* tfield, + std::string prefix, + std::ostream& local_vars); + void generate_serialize_struct(std::ostream& out, + t_struct* tstruct, + std::string prefix, + std::ostream& local_vars); + void generate_serialize_container(std::ostream& out, + bool is_xception, + t_type* ttype, + std::string prefix, + std::ostream& local_vars); + void generate_serialize_map_element(std::ostream& out, + bool is_xception, + t_map* tmap, + std::string iter, + std::string map, + std::ostream& local_vars); + void generate_serialize_set_element(std::ostream& out, + bool is_xception, + t_set* tmap, + std::string iter, + std::ostream& local_vars); + void generate_serialize_list_element(std::ostream& out, + bool is_xception, + t_list* tlist, + std::string iter, + std::ostream& local_vars); + + void delphi_type_usings(std::ostream& out); + std::string delphi_thrift_usings(); + + std::string type_name(t_type* ttype, + bool b_cls = false, + bool b_no_postfix = false, + bool b_exception_factory = false, + bool b_full_exception_factory = false); + std::string normalize_clsnm(std::string name, + std::string prefix, + bool b_no_check_keyword = false); + std::string make_valid_delphi_identifier(std::string const& fromName); + std::string input_arg_prefix(t_type* ttype); + + std::string base_type_name(t_base_type* tbase); + std::string declare_field(t_field* tfield, + bool init = false, + std::string prefix = "", + bool is_xception_class = false); + std::string function_signature(t_function* tfunction, + std::string full_cls = "", + bool is_xception = false); + std::string argument_list(t_struct* tstruct); + std::string constructor_argument_list(t_struct* tstruct, std::string current_indent); + std::string type_to_enum(t_type* ttype); + std::string prop_name(t_field* tfield, bool is_xception = false); + std::string prop_name(std::string name, bool is_xception = false); + std::string constructor_param_name(string name); + + void write_enum(std::string line); + void write_forward_decr(std::string line); + void write_const(std::string line); + void write_struct(std::string line); + void write_service(std::string line); + + virtual std::string autogen_comment() { + return std::string("(**\n") + " * Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + + " *\n" + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + + " *)\n"; + } + + string replace_all(string contents, string search, string replace); + string xml_encode(string contents); + string xmldoc_encode(string contents); + string xmlattrib_encode(string contents); + void generate_delphi_doc(std::ostream& out, t_field* field); + void generate_delphi_doc(std::ostream& out, t_doc* tdoc); + void generate_delphi_doc(std::ostream& out, t_function* tdoc); + void generate_delphi_docstring_comment(std::ostream& out, string contents); + + bool type_can_be_null(t_type* ttype) { + while (ttype->is_typedef()) { + ttype = ((t_typedef*)ttype)->get_type(); + } + + return ttype->is_container() || ttype->is_struct() || ttype->is_xception(); + } + +private: + std::string namespace_name_; + std::ostringstream s_forward_decr; + std::ostringstream s_enum; + std::ostringstream s_const; + std::ostringstream s_struct; + std::ostringstream s_service; + std::ostringstream s_const_impl; + std::ostringstream s_struct_impl; + std::ostringstream s_service_impl; + std::ostringstream s_type_factory_registration; + std::ostringstream s_type_factory_funcs; + bool has_forward; + bool has_enum; + bool has_const; + std::string namespace_dir_; + std::map delphi_keywords; + std::map delphi_reserved_method; + std::map delphi_reserved_method_exception; + std::map types_known; + std::list typedefs_pending; + std::vector uses_list; + void create_keywords(); + bool find_keyword(std::map& keyword_map, std::string name); + std::string normalize_name(std::string name, + bool b_method = false, + bool b_exception_method = false); + std::string empty_value(t_type* type); + bool is_fully_defined_type(t_type* ttype); + void add_defined_type(t_type* ttype); + void init_known_types_list(); + bool is_void(t_type* type); + int indent_impl_; + bool ansistr_binary_; + bool register_types_; + bool constprefix_; + bool events_; + bool xmldoc_; + void indent_up_impl() { ++indent_impl_; }; + void indent_down_impl() { --indent_impl_; }; + std::string indent_impl() { + std::string ind = ""; + int i; + for (i = 0; i < indent_impl_; ++i) { + ind += " "; + } + return ind; + }; + std::ostream& indent_impl(std::ostream& os) { return os << indent_impl(); }; +}; + +string t_delphi_generator::replace_all(string contents, string search, string repl) { + string str(contents); + + size_t slen = search.length(); + size_t rlen = repl.length(); + size_t incr = (rlen > 0) ? rlen : 1; + + if (slen > 0) { + size_t found = str.find(search); + while ((found != string::npos) && (found < str.length())) { + str.replace(found, slen, repl); + found = str.find(search, found + incr); + } + } + + return str; +} + +// XML encoding +string t_delphi_generator::xml_encode(string contents) { + string str(contents); + + // escape the escape + str = replace_all(str, "&", "&"); + + // other standard XML entities + str = replace_all(str, "<", "<"); + str = replace_all(str, ">", ">"); + + return str; +} + +// XML attribute encoding +string t_delphi_generator::xmlattrib_encode(string contents) { + string str(xml_encode(contents)); + + // our attribs are enclosed in " + str = replace_all(str, "\"", "\\\""); + + return str; +} + +// XML encoding for doc comments +string t_delphi_generator::xmldoc_encode(string contents) { + string str(xml_encode(contents)); + + // XMLDoc specific: convert linebreaks into graphs + str = replace_all(str, "\r\n", "\r"); + str = replace_all(str, "\n", "\r"); + str = replace_all(str, "\r", "\n"); + + return str; +} + +void t_delphi_generator::generate_delphi_docstring_comment(ostream& out, string contents) { + if (xmldoc_) { + generate_docstring_comment(out, + "{$REGION 'XMLDoc'}/// \n", + "/// ", + "" + contents + "", + "/// \n{$ENDREGION}\n"); + } +} + +void t_delphi_generator::generate_delphi_doc(ostream& out, t_field* field) { + if (xmldoc_) { + if (field->get_type()->is_enum()) { + string combined_message = xmldoc_encode(field->get_doc()) + "\nget_type())) + "\"/>"; + generate_delphi_docstring_comment(out, combined_message); + } else { + generate_delphi_doc(out, (t_doc*)field); + } + } +} + +void t_delphi_generator::generate_delphi_doc(ostream& out, t_doc* tdoc) { + if (tdoc->has_doc() && xmldoc_) { + generate_delphi_docstring_comment(out, xmldoc_encode(tdoc->get_doc())); + } +} + +void t_delphi_generator::generate_delphi_doc(ostream& out, t_function* tfunction) { + if (tfunction->has_doc() && xmldoc_) { + stringstream ps; + const vector& fields = tfunction->get_arglist()->get_members(); + vector::const_iterator p_iter; + for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { + t_field* p = *p_iter; + ps << "\nget_name()) << "\">"; + if (p->has_doc()) { + std::string str = p->get_doc(); + str.erase(std::remove(str.begin(), str.end(), '\n'), + str.end()); // remove the newlines that appear from the parser + ps << xmldoc_encode(str); + } + ps << ""; + } + generate_docstring_comment(out, + "{$REGION 'XMLDoc'}", + "/// ", + "" + xmldoc_encode(tfunction->get_doc()) + + "" + ps.str(), + "{$ENDREGION}\n"); + } +} + +bool t_delphi_generator::find_keyword(std::map& keyword_map, std::string name) { + std::string::size_type len = name.length(); + + if (len <= 0) { + return false; + } + + std::string::size_type nlast = name.find_last_of('_'); + + if (nlast >= 1) { + if (nlast == (len - 1)) { + string new_name(name, 0, nlast); + return find_keyword(keyword_map, new_name); + } + } + return (keyword_map[name] == 1); +} + +std::string t_delphi_generator::normalize_name(std::string name, + bool b_method, + bool b_exception_method) { + string tmp(name); + std::transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast(std::tolower)); + + bool b_found = false; + + if (find_keyword(delphi_keywords, tmp)) { + b_found = true; + } else if (b_method && find_keyword(delphi_reserved_method, tmp)) { + b_found = true; + } else if (b_exception_method && find_keyword(delphi_reserved_method_exception, tmp)) { + b_found = true; + } + + if (b_found) { + return name + "_"; + } else { + return name; + } +} + +void t_delphi_generator::create_keywords() { + delphi_keywords["and"] = 1; + delphi_keywords["end"] = 1; + delphi_keywords["interface"] = 1; + delphi_keywords["raise"] = 1; + delphi_keywords["uses"] = 1; + delphi_keywords["array"] = 1; + delphi_keywords["except"] = 1; + delphi_keywords["is"] = 1; + delphi_keywords["record"] = 1; + delphi_keywords["var"] = 1; + delphi_keywords["as"] = 1; + delphi_keywords["exports"] = 1; + delphi_keywords["label"] = 1; + delphi_keywords["repeat"] = 1; + delphi_keywords["while"] = 1; + delphi_keywords["asm"] = 1; + delphi_keywords["file"] = 1; + delphi_keywords["library"] = 1; + delphi_keywords["resourcestring"] = 1; + delphi_keywords["with"] = 1; + delphi_keywords["begin"] = 1; + delphi_keywords["finalization"] = 1; + delphi_keywords["mod"] = 1; + delphi_keywords["set"] = 1; + delphi_keywords["xor"] = 1; + delphi_keywords["case"] = 1; + delphi_keywords["finally"] = 1; + delphi_keywords["nil"] = 1; + delphi_keywords["shl"] = 1; + delphi_keywords["class"] = 1; + delphi_keywords["for"] = 1; + delphi_keywords["not"] = 1; + delphi_keywords["shr"] = 1; + delphi_keywords["const"] = 1; + delphi_keywords["function"] = 1; + delphi_keywords["object"] = 1; + delphi_keywords["string"] = 1; + delphi_keywords["constructor"] = 1; + delphi_keywords["goto"] = 1; + delphi_keywords["of"] = 1; + delphi_keywords["then"] = 1; + delphi_keywords["destructor"] = 1; + delphi_keywords["if"] = 1; + delphi_keywords["or"] = 1; + delphi_keywords["threadvar"] = 1; + delphi_keywords["dispinterface"] = 1; + delphi_keywords["implementation"] = 1; + delphi_keywords["out"] = 1; + delphi_keywords["to"] = 1; + delphi_keywords["div"] = 1; + delphi_keywords["in"] = 1; + delphi_keywords["packed"] = 1; + delphi_keywords["try"] = 1; + delphi_keywords["do"] = 1; + delphi_keywords["inherited"] = 1; + delphi_keywords["procedure"] = 1; + delphi_keywords["type"] = 1; + delphi_keywords["downto"] = 1; + delphi_keywords["initialization"] = 1; + delphi_keywords["program"] = 1; + delphi_keywords["unit"] = 1; + delphi_keywords["else"] = 1; + delphi_keywords["inline"] = 1; + delphi_keywords["property"] = 1; + delphi_keywords["until"] = 1; + delphi_keywords["private"] = 1; + delphi_keywords["protected"] = 1; + delphi_keywords["public"] = 1; + delphi_keywords["published"] = 1; + delphi_keywords["automated"] = 1; + delphi_keywords["at"] = 1; + delphi_keywords["on"] = 1; + + // reserved/predefined variables and types (lowercase!) + delphi_keywords["result"] = 1; + delphi_keywords["tbytes"] = 1; + delphi_keywords["tobject"] = 1; + delphi_keywords["tclass"] = 1; + delphi_keywords["tinterfacedobject"] = 1; + + delphi_reserved_method["create"] = 1; + delphi_reserved_method["free"] = 1; + delphi_reserved_method["initinstance"] = 1; + delphi_reserved_method["cleanupinstance"] = 1; + delphi_reserved_method["classtype"] = 1; + delphi_reserved_method["classname"] = 1; + delphi_reserved_method["classnameis"] = 1; + delphi_reserved_method["classparent"] = 1; + delphi_reserved_method["classinfo"] = 1; + delphi_reserved_method["instancesize"] = 1; + delphi_reserved_method["inheritsfrom"] = 1; + delphi_reserved_method["methodaddress"] = 1; + delphi_reserved_method["methodaddress"] = 1; + delphi_reserved_method["methodname"] = 1; + delphi_reserved_method["fieldaddress"] = 1; + delphi_reserved_method["fieldaddress"] = 1; + delphi_reserved_method["getinterface"] = 1; + delphi_reserved_method["getinterfaceentry"] = 1; + delphi_reserved_method["getinterfacetable"] = 1; + delphi_reserved_method["unitname"] = 1; + delphi_reserved_method["equals"] = 1; + delphi_reserved_method["gethashcode"] = 1; + delphi_reserved_method["tostring"] = 1; + delphi_reserved_method["safecallexception"] = 1; + delphi_reserved_method["afterconstruction"] = 1; + delphi_reserved_method["beforedestruction"] = 1; + delphi_reserved_method["dispatch"] = 1; + delphi_reserved_method["defaulthandler"] = 1; + delphi_reserved_method["newinstance"] = 1; + delphi_reserved_method["freeinstance"] = 1; + delphi_reserved_method["destroy"] = 1; + delphi_reserved_method["read"] = 1; + delphi_reserved_method["write"] = 1; + + delphi_reserved_method_exception["setinnerexception"] = 1; + delphi_reserved_method_exception["setstackinfo"] = 1; + delphi_reserved_method_exception["getstacktrace"] = 1; + delphi_reserved_method_exception["raisingexception"] = 1; + delphi_reserved_method_exception["createfmt"] = 1; + delphi_reserved_method_exception["createres"] = 1; + delphi_reserved_method_exception["createresfmt"] = 1; + delphi_reserved_method_exception["createhelp"] = 1; + delphi_reserved_method_exception["createfmthelp"] = 1; + delphi_reserved_method_exception["createreshelp"] = 1; + delphi_reserved_method_exception["createresfmthelp"] = 1; + delphi_reserved_method_exception["getbaseexception"] = 1; + delphi_reserved_method_exception["baseexception"] = 1; + delphi_reserved_method_exception["helpcontext"] = 1; + delphi_reserved_method_exception["innerexception"] = 1; + delphi_reserved_method_exception["message"] = 1; + delphi_reserved_method_exception["stacktrace"] = 1; + delphi_reserved_method_exception["stackinfo"] = 1; + delphi_reserved_method_exception["getexceptionstackinfoproc"] = 1; + delphi_reserved_method_exception["getstackinfostringproc"] = 1; + delphi_reserved_method_exception["cleanupstackinfoproc"] = 1; + delphi_reserved_method_exception["raiseouterexception"] = 1; + delphi_reserved_method_exception["throwouterexception"] = 1; +} + +void t_delphi_generator::add_delphi_uses_list(string unitname) { + vector::const_iterator s_iter; + bool found = false; + for (s_iter = uses_list.begin(); s_iter != uses_list.end(); ++s_iter) { + if ((*s_iter) == unitname) { + found = true; + break; + } + } + if (!found) { + uses_list.push_back(unitname); + } +} + +void t_delphi_generator::init_generator() { + indent_impl_ = 0; + namespace_name_ = program_->get_namespace("delphi"); + has_forward = false; + has_enum = false; + has_const = false; + create_keywords(); + add_delphi_uses_list("Classes"); + add_delphi_uses_list("SysUtils"); + add_delphi_uses_list("Generics.Collections"); + add_delphi_uses_list("Thrift"); + add_delphi_uses_list("Thrift.Utils"); + add_delphi_uses_list("Thrift.Collections"); + add_delphi_uses_list("Thrift.Protocol"); + add_delphi_uses_list("Thrift.Transport"); + + if (register_types_) { + add_delphi_uses_list("Thrift.TypeRegistry"); + } + + init_known_types_list(); + + string unitname, nsname; + const vector& includes = program_->get_includes(); + for (size_t i = 0; i < includes.size(); ++i) { + unitname = includes[i]->get_name(); + nsname = includes[i]->get_namespace("delphi"); + if ("" != nsname) { + unitname = nsname; + } + add_delphi_uses_list(unitname); + } + + MKDIR(get_out_dir().c_str()); +} + +void t_delphi_generator::close_generator() { + std::string unitname = program_name_; + if ("" != namespace_name_) { + unitname = namespace_name_; + } + + for (int i = 0; i < (int)unitname.size(); i++) { + if (unitname[i] == ' ') { + unitname.replace(i, 1, "_"); + } + } + + std::string f_name = get_out_dir() + "/" + unitname + ".pas"; + std::ofstream f_all; + + f_all.open(f_name.c_str()); + + f_all << autogen_comment() << endl; + generate_delphi_doc(f_all, program_); + f_all << "unit " << unitname << ";" << endl << endl; + f_all << "interface" << endl << endl; + f_all << "uses" << endl; + + indent_up(); + + vector::const_iterator s_iter; + for (s_iter = uses_list.begin(); s_iter != uses_list.end(); ++s_iter) { + if (s_iter != uses_list.begin()) { + f_all << ","; + f_all << endl; + } + indent(f_all) << *s_iter; + } + + f_all << ";" << endl << endl; + + indent_down(); + + string tmp_unit(unitname); + for (int i = 0; i < (int)tmp_unit.size(); i++) { + if (tmp_unit[i] == '.') { + tmp_unit.replace(i, 1, "_"); + } + } + + f_all << "const" << endl; + indent_up(); + indent(f_all) << "c" << tmp_unit + << "_Option_AnsiStr_Binary = " << (ansistr_binary_ ? "True" : "False") << ";" + << endl; + indent(f_all) << "c" << tmp_unit + << "_Option_Register_Types = " << (register_types_ ? "True" : "False") << ";" + << endl; + indent(f_all) << "c" << tmp_unit + << "_Option_ConstPrefix = " << (constprefix_ ? "True" : "False") << ";" << endl; + indent(f_all) << "c" << tmp_unit << "_Option_Events = " << (events_ ? "True" : "False") + << ";" << endl; + indent(f_all) << "c" << tmp_unit << "_Option_XmlDoc = " << (xmldoc_ ? "True" : "False") + << ";" << endl; + indent_down(); + + f_all << endl; + f_all << "type" << endl; + if (has_forward) { + f_all << s_forward_decr.str() << endl; + } + if (has_enum) { + indent(f_all) << endl; + indent(f_all) << "{$SCOPEDENUMS ON}" << endl << endl; + f_all << s_enum.str(); + indent(f_all) << "{$SCOPEDENUMS OFF}" << endl << endl; + } + f_all << s_struct.str(); + f_all << s_service.str(); + f_all << s_const.str(); + f_all << "implementation" << endl << endl; + f_all << s_struct_impl.str(); + f_all << s_service_impl.str(); + f_all << s_const_impl.str(); + + if (register_types_) { + f_all << endl; + f_all << "// Type factory methods and registration" << endl; + f_all << s_type_factory_funcs.str(); + f_all << "procedure RegisterTypeFactories;" << endl; + f_all << "begin" << endl; + f_all << s_type_factory_registration.str(); + f_all << "end;" << endl; + } + f_all << endl; + + string constants_class = make_constants_classname(); + + f_all << "initialization" << endl; + if (has_const) { + f_all << "{$IF CompilerVersion < 21.0} // D2010" << endl; + f_all << " " << constants_class.c_str() << "_Initialize;" << endl; + f_all << "{$IFEND}" << endl; + } + if (register_types_) { + f_all << " RegisterTypeFactories;" << endl; + } + f_all << endl; + + f_all << "finalization" << endl; + if (has_const) { + f_all << "{$IF CompilerVersion < 21.0} // D2010" << endl; + f_all << " " << constants_class.c_str() << "_Finalize;" << endl; + f_all << "{$IFEND}" << endl; + } + f_all << endl << endl; + + f_all << "end." << endl; + f_all.close(); + + if (!typedefs_pending.empty()) { + pwarning(0, "%d typedefs with unresolved type references left:\n", typedefs_pending.size()); + for (std::list::iterator iter = typedefs_pending.begin(); + typedefs_pending.end() != iter; + ++iter) { + pwarning(0, "- %s\n", (*iter)->get_symbolic().c_str()); + } + } +} + +void t_delphi_generator::delphi_type_usings(ostream& out) { + indent_up(); + indent(out) << "Classes, SysUtils, Generics.Collections, Thrift.Collections, Thrift.Protocol," + << endl; + indent(out) << "Thrift.Transport;" << endl << endl; + indent_down(); +} + +void t_delphi_generator::generate_forward_declaration(t_struct* tstruct) { + // Forward declare struct def + has_forward = true; + pverbose("forward declaration of %s\n", type_name(tstruct).c_str()); + + string what = tstruct->is_xception() ? "class" : "interface"; + + indent_up(); + indent(s_forward_decr) << type_name(tstruct, tstruct->is_xception(), true) << " = " << what << ";" + << endl; + indent_down(); + + add_defined_type(tstruct); +} + +void t_delphi_generator::generate_typedef(t_typedef* ttypedef) { + t_type* type = ttypedef->get_type(); + + // write now or save for later? + if (!is_fully_defined_type(type)) { + pverbose("typedef %s: unresolved dependencies found\n", type_name(ttypedef).c_str()); + typedefs_pending.push_back(ttypedef); + return; + } + + indent_up(); + generate_delphi_doc(s_struct, ttypedef); + indent(s_struct) << type_name(ttypedef) << " = "; + + // commented out: the benefit is not big enough to risk breaking existing code + // bool container = type->is_list() || type->is_map() || type->is_set(); + // if( ! container) + // s_struct << "type "; //the "type A = type B" syntax leads to E2574 with generics + + s_struct << type_name(ttypedef->get_type()) << ";" << endl << endl; + indent_down(); + + add_defined_type(ttypedef); +} + +bool t_delphi_generator::is_fully_defined_type(t_type* ttype) { + if ((NULL != ttype->get_program()) && (ttype->get_program() != program_)) { + t_scope* scope = ttype->get_program()->scope(); + if (NULL != scope->get_type(ttype->get_name())) { + // printf("type %s found in included scope %s\n", ttype->get_name().c_str(), + // ttype->get_program()->get_name().c_str()); + return true; + } + } + + if (ttype->is_typedef()) { + return (1 == types_known[type_name(ttype)]); + } + + if (ttype->is_base_type()) { + return (1 == types_known[base_type_name((t_base_type*)ttype)]); + } else if (ttype->is_enum()) { + return true; // enums are written first, before all other types + } else if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + return is_fully_defined_type(tmap->get_key_type()) + && is_fully_defined_type(tmap->get_val_type()); + } else if (ttype->is_set()) { + t_set* tset = (t_set*)ttype; + return is_fully_defined_type(tset->get_elem_type()); + } else if (ttype->is_list()) { + t_list* tlist = (t_list*)ttype; + return is_fully_defined_type(tlist->get_elem_type()); + } + + return (1 == types_known[type_name(ttype)]); +} + +void t_delphi_generator::add_defined_type(t_type* ttype) { + // mark as known type + types_known[type_name(ttype)] = 1; + + // check all pending typedefs + std::list::iterator iter; + bool more = true; + while (more && (!typedefs_pending.empty())) { + more = false; + + for (iter = typedefs_pending.begin(); typedefs_pending.end() != iter; ++iter) { + t_typedef* ttypedef = (*iter); + if (is_fully_defined_type(ttypedef->get_type())) { + pverbose("typedef %s: all pending references are now resolved\n", + type_name(ttypedef).c_str()); + typedefs_pending.erase(iter); + generate_typedef(ttypedef); + more = true; + break; + } + } + } +} + +void t_delphi_generator::init_known_types_list() { + // known base types + types_known[type_name(g_type_string)] = 1; + types_known[type_name(g_type_binary)] = 1; + types_known[type_name(g_type_bool)] = 1; + types_known[type_name(g_type_i8)] = 1; + types_known[type_name(g_type_i16)] = 1; + types_known[type_name(g_type_i32)] = 1; + types_known[type_name(g_type_i64)] = 1; + types_known[type_name(g_type_double)] = 1; +} + +void t_delphi_generator::generate_enum(t_enum* tenum) { + has_enum = true; + indent_up(); + generate_delphi_doc(s_enum, tenum); + indent(s_enum) << type_name(tenum, true, true) << " = " + << "(" << endl; + indent_up(); + vector constants = tenum->get_constants(); + if (constants.empty()) { + indent(s_enum) << "dummy = 0 // empty enums are not allowed"; + } else { + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + if (c_iter != constants.begin()) { + s_enum << ","; + s_enum << endl; + } + generate_delphi_doc(s_enum, *c_iter); + indent(s_enum) << normalize_name((*c_iter)->get_name()) << " = " << value; + } + } + s_enum << endl; + indent_down(); + indent(s_enum) << ");" << endl << endl; + indent_down(); +} + +std::string t_delphi_generator::make_valid_delphi_identifier(std::string const& fromName) { + std::string str = fromName; + if (str.empty()) { + return str; + } + + // tests rely on this + assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9')); + + // if the first letter is a number, we add an additional underscore in front of it + char c = str.at(0); + if (('0' <= c) && (c <= '9')) { + str = "_" + str; + } + + // following chars: letter, number or underscore + for (size_t i = 0; i < str.size(); ++i) { + c = str.at(i); + if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9')) + && ('_' != c)) { + str.replace(i, 1, "_"); + } + } + + return str; +} + +std::string t_delphi_generator::make_constants_classname() { + if (constprefix_) { + return make_valid_delphi_identifier("T" + program_name_ + "Constants"); + } else { + return "TConstants"; // compatibility + } +} + +void t_delphi_generator::generate_consts(std::vector consts) { + if (consts.empty()) { + return; + } + + has_const = true; + string constants_class = make_constants_classname(); + + indent_up(); + indent(s_const) << constants_class.c_str() << " = class" << endl; + indent(s_const) << "private" << endl; + indent_up(); + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + if (const_needs_var((*c_iter)->get_type())) { + print_private_field(s_const, + normalize_name((*c_iter)->get_name()), + (*c_iter)->get_type(), + (*c_iter)->get_value()); + } + } + indent_down(); + indent(s_const) << "public" << endl; + indent_up(); + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + generate_delphi_doc(s_const, *c_iter); + print_const_prop(s_const, + normalize_name((*c_iter)->get_name()), + (*c_iter)->get_type(), + (*c_iter)->get_value()); + } + indent(s_const) << "{$IF CompilerVersion >= 21.0}" << endl; + indent(s_const) << "class constructor Create;" << endl; + indent(s_const) << "class destructor Destroy;" << endl; + indent(s_const) << "{$IFEND}" << endl; + indent_down(); + indent(s_const) << "end;" << endl << endl; + indent_down(); + + std::ostringstream vars, code; + + indent_up_impl(); + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + initialize_field(vars, + code, + "F" + prop_name((*c_iter)->get_name()), + (*c_iter)->get_type(), + (*c_iter)->get_value()); + } + indent_down_impl(); + + indent_impl(s_const_impl) << "{$IF CompilerVersion >= 21.0}" << endl; + indent_impl(s_const_impl) << "class constructor " << constants_class.c_str() << ".Create;" + << endl; + + if (!vars.str().empty()) { + indent_impl(s_const_impl) << "var" << endl; + s_const_impl << vars.str(); + } + indent_impl(s_const_impl) << "begin" << endl; + if (!code.str().empty()) { + s_const_impl << code.str(); + } + indent_impl(s_const_impl) << "end;" << endl << endl; + indent_impl(s_const_impl) << "class destructor " << constants_class.c_str() << ".Destroy;" + << endl; + indent_impl(s_const_impl) << "begin" << endl; + indent_up_impl(); + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + if (const_needs_var((*c_iter)->get_type())) { + finalize_field(s_const_impl, + normalize_name((*c_iter)->get_name()), + (*c_iter)->get_type(), + (*c_iter)->get_value()); + } + } + indent_impl(s_const_impl) << "inherited;" << endl; + indent_down_impl(); + indent_impl(s_const_impl) << "end;" << endl; + indent_impl(s_const_impl) << "{$ELSE}" << endl; + + vars.str(""); + code.str(""); + + indent_up_impl(); + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + if (const_needs_var((*c_iter)->get_type())) { + initialize_field(vars, + code, + constants_class + ".F" + prop_name((*c_iter)->get_name()), + (*c_iter)->get_type(), + (*c_iter)->get_value()); + } + } + indent_down_impl(); + + indent_impl(s_const_impl) << "procedure " << constants_class.c_str() << "_Initialize;" << endl; + if (!vars.str().empty()) { + indent_impl(s_const_impl) << "var" << endl; + s_const_impl << vars.str(); + } + indent_impl(s_const_impl) << "begin" << endl; + if (!code.str().empty()) { + s_const_impl << code.str(); + } + indent_impl(s_const_impl) << "end;" << endl << endl; + + indent_impl(s_const_impl) << "procedure " << constants_class.c_str() << "_Finalize;" << endl; + indent_impl(s_const_impl) << "begin" << endl; + indent_up_impl(); + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + finalize_field(s_const_impl, + normalize_name((*c_iter)->get_name()), + (*c_iter)->get_type(), + (*c_iter)->get_value(), + constants_class); + } + indent_down_impl(); + indent_impl(s_const_impl) << "end;" << endl; + indent_impl(s_const_impl) << "{$IFEND}" << endl << endl; +} + +void t_delphi_generator::print_const_def_value(std::ostream& vars, + std::ostream& out, + string name, + t_type* type, + t_const_value* value, + string cls_nm) { + + string cls_prefix; + + if (cls_nm == "") { + cls_prefix = ""; + } else { + cls_prefix = cls_nm + "."; + } + + if (type->is_struct() || type->is_xception()) { + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + string val = render_const_value(vars, out, name, field_type, v_iter->second); + indent_impl(out) << cls_prefix << normalize_name(name) << "." + << prop_name(v_iter->first->get_string(), type->is_xception()) + << " := " << val << ";" << endl; + } + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string key = render_const_value(vars, out, name, ktype, v_iter->first); + string val = render_const_value(vars, out, name, vtype, v_iter->second); + indent_impl(out) << cls_prefix << normalize_name(name) << "[" << key << "]" + << " := " << val << ";" << endl; + } + } else if (type->is_list() || type->is_set()) { + t_type* etype; + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(vars, out, name, etype, *v_iter); + indent_impl(out) << cls_prefix << normalize_name(name) << ".Add(" << val << ");" << endl; + } + } +} + +void t_delphi_generator::print_private_field(std::ostream& out, + string name, + t_type* type, + t_const_value* value) { + (void)value; + indent(out) << "class var F" << name << ": " << type_name(type) << ";" << endl; +} + +bool t_delphi_generator::const_needs_var(t_type* type) { + t_type* truetype = type; + while (truetype->is_typedef()) { + truetype = ((t_typedef*)truetype)->get_type(); + } + return (!truetype->is_base_type()); +} + +void t_delphi_generator::print_const_prop(std::ostream& out, + string name, + t_type* type, + t_const_value* value) { + (void)value; + if (const_needs_var(type)) { + indent(out) << "class property " << name << ": " << type_name(type) << " read F" << name << ";" + << endl; + } else { + std::ostringstream vars; // dummy + string v2 = render_const_value(vars, out, name, type, value); + indent(out) << "const " << name << " = " << v2 << ";" << endl; + } +} + +void t_delphi_generator::print_const_value(std::ostream& vars, + std::ostream& out, + string name, + t_type* type, + t_const_value* value) { + t_type* truetype = type; + while (truetype->is_typedef()) { + truetype = ((t_typedef*)truetype)->get_type(); + } + + if (truetype->is_base_type()) { + // already done + // string v2 = render_const_value( vars, out, name, type, value); + // indent_impl(out) << name << " := " << v2 << ";" << endl; + } else if (truetype->is_enum()) { + indent_impl(out) << name << " := " << type_name(type) << "." << value->get_identifier_name() + << ";" << endl; + } else { + string typname; + typname = type_name(truetype, true, false, type->is_xception(), type->is_xception()); + indent_impl(out) << name << " := " << typname << ".Create;" << endl; + print_const_def_value(vars, out, name, truetype, value); + } +} + +void t_delphi_generator::initialize_field(std::ostream& vars, + std::ostream& out, + string name, + t_type* type, + t_const_value* value) { + print_const_value(vars, out, name, type, value); +} + +void t_delphi_generator::finalize_field(std::ostream& out, + string name, + t_type* type, + t_const_value* value, + string cls_nm) { + (void)out; + (void)name; + (void)type; + (void)value; + (void)cls_nm; +} + +string t_delphi_generator::render_const_value(ostream& vars, + ostream& out, + string name, + t_type* type, + t_const_value* value) { + (void)name; + + t_type* truetype = type; + while (truetype->is_typedef()) { + truetype = ((t_typedef*)truetype)->get_type(); + } + + std::ostringstream render; + + if (truetype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)truetype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + render << "'" << get_escaped_string(value) << "'"; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() > 0) ? "True" : "False"); + break; + case t_base_type::TYPE_I8: + render << "ShortInt( " << value->get_integer() << ")"; + break; + case t_base_type::TYPE_I16: + render << "SmallInt( " << value->get_integer() << ")"; + break; + case t_base_type::TYPE_I32: + render << "LongInt( " << value->get_integer() << ")"; + break; + case t_base_type::TYPE_I64: + render << "Int64( " << value->get_integer() << ")"; + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + render << value->get_integer() << ".0"; // make it a double constant by adding ".0" + } else { + render << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (truetype->is_enum()) { + render << type_name(type, false) << "." << value->get_identifier_name(); + } else { + string t = tmp("tmp"); + vars << " " << t << " : " << type_name(type) << ";" << endl; + print_const_value(vars, out, t, type, value); + render << t; + } + + return render.str(); +} + +void t_delphi_generator::generate_struct(t_struct* tstruct) { + generate_delphi_struct(tstruct, false); +} + +void t_delphi_generator::generate_xception(t_struct* txception) { + generate_delphi_struct(txception, true); +} + +void t_delphi_generator::generate_delphi_struct(t_struct* tstruct, bool is_exception) { + indent_up(); + generate_delphi_struct_definition(s_struct, tstruct, is_exception); + indent_down(); + + add_defined_type(tstruct); + + generate_delphi_struct_impl(s_struct_impl, "", tstruct, is_exception); + if (register_types_) { + generate_delphi_struct_type_factory(s_type_factory_funcs, "", tstruct, is_exception); + generate_delphi_struct_type_factory_registration(s_type_factory_registration, + "", + tstruct, + is_exception); + } +} + +void t_delphi_generator::generate_delphi_struct_impl(ostream& out, + string cls_prefix, + t_struct* tstruct, + bool is_exception, + bool is_result, + bool is_x_factory) { + + if (is_exception && (!is_x_factory)) { + generate_delphi_struct_impl(out, cls_prefix, tstruct, is_exception, is_result, true); + } + + string cls_nm; + + string exception_factory_name; + + if (is_exception) { + exception_factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory"; + } + + if (is_exception) { + cls_nm = type_name(tstruct, true, (!is_x_factory), is_x_factory, true); + } else { + cls_nm = type_name(tstruct, true, false); + } + + std::ostringstream vars, code; + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + indent_up_impl(); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = (*m_iter)->get_type(); + while (t->is_typedef()) { + t = ((t_typedef*)t)->get_type(); + } + if ((*m_iter)->get_value() != NULL) { + initialize_field(vars, + code, + "F" + prop_name((*m_iter)->get_name(), is_exception), + t, + (*m_iter)->get_value()); + if ((*m_iter)->get_req() != t_field::T_REQUIRED) { + indent_impl(code) << "F__isset_" << prop_name((*m_iter), is_exception) << " := True;" + << endl; + } + } + } + indent_down_impl(); + + indent_impl(out) << "constructor " << cls_prefix << cls_nm << "." + << "Create;" << endl; + + if (!vars.str().empty()) { + out << "var" << endl; + out << vars.str(); + } + + indent_impl(out) << "begin" << endl; + indent_up_impl(); + if (is_exception && (!is_x_factory)) { + indent_impl(out) << "inherited Create('');" << endl; + indent_impl(out) << "F" << exception_factory_name << " := T" << exception_factory_name + << "Impl.Create;" << endl; + } else { + indent_impl(out) << "inherited;" << endl; + } + + if (!code.str().empty()) { + out << code.str(); + } + + indent_down_impl(); + indent_impl(out) << "end;" << endl << endl; + + if ((members.size() > 0) && is_exception && (!is_x_factory)) { + indent_impl(out) << "constructor " << cls_prefix << cls_nm << "." + << "Create(" << constructor_argument_list(tstruct, indent_impl()) << ");" + << endl; + indent_impl(out) << "begin" << endl; + indent_up_impl(); + indent_impl(out) << "Create;" << endl; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + string propname = prop_name((*m_iter)->get_name(), is_exception); + string param_name = constructor_param_name((*m_iter)->get_name()); + indent_impl(out) << propname << " := " << param_name << ";" << endl; + } + indent_impl(out) << "UpdateMessageProperty;" << endl; + indent_down_impl(); + indent_impl(out) << "end;" << endl << endl; + } + + indent_impl(out) << "destructor " << cls_prefix << cls_nm << "." + << "Destroy;" << endl; + indent_impl(out) << "begin" << endl; + indent_up_impl(); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = (*m_iter)->get_type(); + while (t->is_typedef()) { + t = ((t_typedef*)t)->get_type(); + } + finalize_field(out, prop_name(*m_iter, is_exception), t, (*m_iter)->get_value()); + } + + indent_impl(out) << "inherited;" << endl; + indent_down_impl(); + indent_impl(out) << "end;" << endl << endl; + + if (tstruct->is_union()) { + indent_impl(out) << "procedure " << cls_prefix << cls_nm << "." + << "ClearUnionValues;" << endl; + indent_impl(out) << "begin" << endl; + indent_up_impl(); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = (*m_iter)->get_type(); + while (t->is_typedef()) { + t = ((t_typedef*)t)->get_type(); + } + + generate_delphi_clear_union_value(out, + cls_prefix, + cls_nm, + t, + *m_iter, + "F", + is_exception, + tstruct->is_union(), + is_x_factory, + exception_factory_name); + } + indent_down_impl(); + indent_impl(out) << "end;" << endl << endl; + } + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = (*m_iter)->get_type(); + while (t->is_typedef()) { + t = ((t_typedef*)t)->get_type(); + } + generate_delphi_property_reader_impl(out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception); + generate_delphi_property_writer_impl(out, + cls_prefix, + cls_nm, + t, + *m_iter, + "F", + is_exception, + tstruct->is_union(), + is_x_factory, + exception_factory_name); + if ((*m_iter)->get_req() != t_field::T_REQUIRED) { + generate_delphi_isset_reader_impl(out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception); + } + } + + if ((!is_exception) || is_x_factory) { + generate_delphi_struct_reader_impl(out, cls_prefix, tstruct, is_exception); + if (is_result) { + generate_delphi_struct_result_writer_impl(out, cls_prefix, tstruct, is_exception); + } else { + generate_delphi_struct_writer_impl(out, cls_prefix, tstruct, is_exception); + } + } + generate_delphi_struct_tostring_impl(out, cls_prefix, tstruct, is_exception, is_x_factory); + + if (is_exception && is_x_factory) { + generate_delphi_create_exception_impl(out, cls_prefix, tstruct, is_exception); + } +} + +void t_delphi_generator::print_delphi_struct_type_factory_func(ostream& out, t_struct* tstruct) { + string struct_intf_name = type_name(tstruct); + out << "Create_"; + out << struct_intf_name; + out << "_Impl"; +} + +void t_delphi_generator::generate_delphi_struct_type_factory(ostream& out, + string cls_prefix, + t_struct* tstruct, + bool is_exception, + bool is_result, + bool is_x_factory) { + (void)cls_prefix; + if (is_exception) + return; + if (is_result) + return; + if (is_x_factory) + return; + + string struct_intf_name = type_name(tstruct); + string cls_nm = type_name(tstruct, true, false); + + out << "function "; + print_delphi_struct_type_factory_func(out, tstruct); + out << ": "; + out << struct_intf_name; + out << ";" << endl; + out << "begin" << endl; + indent_up(); + indent(out) << "Result := " << cls_nm << ".Create;" << endl; + indent_down(); + out << "end;" << endl << endl; +} + +void t_delphi_generator::generate_delphi_struct_type_factory_registration(ostream& out, + string cls_prefix, + t_struct* tstruct, + bool is_exception, + bool is_result, + bool is_x_factory) { + (void)cls_prefix; + if (is_exception) + return; + if (is_result) + return; + if (is_x_factory) + return; + + string struct_intf_name = type_name(tstruct); + + indent(out) << " TypeRegistry.RegisterTypeFactory<" << struct_intf_name << ">("; + print_delphi_struct_type_factory_func(out, tstruct); + out << ");"; + out << endl; +} + +void t_delphi_generator::generate_delphi_struct_definition(ostream& out, + t_struct* tstruct, + bool is_exception, + bool in_class, + bool is_result, + bool is_x_factory) { + bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); + string struct_intf_name; + string struct_name; + string isset_name; + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + string exception_factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory"; + + if (is_exception) { + struct_intf_name = type_name(tstruct, false, false, true); + } else { + struct_intf_name = type_name(tstruct); + } + + if (is_exception) { + struct_name = type_name(tstruct, true, (!is_x_factory), is_x_factory); + } else { + struct_name = type_name(tstruct, true); + } + + if ((!is_exception) || is_x_factory) { + + generate_delphi_doc(out, tstruct); + indent(out) << struct_intf_name << " = interface(IBase)" << endl; + indent_up(); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + generate_delphi_property_reader_definition(out, *m_iter, is_exception); + generate_delphi_property_writer_definition(out, *m_iter, is_exception); + } + + if (is_x_factory) { + out << endl; + indent(out) << "// Create Exception Object" << endl; + indent(out) << "function CreateException: " << type_name(tstruct, true, true) << ";" << endl; + } + + if (members.size() > 0) { + out << endl; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + generate_property(out, *m_iter, true, is_exception); + } + } + + if (members.size() > 0) { + out << endl; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() != t_field::T_REQUIRED) { + generate_delphi_isset_reader_definition(out, *m_iter, is_exception); + } + } + } + + if (members.size() > 0) { + out << endl; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() != t_field::T_REQUIRED) { + isset_name = "__isset_" + prop_name(*m_iter, is_exception); + indent(out) << "property " << isset_name << ": Boolean read Get" << isset_name << ";" + << endl; + } + } + } + + indent_down(); + indent(out) << "end;" << endl << endl; + } + + generate_delphi_doc(out, tstruct); + indent(out) << struct_name << " = "; + if (is_final) { + out << "sealed "; + } + out << "class("; + if (is_exception && (!is_x_factory)) { + out << "TException"; + } else { + out << "TInterfacedObject, IBase, " << struct_intf_name; + } + out << ")" << endl; + + if (is_exception && (!is_x_factory)) { + indent(out) << "public" << endl; + indent_up(); + indent(out) << "type" << endl; + indent_up(); + generate_delphi_struct_definition(out, tstruct, is_exception, in_class, is_result, true); + indent_down(); + indent_down(); + } + + indent(out) << "private" << endl; + indent_up(); + + if (is_exception && (!is_x_factory)) { + indent(out) << "F" << exception_factory_name << " :" << struct_intf_name << ";" << endl << endl; + } + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << declare_field(*m_iter, false, "F", is_exception) << endl; + } + + if (members.size() > 0) { + indent(out) << endl; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() != t_field::T_REQUIRED) { + isset_name = "F__isset_" + prop_name(*m_iter, is_exception); + indent(out) << isset_name << ": Boolean;" << endl; + } + } + } + + indent(out) << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + generate_delphi_property_reader_definition(out, *m_iter, is_exception); + generate_delphi_property_writer_definition(out, *m_iter, is_exception); + } + + if (tstruct->is_union()) { + out << endl; + indent(out) << "// Clear values(for union's property setter)" << endl; + indent(out) << "procedure ClearUnionValues;" << endl; + } + + if (members.size() > 0) { + out << endl; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() != t_field::T_REQUIRED) { + isset_name = "__isset_" + prop_name(*m_iter, is_exception); + indent(out) << "function Get" << isset_name << ": Boolean;" << endl; + } + } + } + + indent_down(); + + indent(out) << "public" << endl; + indent_up(); + + if ((members.size() > 0) && is_exception && (!is_x_factory)) { + indent(out) << "constructor Create; overload;" << endl; + indent(out) << "constructor Create(" << constructor_argument_list(tstruct, indent()) + << "); overload;" << endl; + } else { + indent(out) << "constructor Create;" << endl; + } + + indent(out) << "destructor Destroy; override;" << endl; + + out << endl; + indent(out) << "function ToString: string; override;" << endl; + + if (is_exception && (!is_x_factory)) { + out << endl; + indent(out) << "// Exception Factory" << endl; + indent(out) << "property " << exception_factory_name << ": " << struct_intf_name << " read F" + << exception_factory_name << " write F" << exception_factory_name << ";" << endl; + } + + if ((!is_exception) || is_x_factory) { + out << endl; + indent(out) << "// IBase" << endl; + indent(out) << "procedure Read( const iprot: IProtocol);" << endl; + indent(out) << "procedure Write( const oprot: IProtocol);" << endl; + } + + if (is_exception && is_x_factory) { + out << endl; + indent(out) << "// Create Exception Object" << endl; + indent(out) << "function CreateException: " << type_name(tstruct, true, true) << ";" << endl; + } + + if (members.size() > 0) { + out << endl; + indent(out) << "// Properties" << endl; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + generate_property(out, *m_iter, true, is_exception); + } + } + + if (members.size() > 0) { + out << endl; + indent(out) << "// isset" << endl; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() != t_field::T_REQUIRED) { + isset_name = "__isset_" + prop_name(*m_iter, is_exception); + indent(out) << "property " << isset_name << ": Boolean read Get" << isset_name << ";" + << endl; + } + } + } + + indent_down(); + indent(out) << "end;" << endl << endl; +} + +void t_delphi_generator::generate_service(t_service* tservice) { + indent_up(); + generate_delphi_doc(s_service, tservice); + indent(s_service) << normalize_clsnm(service_name_, "T") << " = class" << endl; + indent(s_service) << "public" << endl; + indent_up(); + indent(s_service) << "type" << endl; + generate_service_interface(tservice); + generate_service_client(tservice); + generate_service_server(tservice); + generate_service_helpers(tservice); + indent_down(); + indent_down(); + indent(s_service) << "end;" << endl; + indent(s_service) << endl; + indent_down(); +} + +void t_delphi_generator::generate_service_interface(t_service* tservice) { + string extends = ""; + string extends_iface = ""; + + indent_up(); + + generate_delphi_doc(s_service, tservice); + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends(), true, true); + extends_iface = extends + ".Iface"; + generate_delphi_doc(s_service, tservice); + indent(s_service) << "Iface = interface(" << extends_iface << ")" << endl; + } else { + indent(s_service) << "Iface = interface" << endl; + } + + indent_up(); + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_delphi_doc(s_service, *f_iter); + indent(s_service) << function_signature(*f_iter) << endl; + } + indent_down(); + indent(s_service) << "end;" << endl << endl; + + indent_down(); +} + +void t_delphi_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_delphi_struct_definition(s_service, ts, false, true); + generate_delphi_struct_impl(s_service_impl, + normalize_clsnm(service_name_, "T") + ".", + ts, + false); + generate_function_helpers(*f_iter); + } +} + +void t_delphi_generator::generate_service_client(t_service* tservice) { + indent_up(); + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_client = extends + ".Client, "; + } + + generate_delphi_doc(s_service, tservice); + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends(), true, true); + extends_client = extends + ".TClient"; + indent(s_service) << "TClient = class(" << extends_client << ", Iface)" << endl; + } else { + indent(s_service) << "TClient = class( TInterfacedObject, Iface)" << endl; + } + + indent(s_service) << "public" << endl; + indent_up(); + + indent(s_service) << "constructor Create( prot: IProtocol); overload;" << endl; + + indent_impl(s_service_impl) << "constructor " << normalize_clsnm(service_name_, "T") + << ".TClient.Create( prot: IProtocol);" << endl; + indent_impl(s_service_impl) << "begin" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "Create( prot, prot );" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl << endl; + + indent(s_service) + << "constructor Create( const iprot: IProtocol; const oprot: IProtocol); overload;" << endl; + + indent_impl(s_service_impl) << "constructor " << normalize_clsnm(service_name_, "T") + << ".TClient.Create( const iprot: IProtocol; const oprot: IProtocol);" + << endl; + indent_impl(s_service_impl) << "begin" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "inherited Create;" << endl; + indent_impl(s_service_impl) << "iprot_ := iprot;" << endl; + indent_impl(s_service_impl) << "oprot_ := oprot;" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl << endl; + + indent_down(); + + if (extends.empty()) { + indent(s_service) << "protected" << endl; + indent_up(); + indent(s_service) << "iprot_: IProtocol;" << endl; + indent(s_service) << "oprot_: IProtocol;" << endl; + indent(s_service) << "seqid_: Integer;" << endl; + indent_down(); + + indent(s_service) << "public" << endl; + indent_up(); + indent(s_service) << "property InputProtocol: IProtocol read iprot_;" << endl; + indent(s_service) << "property OutputProtocol: IProtocol read oprot_;" << endl; + indent_down(); + } + + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + + indent(s_service) << "protected" << endl; + indent_up(); + indent(s_service) << "// Iface" << endl; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string funname = (*f_iter)->get_name(); + generate_delphi_doc(s_service, *f_iter); + indent(s_service) << function_signature(*f_iter) << endl; + } + indent_down(); + + indent(s_service) << "public" << endl; + indent_up(); + + string full_cls = normalize_clsnm(service_name_, "T") + ".TClient"; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string funname = (*f_iter)->get_name(); + + indent_impl(s_service_impl) << function_signature(*f_iter, full_cls) << endl; + indent_impl(s_service_impl) << "begin" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "send_" << funname << "("; + + t_struct* arg_struct = (*f_iter)->get_arglist(); + + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + bool first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + if (first) { + first = false; + } else { + s_service_impl << ", "; + } + s_service_impl << normalize_name((*fld_iter)->get_name()); + } + s_service_impl << ");" << endl; + + if (!(*f_iter)->is_oneway()) { + s_service_impl << indent_impl(); + if (!(*f_iter)->get_returntype()->is_void()) { + s_service_impl << "Result := "; + } + s_service_impl << "recv_" << funname << "();" << endl; + } + + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl << endl; + + t_function send_function(g_type_void, + string("send_") + (*f_iter)->get_name(), + (*f_iter)->get_arglist()); + + string argsname = (*f_iter)->get_name() + "_args"; + string args_clsnm = normalize_clsnm(argsname, "T"); + string args_intfnm = normalize_clsnm(argsname, "I"); + + string argsvar = tmp("_args"); + string msgvar = tmp("_msg"); + + indent(s_service) << function_signature(&send_function) << endl; + indent_impl(s_service_impl) << function_signature(&send_function, full_cls) << endl; + indent_impl(s_service_impl) << "var" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << argsvar << " : " << args_intfnm << ";" << endl; + indent_impl(s_service_impl) << msgvar << " : Thrift.Protocol.TThriftMessage;" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "begin" << endl; + indent_up_impl(); + + indent_impl(s_service_impl) << "seqid_ := seqid_ + 1;" << endl; + indent_impl(s_service_impl) << "Thrift.Protocol.Init( " << msgvar << ", '" << funname + << "', " << ((*f_iter)->is_oneway() ? "TMessageType.Oneway" + : "TMessageType.Call") + << ", seqid_);" << endl; + + indent_impl(s_service_impl) << "oprot_.WriteMessageBegin( " << msgvar << " );" << endl; + indent_impl(s_service_impl) << argsvar << " := " << args_clsnm << "Impl.Create();" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + indent_impl(s_service_impl) << argsvar << "." << prop_name(*fld_iter) + << " := " << normalize_name((*fld_iter)->get_name()) << ";" + << endl; + } + indent_impl(s_service_impl) << argsvar << ".Write(oprot_);" << endl; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + indent_impl(s_service_impl) << argsvar << "." << prop_name(*fld_iter) + << " := " << empty_value((*fld_iter)->get_type()) << ";" << endl; + } + + indent_impl(s_service_impl) << "oprot_.WriteMessageEnd();" << endl; + indent_impl(s_service_impl) << "oprot_.Transport.Flush();" << endl; + + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl << endl; + + if (!(*f_iter)->is_oneway()) { + string org_resultname = (*f_iter)->get_name() + "_result"; + string result_clsnm = normalize_clsnm(org_resultname, "T"); + string result_intfnm = normalize_clsnm(org_resultname, "I"); + + t_struct noargs(program_); + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + &noargs, + (*f_iter)->get_xceptions()); + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + + string exceptvar = tmp("_ex"); + string appexvar = tmp("_ax"); + string retvar = tmp("_ret"); + + indent(s_service) << function_signature(&recv_function) << endl; + indent_impl(s_service_impl) << function_signature(&recv_function, full_cls) << endl; + indent_impl(s_service_impl) << "var" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << msgvar << " : Thrift.Protocol.TThriftMessage;" << endl; + if (xceptions.size() > 0) { + indent_impl(s_service_impl) << exceptvar << " : Exception;" << endl; + } + indent_impl(s_service_impl) << appexvar << " : TApplicationException;" << endl; + indent_impl(s_service_impl) << retvar << " : " << result_intfnm << ";" << endl; + + indent_down_impl(); + indent_impl(s_service_impl) << "begin" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << msgvar << " := iprot_.ReadMessageBegin();" << endl; + indent_impl(s_service_impl) << "if (" << msgvar << ".Type_ = TMessageType.Exception) then" + << endl; + indent_impl(s_service_impl) << "begin" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << appexvar << " := TApplicationException.Read(iprot_);" << endl; + indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << endl; + indent_impl(s_service_impl) << "raise " << appexvar << ";" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl; + + indent_impl(s_service_impl) << retvar << " := " << result_clsnm << "Impl.Create();" << endl; + indent_impl(s_service_impl) << retvar << ".Read(iprot_);" << endl; + indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << endl; + + if (!(*f_iter)->get_returntype()->is_void()) { + indent_impl(s_service_impl) << "if (" << retvar << ".__isset_success) then" << endl; + indent_impl(s_service_impl) << "begin" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "Result := " << retvar << ".Success;" << endl; + t_type* type = (*f_iter)->get_returntype(); + if (type->is_struct() || type->is_xception() || type->is_map() || type->is_list() + || type->is_set()) { + indent_impl(s_service_impl) << retvar << ".Success := nil;" << endl; + } + indent_impl(s_service_impl) << "Exit;" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl; + } + + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + indent_impl(s_service_impl) << "if (" << retvar << ".__isset_" << prop_name(*x_iter) + << ") then" << endl; + indent_impl(s_service_impl) << "begin" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << exceptvar << " := " << retvar << "." << prop_name(*x_iter) + << ".CreateException;" << endl; + indent_impl(s_service_impl) << "raise " << exceptvar << ";" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl; + } + + if (!(*f_iter)->get_returntype()->is_void()) { + indent_impl(s_service_impl) + << "raise TApplicationExceptionMissingResult.Create('" + << (*f_iter)->get_name() << " failed: unknown result');" << endl; + } + + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl << endl; + } + } + + indent_down(); + indent(s_service) << "end;" << endl << endl; +} + +void t_delphi_generator::generate_service_server(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + string extends = ""; + string extends_processor = ""; + + string full_cls = normalize_clsnm(service_name_, "T") + ".TProcessorImpl"; + + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends(), true, true); + extends_processor = extends + ".TProcessorImpl"; + indent(s_service) << "TProcessorImpl = class(" << extends_processor << ", IProcessor)" << endl; + } else { + indent(s_service) << "TProcessorImpl = class( TInterfacedObject, IProcessor)" << endl; + } + + indent(s_service) << "public" << endl; + indent_up(); + indent(s_service) << "constructor Create( iface_: Iface );" << endl; + indent(s_service) << "destructor Destroy; override;" << endl; + indent_down(); + + indent_impl(s_service_impl) << "constructor " << full_cls << ".Create( iface_: Iface );" << endl; + indent_impl(s_service_impl) << "begin" << endl; + indent_up_impl(); + if (tservice->get_extends() != NULL) { + indent_impl(s_service_impl) << "inherited Create( iface_);" << endl; + } else { + indent_impl(s_service_impl) << "inherited Create;" << endl; + } + indent_impl(s_service_impl) << "Self.iface_ := iface_;" << endl; + if (tservice->get_extends() != NULL) { + indent_impl(s_service_impl) << "ASSERT( processMap_ <> nil); // inherited" << endl; + } else { + indent_impl(s_service_impl) + << "processMap_ := TThriftDictionaryImpl.Create;" << endl; + } + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + indent_impl(s_service_impl) << "processMap_.AddOrSetValue( '" << (*f_iter)->get_name() << "', " + << (*f_iter)->get_name() << "_Process);" << endl; + } + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl << endl; + + indent_impl(s_service_impl) << "destructor " << full_cls << ".Destroy;" << endl; + indent_impl(s_service_impl) << "begin" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "inherited;" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl << endl; + + indent(s_service) << "private" << endl; + indent_up(); + indent(s_service) << "iface_: Iface;" << endl; + indent_down(); + + if (tservice->get_extends() == NULL) { + indent(s_service) << "protected" << endl; + indent_up(); + indent(s_service) << "type" << endl; + indent_up(); + indent(s_service) << "TProcessFunction = reference to procedure( seqid: Integer; const iprot: " + "IProtocol; const oprot: IProtocol" + << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl; + indent_down(); + indent_down(); + indent(s_service) << "protected" << endl; + indent_up(); + indent(s_service) << "processMap_: IThriftDictionary;" << endl; + indent_down(); + } + + indent(s_service) << "public" << endl; + indent_up(); + if (extends.empty()) { + indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol; const " + "events : IProcessorEvents): Boolean;" << endl; + } else { + indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol; const " + "events : IProcessorEvents): Boolean; reintroduce;" << endl; + } + + indent_impl(s_service_impl) << "function " << full_cls << ".Process( const iprot: IProtocol; " + "const oprot: IProtocol; const events " + ": IProcessorEvents): Boolean;" << endl; + ; + indent_impl(s_service_impl) << "var" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "msg : Thrift.Protocol.TThriftMessage;" << endl; + indent_impl(s_service_impl) << "fn : TProcessFunction;" << endl; + indent_impl(s_service_impl) << "x : TApplicationException;" << endl; + if (events_) { + indent_impl(s_service_impl) << "context : IRequestEvents;" << endl; + } + indent_down_impl(); + indent_impl(s_service_impl) << "begin" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "try" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "msg := iprot.ReadMessageBegin();" << endl; + indent_impl(s_service_impl) << "fn := nil;" << endl; + indent_impl(s_service_impl) << "if not processMap_.TryGetValue(msg.Name, fn)" << endl; + indent_impl(s_service_impl) << "or not Assigned(fn) then" << endl; + indent_impl(s_service_impl) << "begin" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "TProtocolUtil.Skip(iprot, TType.Struct);" << endl; + indent_impl(s_service_impl) << "iprot.ReadMessageEnd();" << endl; + indent_impl(s_service_impl) << "x := " + "TApplicationExceptionUnknownMethod.Create(" + "'Invalid method name: ''' + msg.Name + '''');" << endl; + indent_impl(s_service_impl) + << "Thrift.Protocol.Init( msg, msg.Name, TMessageType.Exception, msg.SeqID);" + << endl; + indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg);" << endl; + indent_impl(s_service_impl) << "x.Write(oprot);" << endl; + indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl; + indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl; + indent_impl(s_service_impl) << "Result := True;" << endl; + indent_impl(s_service_impl) << "Exit;" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl; + if (events_) { + indent_impl(s_service_impl) << "if events <> nil" << endl; + indent_impl(s_service_impl) << "then context := events.CreateRequestContext(msg.Name)" << endl; + indent_impl(s_service_impl) << "else context := nil;" << endl; + indent_impl(s_service_impl) << "try" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot, context);" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "finally" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "if context <> nil then begin" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "context.CleanupContext;" << endl; + indent_impl(s_service_impl) << "context := nil;" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl; + } else { + indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot);" << endl; + } + indent_down_impl(); + indent_impl(s_service_impl) << "except" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "on TTransportExceptionTimedOut do begin" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "Result := True;" << endl; + indent_impl(s_service_impl) << "Exit;" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl; + indent_impl(s_service_impl) << "else begin" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "Result := False;" << endl; + indent_impl(s_service_impl) << "Exit;" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl; + indent_impl(s_service_impl) << "Result := True;" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(tservice, *f_iter); + } + + indent_down(); + indent(s_service) << "end;" << endl << endl; +} + +void t_delphi_generator::generate_function_helpers(t_function* tfunction) { + if (tfunction->is_oneway()) { + return; + } + + t_struct result(program_, tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "Success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + generate_delphi_struct_definition(s_service, &result, false, true, true); + generate_delphi_struct_impl(s_service_impl, + normalize_clsnm(service_name_, "T") + ".", + &result, + false); +} + +void t_delphi_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + (void)tservice; + string funcname = tfunction->get_name(); + string full_cls = normalize_clsnm(service_name_, "T") + ".TProcessorImpl"; + + string org_argsname = funcname + "_args"; + string args_clsnm = normalize_clsnm(org_argsname, "T"); + string args_intfnm = normalize_clsnm(org_argsname, "I"); + + string org_resultname = funcname + "_result"; + string result_clsnm = normalize_clsnm(org_resultname, "T"); + string result_intfnm = normalize_clsnm(org_resultname, "I"); + + indent(s_service) << "procedure " << funcname + << "_Process( seqid: Integer; const iprot: IProtocol; const oprot: IProtocol" + << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl; + + if (tfunction->is_oneway()) { + indent_impl(s_service_impl) << "// one way processor" << endl; + } else { + indent_impl(s_service_impl) << "// both way processor" << endl; + } + + indent_impl(s_service_impl) + << "procedure " << full_cls << "." << funcname + << "_Process( seqid: Integer; const iprot: IProtocol; const oprot: IProtocol" + << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl; + indent_impl(s_service_impl) << "var" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "args: " << args_intfnm << ";" << endl; + if (!tfunction->is_oneway()) { + indent_impl(s_service_impl) << "msg: Thrift.Protocol.TThriftMessage;" << endl; + indent_impl(s_service_impl) << "ret: " << result_intfnm << ";" << endl; + indent_impl(s_service_impl) << "appx : TApplicationException;" << endl; + } + + indent_down_impl(); + indent_impl(s_service_impl) << "begin" << endl; + indent_up_impl(); + + if (events_) { + indent_impl(s_service_impl) << "if events <> nil then events.PreRead;" << endl; + } + indent_impl(s_service_impl) << "args := " << args_clsnm << "Impl.Create;" << endl; + indent_impl(s_service_impl) << "args.Read(iprot);" << endl; + indent_impl(s_service_impl) << "iprot.ReadMessageEnd();" << endl; + if (events_) { + indent_impl(s_service_impl) << "if events <> nil then events.PostRead;" << endl; + } + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + if (!tfunction->is_oneway()) { + indent_impl(s_service_impl) << "ret := " << result_clsnm << "Impl.Create;" << endl; + } + + indent_impl(s_service_impl) << "try" << endl; + indent_up_impl(); + + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + s_service_impl << indent_impl(); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + s_service_impl << "ret.Success := "; + } + s_service_impl << "iface_." << normalize_name(tfunction->get_name(), true) << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + s_service_impl << ", "; + } + s_service_impl << "args." << prop_name(*f_iter); + } + s_service_impl << ");" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent_impl(s_service_impl) << "args." << prop_name(*f_iter) + << " := " << empty_value((*f_iter)->get_type()) << ";" << endl; + } + + indent_down_impl(); + indent_impl(s_service_impl) << "except" << endl; + indent_up_impl(); + + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + indent_impl(s_service_impl) << "on E: " << type_name((*x_iter)->get_type(), true, true) + << " do begin" << endl; + indent_up_impl(); + if (!tfunction->is_oneway()) { + string factory_name = normalize_clsnm((*x_iter)->get_type()->get_name(), "", true) + + "Factory"; + indent_impl(s_service_impl) << "ret." << prop_name(*x_iter) << " := E." << factory_name << ";" + << endl; + } + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl; + } + + indent_impl(s_service_impl) << "on E: Exception do begin" << endl; + indent_up_impl(); + if(events_) { + indent_impl(s_service_impl) << "if events <> nil then events.UnhandledError(E);" << endl; + } + if (!tfunction->is_oneway()) { + indent_impl(s_service_impl) << "appx := TApplicationExceptionInternalError.Create(E.Message);" + << endl; + indent_impl(s_service_impl) << "try" << endl; + indent_up_impl(); + if(events_) { + indent_impl(s_service_impl) << "if events <> nil then events.PreWrite;" << endl; + } + indent_impl(s_service_impl) << "Thrift.Protocol.Init( msg, '" + << tfunction->get_name() << "', TMessageType.Exception, seqid);" + << endl; + indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg);" << endl; + indent_impl(s_service_impl) << "appx.Write(oprot);" << endl; + indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl; + indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl; + if(events_) { + indent_impl(s_service_impl) << "if events <> nil then events.PostWrite;" << endl; + } + indent_impl(s_service_impl) << "Exit;" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "finally" << endl; + indent_up_impl(); + indent_impl(s_service_impl) << "appx.Free;" << endl; + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl; + } + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl; + + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl; + + if (!tfunction->is_oneway()) { + if (events_) { + indent_impl(s_service_impl) << "if events <> nil then events.PreWrite;" << endl; + } + indent_impl(s_service_impl) << "Thrift.Protocol.Init( msg, '" + << tfunction->get_name() << "', TMessageType.Reply, seqid); " + << endl; + indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg); " << endl; + indent_impl(s_service_impl) << "ret.Write(oprot);" << endl; + indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl; + indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl; + if (events_) { + indent_impl(s_service_impl) << "if events <> nil then events.PostWrite;" << endl; + } + } else if (events_) { + indent_impl(s_service_impl) << "if events <> nil then events.OnewayComplete;" << endl; + } + + indent_down_impl(); + indent_impl(s_service_impl) << "end;" << endl << endl; +} + +void t_delphi_generator::generate_deserialize_field(ostream& out, + bool is_xception, + t_field* tfield, + string prefix, + ostream& local_vars) { + t_type* type = tfield->get_type(); + while (type->is_typedef()) { + type = ((t_typedef*)type)->get_type(); + } + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = prefix + prop_name(tfield, is_xception); + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name, ""); + } else if (type->is_container()) { + generate_deserialize_container(out, is_xception, type, name, local_vars); + } else if (type->is_base_type() || type->is_enum()) { + indent_impl(out) << name << " := "; + + if (type->is_enum()) { + out << type_name(type, false) << "("; + } + + out << "iprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + if (ansistr_binary_) { + out << "ReadAnsiString();"; + } else { + out << "ReadBinary();"; + } + } else { + out << "ReadString();"; + } + break; + case t_base_type::TYPE_BOOL: + out << "ReadBool();"; + break; + case t_base_type::TYPE_I8: + out << "ReadByte();"; + break; + case t_base_type::TYPE_I16: + out << "ReadI16();"; + break; + case t_base_type::TYPE_I32: + out << "ReadI32();"; + break; + case t_base_type::TYPE_I64: + out << "ReadI64();"; + break; + case t_base_type::TYPE_DOUBLE: + out << "ReadDouble();"; + break; + default: + throw "compiler error: no Delphi name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "ReadI32()"; + out << ");"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +void t_delphi_generator::generate_deserialize_struct(ostream& out, + t_struct* tstruct, + string name, + string prefix) { + string typ_name; + + if (tstruct->is_xception()) { + typ_name = type_name(tstruct, true, false, true, true); + } else { + typ_name = type_name(tstruct, true, false); + } + + indent_impl(out) << prefix << name << " := " << typ_name << ".Create;" << endl; + indent_impl(out) << prefix << name << ".Read(iprot);" << endl; +} + +void t_delphi_generator::generate_deserialize_container(ostream& out, + bool is_xception, + t_type* ttype, + string name, + std::ostream& local_vars) { + + string obj; + string counter; + string local_var; + + if (ttype->is_map()) { + obj = tmp("_map"); + } else if (ttype->is_set()) { + obj = tmp("_set"); + } else if (ttype->is_list()) { + obj = tmp("_list"); + } + + if (ttype->is_map()) { + local_var = obj + ": TThriftMap;"; + } else if (ttype->is_set()) { + local_var = obj + ": TThriftSet;"; + } else if (ttype->is_list()) { + local_var = obj + ": TThriftList;"; + } + local_vars << " " << local_var << endl; + counter = tmp("_i"); + local_var = counter + ": Integer;"; + local_vars << " " << local_var << endl; + + indent_impl(out) << name << " := " << type_name(ttype, true) << ".Create;" << endl; + + if (ttype->is_map()) { + indent_impl(out) << obj << " := iprot.ReadMapBegin();" << endl; + } else if (ttype->is_set()) { + indent_impl(out) << obj << " := iprot.ReadSetBegin();" << endl; + } else if (ttype->is_list()) { + indent_impl(out) << obj << " := iprot.ReadListBegin();" << endl; + } + + indent_impl(out) << "for " << counter << " := 0 to " << obj << ".Count - 1 do" << endl; + indent_impl(out) << "begin" << endl; + indent_up_impl(); + if (ttype->is_map()) { + generate_deserialize_map_element(out, is_xception, (t_map*)ttype, name, local_vars); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, is_xception, (t_set*)ttype, name, local_vars); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, is_xception, (t_list*)ttype, name, local_vars); + } + indent_down_impl(); + indent_impl(out) << "end;" << endl; + + if (ttype->is_map()) { + indent_impl(out) << "iprot.ReadMapEnd();" << endl; + } else if (ttype->is_set()) { + indent_impl(out) << "iprot.ReadSetEnd();" << endl; + } else if (ttype->is_list()) { + indent_impl(out) << "iprot.ReadListEnd();" << endl; + } +} + +void t_delphi_generator::generate_deserialize_map_element(ostream& out, + bool is_xception, + t_map* tmap, + string prefix, + ostream& local_vars) { + + string key = tmp("_key"); + string val = tmp("_val"); + string local_var; + + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + local_vars << " " << declare_field(&fkey) << endl; + local_vars << " " << declare_field(&fval) << endl; + + generate_deserialize_field(out, is_xception, &fkey, "", local_vars); + generate_deserialize_field(out, is_xception, &fval, "", local_vars); + + indent_impl(out) << prefix << ".AddOrSetValue( " << key << ", " << val << ");" << endl; +} + +void t_delphi_generator::generate_deserialize_set_element(ostream& out, + bool is_xception, + t_set* tset, + string prefix, + ostream& local_vars) { + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); + local_vars << " " << declare_field(&felem) << endl; + generate_deserialize_field(out, is_xception, &felem, "", local_vars); + indent_impl(out) << prefix << ".Add(" << elem << ");" << endl; +} + +void t_delphi_generator::generate_deserialize_list_element(ostream& out, + bool is_xception, + t_list* tlist, + string prefix, + ostream& local_vars) { + string elem = tmp("_elem"); + t_field felem(tlist->get_elem_type(), elem); + local_vars << " " << declare_field(&felem) << endl; + generate_deserialize_field(out, is_xception, &felem, "", local_vars); + indent_impl(out) << prefix << ".Add(" << elem << ");" << endl; +} + +void t_delphi_generator::generate_serialize_field(ostream& out, + bool is_xception, + t_field* tfield, + string prefix, + ostream& local_vars) { + (void)local_vars; + + t_type* type = tfield->get_type(); + while (type->is_typedef()) { + type = ((t_typedef*)type)->get_type(); + } + + string name = prefix + prop_name(tfield, is_xception); + + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name; + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, name, local_vars); + } else if (type->is_container()) { + generate_serialize_container(out, is_xception, type, name, local_vars); + } else if (type->is_base_type() || type->is_enum()) { + + indent_impl(out) << "oprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + if (ansistr_binary_) { + out << "WriteAnsiString("; + } else { + out << "WriteBinary("; + } + } else { + out << "WriteString("; + } + out << name << ");"; + break; + case t_base_type::TYPE_BOOL: + out << "WriteBool(" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "WriteByte(" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "WriteI16(" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "WriteI32(" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "WriteI64(" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "WriteDouble(" << name << ");"; + break; + default: + throw "compiler error: no Delphi name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "WriteI32(Integer(" << name << "));"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n", + prefix.c_str(), + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +void t_delphi_generator::generate_serialize_struct(ostream& out, + t_struct* tstruct, + string prefix, + ostream& local_vars) { + (void)local_vars; + (void)tstruct; + out << indent_impl() << prefix << ".Write(oprot);" << endl; +} + +void t_delphi_generator::generate_serialize_container(ostream& out, + bool is_xception, + t_type* ttype, + string prefix, + ostream& local_vars) { + string obj; + if (ttype->is_map()) { + obj = tmp("map"); + local_vars << " " << obj << " : TThriftMap;" << endl; + indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", " + << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " + << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix + << ".Count);" << endl; + indent_impl(out) << "oprot.WriteMapBegin( " << obj << ");" << endl; + } else if (ttype->is_set()) { + obj = tmp("set_"); + local_vars << " " << obj << " : TThriftSet;" << endl; + indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", " + << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix + << ".Count);" << endl; + indent_impl(out) << "oprot.WriteSetBegin( " << obj << ");" << endl; + } else if (ttype->is_list()) { + obj = tmp("list_"); + local_vars << " " << obj << " : TThriftList;" << endl; + indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", " + << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix + << ".Count);" << endl; + indent_impl(out) << "oprot.WriteListBegin( " << obj << ");" << endl; + } + + string iter = tmp("_iter"); + if (ttype->is_map()) { + local_vars << " " << iter << ": " << type_name(((t_map*)ttype)->get_key_type()) << ";" << endl; + indent_impl(out) << "for " << iter << " in " << prefix << ".Keys do" << endl; + indent_impl(out) << "begin" << endl; + indent_up_impl(); + } else if (ttype->is_set()) { + local_vars << " " << iter << ": " << type_name(((t_set*)ttype)->get_elem_type()) << ";" + << endl; + indent_impl(out) << "for " << iter << " in " << prefix << " do" << endl; + indent_impl(out) << "begin" << endl; + indent_up_impl(); + } else if (ttype->is_list()) { + local_vars << " " << iter << ": " << type_name(((t_list*)ttype)->get_elem_type()) << ";" + << endl; + indent_impl(out) << "for " << iter << " in " << prefix << " do" << endl; + indent_impl(out) << "begin" << endl; + indent_up_impl(); + } + + if (ttype->is_map()) { + generate_serialize_map_element(out, is_xception, (t_map*)ttype, iter, prefix, local_vars); + } else if (ttype->is_set()) { + generate_serialize_set_element(out, is_xception, (t_set*)ttype, iter, local_vars); + } else if (ttype->is_list()) { + generate_serialize_list_element(out, is_xception, (t_list*)ttype, iter, local_vars); + } + + indent_down_impl(); + indent_impl(out) << "end;" << endl; + + if (ttype->is_map()) { + indent_impl(out) << "oprot.WriteMapEnd();" << endl; + } else if (ttype->is_set()) { + indent_impl(out) << "oprot.WriteSetEnd();" << endl; + } else if (ttype->is_list()) { + indent_impl(out) << "oprot.WriteListEnd();" << endl; + } +} + +void t_delphi_generator::generate_serialize_map_element(ostream& out, + bool is_xception, + t_map* tmap, + string iter, + string map, + ostream& local_vars) { + t_field kfield(tmap->get_key_type(), iter); + generate_serialize_field(out, is_xception, &kfield, "", local_vars); + t_field vfield(tmap->get_val_type(), map + "[" + iter + "]"); + generate_serialize_field(out, is_xception, &vfield, "", local_vars); +} + +void t_delphi_generator::generate_serialize_set_element(ostream& out, + bool is_xception, + t_set* tset, + string iter, + ostream& local_vars) { + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, is_xception, &efield, "", local_vars); +} + +void t_delphi_generator::generate_serialize_list_element(ostream& out, + bool is_xception, + t_list* tlist, + string iter, + ostream& local_vars) { + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, is_xception, &efield, "", local_vars); +} + +void t_delphi_generator::generate_property(ostream& out, + t_field* tfield, + bool isPublic, + bool is_xception) { + generate_delphi_property(out, is_xception, tfield, isPublic, "Get"); +} + +void t_delphi_generator::generate_delphi_property(ostream& out, + bool struct_is_xception, + t_field* tfield, + bool isPublic, + std::string fieldPrefix) { + (void)isPublic; + + t_type* ftype = tfield->get_type(); + bool is_xception = ftype->is_xception(); + generate_delphi_doc(out, tfield); + indent(out) << "property " << prop_name(tfield, struct_is_xception) << ": " + << type_name(ftype, false, true, is_xception, true) << " read " + << fieldPrefix + prop_name(tfield, struct_is_xception) << " write Set" + << prop_name(tfield, struct_is_xception) << ";" << endl; +} + +std::string t_delphi_generator::prop_name(t_field* tfield, bool is_xception) { + return prop_name(tfield->get_name(), is_xception); +} + +std::string t_delphi_generator::prop_name(string name, bool is_xception) { + string ret = name; + ret[0] = toupper(ret[0]); + return normalize_name(ret, true, is_xception); +} + +std::string t_delphi_generator::constructor_param_name(string name) { + string ret = name; + ret[0] = toupper(ret[0]); + ret = "A" + ret; + return normalize_name(ret, false, false); +} + +string t_delphi_generator::normalize_clsnm(string clsnm, string prefix, bool b_no_check_keyword) { + if (clsnm.size() > 0) { + clsnm[0] = toupper(clsnm[0]); + } + if (b_no_check_keyword) { + return prefix + clsnm; + } else { + return normalize_name(prefix + clsnm); + } +} + +string t_delphi_generator::type_name(t_type* ttype, + bool b_cls, + bool b_no_postfix, + bool b_exception_factory, + bool b_full_exception_factory) { + + if (ttype->is_typedef()) { + t_typedef* tdef = (t_typedef*)ttype; + if (tdef->is_forward_typedef()) { // forward types according to THRIFT-2421 + if (tdef->get_type() != NULL) { + return type_name(tdef->get_type(), + b_cls, + b_no_postfix, + b_exception_factory, + b_full_exception_factory); + } else { + throw "unresolved forward declaration: " + tdef->get_symbolic(); + } + } else { + return normalize_name("T" + tdef->get_symbolic()); + } + } + + string typ_nm; + + string s_factory; + + if (ttype->is_base_type()) { + return base_type_name((t_base_type*)ttype); + } else if (ttype->is_enum()) { + b_cls = true; + b_no_postfix = true; + } else if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + if (b_cls) { + typ_nm = "TThriftDictionaryImpl"; + } else { + typ_nm = "IThriftDictionary"; + } + return typ_nm + "<" + type_name(tmap->get_key_type()) + ", " + type_name(tmap->get_val_type()) + + ">"; + } else if (ttype->is_set()) { + t_set* tset = (t_set*)ttype; + if (b_cls) { + typ_nm = "THashSetImpl"; + } else { + typ_nm = "IHashSet"; + } + return typ_nm + "<" + type_name(tset->get_elem_type()) + ">"; + } else if (ttype->is_list()) { + t_list* tlist = (t_list*)ttype; + if (b_cls) { + typ_nm = "TThriftListImpl"; + } else { + typ_nm = "IThriftList"; + } + return typ_nm + "<" + type_name(tlist->get_elem_type()) + ">"; + } + + string type_prefix; + + if (b_cls) { + type_prefix = "T"; + } else { + type_prefix = "I"; + } + + string nm = normalize_clsnm(ttype->get_name(), type_prefix); + + if (b_exception_factory) { + nm = nm + "Factory"; + } + + if (b_cls) { + if (!b_no_postfix) { + nm = nm + "Impl"; + } + } + + if (b_exception_factory && b_full_exception_factory) { + return type_name(ttype, true, true, false, false) + "." + nm; + } + + return nm; +} + +// returns "const " for some argument types +string t_delphi_generator::input_arg_prefix(t_type* ttype) { + + // base types + if (ttype->is_base_type()) { + switch (((t_base_type*)ttype)->get_base()) { + + // these should be const'ed for optimal performamce + case t_base_type::TYPE_STRING: // refcounted pointer + case t_base_type::TYPE_I64: // larger than 32 bit + case t_base_type::TYPE_DOUBLE: // larger than 32 bit + return "const "; + + // all others don't need to be + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_BOOL: + case t_base_type::TYPE_VOID: + return ""; + + // we better always report any unknown types + default: + throw "compiler error: no input_arg_prefix() for base type " + + t_base_type::t_base_name(((t_base_type*)ttype)->get_base()); + } + + // enums + } else if (ttype->is_enum()) { + return ""; // usually <= 32 bit + + // containers + } else if (ttype->is_map()) { + return "const "; // refcounted pointer + + } else if (ttype->is_set()) { + return "const "; // refcounted pointer + + } else if (ttype->is_list()) { + return "const "; // refcounted pointer + } + + // any other type, either TSomething or ISomething + return "const "; // possibly refcounted pointer +} + +string t_delphi_generator::base_type_name(t_base_type* tbase) { + switch (tbase->get_base()) { + case t_base_type::TYPE_VOID: + // no "void" in Delphi language + return ""; + case t_base_type::TYPE_STRING: + if (tbase->is_binary()) { + if (ansistr_binary_) { + return "AnsiString"; + } else { + return "TBytes"; + } + } else { + return "string"; + } + case t_base_type::TYPE_BOOL: + return "Boolean"; + case t_base_type::TYPE_I8: + return "ShortInt"; + case t_base_type::TYPE_I16: + return "SmallInt"; + case t_base_type::TYPE_I32: + return "Integer"; + case t_base_type::TYPE_I64: + return "Int64"; + case t_base_type::TYPE_DOUBLE: + return "Double"; + default: + throw "compiler error: no Delphi name for base type " + + t_base_type::t_base_name(tbase->get_base()); + } +} + +string t_delphi_generator::declare_field(t_field* tfield, + bool init, + std::string prefix, + bool is_xception_class) { + (void)init; + + t_type* ftype = tfield->get_type(); + bool is_xception = ftype->is_xception(); + + string result = prefix + prop_name(tfield, is_xception_class) + ": " + + type_name(ftype, false, true, is_xception, true) + ";"; + return result; +} + +string t_delphi_generator::function_signature(t_function* tfunction, + std::string full_cls, + bool is_xception) { + t_type* ttype = tfunction->get_returntype(); + string prefix; + if (full_cls == "") { + prefix = ""; + } else { + prefix = full_cls + "."; + } + if (is_void(ttype)) { + return "procedure " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "(" + + argument_list(tfunction->get_arglist()) + ");"; + } else { + return "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "(" + + argument_list(tfunction->get_arglist()) + "): " + + type_name(ttype, false, true, is_xception, true) + ";"; + } +} + +string t_delphi_generator::argument_list(t_struct* tstruct) { + string result = ""; + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + t_type* tt; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += "; "; + } + + tt = (*f_iter)->get_type(); + result += input_arg_prefix(tt); // const? + result += normalize_name((*f_iter)->get_name()) + ": " + + type_name(tt, false, true, tt->is_xception(), true); + } + return result; +} + +string t_delphi_generator::constructor_argument_list(t_struct* tstruct, string current_indent) { + ostringstream result; + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + t_type* tt; + string line = ""; + string newline_indent = current_indent + " "; + + bool firstline = true; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + line += ";"; + } + + if (line.size() > 80) { + if (firstline) { + result << endl << newline_indent; + firstline = false; + } + result << line << endl; + line = newline_indent; + } else if (line.size() > 0) { + line += " "; + } + + tt = (*f_iter)->get_type(); + line += input_arg_prefix(tt); // const? + line += constructor_param_name((*f_iter)->get_name()) + ": " + + type_name(tt, false, true, tt->is_xception(), true); + } + + if (line.size() > 0) { + result << line; + } + + string result_str; + + if (firstline) { + result_str = " " + result.str(); + } else { + result_str = result.str(); + } + + return result_str; +} + +string t_delphi_generator::type_to_enum(t_type* type) { + while (type->is_typedef()) { + type = ((t_typedef*)type)->get_type(); + } + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "TType.String_"; + case t_base_type::TYPE_BOOL: + return "TType.Bool_"; + case t_base_type::TYPE_I8: + return "TType.Byte_"; + case t_base_type::TYPE_I16: + return "TType.I16"; + case t_base_type::TYPE_I32: + return "TType.I32"; + case t_base_type::TYPE_I64: + return "TType.I64"; + case t_base_type::TYPE_DOUBLE: + return "TType.Double_"; + } + } else if (type->is_enum()) { + return "TType.I32"; + } else if (type->is_struct() || type->is_xception()) { + return "TType.Struct"; + } else if (type->is_map()) { + return "TType.Map"; + } else if (type->is_set()) { + return "TType.Set_"; + } else if (type->is_list()) { + return "TType.List"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +string t_delphi_generator::empty_value(t_type* type) { + while (type->is_typedef()) { + type = ((t_typedef*)type)->get_type(); + } + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + return "0"; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + if (ansistr_binary_) { + return "''"; + } else { + return "nil"; + } + } else { + return "''"; + } + case t_base_type::TYPE_BOOL: + return "False"; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + return "0"; + case t_base_type::TYPE_DOUBLE: + return "0.0"; + } + } else if (type->is_enum()) { + return "T" + type->get_name() + "(0)"; + } else if (type->is_struct() || type->is_xception()) { + return "nil"; + } else if (type->is_map()) { + return "nil"; + } else if (type->is_set()) { + return "nil"; + } else if (type->is_list()) { + return "nil"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +void t_delphi_generator::generate_delphi_property_writer_definition(ostream& out, + t_field* tfield, + bool is_xception_class) { + t_type* ftype = tfield->get_type(); + bool is_xception = ftype->is_xception(); + + indent(out) << "procedure Set" << prop_name(tfield, is_xception_class) + << "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");" + << endl; +} + +void t_delphi_generator::generate_delphi_property_reader_definition(ostream& out, + t_field* tfield, + bool is_xception_class) { + t_type* ftype = tfield->get_type(); + bool is_xception = ftype->is_xception(); + + indent(out) << "function Get" << prop_name(tfield, is_xception_class) << ": " + << type_name(ftype, false, true, is_xception, true) << ";" << endl; +} + +void t_delphi_generator::generate_delphi_isset_reader_definition(ostream& out, + t_field* tfield, + bool is_xception) { + indent(out) << "function Get__isset_" << prop_name(tfield, is_xception) << ": Boolean;" << endl; +} + +void t_delphi_generator::generate_delphi_clear_union_value(ostream& out, + std::string cls_prefix, + std::string name, + t_type* type, + t_field* tfield, + std::string fieldPrefix, + bool is_xception_class, + bool is_union, + bool is_xception_factory, + std::string xception_factory_name) { + (void)cls_prefix; + (void)name; + (void)type; + (void)is_union; + (void)is_xception_factory; + (void)xception_factory_name; + + t_type* ftype = tfield->get_type(); + bool is_xception = ftype->is_xception(); + + indent_impl(out) << "if F__isset_" << prop_name(tfield, is_xception_class) << " then begin" + << endl; + indent_up_impl(); + indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := False;" << endl; + indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := " + << "Default( " << type_name(ftype, false, true, is_xception, true) << ");" + << endl; + indent_down_impl(); + indent_impl(out) << "end;" << endl; +} + +void t_delphi_generator::generate_delphi_property_writer_impl(ostream& out, + std::string cls_prefix, + std::string name, + t_type* type, + t_field* tfield, + std::string fieldPrefix, + bool is_xception_class, + bool is_union, + bool is_xception_factory, + std::string xception_factroy_name) { + (void)type; + + t_type* ftype = tfield->get_type(); + bool is_xception = ftype->is_xception(); + + indent_impl(out) << "procedure " << cls_prefix << name << "." + << "Set" << prop_name(tfield, is_xception_class) + << "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");" + << endl; + indent_impl(out) << "begin" << endl; + indent_up_impl(); + if (is_union) { + indent_impl(out) << "ClearUnionValues;" << endl; + } + if (tfield->get_req() != t_field::T_REQUIRED) { + indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := True;" << endl; + } + indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := Value;" << endl; + + if (is_xception_class && (!is_xception_factory)) { + indent_impl(out) << "F" << xception_factroy_name << "." << prop_name(tfield, is_xception_class) + << " := Value;" << endl; + } + + indent_down_impl(); + indent_impl(out) << "end;" << endl << endl; +} + +void t_delphi_generator::generate_delphi_property_reader_impl(ostream& out, + std::string cls_prefix, + std::string name, + t_type* type, + t_field* tfield, + std::string fieldPrefix, + bool is_xception_class) { + (void)type; + + t_type* ftype = tfield->get_type(); + bool is_xception = ftype->is_xception(); + + indent_impl(out) << "function " << cls_prefix << name << "." + << "Get" << prop_name(tfield, is_xception_class) << ": " + << type_name(ftype, false, true, is_xception, true) << ";" << endl; + indent_impl(out) << "begin" << endl; + indent_up_impl(); + indent_impl(out) << "Result := " << fieldPrefix << prop_name(tfield, is_xception_class) << ";" + << endl; + indent_down_impl(); + indent_impl(out) << "end;" << endl << endl; +} + +void t_delphi_generator::generate_delphi_isset_reader_impl(ostream& out, + std::string cls_prefix, + std::string name, + t_type* type, + t_field* tfield, + std::string fieldPrefix, + bool is_xception) { + (void)type; + + string isset_name = "__isset_" + prop_name(tfield, is_xception); + indent_impl(out) << "function " << cls_prefix << name << "." + << "Get" << isset_name << ": Boolean;" << endl; + indent_impl(out) << "begin" << endl; + indent_up_impl(); + indent_impl(out) << "Result := " << fieldPrefix << isset_name << ";" << endl; + indent_down_impl(); + indent_impl(out) << "end;" << endl << endl; +} + +void t_delphi_generator::generate_delphi_create_exception_impl(ostream& out, + string cls_prefix, + t_struct* tstruct, + bool is_exception) { + (void)cls_prefix; + + string exception_cls_nm = type_name(tstruct, true, true); + string cls_nm = type_name(tstruct, true, false, is_exception, is_exception); + + indent_impl(out) << "function " << cls_nm << ".CreateException: " << exception_cls_nm << ";" + << endl; + + indent_impl(out) << "begin" << endl; + indent_up_impl(); + + indent_impl(out) << "Result := " << exception_cls_nm << ".Create;" << endl; + string factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory"; + indent_impl(out) << "Result." << factory_name << " := Self;" << endl; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + string propname; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + propname = prop_name(*f_iter, is_exception); + if ((*f_iter)->get_req() != t_field::T_REQUIRED) { + indent_impl(out) << "if __isset_" << propname << " then" << endl; + indent_impl(out) << "begin" << endl; + indent_up_impl(); + } + indent_impl(out) << "Result." << propname << " := " << propname << ";" << endl; + if ((*f_iter)->get_req() != t_field::T_REQUIRED) { + indent_down_impl(); + indent_impl(out) << "end;" << endl; + } + } + + indent_impl(out) << "Result.UpdateMessageProperty;" << endl; + + indent_down_impl(); + indent_impl(out) << "end;" << endl << endl; +} + +void t_delphi_generator::generate_delphi_struct_reader_impl(ostream& out, + string cls_prefix, + t_struct* tstruct, + bool is_exception) { + + ostringstream local_vars; + ostringstream code_block; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + indent_impl(code_block) << "begin" << endl; + indent_up_impl(); + + indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl; + indent_impl(code_block) << "tracker := iprot.NextRecursionLevel;" << endl; + + // local bools for required fields + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + indent_impl(local_vars) << "_req_isset_" << prop_name(*f_iter, is_exception) << " : Boolean;" + << endl; + indent_impl(code_block) << "_req_isset_" << prop_name(*f_iter, is_exception) << " := FALSE;" + << endl; + } + } + + indent_impl(code_block) << "struc := iprot.ReadStructBegin;" << endl; + + indent_impl(code_block) << "try" << endl; + indent_up_impl(); + + indent_impl(code_block) << "while (true) do" << endl; + indent_impl(code_block) << "begin" << endl; + indent_up_impl(); + + indent_impl(code_block) << "field_ := iprot.ReadFieldBegin();" << endl; + + indent_impl(code_block) << "if (field_.Type_ = TType.Stop) then" << endl; + indent_impl(code_block) << "begin" << endl; + indent_up_impl(); + indent_impl(code_block) << "Break;" << endl; + indent_down_impl(); + indent_impl(code_block) << "end;" << endl; + + bool first = true; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + + if (first) { + indent_impl(code_block) << "case field_.ID of" << endl; + indent_up_impl(); + } + + first = false; + if (f_iter != fields.begin()) { + code_block << ";" << endl; + } + indent_impl(code_block) << (*f_iter)->get_key() << ": begin" << endl; + indent_up_impl(); + indent_impl(code_block) << "if (field_.Type_ = " << type_to_enum((*f_iter)->get_type()) + << ") then begin" << endl; + indent_up_impl(); + + generate_deserialize_field(code_block, is_exception, *f_iter, "Self.", local_vars); + + // required field? + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + indent_impl(code_block) << "_req_isset_" << prop_name(*f_iter, is_exception) << " := TRUE;" + << endl; + } + + indent_down_impl(); + + indent_impl(code_block) << "end else begin" << endl; + indent_up_impl(); + indent_impl(code_block) << "TProtocolUtil.Skip(iprot, field_.Type_);" << endl; + indent_down_impl(); + indent_impl(code_block) << "end;" << endl; + indent_down_impl(); + indent_impl(code_block) << "end"; + } + + if (!first) { + code_block << endl; + indent_impl(code_block) << "else begin" << endl; + indent_up_impl(); + } + + indent_impl(code_block) << "TProtocolUtil.Skip(iprot, field_.Type_);" << endl; + + if (!first) { + indent_down_impl(); + indent_impl(code_block) << "end;" << endl; + indent_down_impl(); + indent_impl(code_block) << "end;" << endl; + } + + indent_impl(code_block) << "iprot.ReadFieldEnd;" << endl; + + indent_down_impl(); + + indent_impl(code_block) << "end;" << endl; + indent_down_impl(); + + indent_impl(code_block) << "finally" << endl; + indent_up_impl(); + indent_impl(code_block) << "iprot.ReadStructEnd;" << endl; + indent_down_impl(); + indent_impl(code_block) << "end;" << endl; + + // all required fields have been read? + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + indent_impl(code_block) << "if not _req_isset_" << prop_name(*f_iter, is_exception) << endl; + indent_impl(code_block) + << "then raise TProtocolExceptionInvalidData.Create(" + << "'required field " << prop_name(*f_iter, is_exception) << " not set');" + << endl; + } + } + + indent_down_impl(); + indent_impl(code_block) << "end;" << endl << endl; + + string cls_nm; + + cls_nm = type_name(tstruct, true, false, is_exception, is_exception); + + indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Read( const iprot: IProtocol);" + << endl; + indent_impl(out) << "var" << endl; + indent_up_impl(); + indent_impl(out) << "field_ : TThriftField;" << endl; + indent_impl(out) << "struc : TThriftStruct;" << endl; + indent_down_impl(); + out << local_vars.str() << endl; + out << code_block.str(); +} + +void t_delphi_generator::generate_delphi_struct_result_writer_impl(ostream& out, + string cls_prefix, + t_struct* tstruct, + bool is_exception) { + + ostringstream local_vars; + ostringstream code_block; + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + indent_impl(code_block) << "begin" << endl; + indent_up_impl(); + + indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl; + indent_impl(code_block) << "tracker := oprot.NextRecursionLevel;" << endl; + + indent_impl(code_block) << "Thrift.Protocol.Init( struc, '" << name << "');" << endl; + indent_impl(code_block) << "oprot.WriteStructBegin(struc);" << endl; + + if (fields.size() > 0) { + indent_impl(code_block) << "Thrift.Protocol.Init( field_);" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent_impl(code_block) << "if (__isset_" << prop_name(*f_iter, is_exception) << ") then" + << endl; + indent_impl(code_block) << "begin" << endl; + indent_up_impl(); + indent_impl(code_block) << "field_.Name := '" << (*f_iter)->get_name() << "';" << endl; + indent_impl(code_block) << "field_.Type_ := " << type_to_enum((*f_iter)->get_type()) << ";" + << endl; + indent_impl(code_block) << "field_.ID := " << (*f_iter)->get_key() << ";" << endl; + indent_impl(code_block) << "oprot.WriteFieldBegin(field_);" << endl; + generate_serialize_field(code_block, is_exception, *f_iter, "Self.", local_vars); + indent_impl(code_block) << "oprot.WriteFieldEnd();" << endl; + indent_down_impl(); + } + } + + indent_impl(code_block) << "oprot.WriteFieldStop();" << endl; + indent_impl(code_block) << "oprot.WriteStructEnd();" << endl; + + indent_down_impl(); + indent_impl(code_block) << "end;" << endl << endl; + + string cls_nm; + + cls_nm = type_name(tstruct, true, false, is_exception, is_exception); + + indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Write( const oprot: IProtocol);" + << endl; + indent_impl(out) << "var" << endl; + indent_up_impl(); + indent_impl(out) << "struc : TThriftStruct;" << endl; + + if (fields.size() > 0) { + indent_impl(out) << "field_ : TThriftField;" << endl; + } + + out << local_vars.str(); + indent_down_impl(); + out << code_block.str(); +} + +void t_delphi_generator::generate_delphi_struct_writer_impl(ostream& out, + string cls_prefix, + t_struct* tstruct, + bool is_exception) { + + ostringstream local_vars; + ostringstream code_block; + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + indent_impl(code_block) << "begin" << endl; + indent_up_impl(); + + indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl; + indent_impl(code_block) << "tracker := oprot.NextRecursionLevel;" << endl; + + indent_impl(code_block) << "Thrift.Protocol.Init( struc, '" << name << "');" << endl; + indent_impl(code_block) << "oprot.WriteStructBegin(struc);" << endl; + + if (fields.size() > 0) { + indent_impl(code_block) << "Thrift.Protocol.Init( field_);" << endl; + } + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + string fieldname = prop_name((*f_iter), is_exception); + bool null_allowed = type_can_be_null((*f_iter)->get_type()); + bool is_required = ((*f_iter)->get_req() == t_field::T_REQUIRED); + bool has_isset = (!is_required); + if (is_required && null_allowed) { + null_allowed = false; + indent_impl(code_block) << "if (Self." << fieldname << " = nil)" << endl; + indent_impl(code_block) << "then raise TProtocolExceptionInvalidData.Create(" + << "'required field " << fieldname << " not set');" + << endl; + } + if (null_allowed) { + indent_impl(code_block) << "if (Self." << fieldname << " <> nil)"; + if (has_isset) { + code_block << " and __isset_" << fieldname; + } + code_block << " then begin" << endl; + indent_up_impl(); + } else { + if (has_isset) { + indent_impl(code_block) << "if (__isset_" << fieldname << ") then begin" << endl; + indent_up_impl(); + } + } + indent_impl(code_block) << "field_.Name := '" << (*f_iter)->get_name() << "';" << endl; + indent_impl(code_block) << "field_.Type_ := " << type_to_enum((*f_iter)->get_type()) << ";" + << endl; + indent_impl(code_block) << "field_.ID := " << (*f_iter)->get_key() << ";" << endl; + indent_impl(code_block) << "oprot.WriteFieldBegin(field_);" << endl; + generate_serialize_field(code_block, is_exception, *f_iter, "Self.", local_vars); + indent_impl(code_block) << "oprot.WriteFieldEnd();" << endl; + if (null_allowed || has_isset) { + indent_down_impl(); + indent_impl(code_block) << "end;" << endl; + } + } + + indent_impl(code_block) << "oprot.WriteFieldStop();" << endl; + indent_impl(code_block) << "oprot.WriteStructEnd();" << endl; + + indent_down_impl(); + indent_impl(code_block) << "end;" << endl << endl; + + string cls_nm; + + cls_nm = type_name(tstruct, true, false, is_exception, is_exception); + + indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Write( const oprot: IProtocol);" + << endl; + indent_impl(out) << "var" << endl; + indent_up_impl(); + indent_impl(out) << "struc : TThriftStruct;" << endl; + if (fields.size() > 0) { + indent_impl(out) << "field_ : TThriftField;" << endl; + } + out << local_vars.str(); + indent_down_impl(); + out << code_block.str(); +} + +void t_delphi_generator::generate_delphi_struct_tostring_impl(ostream& out, + string cls_prefix, + t_struct* tstruct, + bool is_exception, + bool is_x_factory) { + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + string cls_nm; + + if (is_exception) { + cls_nm = type_name(tstruct, true, (!is_x_factory), is_x_factory, true); + } else { + cls_nm = type_name(tstruct, true, false); + } + + string tmp_sb = tmp("_sb"); + string tmp_first = tmp("_first"); + bool useFirstFlag = false; + + indent_impl(out) << "function " << cls_prefix << cls_nm << ".ToString: string;" << endl; + indent_impl(out) << "var" << endl; + indent_up_impl(); + indent_impl(out) << tmp_sb << " : TThriftStringBuilder;" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool is_optional = ((*f_iter)->get_req() != t_field::T_REQUIRED); + if (is_optional) { + indent_impl(out) << tmp_first << " : Boolean;" << endl; + useFirstFlag = true; + } + break; + } + indent_down_impl(); + indent_impl(out) << "begin" << endl; + indent_up_impl(); + + indent_impl(out) << tmp_sb << " := TThriftStringBuilder.Create('(');" << endl; + indent_impl(out) << "try" << endl; + indent_up_impl(); + + if (useFirstFlag) { + indent_impl(out) << tmp_first << " := TRUE;" << endl; + } + + bool had_required = false; // set to true after first required field has been processed + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool null_allowed = type_can_be_null((*f_iter)->get_type()); + bool is_optional = ((*f_iter)->get_req() != t_field::T_REQUIRED); + if (null_allowed) { + indent_impl(out) << "if (Self." << prop_name((*f_iter), is_exception) << " <> nil)"; + if (is_optional) { + out << " and __isset_" << prop_name(*f_iter, is_exception); + } + out << " then begin" << endl; + indent_up_impl(); + } else { + if (is_optional) { + indent_impl(out) << "if (__isset_" << prop_name(*f_iter, is_exception) << ") then begin" + << endl; + indent_up_impl(); + } + } + + if (useFirstFlag && (!had_required)) { + indent_impl(out) << "if not " << tmp_first << " then " << tmp_sb << ".Append(',');" << endl; + if (is_optional) { + indent_impl(out) << tmp_first << " := FALSE;" << endl; + } + indent_impl(out) << tmp_sb << ".Append('" << prop_name((*f_iter), is_exception) << ": ');" + << endl; + } else { + indent_impl(out) << tmp_sb << ".Append(', " << prop_name((*f_iter), is_exception) << ": ');" + << endl; + } + + t_type* ttype = (*f_iter)->get_type(); + while (ttype->is_typedef()) { + ttype = ((t_typedef*)ttype)->get_type(); + } + + if (ttype->is_xception() || ttype->is_struct()) { + indent_impl(out) << "if (Self." << prop_name((*f_iter), is_exception) << " = nil) then " << tmp_sb + << ".Append('') else " << tmp_sb << ".Append( Self." + << prop_name((*f_iter), is_exception) << ".ToString());" << endl; + } else if (ttype->is_enum()) { + indent_impl(out) << tmp_sb << ".Append(Integer( Self." << prop_name((*f_iter), is_exception) + << "));" << endl; + } else { + indent_impl(out) << tmp_sb << ".Append( Self." << prop_name((*f_iter), is_exception) << ");" + << endl; + } + + if (null_allowed || is_optional) { + indent_down_impl(); + indent_impl(out) << "end;" << endl; + } + + if (!is_optional) { + had_required = true; // now __first must be false, so we don't need to check it anymore + } + } + + indent_impl(out) << tmp_sb << ".Append(')');" << endl; + indent_impl(out) << "Result := " << tmp_sb << ".ToString;" << endl; + if (useFirstFlag) { + indent_impl(out) << "if " << tmp_first << " then {prevent warning};" << endl; + } + + indent_down_impl(); + indent_impl(out) << "finally" << endl; + indent_up_impl(); + indent_impl(out) << tmp_sb << ".Free;" << endl; + indent_down_impl(); + indent_impl(out) << "end;" << endl; + + indent_down_impl(); + indent_impl(out) << "end;" << endl << endl; +} + +bool t_delphi_generator::is_void(t_type* type) { + while (type->is_typedef()) { + type = ((t_typedef*)type)->get_type(); + } + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + if (tbase == t_base_type::TYPE_VOID) { + return true; + } + } + return false; +} + +THRIFT_REGISTER_GENERATOR( + delphi, + "delphi", + " ansistr_binary: Use AnsiString for binary datatype (default is TBytes).\n" + " register_types: Enable TypeRegistry, allows for creation of struct, union\n" + " and container instances by interface or TypeInfo()\n" + " constprefix: Name TConstants classes after IDL to reduce ambiguities\n" + " events: Enable and use processing events in the generated code.\n" + " xmldoc: Enable XMLDoc comments for Help Insight etc.\n") diff --git a/compiler/cpp/src/thrift/generate/t_erl_generator.cc b/compiler/cpp/src/thrift/generate/t_erl_generator.cc new file mode 100644 index 0000000..372c78b --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_erl_generator.cc @@ -0,0 +1,1251 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "thrift/platform.h" +#include "thrift/version.h" +#include "thrift/generate/t_generator.h" + +using std::map; +using std::ofstream; +using std::ostream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const std::string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * Erlang code generator. + * + */ +class t_erl_generator : public t_generator { +public: + t_erl_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + legacy_names_ = false; + maps_ = false; + otp16_ = false; + export_lines_first_ = true; + export_types_lines_first_ = true; + + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("legacynames") == 0) { + legacy_names_ = true; + } else if( iter->first.compare("maps") == 0) { + maps_ = true; + } else if( iter->first.compare("otp16") == 0) { + otp16_ = true; + } else { + throw "unknown option erl:" + iter->first; + } + } + + if (maps_ && otp16_) { + throw "argument error: Cannot specify both maps and otp16; maps are not available for Erlang/OTP R16 or older"; + } + + out_dir_base_ = "gen-erl"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + void generate_member_type(std::ostream& out, t_type* type); + void generate_member_value(std::ostream& out, t_type* type, t_const_value* value); + + std::string render_member_type(t_field* field); + std::string render_member_value(t_field* field); + std::string render_member_requiredness(t_field* field); + + // std::string render_default_value(t_type* type); + std::string render_default_value(t_field* field); + std::string render_const_value(t_type* type, t_const_value* value); + std::string render_type_term(t_type* ttype, bool expand_structs, bool extended_info = false); + + /** + * Struct generation code + */ + + void generate_erl_struct(t_struct* tstruct, bool is_exception); + void generate_erl_struct_definition(std::ostream& out, t_struct* tstruct); + void generate_erl_struct_member(std::ostream& out, t_field* tmember); + void generate_erl_struct_info(std::ostream& out, t_struct* tstruct); + void generate_erl_extended_struct_info(std::ostream& out, t_struct* tstruct); + void generate_erl_function_helpers(t_function* tfunction); + void generate_type_metadata(std::string function_name, vector names); + void generate_enum_info(t_enum* tenum); + void generate_enum_metadata(); + void generate_const_function(t_const* tconst, ostringstream& exports, ostringstream& functions); + void generate_const_functions(); + + /** + * Service-level generation functions + */ + + void generate_service_helpers(t_service* tservice); + void generate_service_metadata(t_service* tservice); + void generate_service_interface(t_service* tservice); + void generate_function_info(t_service* tservice, t_function* tfunction); + + /** + * Helper rendering functions + */ + + std::string erl_autogen_comment(); + std::string erl_imports(); + std::string render_includes(); + std::string type_name(t_type* ttype); + std::string render_const_list_values(t_type* type, t_const_value* value); + + std::string function_signature(t_function* tfunction, std::string prefix = ""); + + std::string argument_list(t_struct* tstruct); + std::string type_to_enum(t_type* ttype); + std::string type_module(t_type* ttype); + + std::string make_safe_for_module_name(std::string in) { + if (legacy_names_) { + return decapitalize(in); + } else { + return underscore(in); + } + } + + std::string atomify(std::string in) { + if (legacy_names_) { + return "'" + decapitalize(in) + "'"; + } else { + return "'" + in + "'"; + } + } + + std::string constify(std::string in) { + if (legacy_names_) { + return capitalize(in); + } else { + return uppercase(in); + } + } + + static std::string comment(string in); + +private: + bool has_default_value(t_field*); + + /* if true retain pre 0.9.2 naming scheme for functions, atoms and consts */ + bool legacy_names_; + + /* if true use maps instead of dicts in generated code */ + bool maps_; + + /* if true use non-namespaced dict and set instead of dict:dict and sets:set */ + bool otp16_; + + /** + * add function to export list + */ + + void export_function(t_function* tfunction, std::string prefix = ""); + void export_string(std::string name, int num); + + void export_types_string(std::string name, int num); + + /** + * write out headers and footers for hrl files + */ + + void hrl_header(std::ostream& out, std::string name); + void hrl_footer(std::ostream& out, std::string name); + + /** + * stuff to spit out at the top of generated files + */ + + bool export_lines_first_; + std::ostringstream export_lines_; + + bool export_types_lines_first_; + std::ostringstream export_types_lines_; + + /** + * File streams + */ + + std::ostringstream f_info_; + std::ostringstream f_info_ext_; + + std::ofstream f_types_file_; + std::ofstream f_types_hrl_file_; + + std::ofstream f_consts_file_; + std::ofstream f_consts_hrl_file_; + + std::ostringstream f_service_; + std::ofstream f_service_file_; + std::ofstream f_service_hrl_; + + /** + * Metadata containers + */ + std::vector v_struct_names_; + std::vector v_enum_names_; + std::vector v_exception_names_; + std::vector v_enums_; + std::vector v_consts_; +}; + +/** + * UI for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_erl_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + + // setup export lines + export_lines_first_ = true; + export_types_lines_first_ = true; + + string program_module_name = make_safe_for_module_name(program_name_); + + // types files + string f_types_name = get_out_dir() + program_module_name + "_types.erl"; + string f_types_hrl_name = get_out_dir() + program_module_name + "_types.hrl"; + + f_types_file_.open(f_types_name.c_str()); + f_types_hrl_file_.open(f_types_hrl_name.c_str()); + + hrl_header(f_types_hrl_file_, program_module_name + "_types"); + + f_types_file_ << erl_autogen_comment() << endl + << "-module(" << program_module_name << "_types)." << endl + << erl_imports() << endl; + + f_types_file_ << "-include(\"" << program_module_name << "_types.hrl\")." << endl + << endl; + + f_types_hrl_file_ << render_includes() << endl; + + // consts files + string f_consts_name = get_out_dir() + program_module_name + "_constants.erl"; + string f_consts_hrl_name = get_out_dir() + program_module_name + "_constants.hrl"; + + f_consts_file_.open(f_consts_name.c_str()); + f_consts_hrl_file_.open(f_consts_hrl_name.c_str()); + + f_consts_file_ << erl_autogen_comment() << endl + << "-module(" << program_module_name << "_constants)." << endl + << erl_imports() << endl + << "-include(\"" << program_module_name << "_types.hrl\")." << endl + << endl; + + f_consts_hrl_file_ << erl_autogen_comment() << endl << erl_imports() << endl + << "-include(\"" << program_module_name << "_types.hrl\")." << endl << endl; +} + +/** + * Boilerplate at beginning and end of header files + */ +void t_erl_generator::hrl_header(ostream& out, string name) { + out << "-ifndef(_" << name << "_included)." << endl << "-define(_" << name << "_included, yeah)." + << endl; +} + +void t_erl_generator::hrl_footer(ostream& out, string name) { + (void)name; + out << "-endif." << endl; +} + +/** + * Renders all the imports necessary for including another Thrift program + */ +string t_erl_generator::render_includes() { + const vector& includes = program_->get_includes(); + string result = ""; + for (size_t i = 0; i < includes.size(); ++i) { + result += "-include(\"" + make_safe_for_module_name(includes[i]->get_name()) + + "_types.hrl\").\n"; + } + if (includes.size() > 0) { + result += "\n"; + } + return result; +} + +/** + * Autogen'd comment + */ +string t_erl_generator::erl_autogen_comment() { + return std::string("%%\n") + "%% Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + + "%%\n" + "%% DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + + "%%\n"; +} + +/** + * Comment out text + */ + +string t_erl_generator::comment(string in) { + size_t pos = 0; + in.insert(pos, "%% "); + while ((pos = in.find_first_of('\n', pos)) != string::npos) { + in.insert(++pos, "%% "); + } + return in; +} + +/** + * Prints standard thrift imports + */ +string t_erl_generator::erl_imports() { + return ""; +} + +/** + * Closes the type files + */ +void t_erl_generator::close_generator() { + + export_types_string("struct_info", 1); + export_types_string("struct_info_ext", 1); + export_types_string("enum_info", 1); + export_types_string("enum_names", 0); + export_types_string("struct_names", 0); + export_types_string("exception_names", 0); + + f_types_file_ << "-export([" << export_types_lines_.str() << "])." << endl << endl; + + f_types_file_ << f_info_.str(); + f_types_file_ << "struct_info(_) -> erlang:error(function_clause)." << endl << endl; + + f_types_file_ << f_info_ext_.str(); + f_types_file_ << "struct_info_ext(_) -> erlang:error(function_clause)." << endl << endl; + + generate_const_functions(); + + generate_type_metadata("struct_names", v_struct_names_); + generate_enum_metadata(); + generate_type_metadata("enum_names", v_enum_names_); + generate_type_metadata("exception_names", v_exception_names_); + + hrl_footer(f_types_hrl_file_, string("BOGUS")); + + f_types_file_.close(); + f_types_hrl_file_.close(); + f_consts_file_.close(); + f_consts_hrl_file_.close(); +} + +void t_erl_generator::generate_type_metadata(std::string function_name, vector names) { + vector::iterator s_iter; + size_t num_structs = names.size(); + + indent(f_types_file_) << function_name << "() ->\n"; + indent_up(); + indent(f_types_file_) << "["; + + + for(size_t i=0; i < num_structs; i++) { + f_types_file_ << names.at(i); + + if (i < num_structs - 1) { + f_types_file_ << ", "; + } + } + + f_types_file_ << "].\n\n"; + indent_down(); +} + +/** + * Generates a typedef. no op + * + * @param ttypedef The type definition + */ +void t_erl_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + + +void t_erl_generator::generate_const_function(t_const* tconst, ostringstream& exports, ostringstream& functions) { + t_type* type = get_true_type(tconst->get_type()); + string name = tconst->get_name(); + t_const_value* value = tconst->get_value(); + + if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + string const_fun_name = lowercase(name); + + // Emit const function export. + if (exports.tellp() > 0) { exports << ", "; } + exports << const_fun_name << "/1, " << const_fun_name << "/2"; + + // Emit const function definition. + map::const_iterator i, end = value->get_map().end(); + // The one-argument form throws an error if the key does not exist in the map. + for (i = value->get_map().begin(); i != end;) { + functions << const_fun_name << "(" << render_const_value(ktype, i->first) << ") -> " + << render_const_value(vtype, i->second); + ++i; + functions << (i != end ? ";\n" : ".\n\n"); + } + + // The two-argument form returns a default value if the key does not exist in the map. + for (i = value->get_map().begin(); i != end; ++i) { + functions << const_fun_name << "(" << render_const_value(ktype, i->first) << ", _) -> " + << render_const_value(vtype, i->second) << ";\n"; + } + functions << const_fun_name << "(_, Default) -> Default.\n\n"; + } else if (type->is_list()) { + string const_fun_name = lowercase(name); + + if (exports.tellp() > 0) { exports << ", "; } + exports << const_fun_name << "/1, " << const_fun_name << "/2"; + + size_t list_size = value->get_list().size(); + string rendered_list = render_const_list_values(type, value); + functions << const_fun_name << "(N) when N >= 1, N =< " << list_size << " ->\n" + << indent_str() << "element(N, {" << rendered_list << "}).\n"; + functions << const_fun_name << "(N, _) when N >= 1, N =< " << list_size << " ->\n" + << indent_str() << "element(N, {" << rendered_list << "});\n" + << const_fun_name << "(_, Default) -> Default.\n\n"; + indent_down(); + } +} + +void t_erl_generator::generate_const_functions() { + ostringstream exports; + ostringstream functions; + vector::iterator c_iter; + for (c_iter = v_consts_.begin(); c_iter != v_consts_.end(); ++c_iter) { + generate_const_function(*c_iter, exports, functions); + } + if (exports.tellp() > 0) { + f_consts_file_ << "-export([" << exports.str() << "]).\n\n" + << functions.str(); + } +} + + +/** + * Generates code for an enumerated type. Done using a class to scope + * the values. + * + * @param tenum The enumeration + */ +void t_erl_generator::generate_enum(t_enum* tenum) { + vector constants = tenum->get_constants(); + vector::iterator c_iter; + + v_enums_.push_back(tenum); + v_enum_names_.push_back(atomify(tenum->get_name())); + + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + string name = (*c_iter)->get_name(); + indent(f_types_hrl_file_) << "-define(" << constify(make_safe_for_module_name(program_name_)) + << "_" << constify(tenum->get_name()) << "_" << constify(name) << ", " + << value << ")." << endl; + } + + f_types_hrl_file_ << endl; +} + +void t_erl_generator::generate_enum_info(t_enum* tenum){ + vector constants = tenum->get_constants(); + size_t num_constants = constants.size(); + + indent(f_types_file_) << "enum_info(" << atomify(tenum->get_name()) << ") ->\n"; + indent_up(); + indent(f_types_file_) << "[\n"; + + for(size_t i=0; i < num_constants; i++) { + indent_up(); + t_enum_value* value = constants.at(i); + indent(f_types_file_) << "{" << atomify(value->get_name()) << ", " << value->get_value() << "}"; + + if (i < num_constants - 1) { + f_types_file_ << ",\n"; + } + indent_down(); + } + f_types_file_ << "\n"; + indent(f_types_file_) << "];\n\n"; + indent_down(); +} + +void t_erl_generator::generate_enum_metadata() { + size_t enum_count = v_enums_.size(); + + for(size_t i=0; i < enum_count; i++) { + t_enum* tenum = v_enums_.at(i); + generate_enum_info(tenum); + } + + indent(f_types_file_) << "enum_info(_) -> erlang:error(function_clause).\n\n"; +} + +/** + * Generate a constant value + */ +void t_erl_generator::generate_const(t_const* tconst) { + t_type* type = tconst->get_type(); + string name = tconst->get_name(); + t_const_value* value = tconst->get_value(); + + // Save the tconst so that function can be emitted in generate_const_functions(). + v_consts_.push_back(tconst); + + f_consts_hrl_file_ << "-define(" << constify(make_safe_for_module_name(program_name_)) << "_" + << constify(name) << ", " << render_const_value(type, value) << ")." << endl << endl; +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +string t_erl_generator::render_const_value(t_type* type, t_const_value* value) { + type = get_true_type(type); + std::ostringstream out; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + out << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + out << (value->get_integer() > 0 ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + out << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + out << value->get_integer(); + } else { + out << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + indent(out) << value->get_integer(); + + } else if (type->is_struct() || type->is_xception()) { + out << "#" << type_name(type) << "{"; + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + + bool first = true; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + + if (first) { + first = false; + } else { + out << ","; + } + out << v_iter->first->get_string(); + out << " = "; + out << render_const_value(field_type, v_iter->second); + } + indent_down(); + indent(out) << "}"; + + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + + if (maps_) { + out << "maps:from_list(["; + } else { + out << "dict:from_list(["; + } + map::const_iterator i, end = value->get_map().end(); + for (i = value->get_map().begin(); i != end;) { + out << "{" << render_const_value(ktype, i->first) << "," + << render_const_value(vtype, i->second) << "}"; + if (++i != end) { + out << ","; + } + } + out << "])"; + } else if (type->is_set()) { + t_type* etype = ((t_set*)type)->get_elem_type(); + out << "sets:from_list(["; + vector::const_iterator i, end = value->get_list().end(); + for (i = value->get_list().begin(); i != end;) { + out << render_const_value(etype, *i); + if (++i != end) { + out << ","; + } + } + out << "])"; + } else if (type->is_list()) { + out << "[" << render_const_list_values(type, value) << "]"; + } else { + throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); + } + return out.str(); +} + +string t_erl_generator::render_const_list_values(t_type* type, t_const_value* value) { + std::ostringstream out; + t_type* etype = ((t_list*)type)->get_elem_type(); + + bool first = true; + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + if (first) { + first = false; + } else { + out << ","; + } + out << render_const_value(etype, *v_iter); + } + return out.str(); +} + + +string t_erl_generator::render_default_value(t_field* field) { + t_type* type = field->get_type(); + if (type->is_struct() || type->is_xception()) { + return "#" + type_name(type) + "{}"; + } else if (type->is_map()) { + if (maps_) { + return "#{}"; + } else { + return "dict:new()"; + } + } else if (type->is_set()) { + return "sets:new()"; + } else if (type->is_list()) { + return "[]"; + } else { + return "undefined"; + } +} + +string t_erl_generator::render_member_type(t_field* field) { + t_type* type = get_true_type(field->get_type()); + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + return "string() | binary()"; + case t_base_type::TYPE_BOOL: + return "boolean()"; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + return "integer()"; + case t_base_type::TYPE_DOUBLE: + return "float()"; + default: + throw "compiler error: unsupported base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + return "integer()"; + } else if (type->is_struct() || type->is_xception()) { + return type_name(type) + "()"; + } else if (type->is_map()) { + if (maps_) { + return "#{}"; + } else if (otp16_) { + return "dict()"; + } else { + return "dict:dict()"; + } + } else if (type->is_set()) { + if (otp16_) { + return "set()"; + } else { + return "sets:set()"; + } + } else if (type->is_list()) { + return "list()"; + } else { + throw "compiler error: unsupported type " + type->get_name(); + } +} + +string t_erl_generator::render_member_requiredness(t_field* field) { + switch (field->get_req()) { + case t_field::T_REQUIRED: + return "required"; + case t_field::T_OPTIONAL: + return "optional"; + default: + return "undefined"; + } +} + +/** + * Generates a struct + */ +void t_erl_generator::generate_struct(t_struct* tstruct) { + v_struct_names_.push_back(type_name(tstruct)); + generate_erl_struct(tstruct, false); +} + +/** + * Generates a struct definition for a thrift exception. Basically the same + * as a struct but extends the Exception class. + * + * @param txception The struct definition + */ +void t_erl_generator::generate_xception(t_struct* txception) { + v_exception_names_.push_back(type_name(txception)); + generate_erl_struct(txception, true); +} + +/** + * Generates a struct + */ +void t_erl_generator::generate_erl_struct(t_struct* tstruct, bool is_exception) { + (void)is_exception; + generate_erl_struct_definition(f_types_hrl_file_, tstruct); + generate_erl_struct_info(f_info_, tstruct); + generate_erl_extended_struct_info(f_info_ext_, tstruct); +} + +/** + * Generates a struct definition for a thrift data type. + * + * @param tstruct The struct definition + */ +void t_erl_generator::generate_erl_struct_definition(ostream& out, t_struct* tstruct) { + indent(out) << "%% struct " << type_name(tstruct) << endl << endl; + + std::stringstream buf; + buf << indent() << "-record(" << type_name(tstruct) << ", {"; + string field_indent(buf.str().size(), ' '); + + const vector& members = tstruct->get_members(); + for (vector::const_iterator m_iter = members.begin(); m_iter != members.end();) { + generate_erl_struct_member(buf, *m_iter); + if (++m_iter != members.end()) { + buf << "," << endl << field_indent; + } + } + buf << "})."; + + out << buf.str() << endl; + out << "-type " + type_name(tstruct) << "() :: #" + type_name(tstruct) + "{}." << endl << endl; +} + +/** + * Generates the record field definition + */ + +void t_erl_generator::generate_erl_struct_member(ostream& out, t_field* tmember) { + out << atomify(tmember->get_name()); + if (has_default_value(tmember)) + out << " = " << render_member_value(tmember); + out << " :: " << render_member_type(tmember); +} + +bool t_erl_generator::has_default_value(t_field* field) { + t_type* type = field->get_type(); + if (!field->get_value()) { + if (field->get_req() == t_field::T_REQUIRED) { + if (type->is_struct() || type->is_xception() || type->is_map() || type->is_set() + || type->is_list()) { + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return true; + } +} + +string t_erl_generator::render_member_value(t_field* field) { + if (!field->get_value()) { + return render_default_value(field); + } else { + return render_const_value(field->get_type(), field->get_value()); + } +} + +/** + * Generates the read method for a struct + */ +void t_erl_generator::generate_erl_struct_info(ostream& out, t_struct* tstruct) { + indent(out) << "struct_info(" << type_name(tstruct) << ") ->" << endl; + indent_up(); + out << indent() << render_type_term(tstruct, true) << ";" << endl; + indent_down(); + out << endl; +} + +void t_erl_generator::generate_erl_extended_struct_info(ostream& out, t_struct* tstruct) { + indent(out) << "struct_info_ext(" << type_name(tstruct) << ") ->" << endl; + indent_up(); + out << indent() << render_type_term(tstruct, true, true) << ";" << endl; + indent_down(); + out << endl; +} + +/** + * Generates a thrift service. + * + * @param tservice The service definition + */ +void t_erl_generator::generate_service(t_service* tservice) { + service_name_ = make_safe_for_module_name(service_name_); + + string f_service_hrl_name = get_out_dir() + service_name_ + "_thrift.hrl"; + string f_service_name = get_out_dir() + service_name_ + "_thrift.erl"; + f_service_file_.open(f_service_name.c_str()); + f_service_hrl_.open(f_service_hrl_name.c_str()); + + // Reset service text aggregating stream streams + f_service_.str(""); + export_lines_.str(""); + export_lines_first_ = true; + + hrl_header(f_service_hrl_, service_name_); + + if (tservice->get_extends() != NULL) { + f_service_hrl_ << "-include(\"" + << make_safe_for_module_name(tservice->get_extends()->get_name()) + << "_thrift.hrl\"). % inherit " << endl; + } + + f_service_hrl_ << "-include(\"" << make_safe_for_module_name(program_name_) << "_types.hrl\")." + << endl << endl; + + // Generate the three main parts of the service (well, two for now in PHP) + generate_service_helpers(tservice); // cpiro: New Erlang Order + + generate_service_interface(tservice); + + generate_service_metadata(tservice); + + // indent_down(); + + f_service_file_ << erl_autogen_comment() << endl << "-module(" << service_name_ << "_thrift)." + << endl << "-behaviour(thrift_service)." << endl << endl << erl_imports() << endl; + + f_service_file_ << "-include(\"" << make_safe_for_module_name(tservice->get_name()) + << "_thrift.hrl\")." << endl << endl; + + f_service_file_ << "-export([" << export_lines_.str() << "])." << endl << endl; + + f_service_file_ << f_service_.str(); + + hrl_footer(f_service_hrl_, f_service_name); + + // Close service file + f_service_file_.close(); + f_service_hrl_.close(); +} + +void t_erl_generator::generate_service_metadata(t_service* tservice) { + export_string("function_names", 0); + vector functions = tservice->get_functions(); + vector::iterator f_iter; + size_t num_functions = functions.size(); + + indent(f_service_) << "function_names() -> " << endl; + indent_up(); + indent(f_service_) << "["; + + for (size_t i=0; i < num_functions; i++) { + t_function* current = functions.at(i); + f_service_ << atomify(current->get_name()); + if (i < num_functions - 1) { + f_service_ << ", "; + } + } + + f_service_ << "].\n\n"; + indent_down(); +} + +/** + * Generates helper functions for a service. + * + * @param tservice The service to generate a header definition for + */ +void t_erl_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + // indent(f_service_) << + // "% HELPER FUNCTIONS AND STRUCTURES" << endl << endl; + + export_string("struct_info", 1); + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_erl_function_helpers(*f_iter); + } + f_service_ << "struct_info(_) -> erlang:error(function_clause)." << endl; +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_erl_generator::generate_erl_function_helpers(t_function* tfunction) { + (void)tfunction; +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_erl_generator::generate_service_interface(t_service* tservice) { + + export_string("function_info", 2); + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + f_service_ << "%%% interface" << endl; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << indent() << "% " << function_signature(*f_iter) << endl; + + generate_function_info(tservice, *f_iter); + } + + // Inheritance - pass unknown functions to base class + if (tservice->get_extends() != NULL) { + indent(f_service_) << "function_info(Function, InfoType) ->" << endl; + indent_up(); + indent(f_service_) << make_safe_for_module_name(tservice->get_extends()->get_name()) + << "_thrift:function_info(Function, InfoType)." << endl; + indent_down(); + } else { + // return function_clause error for non-existent functions + indent(f_service_) << "function_info(_Func, _Info) -> erlang:error(function_clause)." << endl; + } + + indent(f_service_) << endl; +} + +/** + * Generates a function_info(FunctionName, params_type) and + * function_info(FunctionName, reply_type) + */ +void t_erl_generator::generate_function_info(t_service* tservice, t_function* tfunction) { + (void)tservice; + string name_atom = atomify(tfunction->get_name()); + + t_struct* xs = tfunction->get_xceptions(); + t_struct* arg_struct = tfunction->get_arglist(); + + // function_info(Function, params_type): + indent(f_service_) << "function_info(" << name_atom << ", params_type) ->" << endl; + indent_up(); + + indent(f_service_) << render_type_term(arg_struct, true) << ";" << endl; + + indent_down(); + + // function_info(Function, reply_type): + indent(f_service_) << "function_info(" << name_atom << ", reply_type) ->" << endl; + indent_up(); + + if (!tfunction->get_returntype()->is_void()) + indent(f_service_) << render_type_term(tfunction->get_returntype(), false) << ";" << endl; + else if (tfunction->is_oneway()) + indent(f_service_) << "oneway_void;" << endl; + else + indent(f_service_) << "{struct, []}" + << ";" << endl; + indent_down(); + + // function_info(Function, exceptions): + indent(f_service_) << "function_info(" << name_atom << ", exceptions) ->" << endl; + indent_up(); + indent(f_service_) << render_type_term(xs, true) << ";" << endl; + indent_down(); +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_erl_generator::function_signature(t_function* tfunction, string prefix) { + return prefix + tfunction->get_name() + "(This" + + capitalize(argument_list(tfunction->get_arglist())) + ")"; +} + +/** + * Add a function to the exports list + */ +void t_erl_generator::export_string(string name, int num) { + if (export_lines_first_) { + export_lines_first_ = false; + } else { + export_lines_ << ", "; + } + export_lines_ << name << "/" << num; +} + +void t_erl_generator::export_types_string(string name, int num) { + if (export_types_lines_first_) { + export_types_lines_first_ = false; + } else { + export_types_lines_ << ", "; + } + export_types_lines_ << name << "/" << num; +} + +void t_erl_generator::export_function(t_function* tfunction, string prefix) { + t_struct::members_type::size_type num = tfunction->get_arglist()->get_members().size(); + if (num > static_cast(std::numeric_limits().max())) { + throw "integer overflow in t_erl_generator::export_function, name " + tfunction->get_name(); + } + export_string(prefix + tfunction->get_name(), + 1 // This + + static_cast(num)); +} + +/** + * Renders a field list + */ +string t_erl_generator::argument_list(t_struct* tstruct) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + result += ", "; // initial comma to compensate for initial This + } else { + result += ", "; + } + result += capitalize((*f_iter)->get_name()); + } + return result; +} + +string t_erl_generator::type_name(t_type* ttype) { + string prefix = ttype->get_program()->get_namespace("erl"); + size_t prefix_length = prefix.length(); + if (prefix_length > 0 && prefix[prefix_length - 1] != '_') { + prefix += '.'; + } + + string name = ttype->get_name(); + + return atomify(prefix + name); +} + +/** + * Converts the parse type to a Erlang "type" (macro for int constants) + */ +string t_erl_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "?tType_STRING"; + case t_base_type::TYPE_BOOL: + return "?tType_BOOL"; + case t_base_type::TYPE_I8: + return "?tType_I8"; + case t_base_type::TYPE_I16: + return "?tType_I16"; + case t_base_type::TYPE_I32: + return "?tType_I32"; + case t_base_type::TYPE_I64: + return "?tType_I64"; + case t_base_type::TYPE_DOUBLE: + return "?tType_DOUBLE"; + } + } else if (type->is_enum()) { + return "?tType_I32"; + } else if (type->is_struct() || type->is_xception()) { + return "?tType_STRUCT"; + } else if (type->is_map()) { + return "?tType_MAP"; + } else if (type->is_set()) { + return "?tType_SET"; + } else if (type->is_list()) { + return "?tType_LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** + * Generate an Erlang term which represents a thrift type + */ +std::string t_erl_generator::render_type_term(t_type* type, + bool expand_structs, + bool extended_info) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "string"; + case t_base_type::TYPE_BOOL: + return "bool"; + case t_base_type::TYPE_I8: + return "byte"; + case t_base_type::TYPE_I16: + return "i16"; + case t_base_type::TYPE_I32: + return "i32"; + case t_base_type::TYPE_I64: + return "i64"; + case t_base_type::TYPE_DOUBLE: + return "double"; + } + } else if (type->is_enum()) { + return "i32"; + } else if (type->is_struct() || type->is_xception()) { + if (expand_structs) { + + std::stringstream buf; + buf << "{struct, ["; + string field_indent(buf.str().size(), ' '); + + t_struct::members_type const& fields = static_cast(type)->get_members(); + t_struct::members_type::const_iterator i, end = fields.end(); + for (i = fields.begin(); i != end;) { + t_struct::members_type::value_type member = *i; + int32_t key = member->get_key(); + string type = render_type_term(member->get_type(), false, false); // recursive call + + if (!extended_info) { + // Convert to format: {struct, [{Fid, Type}|...]} + buf << "{" << key << ", " << type << "}"; + } else { + // Convert to format: {struct, [{Fid, Req, Type, Name, Def}|...]} + string name = member->get_name(); + string value = render_member_value(member); + string requiredness = render_member_requiredness(member); + buf << "{" << key << ", " << requiredness << ", " << type << ", " << atomify(name) << ", " + << value << "}"; + } + + if (++i != end) { + buf << "," << endl << field_indent; + } + } + + buf << "]}" << endl; + return buf.str(); + } else { + return "{struct, {" + atomify(type_module(type)) + ", " + type_name(type) + "}}"; + } + } else if (type->is_map()) { + // {map, KeyType, ValType} + t_type* key_type = ((t_map*)type)->get_key_type(); + t_type* val_type = ((t_map*)type)->get_val_type(); + + return "{map, " + render_type_term(key_type, false) + ", " + render_type_term(val_type, false) + + "}"; + + } else if (type->is_set()) { + t_type* elem_type = ((t_set*)type)->get_elem_type(); + + return "{set, " + render_type_term(elem_type, false) + "}"; + + } else if (type->is_list()) { + t_type* elem_type = ((t_list*)type)->get_elem_type(); + + return "{list, " + render_type_term(elem_type, false) + "}"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +std::string t_erl_generator::type_module(t_type* ttype) { + return make_safe_for_module_name(ttype->get_program()->get_name()) + "_types"; +} + +THRIFT_REGISTER_GENERATOR( + erl, + "Erlang", + " legacynames: Output files retain naming conventions of Thrift 0.9.1 and earlier.\n" + " maps: Generate maps instead of dicts.\n" + " otp16: Generate non-namespaced dict and set instead of dict:dict and sets:set.\n") diff --git a/compiler/cpp/src/thrift/generate/t_generator.cc b/compiler/cpp/src/thrift/generate/t_generator.cc new file mode 100644 index 0000000..0c1f49d --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_generator.cc @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "thrift/generate/t_generator.h" +using namespace std; + +/** + * Top level program generation function. Calls the generator subclass methods + * for preparing file streams etc. then iterates over all the parts of the + * program to perform the correct actions. + * + * @param program The thrift program to compile into C++ source + */ +void t_generator::generate_program() { + // Initialize the generator + init_generator(); + + // Generate enums + vector enums = program_->get_enums(); + vector::iterator en_iter; + for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { + generate_enum(*en_iter); + } + + // Generate typedefs + vector typedefs = program_->get_typedefs(); + vector::iterator td_iter; + for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { + generate_typedef(*td_iter); + } + + // Generate structs, exceptions, and unions in declared order + vector objects = program_->get_objects(); + + vector::iterator o_iter; + for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { + generate_forward_declaration(*o_iter); + } + for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { + if ((*o_iter)->is_xception()) { + generate_xception(*o_iter); + } else { + generate_struct(*o_iter); + } + } + + // Generate constants + vector consts = program_->get_consts(); + generate_consts(consts); + + // Generate services + vector services = program_->get_services(); + vector::iterator sv_iter; + for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { + service_name_ = get_service_name(*sv_iter); + generate_service(*sv_iter); + } + + // Close the generator + close_generator(); +} + +string t_generator::escape_string(const string& in) const { + string result = ""; + for (string::const_iterator it = in.begin(); it < in.end(); it++) { + std::map::const_iterator res = escape_.find(*it); + if (res != escape_.end()) { + result.append(res->second); + } else { + result.push_back(*it); + } + } + return result; +} + +void t_generator::generate_consts(vector consts) { + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + generate_const(*c_iter); + } +} + +void t_generator::generate_docstring_comment(ostream& out, + const string& comment_start, + const string& line_prefix, + const string& contents, + const string& comment_end) { + if (comment_start != "") + indent(out) << comment_start; + stringstream docs(contents, ios_base::in); + while (!(docs.eof() || docs.fail())) { + char line[1024]; + docs.getline(line, 1024); + + // Just prnt a newline when the line & prefix are empty. + if (strlen(line) == 0 && line_prefix == "" && !docs.eof()) { + out << std::endl; + } else if (strlen(line) > 0 || !docs.eof()) { // skip the empty last line + indent(out) << line_prefix << line << std::endl; + } + } + if (comment_end != "") + indent(out) << comment_end; +} + +void t_generator_registry::register_generator(t_generator_factory* factory) { + gen_map_t& the_map = get_generator_map(); + if (the_map.find(factory->get_short_name()) != the_map.end()) { + failure("Duplicate generators for language \"%s\"!\n", factory->get_short_name().c_str()); + } + the_map[factory->get_short_name()] = factory; +} + +void t_generator::parse_options(const string& options, + string& language, + map& parsed_options) { + string::size_type colon = options.find(':'); + language = options.substr(0, colon); + + if (colon != string::npos) { + string::size_type pos = colon + 1; + while (pos != string::npos && pos < options.size()) { + string::size_type next_pos = options.find(',', pos); + string option = options.substr(pos, next_pos - pos); + pos = ((next_pos == string::npos) ? next_pos : next_pos + 1); + + string::size_type separator = option.find('='); + string key, value; + if (separator == string::npos) { + key = option; + value = ""; + } else { + key = option.substr(0, separator); + value = option.substr(separator + 1); + } + + parsed_options[key] = value; + } + } +} + +t_generator* t_generator_registry::get_generator(t_program* program, + const string& language, + const map& parsed_options, + const std::string& options) { + gen_map_t& the_map = get_generator_map(); + gen_map_t::iterator iter = the_map.find(language); + + if (iter == the_map.end()) { + return NULL; + } + + return iter->second->get_generator(program, parsed_options, options); +} + +t_generator* t_generator_registry::get_generator(t_program* program, const string& options) { + string language; + map parsed_options; + t_generator::parse_options(options, language, parsed_options); + return get_generator(program, language, parsed_options, options); +} + +t_generator_registry::gen_map_t& t_generator_registry::get_generator_map() { + // http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12 + static gen_map_t* the_map = new gen_map_t(); + return *the_map; +} + +t_generator_factory::t_generator_factory(const std::string& short_name, + const std::string& long_name, + const std::string& documentation) + : short_name_(short_name), long_name_(long_name), documentation_(documentation) { + t_generator_registry::register_generator(this); +} diff --git a/compiler/cpp/src/thrift/generate/t_generator.h b/compiler/cpp/src/thrift/generate/t_generator.h new file mode 100644 index 0000000..fc3f323 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_generator.h @@ -0,0 +1,322 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_GENERATOR_H +#define T_GENERATOR_H + +#include +#include +#include +#include +#include "thrift/common.h" +#include "thrift/version.h" +#include "thrift/generate/t_generator_registry.h" +#include "thrift/parse/t_program.h" + +/** + * Base class for a thrift code generator. This class defines the basic + * routines for code generation and contains the top level method that + * dispatches code generation across various components. + * + */ +class t_generator { +public: + t_generator(t_program* program) { + tmp_ = 0; + indent_ = 0; + program_ = program; + program_name_ = get_program_name(program); + escape_['\n'] = "\\n"; + escape_['\r'] = "\\r"; + escape_['\t'] = "\\t"; + escape_['"'] = "\\\""; + escape_['\\'] = "\\\\"; + } + + virtual ~t_generator() {} + + /** + * Framework generator method that iterates over all the parts of a program + * and performs general actions. This is implemented by the base class and + * should not normally be overwritten in the subclasses. + */ + virtual void generate_program(); + + const t_program* get_program() const { return program_; } + + void generate_docstring_comment(std::ostream& out, + const std::string& comment_start, + const std::string& line_prefix, + const std::string& contents, + const std::string& comment_end); + + static void parse_options(const std::string& options, std::string& language, + std::map& parsed_options); + + /** + * check whether sub-namespace declaraction is used by generator. + * e.g. allow + * namespace py.twisted bar + * to specify namespace to use when -gen py:twisted is specified. + * Will be called with subnamespace, i.e. is_valid_namespace("twisted") + * will be called for the above example. + */ + static bool is_valid_namespace(const std::string& sub_namespace) { + (void)sub_namespace; + return false; + } + + /** + * Escape string to use one in generated sources. + */ + virtual std::string escape_string(const std::string& in) const; + + std::string get_escaped_string(t_const_value* constval) { + return escape_string(constval->get_string()); + } + +protected: + /** + * Optional methods that may be imlemented by subclasses to take necessary + * steps at the beginning or end of code generation. + */ + + virtual void init_generator() {} + virtual void close_generator() {} + + virtual void generate_consts(std::vector consts); + + /** + * Pure virtual methods implemented by the generator subclasses. + */ + + virtual void generate_typedef(t_typedef* ttypedef) = 0; + virtual void generate_enum(t_enum* tenum) = 0; + virtual void generate_const(t_const* tconst) { (void)tconst; } + virtual void generate_struct(t_struct* tstruct) = 0; + virtual void generate_service(t_service* tservice) = 0; + virtual void generate_forward_declaration(t_struct*) {} + virtual void generate_xception(t_struct* txception) { + // By default exceptions are the same as structs + generate_struct(txception); + } + + /** + * Method to get the program name, may be overridden + */ + virtual std::string get_program_name(t_program* tprogram) { return tprogram->get_name(); } + + /** + * Method to get the service name, may be overridden + */ + virtual std::string get_service_name(t_service* tservice) { return tservice->get_name(); } + + /** + * Get the current output directory + */ + virtual std::string get_out_dir() const { + if (program_->is_out_path_absolute()) { + return program_->get_out_path() + "/"; + } + + return program_->get_out_path() + out_dir_base_ + "/"; + } + + /** + * Creates a unique temporary variable name, which is just "name" with a + * number appended to it (i.e. name35) + */ + std::string tmp(std::string name) { + std::ostringstream out; + out << name << tmp_++; + return out.str(); + } + + /** + * Generates a comment about this code being autogenerated, using C++ style + * comments, which are also fair game in Java / PHP, yay! + * + * @return C-style comment mentioning that this file is autogenerated. + */ + virtual std::string autogen_comment() { + return std::string("/**\n") + " * " + autogen_summary() + "\n" + " *\n" + + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + + " * @generated\n" + " */\n"; + } + + virtual std::string autogen_summary() { + return std::string("Autogenerated by Thrift Compiler (") + THRIFT_VERSION + ")"; + } + + /** + * Indentation level modifiers + */ + + void indent_up() { ++indent_; } + + void indent_down() { --indent_; } + + /** + * Indentation validation helper + */ + int indent_count() { return indent_; } + + void indent_validate( int expected, const char * func_name) { + if (indent_ != expected) { + pverbose("Wrong indent count in %s: difference = %i \n", func_name, (expected - indent_)); + } + } + + + /** + * Indentation print function + */ + std::string indent() { + std::string ind = ""; + int i; + for (i = 0; i < indent_; ++i) { + ind += indent_str(); + } + return ind; + } + + /** + * Indentation utility wrapper + */ + std::ostream& indent(std::ostream& os) { return os << indent(); } + + /** + * Capitalization helpers + */ + std::string capitalize(std::string in) { + in[0] = toupper(in[0]); + return in; + } + std::string decapitalize(std::string in) { + in[0] = tolower(in[0]); + return in; + } + static std::string lowercase(std::string in) { + for (size_t i = 0; i < in.size(); ++i) { + in[i] = tolower(in[i]); + } + return in; + } + static std::string uppercase(std::string in) { + for (size_t i = 0; i < in.size(); ++i) { + in[i] = toupper(in[i]); + } + return in; + } + /** + * Transforms a camel case string to an equivalent one separated by underscores + * e.g. aMultiWord -> a_multi_word + * someName -> some_name + * CamelCase -> camel_case + * name -> name + * Name -> name + */ + std::string underscore(std::string in) { + in[0] = tolower(in[0]); + for (size_t i = 1; i < in.size(); ++i) { + if (isupper(in[i])) { + in[i] = tolower(in[i]); + in.insert(i, "_"); + } + } + return in; + } + /** + * Transforms a string with words separated by underscores to a camel case equivalent + * e.g. a_multi_word -> aMultiWord + * some_name -> someName + * name -> name + */ + std::string camelcase(std::string in) { + std::ostringstream out; + bool underscore = false; + + for (size_t i = 0; i < in.size(); i++) { + if (in[i] == '_') { + underscore = true; + continue; + } + if (underscore) { + out << (char)toupper(in[i]); + underscore = false; + continue; + } + out << in[i]; + } + + return out.str(); + } + +public: + /** + * Get the true type behind a series of typedefs. + */ + static const t_type* get_true_type(const t_type* type) { return type->get_true_type(); } + static t_type* get_true_type(t_type* type) { return type->get_true_type(); } + +protected: + /** + * The program being generated + */ + t_program* program_; + + /** + * Quick accessor for formatted program name that is currently being + * generated. + */ + std::string program_name_; + + /** + * Quick accessor for formatted service name that is currently being + * generated. + */ + std::string service_name_; + + /** + * Output type-specifc directory name ("gen-*") + */ + std::string out_dir_base_; + + /** + * Map of characters to escape in string literals. + */ + std::map escape_; + + virtual std::string indent_str() const { + return " "; + } + +private: + /** + * Current code indentation level + */ + int indent_; + + /** + * Temporary variable counter, for making unique variable names + */ + int tmp_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/generate/t_generator_registry.h b/compiler/cpp/src/thrift/generate/t_generator_registry.h new file mode 100644 index 0000000..1f02167 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_generator_registry.h @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_GENERATOR_REGISTRY_H +#define T_GENERATOR_REGISTRY_H + +class t_generator; + +/** + * A factory for producing generator classes of a particular language. + * + * This class is also responsible for: + * - Registering itself with the generator registry. + * - Providing documentation for the generators it produces. + */ +class t_generator_factory { +public: + t_generator_factory(const std::string& short_name, + const std::string& long_name, + const std::string& documentation); + + virtual ~t_generator_factory() {} + + virtual t_generator* get_generator( + // The program to generate. + t_program* program, + // Note: parsed_options will not exist beyond the call to get_generator. + const std::map& parsed_options, + // Note: option_string might not exist beyond the call to get_generator. + const std::string& option_string) = 0; + + virtual bool is_valid_namespace(const std::string& sub_namespace) = 0; + + std::string get_short_name() { return short_name_; } + std::string get_long_name() { return long_name_; } + std::string get_documentation() { return documentation_; } + +private: + std::string short_name_; + std::string long_name_; + std::string documentation_; +}; + +template +class t_generator_factory_impl : public t_generator_factory { +public: + t_generator_factory_impl(const std::string& short_name, + const std::string& long_name, + const std::string& documentation) + : t_generator_factory(short_name, long_name, documentation) {} + + virtual t_generator* get_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) { + return new generator(program, parsed_options, option_string); + } + + virtual bool is_valid_namespace(const std::string& sub_namespace) { + return generator::is_valid_namespace(sub_namespace); + } +}; + +class t_generator_registry { +public: + static void register_generator(t_generator_factory* factory); + + static t_generator* get_generator(t_program* program, const std::string& options); + static t_generator* get_generator(t_program* program, + const std::string& laugnage, + const std::map& parsed_options, + const std::string& options); + + typedef std::map gen_map_t; + static gen_map_t& get_generator_map(); + +private: + t_generator_registry(); + t_generator_registry(const t_generator_registry&); +}; + +#define THRIFT_REGISTER_GENERATOR(language, long_name, doc) \ + class t_##language##_generator_factory_impl \ + : public t_generator_factory_impl { \ + public: \ + t_##language##_generator_factory_impl() \ + : t_generator_factory_impl(#language, long_name, doc) {} \ + }; \ + static t_##language##_generator_factory_impl _registerer; + +#endif diff --git a/compiler/cpp/src/thrift/generate/t_go_generator.cc b/compiler/cpp/src/thrift/generate/t_go_generator.cc new file mode 100644 index 0000000..6cce32b --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_go_generator.cc @@ -0,0 +1,3639 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * This file is programmatically sanitized for style: + * astyle --style=1tbs -f -p -H -j -U t_go_generator.cc + * + * The output of astyle should not be taken unquestioningly, but it is a good + * guide for ensuring uniformity and readability. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "thrift/platform.h" +#include "thrift/version.h" +#include "thrift/generate/t_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * A helper for automatically formatting the emitted Go code from the Thrift + * IDL per the Go style guide. + * + * Returns: + * - true, if the formatting process succeeded. + * - false, if the formatting process failed, which means the basic output was + * still generated. + */ +bool format_go_output(const string& file_path); + +const string DEFAULT_THRIFT_IMPORT = "git.apache.org/thrift.git/lib/go/thrift"; +static std::string package_flag; + +/** + * Go code generator. + */ +class t_go_generator : public t_generator { +public: + t_go_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + + gen_thrift_import_ = DEFAULT_THRIFT_IMPORT; + gen_package_prefix_ = ""; + package_flag = ""; + read_write_private_ = false; + legacy_context_ = false; + ignore_initialisms_ = false; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("package_prefix") == 0) { + gen_package_prefix_ = (iter->second); + } else if( iter->first.compare("thrift_import") == 0) { + gen_thrift_import_ = (iter->second); + } else if( iter->first.compare("package") == 0) { + package_flag = (iter->second); + } else if( iter->first.compare("read_write_private") == 0) { + read_write_private_ = true; + } else if( iter->first.compare("legacy_context") == 0) { + legacy_context_ = true; + } else if( iter->first.compare("ignore_initialisms") == 0) { + ignore_initialisms_ = true; + } else { + throw "unknown option go:" + iter->first; + } + } + + out_dir_base_ = "gen-go"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + std::string render_const_value(t_type* type, t_const_value* value, const string& name); + + /** + * Struct generation code + */ + + void generate_go_struct(t_struct* tstruct, bool is_exception); + void generate_go_struct_definition(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false, + bool is_result = false, + bool is_args = false); + void generate_go_struct_initializer(std::ofstream& out, + t_struct* tstruct, + bool is_args_or_result = false); + void generate_isset_helpers(std::ofstream& out, + t_struct* tstruct, + const string& tstruct_name, + bool is_result = false); + void generate_countsetfields_helper(std::ofstream& out, + t_struct* tstruct, + const string& tstruct_name, + bool is_result = false); + void generate_go_struct_reader(std::ofstream& out, + t_struct* tstruct, + const string& tstruct_name, + bool is_result = false); + void generate_go_struct_writer(std::ofstream& out, + t_struct* tstruct, + const string& tstruct_name, + bool is_result = false, + bool uses_countsetfields = false); + void generate_go_function_helpers(t_function* tfunction); + void get_publicized_name_and_def_value(t_field* tfield, + string* OUT_pub_name, + t_const_value** OUT_def_value) const; + + /** + * Service-level generation functions + */ + + void generate_service_helpers(t_service* tservice); + void generate_service_interface(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_remote(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* tfunction); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, + t_field* tfield, + bool declare, + std::string prefix = "", + bool inclass = false, + bool coerceData = false, + bool inkey = false, + bool in_container = false); + + void generate_deserialize_struct(std::ofstream& out, + t_struct* tstruct, + bool is_pointer_field, + bool declare, + std::string prefix = ""); + + void generate_deserialize_container(std::ofstream& out, + t_type* ttype, + bool pointer_field, + bool declare, + std::string prefix = ""); + + void generate_deserialize_set_element(std::ofstream& out, + t_set* tset, + bool declare, + std::string prefix = ""); + + void generate_deserialize_map_element(std::ofstream& out, + t_map* tmap, + bool declare, + std::string prefix = ""); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + bool declare, + std::string prefix = ""); + + void generate_serialize_field(std::ofstream& out, + t_field* tfield, + std::string prefix = "", + bool inkey = false); + + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_serialize_container(std::ofstream& out, + t_type* ttype, + bool pointer_field, + std::string prefix = ""); + + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string kiter, + std::string viter); + + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + + void generate_go_docstring(std::ofstream& out, t_struct* tstruct); + + void generate_go_docstring(std::ofstream& out, t_function* tfunction); + + void generate_go_docstring(std::ofstream& out, + t_doc* tdoc, + t_struct* tstruct, + const char* subheader); + + void generate_go_docstring(std::ofstream& out, t_doc* tdoc); + + /** + * Helper rendering functions + */ + + std::string go_autogen_comment(); + std::string go_package(); + std::string go_imports_begin(bool consts); + std::string go_imports_end(); + std::string render_includes(bool consts); + std::string render_included_programs(string& unused_protection); + std::string render_import_protection(); + std::string render_fastbinary_includes(); + std::string declare_argument(t_field* tfield); + std::string render_field_initial_value(t_field* tfield, const string& name, bool optional_field); + std::string type_name(t_type* ttype); + std::string module_name(t_type* ttype); + std::string function_signature(t_function* tfunction, std::string prefix = ""); + std::string function_signature_if(t_function* tfunction, + std::string prefix = "", + bool addError = false); + std::string argument_list(t_struct* tstruct); + std::string type_to_enum(t_type* ttype); + std::string type_to_go_type(t_type* ttype); + std::string type_to_go_type_with_opt(t_type* ttype, + bool optional_field); + std::string type_to_go_key_type(t_type* ttype); + std::string type_to_spec_args(t_type* ttype); + + static std::string get_real_go_module(const t_program* program) { + + if (!package_flag.empty()) { + return package_flag; + } + std::string real_module = program->get_namespace("go"); + if (!real_module.empty()) { + return real_module; + } + + return lowercase(program->get_name()); + } + +private: + std::string gen_package_prefix_; + std::string gen_thrift_import_; + bool read_write_private_; + bool legacy_context_; + bool ignore_initialisms_; + + /** + * File streams + */ + + std::ofstream f_types_; + std::string f_types_name_; + std::ofstream f_consts_; + std::string f_consts_name_; + std::stringstream f_const_values_; + + std::string package_name_; + std::string package_dir_; + std::string read_method_name_; + std::string write_method_name_; + + std::set commonInitialisms; + + std::string camelcase(const std::string& value) const; + void fix_common_initialism(std::string& value, int i) const; + std::string publicize(const std::string& value, bool is_args_or_result = false) const; + std::string privatize(const std::string& value) const; + std::string new_prefix(const std::string& value) const; + static std::string variable_name_to_go_name(const std::string& value); + static bool is_pointer_field(t_field* tfield, bool in_container = false); + static bool omit_initialization(t_field* tfield); +}; + +// returns true if field initialization can be omitted since it has corresponding go type zero value +// or default value is not set +bool t_go_generator::omit_initialization(t_field* tfield) { + t_const_value* value = tfield->get_value(); + if (!value) { + return true; + } + t_type* type = tfield->get_type()->get_true_type(); + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + throw ""; + + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + //[]byte are always inline + return false; + } + // strings are pointers if has no default + return value->get_string().empty(); + + case t_base_type::TYPE_BOOL: + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + return value->get_integer() == 0; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + return value->get_integer() == 0; + } else { + return value->get_double() == 0.; + } + } + } + return false; +} + +// Returns true if the type need a reference if used as optional without default +static bool type_need_reference(t_type* type) { + type = type->get_true_type(); + if (type->is_map() || type->is_set() || type->is_list() || type->is_struct() + || type->is_xception() || type->is_binary()) { + return false; + } + return true; +} + +// returns false if field could not use comparison to default value as !IsSet* +bool t_go_generator::is_pointer_field(t_field* tfield, bool in_container_value) { + (void)in_container_value; + if (tfield->annotations_.count("cpp.ref") != 0) { + return true; + } + t_type* type = tfield->get_type()->get_true_type(); + // Structs in containers are pointers + if (type->is_struct() || type->is_xception()) { + return true; + } + if (!(tfield->get_req() == t_field::T_OPTIONAL)) { + return false; + } + + bool has_default = tfield->get_value(); + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + throw ""; + + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + //[]byte are always inline + return false; + } + // strings are pointers if has no default + return !has_default; + + case t_base_type::TYPE_BOOL: + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + case t_base_type::TYPE_DOUBLE: + return !has_default; + } + } else if (type->is_enum()) { + return !has_default; + } else if (type->is_struct() || type->is_xception()) { + return true; + } else if (type->is_map()) { + return has_default; + } else if (type->is_set()) { + return has_default; + } else if (type->is_list()) { + return has_default; + } else if (type->is_typedef()) { + return has_default; + } + + throw "INVALID TYPE IN type_to_go_type: " + type->get_name(); +} + +std::string t_go_generator::camelcase(const std::string& value) const { + std::string value2(value); + std::setlocale(LC_ALL, "C"); // set locale to classic + + // Fix common initialism in first word + fix_common_initialism(value2, 0); + + // as long as we are changing things, let's change _ followed by lowercase to + // capital and fix common initialisms + for (std::string::size_type i = 1; i < value2.size() - 1; ++i) { + if (value2[i] == '_') { + if (islower(value2[i + 1])) { + value2.replace(i, 2, 1, toupper(value2[i + 1])); + } + + if (i > static_cast(std::numeric_limits().max())) { + throw "integer overflow in t_go_generator::camelcase, value = " + value; + } + fix_common_initialism(value2, static_cast(i)); + } + } + + return value2; +} + +// Checks to see if the word starting at i in value contains a common initialism +// and if so replaces it with the upper case version of the word. +void t_go_generator::fix_common_initialism(std::string& value, int i) const { + if (!ignore_initialisms_) { + size_t wordLen = value.find('_', i); + if (wordLen != std::string::npos) { + wordLen -= i; + } + std::string word = value.substr(i, wordLen); + std::transform(word.begin(), word.end(), word.begin(), ::toupper); + if (commonInitialisms.find(word) != commonInitialisms.end()) { + value.replace(i, word.length(), word); + } + } +} + +std::string t_go_generator::publicize(const std::string& value, bool is_args_or_result) const { + if (value.size() <= 0) { + return value; + } + + std::string value2(value), prefix; + + string::size_type dot_pos = value.rfind('.'); + if (dot_pos != string::npos) { + prefix = value.substr(0, dot_pos + 1) + prefix; + value2 = value.substr(dot_pos + 1); + } + + if (!isupper(value2[0])) { + value2[0] = toupper(value2[0]); + } + + value2 = camelcase(value2); + + // final length before further checks, the string may become longer + size_t len_before = value2.length(); + + // IDL identifiers may start with "New" which interferes with the CTOR pattern + // Adding an extra underscore to all those identifiers solves this + if ((len_before >= 3) && (value2.substr(0, 3) == "New")) { + value2 += '_'; + } + + // IDL identifiers may end with "Args"/"Result" which interferes with the implicit service + // function structs + // Adding another extra underscore to all those identifiers solves this + // Suppress this check for the actual helper struct names + if (!is_args_or_result) { + bool ends_with_args = (len_before >= 4) && (value2.substr(len_before - 4, 4) == "Args"); + bool ends_with_rslt = (len_before >= 6) && (value2.substr(len_before - 6, 6) == "Result"); + if (ends_with_args || ends_with_rslt) { + value2 += '_'; + } + } + + // Avoid naming collisions with other services + if (is_args_or_result) { + prefix += publicize(service_name_); + } + + return prefix + value2; +} + +std::string t_go_generator::new_prefix(const std::string& value) const { + if (value.size() <= 0) { + return value; + } + + string::size_type dot_pos = value.rfind('.'); + if (dot_pos != string::npos) { + return value.substr(0, dot_pos + 1) + "New" + publicize(value.substr(dot_pos + 1)); + } + return "New" + publicize(value); +} + +std::string t_go_generator::privatize(const std::string& value) const { + if (value.size() <= 0) { + return value; + } + + std::string value2(value); + + if (!islower(value2[0])) { + value2[0] = tolower(value2[0]); + } + + value2 = camelcase(value2); + + return value2; +} + +std::string t_go_generator::variable_name_to_go_name(const std::string& value) { + if (value.size() <= 0) { + return value; + } + + std::string value2(value); + std::transform(value2.begin(), value2.end(), value2.begin(), ::tolower); + + switch (value[0]) { + case 'b': + case 'B': + if (value2 != "break") { + return value; + } + + break; + + case 'c': + case 'C': + if (value2 != "case" && value2 != "chan" && value2 != "const" && value2 != "continue") { + return value; + } + + break; + + case 'd': + case 'D': + if (value2 != "default" && value2 != "defer") { + return value; + } + + break; + + case 'e': + case 'E': + if (value2 != "else" && value2 != "error") { + return value; + } + + break; + + case 'f': + case 'F': + if (value2 != "fallthrough" && value2 != "for" && value2 != "func") { + return value; + } + + break; + + case 'g': + case 'G': + if (value2 != "go" && value2 != "goto") { + return value; + } + + break; + + case 'i': + case 'I': + if (value2 != "if" && value2 != "import" && value2 != "interface") { + return value; + } + + break; + + case 'm': + case 'M': + if (value2 != "map") { + return value; + } + + break; + + case 'p': + case 'P': + if (value2 != "package") { + return value; + } + + break; + + case 'r': + case 'R': + if (value2 != "range" && value2 != "return") { + return value; + } + + break; + + case 's': + case 'S': + if (value2 != "select" && value2 != "struct" && value2 != "switch") { + return value; + } + + break; + + case 't': + case 'T': + if (value2 != "type") { + return value; + } + + break; + + case 'v': + case 'V': + if (value2 != "var") { + return value; + } + + break; + + default: + return value; + } + + return value2 + "_a1"; +} + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_go_generator::init_generator() { + // Make output directory + string module = get_real_go_module(program_); + string target = module; + package_dir_ = get_out_dir(); + + // This set is taken from https://github.com/golang/lint/blob/master/lint.go#L692 + commonInitialisms.insert("API"); + commonInitialisms.insert("ASCII"); + commonInitialisms.insert("CPU"); + commonInitialisms.insert("CSS"); + commonInitialisms.insert("DNS"); + commonInitialisms.insert("EOF"); + commonInitialisms.insert("GUID"); + commonInitialisms.insert("HTML"); + commonInitialisms.insert("HTTP"); + commonInitialisms.insert("HTTPS"); + commonInitialisms.insert("ID"); + commonInitialisms.insert("IP"); + commonInitialisms.insert("JSON"); + commonInitialisms.insert("LHS"); + commonInitialisms.insert("QPS"); + commonInitialisms.insert("RAM"); + commonInitialisms.insert("RHS"); + commonInitialisms.insert("RPC"); + commonInitialisms.insert("SLA"); + commonInitialisms.insert("SMTP"); + commonInitialisms.insert("SSH"); + commonInitialisms.insert("TCP"); + commonInitialisms.insert("TLS"); + commonInitialisms.insert("TTL"); + commonInitialisms.insert("UDP"); + commonInitialisms.insert("UI"); + commonInitialisms.insert("UID"); + commonInitialisms.insert("UUID"); + commonInitialisms.insert("URI"); + commonInitialisms.insert("URL"); + commonInitialisms.insert("UTF8"); + commonInitialisms.insert("VM"); + commonInitialisms.insert("XML"); + commonInitialisms.insert("XSRF"); + commonInitialisms.insert("XSS"); + + // names of read and write methods + if (read_write_private_) { + read_method_name_ = "read"; + write_method_name_ = "write"; + } else { + read_method_name_ = "Read"; + write_method_name_ = "Write"; + } + + while (true) { + // TODO: Do better error checking here. + MKDIR(package_dir_.c_str()); + + if (module.empty()) { + break; + } + + string::size_type pos = module.find('.'); + + if (pos == string::npos) { + package_dir_ += "/"; + package_dir_ += module; + package_name_ = module; + module.clear(); + } else { + package_dir_ += "/"; + package_dir_ += module.substr(0, pos); + module.erase(0, pos + 1); + } + } + + string::size_type loc; + + while ((loc = target.find(".")) != string::npos) { + target.replace(loc, 1, 1, '/'); + } + + // Make output files + f_types_name_ = package_dir_ + "/" + program_name_ + ".go"; + f_types_.open(f_types_name_.c_str()); + + f_consts_name_ = package_dir_ + "/" + program_name_ + "-consts.go"; + f_consts_.open(f_consts_name_.c_str()); + + vector services = program_->get_services(); + vector::iterator sv_iter; + + for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { + string service_dir = package_dir_ + "/" + underscore((*sv_iter)->get_name()) + "-remote"; + MKDIR(service_dir.c_str()); + } + + // Print header + f_types_ << go_autogen_comment() << go_package() << render_includes(false); + + f_consts_ << go_autogen_comment() << go_package() << render_includes(true); + + f_const_values_ << endl << "func init() {" << endl; + + // Create file for the GoUnusedProtection__ variable + string f_unused_prot_name_ = package_dir_ + "/" + "GoUnusedProtection__.go"; + ofstream f_unused_prot_; + f_unused_prot_.open(f_unused_prot_name_.c_str()); + f_unused_prot_ << go_autogen_comment() << go_package() << render_import_protection(); + f_unused_prot_.close(); +} + + +string t_go_generator::render_included_programs(string& unused_protection) { + const vector& includes = program_->get_includes(); + string result = ""; + + unused_protection = ""; + + string local_namespace = program_->get_namespace("go"); + for (size_t i = 0; i < includes.size(); ++i) { + if (!local_namespace.empty() && local_namespace == includes[i]->get_namespace("go")) { + continue; + } + + string go_module = get_real_go_module(includes[i]); + size_t found = 0; + for (size_t j = 0; j < go_module.size(); j++) { + // Import statement uses slashes ('/') in namespace + if (go_module[j] == '.') { + go_module[j] = '/'; + found = j + 1; + } + } + + result += "\t\"" + gen_package_prefix_ + go_module + "\"\n"; + unused_protection += "var _ = " + go_module.substr(found) + ".GoUnusedProtection__\n"; + } + + return result; +} + +/** + * Renders all the imports necessary for including another Thrift program. + * If consts include the additional imports. + */ +string t_go_generator::render_includes(bool consts) { + const vector& includes = program_->get_includes(); + string result = ""; + string unused_prot = ""; + + string local_namespace = program_->get_namespace("go"); + for (size_t i = 0; i < includes.size(); ++i) { + if (!local_namespace.empty() && local_namespace == includes[i]->get_namespace("go")) { + continue; + } + + string go_module = get_real_go_module(includes[i]); + size_t found = 0; + for (size_t j = 0; j < go_module.size(); j++) { + // Import statement uses slashes ('/') in namespace + if (go_module[j] == '.') { + go_module[j] = '/'; + found = j + 1; + } + } + + result += "\t\"" + gen_package_prefix_ + go_module + "\"\n"; + unused_prot += "var _ = " + go_module.substr(found) + ".GoUnusedProtection__\n"; + } + + if (includes.size() > 0) { + result += "\n"; + } + + return go_imports_begin(consts) + result + go_imports_end() + unused_prot; +} + +string t_go_generator::render_import_protection() { + return string("var GoUnusedProtection__ int;\n\n"); +} + +/** + * Renders all the imports necessary to use the accelerated TBinaryProtocol + */ +string t_go_generator::render_fastbinary_includes() { + return ""; +} + +/** + * Autogen'd comment + */ +string t_go_generator::go_autogen_comment() { + return + std::string() + + "// Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + "// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n\n"; +} + +/** + * Prints standard thrift package + */ +string t_go_generator::go_package() { + return string("package ") + package_name_ + "\n\n"; +} + +/** + * Render the beginning of the import statement. + * If consts include the additional imports. + */ +string t_go_generator::go_imports_begin(bool consts) { + string extra; + + // If not writing constants, and there are enums, need extra imports. + if (!consts && get_program()->get_enums().size() > 0) { + extra += + "\t\"database/sql/driver\"\n" + "\t\"errors\"\n"; + } + if (legacy_context_) { + extra += + "\t\"golang.org/x/net/context\"\n"; + } else { + extra += + "\t\"context\"\n"; + } + return string( + "import (\n" + "\t\"bytes\"\n" + "\t\"reflect\"\n" + + extra + + "\t\"fmt\"\n" + "\t\"" + gen_thrift_import_ + "\"\n"); +} + +/** + * End the import statement, include undscore-assignments + * + * These "_ =" prevent the go compiler complaining about unused imports. + * This will have to do in lieu of more intelligent import statement construction + */ +string t_go_generator::go_imports_end() { + return string( + ")\n\n" + "// (needed to ensure safety because of naive import list construction.)\n" + "var _ = thrift.ZERO\n" + "var _ = fmt.Printf\n" + "var _ = context.Background\n" + "var _ = reflect.DeepEqual\n" + "var _ = bytes.Equal\n\n"); +} + +/** + * Closes the type files + */ +void t_go_generator::close_generator() { + f_const_values_ << "}" << endl << endl; + f_consts_ << f_const_values_.str(); + + // Close types and constants files + f_consts_.close(); + f_types_.close(); + format_go_output(f_types_name_); + format_go_output(f_consts_name_); +} + +/** + * Generates a typedef. + * + * @param ttypedef The type definition + */ +void t_go_generator::generate_typedef(t_typedef* ttypedef) { + generate_go_docstring(f_types_, ttypedef); + string new_type_name(publicize(ttypedef->get_symbolic())); + string base_type(type_to_go_type(ttypedef->get_type())); + + if (base_type == new_type_name) { + return; + } + + f_types_ << "type " << new_type_name << " " << base_type << endl << endl; + // Generate a convenience function that converts an instance of a type + // (which may be a constant) into a pointer to an instance of a type. + f_types_ << "func " << new_type_name << "Ptr(v " << new_type_name << ") *" << new_type_name + << " { return &v }" << endl << endl; +} + +/** + * Generates code for an enumerated type. Done using a class to scope + * the values. + * + * @param tenum The enumeration + */ +void t_go_generator::generate_enum(t_enum* tenum) { + std::ostringstream to_string_mapping, from_string_mapping; + std::string tenum_name(publicize(tenum->get_name())); + generate_go_docstring(f_types_, tenum); + f_types_ << "type " << tenum_name << " int64" << endl << "const (" << endl; + + to_string_mapping << indent() << "func (p " << tenum_name << ") String() string {" << endl; + to_string_mapping << indent() << " switch p {" << endl; + + from_string_mapping << indent() << "func " << tenum_name << "FromString(s string) (" << tenum_name + << ", error) {" << endl; + from_string_mapping << indent() << " switch s {" << endl; + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + int value = -1; + + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + value = (*c_iter)->get_value(); + + string iter_std_name(escape_string((*c_iter)->get_name())); + string iter_name((*c_iter)->get_name()); + f_types_ << indent() << " " << tenum_name << "_" << iter_name << ' ' << tenum_name << " = " + << value << endl; + // Dictionaries to/from string names of enums + to_string_mapping << indent() << " case " << tenum_name << "_" << iter_name << ": return \"" + << iter_std_name << "\"" << endl; + + if (iter_std_name != escape_string(iter_name)) { + from_string_mapping << indent() << " case \"" << iter_std_name << "\", \"" + << escape_string(iter_name) << "\": return " << tenum_name << "_" + << iter_name << ", nil " << endl; + } else { + from_string_mapping << indent() << " case \"" << iter_std_name << "\": return " << tenum_name + << "_" << iter_name << ", nil " << endl; + } + } + + to_string_mapping << indent() << " }" << endl; + to_string_mapping << indent() << " return \"\"" << endl; + to_string_mapping << indent() << "}" << endl; + from_string_mapping << indent() << " }" << endl; + from_string_mapping << indent() << " return " << tenum_name << "(0)," + << " fmt.Errorf(\"not a valid " << tenum_name << " string\")" << endl; + from_string_mapping << indent() << "}" << endl; + + f_types_ << ")" << endl << endl << to_string_mapping.str() << endl << from_string_mapping.str() + << endl << endl; + + // Generate a convenience function that converts an instance of an enum + // (which may be a constant) into a pointer to an instance of that enum + // type. + f_types_ << "func " << tenum_name << "Ptr(v " << tenum_name << ") *" << tenum_name + << " { return &v }" << endl << endl; + + // Generate MarshalText + f_types_ << "func (p " << tenum_name << ") MarshalText() ([]byte, error) {" << endl; + f_types_ << "return []byte(p.String()), nil" << endl; + f_types_ << "}" << endl << endl; + + // Generate UnmarshalText + f_types_ << "func (p *" << tenum_name << ") UnmarshalText(text []byte) error {" << endl; + f_types_ << "q, err := " << tenum_name << "FromString(string(text))" << endl; + f_types_ << "if (err != nil) {" << endl << "return err" << endl << "}" << endl; + f_types_ << "*p = q" << endl; + f_types_ << "return nil" << endl; + f_types_ << "}" << endl << endl; + + // Generate Scan for sql.Scanner interface + f_types_ << "func (p *" << tenum_name << ") Scan(value interface{}) error {" <get_type(); + string name = publicize(tconst->get_name()); + t_const_value* value = tconst->get_value(); + + if (type->is_base_type() || type->is_enum()) { + indent(f_consts_) << "const " << name << " = " << render_const_value(type, value, name) << endl; + } else { + f_const_values_ << indent() << name << " = " << render_const_value(type, value, name) << endl + << endl; + + f_consts_ << indent() << "var " << name << " " << type_to_go_type(type) << endl; + } +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +string t_go_generator::render_const_value(t_type* type, t_const_value* value, const string& name) { + type = get_true_type(type); + std::ostringstream out; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + + switch (tbase) { + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "[]byte(\"" << get_escaped_string(value) << "\")"; + } else { + out << '"' << get_escaped_string(value) << '"'; + } + + break; + + case t_base_type::TYPE_BOOL: + out << (value->get_integer() > 0 ? "true" : "false"); + break; + + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + out << value->get_integer(); + break; + + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + out << value->get_integer(); + } else { + out << value->get_double(); + } + + break; + + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + indent(out) << value->get_integer(); + } else if (type->is_struct() || type->is_xception()) { + out << "&" << publicize(type_name(type)) << "{"; + indent_up(); + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + + out << endl << indent() << publicize(v_iter->first->get_string()) << ": " + << render_const_value(field_type, v_iter->second, name) << "," << endl; + } + + indent_down(); + out << "}"; + + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + out << "map[" << type_to_go_type(ktype) << "]" << type_to_go_type(vtype) << "{" << endl; + indent_up(); + map::const_iterator v_iter; + + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + out << indent() << render_const_value(ktype, v_iter->first, name) << ": " + << render_const_value(vtype, v_iter->second, name) << "," << endl; + } + + indent_down(); + out << indent() << "}"; + } else if (type->is_list()) { + t_type* etype = ((t_list*)type)->get_elem_type(); + const vector& val = value->get_list(); + out << "[]" << type_to_go_type(etype) << "{" << endl; + indent_up(); + vector::const_iterator v_iter; + + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + out << indent() << render_const_value(etype, *v_iter, name) << ", "; + } + + indent_down(); + out << indent() << "}"; + } else if (type->is_set()) { + t_type* etype = ((t_set*)type)->get_elem_type(); + const vector& val = value->get_list(); + out << "[]" << type_to_go_key_type(etype) << "{" << endl; + indent_up(); + vector::const_iterator v_iter; + + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + out << indent() << render_const_value(etype, *v_iter, name) << ", "; + } + + indent_down(); + out << indent() << "}"; + } else { + throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); + } + + return out.str(); +} + +/** + * Generates a go struct + */ +void t_go_generator::generate_struct(t_struct* tstruct) { + generate_go_struct(tstruct, false); +} + +/** + * Generates a struct definition for a thrift exception. Basically the same + * as a struct but extends the Exception class. + * + * @param txception The struct definition + */ +void t_go_generator::generate_xception(t_struct* txception) { + generate_go_struct(txception, true); +} + +/** + * Generates a go struct + */ +void t_go_generator::generate_go_struct(t_struct* tstruct, bool is_exception) { + generate_go_struct_definition(f_types_, tstruct, is_exception); +} + +void t_go_generator::get_publicized_name_and_def_value(t_field* tfield, + string* OUT_pub_name, + t_const_value** OUT_def_value) const { + const string base_field_name = tfield->get_name(); + const string escaped_field_name = escape_string(base_field_name); + *OUT_pub_name = publicize(escaped_field_name); + *OUT_def_value = tfield->get_value(); +} + +void t_go_generator::generate_go_struct_initializer(ofstream& out, + t_struct* tstruct, + bool is_args_or_result) { + out << publicize(type_name(tstruct), is_args_or_result) << "{"; + const vector& members = tstruct->get_members(); + for (vector::const_iterator m_iter = members.begin(); m_iter != members.end(); + ++m_iter) { + bool pointer_field = is_pointer_field(*m_iter); + string publicized_name; + t_const_value* def_value; + get_publicized_name_and_def_value(*m_iter, &publicized_name, &def_value); + if (!pointer_field && def_value != NULL && !omit_initialization(*m_iter)) { + out << endl << indent() << publicized_name << ": " + << render_field_initial_value(*m_iter, (*m_iter)->get_name(), pointer_field) << "," + << endl; + } + } + + out << "}" << endl; +} + +/** + * Generates a struct definition for a thrift data type. + * + * @param tstruct The struct definition + */ +void t_go_generator::generate_go_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool is_result, + bool is_args) { + const vector& members = tstruct->get_members(); + const vector& sorted_members = tstruct->get_sorted_members(); + vector::const_iterator m_iter; + + std::string tstruct_name(publicize(tstruct->get_name(), is_args || is_result)); + generate_go_docstring(out, tstruct); + out << indent() << "type " << tstruct_name << " struct {" << endl; + /* + Here we generate the structure specification for the fastbinary codec. + These specifications have the following structure: + thrift_spec -> tuple of item_spec + item_spec -> nil | (tag, type_enum, name, spec_args, default) + tag -> integer + type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ... + name -> string_literal + default -> nil # Handled by __init__ + spec_args -> nil # For simple types + | (type_enum, spec_args) # Value type for list/set + | (type_enum, spec_args, type_enum, spec_args) + # Key and value for map + | (class_name, spec_args_ptr) # For struct/exception + class_name -> identifier # Basically a pointer to the class + spec_args_ptr -> expression # just class_name.spec_args + + TODO(dreiss): Consider making this work for structs with negative tags. + */ + // TODO(dreiss): Look into generating an empty tuple instead of nil + // for structures with no members. + // TODO(dreiss): Test encoding of structs where some inner structs + // don't have thrift_spec. + indent_up(); + + int num_setable = 0; + if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) { + int sorted_keys_pos = 0; + + for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) { + // Set field to optional if field is union, this is so we can get a + // pointer to the field. + if (tstruct->is_union()) + (*m_iter)->set_req(t_field::T_OPTIONAL); + if (sorted_keys_pos != (*m_iter)->get_key()) { + int first_unused = std::max(1, sorted_keys_pos++); + while (sorted_keys_pos != (*m_iter)->get_key()) { + ++sorted_keys_pos; + } + int last_unused = sorted_keys_pos - 1; + if (first_unused < last_unused) { + indent(out) << "// unused fields # " << first_unused << " to " << last_unused << endl; + } else if (first_unused == last_unused) { + indent(out) << "// unused field # " << first_unused << endl; + } + } + + t_type* fieldType = (*m_iter)->get_type(); + string goType = type_to_go_type_with_opt(fieldType, is_pointer_field(*m_iter)); + string gotag = "db:\"" + escape_string((*m_iter)->get_name()) + "\" "; + if ((*m_iter)->get_req() == t_field::T_OPTIONAL) { + gotag += "json:\"" + escape_string((*m_iter)->get_name()) + ",omitempty\""; + } else { + gotag += "json:\"" + escape_string((*m_iter)->get_name()) + "\""; + } + + // Check for user override of db and json tags using "go.tag" + std::map::iterator it = (*m_iter)->annotations_.find("go.tag"); + if (it != (*m_iter)->annotations_.end()) { + gotag = it->second; + } + indent(out) << publicize((*m_iter)->get_name()) << " " << goType << " `thrift:\"" + << escape_string((*m_iter)->get_name()) << "," << sorted_keys_pos; + if ((*m_iter)->get_req() == t_field::T_REQUIRED) { + out << ",required"; + } + + out << "\" " << gotag << "`" << endl; + sorted_keys_pos++; + } + } else { + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + // This fills in default values, as opposed to nulls + out << indent() << publicize((*m_iter)->get_name()) << " " + << type_to_go_type((*m_iter)->get_type()) << endl; + } + } + + indent_down(); + out << indent() << "}" << endl << endl; + out << indent() << "func New" << tstruct_name << "() *" << tstruct_name << " {" << endl; + out << indent() << " return &"; + generate_go_struct_initializer(out, tstruct, is_result || is_args); + out << indent() << "}" << endl << endl; + // Default values for optional fields + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + string publicized_name; + t_const_value* def_value; + get_publicized_name_and_def_value(*m_iter, &publicized_name, &def_value); + t_type* fieldType = (*m_iter)->get_type(); + string goType = type_to_go_type_with_opt(fieldType, false); + string def_var_name = tstruct_name + "_" + publicized_name + "_DEFAULT"; + if ((*m_iter)->get_req() == t_field::T_OPTIONAL || is_pointer_field(*m_iter)) { + out << indent() << "var " << def_var_name << " " << goType; + if (def_value != NULL) { + out << " = " << render_const_value(fieldType, def_value, (*m_iter)->get_name()); + } + out << endl; + } + if (is_pointer_field(*m_iter)) { + string goOptType = type_to_go_type_with_opt(fieldType, true); + string maybepointer = goOptType != goType ? "*" : ""; + out << indent() << "func (p *" << tstruct_name << ") Get" << publicized_name << "() " + << goType << " {" << endl; + out << indent() << " if !p.IsSet" << publicized_name << "() {" << endl; + out << indent() << " return " << def_var_name << endl; + out << indent() << " }" << endl; + out << indent() << "return " << maybepointer << "p." << publicized_name << endl; + out << indent() << "}" << endl; + num_setable += 1; + } else { + out << endl; + out << indent() << "func (p *" << tstruct_name << ") Get" << publicized_name << "() " + << goType << " {" << endl; + out << indent() << " return p." << publicized_name << endl; + out << indent() << "}" << endl; + } + } + + if (tstruct->is_union() && num_setable > 0) { + generate_countsetfields_helper(out, tstruct, tstruct_name, is_result); + } + + generate_isset_helpers(out, tstruct, tstruct_name, is_result); + generate_go_struct_reader(out, tstruct, tstruct_name, is_result); + generate_go_struct_writer(out, tstruct, tstruct_name, is_result, num_setable > 0); + + out << indent() << "func (p *" << tstruct_name << ") String() string {" << endl; + out << indent() << " if p == nil {" << endl; + out << indent() << " return \"\"" << endl; + out << indent() << " }" << endl; + out << indent() << " return fmt.Sprintf(\"" << escape_string(tstruct_name) << "(%+v)\", *p)" + << endl; + out << indent() << "}" << endl << endl; + + if (is_exception) { + out << indent() << "func (p *" << tstruct_name << ") Error() string {" << endl; + out << indent() << " return p.String()" << endl; + out << indent() << "}" << endl << endl; + } +} + +/** + * Generates the IsSet helper methods for a struct + */ +void t_go_generator::generate_isset_helpers(ofstream& out, + t_struct* tstruct, + const string& tstruct_name, + bool is_result) { + (void)is_result; + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + const string escaped_tstruct_name(escape_string(tstruct->get_name())); + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + const string field_name(publicize(escape_string((*f_iter)->get_name()))); + if ((*f_iter)->get_req() == t_field::T_OPTIONAL || is_pointer_field(*f_iter)) { + out << indent() << "func (p *" << tstruct_name << ") IsSet" << field_name << "() bool {" + << endl; + indent_up(); + t_type* ttype = (*f_iter)->get_type()->get_true_type(); + bool is_byteslice = ttype->is_binary(); + bool compare_to_nil_only = ttype->is_set() || ttype->is_list() || ttype->is_map() + || (is_byteslice && !(*f_iter)->get_value()); + if (is_pointer_field(*f_iter) || compare_to_nil_only) { + out << indent() << "return p." << field_name << " != nil" << endl; + } else { + string def_var_name = tstruct_name + "_" + field_name + "_DEFAULT"; + if (is_byteslice) { + out << indent() << "return !bytes.Equal(p." << field_name << ", " << def_var_name << ")" + << endl; + } else { + out << indent() << "return p." << field_name << " != " << def_var_name << endl; + } + } + indent_down(); + out << indent() << "}" << endl << endl; + } + } +} + +/** + * Generates the CountSetFields helper method for a struct + */ +void t_go_generator::generate_countsetfields_helper(ofstream& out, + t_struct* tstruct, + const string& tstruct_name, + bool is_result) { + (void)is_result; + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + const string escaped_tstruct_name(escape_string(tstruct->get_name())); + + out << indent() << "func (p *" << tstruct_name << ") CountSetFields" << tstruct_name << "() int {" + << endl; + indent_up(); + out << indent() << "count := 0" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) + continue; + + t_type* type = (*f_iter)->get_type()->get_true_type(); + + if (!(is_pointer_field(*f_iter) || type->is_map() || type->is_set() || type->is_list())) + continue; + + const string field_name(publicize(escape_string((*f_iter)->get_name()))); + + out << indent() << "if (p.IsSet" << field_name << "()) {" << endl; + indent_up(); + out << indent() << "count++" << endl; + indent_down(); + out << indent() << "}" << endl; + } + + out << indent() << "return count" << endl << endl; + indent_down(); + out << indent() << "}" << endl << endl; +} + +/** + * Generates the read method for a struct + */ +void t_go_generator::generate_go_struct_reader(ofstream& out, + t_struct* tstruct, + const string& tstruct_name, + bool is_result) { + (void)is_result; + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + string escaped_tstruct_name(escape_string(tstruct->get_name())); + out << indent() << "func (p *" << tstruct_name << ") " << read_method_name_ << "(iprot thrift.TProtocol) error {" + << endl; + indent_up(); + out << indent() << "if _, err := iprot.ReadStructBegin(); err != nil {" << endl; + out << indent() << " return thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)" + << endl; + out << indent() << "}" << endl << endl; + + // Required variables does not have IsSet functions, so we need tmp vars to check them. + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + const string field_name(publicize(escape_string((*f_iter)->get_name()))); + indent(out) << "var isset" << field_name << " bool = false;" << endl; + } + } + out << endl; + + // Loop over reading in fields + indent(out) << "for {" << endl; + indent_up(); + // Read beginning field marker + out << indent() << "_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()" << endl; + out << indent() << "if err != nil {" << endl; + out << indent() << " return thrift.PrependError(fmt.Sprintf(" + "\"%T field %d read error: \", p, fieldId), err)" << endl; + out << indent() << "}" << endl; + // Check for field STOP marker and break + out << indent() << "if fieldTypeId == thrift.STOP { break; }" << endl; + + string thriftFieldTypeId; + // Generate deserialization code for known cases + int32_t field_id = -1; + + // Switch statement on the field we are reading, false if no fields present + bool have_switch = !fields.empty(); + if (have_switch) { + indent(out) << "switch fieldId {" << endl; + } + + // All the fields we know + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + field_id = (*f_iter)->get_key(); + + // if negative id, ensure we generate a valid method name + string field_method_prefix("ReadField"); + int32_t field_method_suffix = field_id; + + if (field_method_suffix < 0) { + field_method_prefix += "_"; + field_method_suffix *= -1; + } + + out << indent() << "case " << field_id << ":" << endl; + indent_up(); + thriftFieldTypeId = type_to_enum((*f_iter)->get_type()); + + if (thriftFieldTypeId == "thrift.BINARY") { + thriftFieldTypeId = "thrift.STRING"; + } + + out << indent() << "if fieldTypeId == " << thriftFieldTypeId << " {" << endl; + out << indent() << " if err := p." << field_method_prefix << field_method_suffix << "(iprot); err != nil {" + << endl; + out << indent() << " return err" << endl; + out << indent() << " }" << endl; + out << indent() << "} else {" << endl; + out << indent() << " if err := iprot.Skip(fieldTypeId); err != nil {" << endl; + out << indent() << " return err" << endl; + out << indent() << " }" << endl; + out << indent() << "}" << endl; + + // Mark required field as read + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + const string field_name(publicize(escape_string((*f_iter)->get_name()))); + out << indent() << "isset" << field_name << " = true" << endl; + } + + indent_down(); + } + + // Begin switch default case + if (have_switch) { + out << indent() << "default:" << endl; + indent_up(); + } + + // Skip unknown fields in either case + out << indent() << "if err := iprot.Skip(fieldTypeId); err != nil {" << endl; + out << indent() << " return err" << endl; + out << indent() << "}" << endl; + + // End switch default case + if (have_switch) { + indent_down(); + out << indent() << "}" << endl; + } + + // Read field end marker + out << indent() << "if err := iprot.ReadFieldEnd(); err != nil {" << endl; + out << indent() << " return err" << endl; + out << indent() << "}" << endl; + indent_down(); + out << indent() << "}" << endl; + out << indent() << "if err := iprot.ReadStructEnd(); err != nil {" << endl; + out << indent() << " return thrift.PrependError(fmt.Sprintf(" + "\"%T read struct end error: \", p), err)" << endl; + out << indent() << "}" << endl; + + // Return error if any required fields are missing. + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + const string field_name(publicize(escape_string((*f_iter)->get_name()))); + out << indent() << "if !isset" << field_name << "{" << endl; + out << indent() << " return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, " + "fmt.Errorf(\"Required field " << field_name << " is not set\"));" << endl; + out << indent() << "}" << endl; + } + } + + out << indent() << "return nil" << endl; + indent_down(); + out << indent() << "}" << endl << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + string field_type_name(publicize((*f_iter)->get_type()->get_name())); + string field_name(publicize((*f_iter)->get_name())); + string field_method_prefix("ReadField"); + int32_t field_id = (*f_iter)->get_key(); + int32_t field_method_suffix = field_id; + + if (field_method_suffix < 0) { + field_method_prefix += "_"; + field_method_suffix *= -1; + } + + out << indent() << "func (p *" << tstruct_name << ") " << field_method_prefix << field_method_suffix + << "(iprot thrift.TProtocol) error {" << endl; + indent_up(); + generate_deserialize_field(out, *f_iter, false, "p."); + indent_down(); + out << indent() << " return nil" << endl; + out << indent() << "}" << endl << endl; + } +} + +void t_go_generator::generate_go_struct_writer(ofstream& out, + t_struct* tstruct, + const string& tstruct_name, + bool is_result, + bool uses_countsetfields) { + (void)is_result; + string name(tstruct->get_name()); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + indent(out) << "func (p *" << tstruct_name << ") " << write_method_name_ << "(oprot thrift.TProtocol) error {" << endl; + indent_up(); + if (tstruct->is_union() && uses_countsetfields) { + std::string tstruct_name(publicize(tstruct->get_name())); + out << indent() << "if c := p.CountSetFields" << tstruct_name << "(); c != 1 {" << endl + << indent() + << " return fmt.Errorf(\"%T write union: exactly one field must be set (%d set).\", p, c)" + << endl << indent() << "}" << endl; + } + out << indent() << "if err := oprot.WriteStructBegin(\"" << name << "\"); err != nil {" << endl; + out << indent() << " return thrift.PrependError(fmt.Sprintf(" + "\"%T write struct begin error: \", p), err) }" << endl; + + string field_name; + string escape_field_name; + // t_const_value* field_default_value; + t_field::e_req field_required; + int32_t field_id = -1; + + out << indent() << "if p != nil {" << endl; + indent_up(); + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + string field_method_prefix("writeField"); + field_name = (*f_iter)->get_name(); + escape_field_name = escape_string(field_name); + field_id = (*f_iter)->get_key(); + int32_t field_method_suffix = field_id; + + if (field_method_suffix < 0) { + field_method_prefix += "_"; + field_method_suffix *= -1; + } + + out << indent() << "if err := p." << field_method_prefix << field_method_suffix + << "(oprot); err != nil { return err }" << endl; + } + + indent_down(); + out << indent() << "}" << endl; + + // Write the struct map + out << indent() << "if err := oprot.WriteFieldStop(); err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"write field stop error: \", err) }" << endl; + out << indent() << "if err := oprot.WriteStructEnd(); err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"write struct stop error: \", err) }" << endl; + out << indent() << "return nil" << endl; + indent_down(); + out << indent() << "}" << endl << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + string field_method_prefix("writeField"); + field_id = (*f_iter)->get_key(); + field_name = (*f_iter)->get_name(); + escape_field_name = escape_string(field_name); + // field_default_value = (*f_iter)->get_value(); + field_required = (*f_iter)->get_req(); + int32_t field_method_suffix = field_id; + + if (field_method_suffix < 0) { + field_method_prefix += "_"; + field_method_suffix *= -1; + } + + out << indent() << "func (p *" << tstruct_name << ") " << field_method_prefix << field_method_suffix + << "(oprot thrift.TProtocol) (err error) {" << endl; + indent_up(); + + if (field_required == t_field::T_OPTIONAL) { + out << indent() << "if p.IsSet" << publicize(field_name) << "() {" << endl; + indent_up(); + } + + out << indent() << "if err := oprot.WriteFieldBegin(\"" << escape_field_name << "\", " + << type_to_enum((*f_iter)->get_type()) << ", " << field_id << "); err != nil {" << endl; + out << indent() << " return thrift.PrependError(fmt.Sprintf(\"%T write field begin error " + << field_id << ":" << escape_field_name << ": \", p), err) }" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "p."); + + // Write field closer + out << indent() << "if err := oprot.WriteFieldEnd(); err != nil {" << endl; + out << indent() << " return thrift.PrependError(fmt.Sprintf(\"%T write field end error " + << field_id << ":" << escape_field_name << ": \", p), err) }" << endl; + + if (field_required == t_field::T_OPTIONAL) { + indent_down(); + out << indent() << "}" << endl; + } + + indent_down(); + out << indent() << " return err" << endl; + out << indent() << "}" << endl << endl; + } +} + +/** + * Generates a thrift service. + * + * @param tservice The service definition + */ +void t_go_generator::generate_service(t_service* tservice) { + string test_suffix("_test"); + string filename = lowercase(service_name_); + string f_service_name; + + generate_service_interface(tservice); + generate_service_client(tservice); + generate_service_server(tservice); + generate_service_helpers(tservice); + generate_service_remote(tservice); + f_types_ << endl; +} + +/** + * Generates helper functions for a service. + * + * @param tservice The service to generate a header definition for + */ +void t_go_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + f_types_ << "// HELPER FUNCTIONS AND STRUCTURES" << endl << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_go_struct_definition(f_types_, ts, false, false, true); + generate_go_function_helpers(*f_iter); + } +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_go_generator::generate_go_function_helpers(t_function* tfunction) { + if (!tfunction->is_oneway()) { + t_struct result(program_, tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + success.set_req(t_field::T_OPTIONAL); + + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* f = *f_iter; + f->set_req(t_field::T_OPTIONAL); + result.append(f); + } + + generate_go_struct_definition(f_types_, &result, false, true); + } +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_go_generator::generate_service_interface(t_service* tservice) { + string extends = ""; + string extends_if = ""; + string serviceName(publicize(tservice->get_name())); + string interfaceName = serviceName; + + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + size_t index = extends.rfind("."); + + if (index != string::npos) { + extends_if = "\n" + indent() + " " + extends.substr(0, index + 1) + + publicize(extends.substr(index + 1)) + "\n"; + } else { + extends_if = "\n" + indent() + publicize(extends) + "\n"; + } + } + + f_types_ << indent() << "type " << interfaceName << " interface {" << extends_if; + indent_up(); + generate_go_docstring(f_types_, tservice); + vector functions = tservice->get_functions(); + + if (!functions.empty()) { + f_types_ << endl; + vector::iterator f_iter; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_go_docstring(f_types_, (*f_iter)); + f_types_ << indent() << function_signature_if(*f_iter, "", true) << endl; + } + } + + indent_down(); + f_types_ << indent() << "}" << endl << endl; +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_go_generator::generate_service_client(t_service* tservice) { + string extends = ""; + string extends_field = ""; + string extends_client = ""; + string extends_client_new = ""; + string serviceName(publicize(tservice->get_name())); + + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + size_t index = extends.rfind("."); + + if (index != string::npos) { + extends_client = extends.substr(0, index + 1) + publicize(extends.substr(index + 1)) + + "Client"; + extends_client_new = extends.substr(0, index + 1) + "New" + + publicize(extends.substr(index + 1)) + "Client"; + } else { + extends_client = publicize(extends) + "Client"; + extends_client_new = "New" + extends_client; + } + } + + extends_field = extends_client.substr(extends_client.find(".") + 1); + + generate_go_docstring(f_types_, tservice); + f_types_ << indent() << "type " << serviceName << "Client struct {" << endl; + indent_up(); + + f_types_ << indent() << "c thrift.TClient" << endl; + if (!extends_client.empty()) { + f_types_ << indent() << "*" << extends_client << endl; + } + + indent_down(); + f_types_ << indent() << "}" << endl << endl; + + // Legacy constructor function + f_types_ << indent() << "// Deprecated: Use New" << serviceName << " instead" << endl; + f_types_ << indent() << "func New" << serviceName + << "ClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *" << serviceName + << "Client {" << endl; + indent_up(); + f_types_ << indent() << "return &" << serviceName << "Client"; + + if (!extends.empty()) { + f_types_ << "{" << extends_field << ": " << extends_client_new << "Factory(t, f)}"; + } else { + indent_up(); + f_types_ << "{" << endl; + f_types_ << indent() << "c: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t))," << endl; + indent_down(); + f_types_ << indent() << "}" << endl; + } + + indent_down(); + f_types_ << indent() << "}" << endl << endl; + // Legacy constructor function with custom input & output protocols + f_types_ << indent() << "// Deprecated: Use New" << serviceName << " instead" << endl; + f_types_ + << indent() << "func New" << serviceName + << "ClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *" + << serviceName << "Client {" << endl; + indent_up(); + f_types_ << indent() << "return &" << serviceName << "Client"; + + if (!extends.empty()) { + f_types_ << "{" << extends_field << ": " << extends_client_new << "Protocol(t, iprot, oprot)}" + << endl; + } else { + indent_up(); + f_types_ << "{" << endl; + f_types_ << indent() << "c: thrift.NewTStandardClient(iprot, oprot)," << endl; + indent_down(); + f_types_ << indent() << "}" << endl; + } + + indent_down(); + f_types_ << indent() << "}" << endl << endl; + + // Constructor function + f_types_ << indent() << "func New" << serviceName + << "Client(c thrift.TClient) *" << serviceName << "Client {" << endl; + indent_up(); + f_types_ << indent() << "return &" << serviceName << "Client{" << endl; + + indent_up(); + f_types_ << indent() << "c: c," << endl; + if (!extends.empty()) { + f_types_ << indent() << extends_field << ": " << extends_client_new << "(c)," << endl; + } + indent_down(); + f_types_ << indent() << "}" << endl; + + indent_down(); + f_types_ << indent() << "}" << endl << endl; + + // Generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* arg_struct = (*f_iter)->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + string funname = publicize((*f_iter)->get_name()); + // Open function + generate_go_docstring(f_types_, (*f_iter)); + f_types_ << indent() << "func (p *" << serviceName << "Client) " + << function_signature_if(*f_iter, "", true) << " {" << endl; + indent_up(); + + std::string method = (*f_iter)->get_name(); + std::string argsType = publicize(method + "_args", true); + std::string argsName = tmp("_args"); + f_types_ << indent() << "var " << argsName << " " << argsType << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_types_ << indent() << argsName << "." << publicize((*fld_iter)->get_name()) + << " = " << variable_name_to_go_name((*fld_iter)->get_name()) << endl; + } + + if (!(*f_iter)->is_oneway()) { + std::string resultName = tmp("_result"); + std::string resultType = publicize(method + "_result", true); + f_types_ << indent() << "var " << resultName << " " << resultType << endl; + f_types_ << indent() << "if err = p.c.Call(ctx, \"" + << method << "\", &" << argsName << ", &" << resultName << "); err != nil {" << endl; + + indent_up(); + f_types_ << indent() << "return" << endl; + indent_down(); + f_types_ << indent() << "}" << endl; + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + if (!xceptions.empty()) { + f_types_ << indent() << "switch {" << endl; + + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + const std::string pubname = publicize((*x_iter)->get_name()); + const std::string field = resultName + "." + pubname; + + f_types_ << indent() << "case " << field << "!= nil:" << endl; + indent_up(); + + if (!(*f_iter)->get_returntype()->is_void()) { + f_types_ << indent() << "return r, " << field << endl; + } else { + f_types_ << indent() << "return "<< field << endl; + } + + indent_down(); + } + + f_types_ << indent() << "}" << endl << endl; + } + + if (!(*f_iter)->get_returntype()->is_void()) { + f_types_ << indent() << "return " << resultName << ".GetSuccess(), nil" << endl; + } else { + f_types_ << indent() << "return nil" << endl; + } + } else { + // TODO: would be nice to not to duplicate the call generation + f_types_ << indent() << "if err := p.c.Call(ctx, \"" + << method << "\", &"<< argsName << ", nil); err != nil {" << endl; + + indent_up(); + f_types_ << indent() << "return err" << endl; + indent_down(); + f_types_ << indent() << "}" << endl; + f_types_ << indent() << "return nil" << endl; + } + + indent_down(); + f_types_ << "}" << endl << endl; + } +} + +/** + * Generates a command line tool for making remote requests + * + * @param tservice The service to generate a remote for. + */ +void t_go_generator::generate_service_remote(t_service* tservice) { + vector functions = tservice->get_functions(); + t_service* parent = tservice->get_extends(); + + // collect inherited functions + while (parent != NULL) { + vector p_functions = parent->get_functions(); + functions.insert(functions.end(), p_functions.begin(), p_functions.end()); + parent = parent->get_extends(); + } + + vector::iterator f_iter; + string f_remote_name = package_dir_ + "/" + underscore(service_name_) + "-remote/" + + underscore(service_name_) + "-remote.go"; + ofstream f_remote; + f_remote.open(f_remote_name.c_str()); + string service_module = get_real_go_module(program_); + string::size_type loc; + + while ((loc = service_module.find(".")) != string::npos) { + service_module.replace(loc, 1, 1, '/'); + } + if (!gen_package_prefix_.empty()) { + service_module = gen_package_prefix_ + service_module; + } + + string unused_protection; + + string ctxPackage = "context"; + if (legacy_context_) { + ctxPackage = "golang.org/x/net/context"; + } + + f_remote << go_autogen_comment(); + f_remote << indent() << "package main" << endl << endl; + f_remote << indent() << "import (" << endl; + f_remote << indent() << " \"" << ctxPackage << "\"" << endl; + f_remote << indent() << " \"flag\"" << endl; + f_remote << indent() << " \"fmt\"" << endl; + f_remote << indent() << " \"math\"" << endl; + f_remote << indent() << " \"net\"" << endl; + f_remote << indent() << " \"net/url\"" << endl; + f_remote << indent() << " \"os\"" << endl; + f_remote << indent() << " \"strconv\"" << endl; + f_remote << indent() << " \"strings\"" << endl; + f_remote << indent() << " \"" + gen_thrift_import_ + "\"" << endl; + f_remote << indent() << render_included_programs(unused_protection); + f_remote << indent() << " \"" << service_module << "\"" << endl; + f_remote << indent() << ")" << endl; + f_remote << indent() << endl; + f_remote << indent() << unused_protection; // filled in render_included_programs() + f_remote << indent() << endl; + f_remote << indent() << "func Usage() {" << endl; + f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Usage of \", os.Args[0], \" " + "[-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:\")" + << endl; + f_remote << indent() << " flag.PrintDefaults()" << endl; + f_remote << indent() << " fmt.Fprintln(os.Stderr, \"\\nFunctions:\")" << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_remote << " fmt.Fprintln(os.Stderr, \" " << (*f_iter)->get_returntype()->get_name() << " " + << (*f_iter)->get_name() << "("; + t_struct* arg_struct = (*f_iter)->get_arglist(); + const std::vector& args = arg_struct->get_members(); + vector::const_iterator a_iter; + std::vector::size_type num_args = args.size(); + bool first = true; + + for (std::vector::size_type i = 0; i < num_args; ++i) { + if (first) { + first = false; + } else { + f_remote << ", "; + } + + f_remote << args[i]->get_type()->get_name() << " " << args[i]->get_name(); + } + + f_remote << ")\")" << endl; + } + + f_remote << indent() << " fmt.Fprintln(os.Stderr)" << endl; + f_remote << indent() << " os.Exit(0)" << endl; + f_remote << indent() << "}" << endl; + f_remote << indent() << endl; + f_remote << indent() << "func main() {" << endl; + indent_up(); + f_remote << indent() << "flag.Usage = Usage" << endl; + f_remote << indent() << "var host string" << endl; + f_remote << indent() << "var port int" << endl; + f_remote << indent() << "var protocol string" << endl; + f_remote << indent() << "var urlString string" << endl; + f_remote << indent() << "var framed bool" << endl; + f_remote << indent() << "var useHttp bool" << endl; + f_remote << indent() << "var parsedUrl *url.URL" << endl; + f_remote << indent() << "var trans thrift.TTransport" << endl; + f_remote << indent() << "_ = strconv.Atoi" << endl; + f_remote << indent() << "_ = math.Abs" << endl; + f_remote << indent() << "flag.Usage = Usage" << endl; + f_remote << indent() << "flag.StringVar(&host, \"h\", \"localhost\", \"Specify host and port\")" + << endl; + f_remote << indent() << "flag.IntVar(&port, \"p\", 9090, \"Specify port\")" << endl; + f_remote << indent() << "flag.StringVar(&protocol, \"P\", \"binary\", \"" + "Specify the protocol (binary, compact, simplejson, json)\")" << endl; + f_remote << indent() << "flag.StringVar(&urlString, \"u\", \"\", \"Specify the url\")" << endl; + f_remote << indent() << "flag.BoolVar(&framed, \"framed\", false, \"Use framed transport\")" + << endl; + f_remote << indent() << "flag.BoolVar(&useHttp, \"http\", false, \"Use http\")" << endl; + f_remote << indent() << "flag.Parse()" << endl; + f_remote << indent() << endl; + f_remote << indent() << "if len(urlString) > 0 {" << endl; + f_remote << indent() << " var err error" << endl; + f_remote << indent() << " parsedUrl, err = url.Parse(urlString)" << endl; + f_remote << indent() << " if err != nil {" << endl; + f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << endl; + f_remote << indent() << " flag.Usage()" << endl; + f_remote << indent() << " }" << endl; + f_remote << indent() << " host = parsedUrl.Host" << endl; + f_remote << indent() << " useHttp = len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == \"http\"" + << endl; + f_remote << indent() << "} else if useHttp {" << endl; + f_remote << indent() << " _, err := url.Parse(fmt.Sprint(\"http://\", host, \":\", port))" + << endl; + f_remote << indent() << " if err != nil {" << endl; + f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << endl; + f_remote << indent() << " flag.Usage()" << endl; + f_remote << indent() << " }" << endl; + f_remote << indent() << "}" << endl; + f_remote << indent() << endl; + f_remote << indent() << "cmd := flag.Arg(0)" << endl; + f_remote << indent() << "var err error" << endl; + f_remote << indent() << "if useHttp {" << endl; + f_remote << indent() << " trans, err = thrift.NewTHttpClient(parsedUrl.String())" << endl; + f_remote << indent() << "} else {" << endl; + f_remote << indent() << " portStr := fmt.Sprint(port)" << endl; + f_remote << indent() << " if strings.Contains(host, \":\") {" << endl; + f_remote << indent() << " host, portStr, err = net.SplitHostPort(host)" << endl; + f_remote << indent() << " if err != nil {" << endl; + f_remote << indent() << " fmt.Fprintln(os.Stderr, \"error with host:\", err)" + << endl; + f_remote << indent() << " os.Exit(1)" << endl; + f_remote << indent() << " }" << endl; + f_remote << indent() << " }" << endl; + f_remote << indent() << " trans, err = thrift.NewTSocket(net.JoinHostPort(host, portStr))" + << endl; + f_remote << indent() << " if err != nil {" << endl; + f_remote << indent() << " fmt.Fprintln(os.Stderr, \"error resolving address:\", err)" << endl; + f_remote << indent() << " os.Exit(1)" << endl; + f_remote << indent() << " }" << endl; + f_remote << indent() << " if framed {" << endl; + f_remote << indent() << " trans = thrift.NewTFramedTransport(trans)" << endl; + f_remote << indent() << " }" << endl; + f_remote << indent() << "}" << endl; + f_remote << indent() << "if err != nil {" << endl; + f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Error creating transport\", err)" << endl; + f_remote << indent() << " os.Exit(1)" << endl; + f_remote << indent() << "}" << endl; + f_remote << indent() << "defer trans.Close()" << endl; + f_remote << indent() << "var protocolFactory thrift.TProtocolFactory" << endl; + f_remote << indent() << "switch protocol {" << endl; + f_remote << indent() << "case \"compact\":" << endl; + f_remote << indent() << " protocolFactory = thrift.NewTCompactProtocolFactory()" << endl; + f_remote << indent() << " break" << endl; + f_remote << indent() << "case \"simplejson\":" << endl; + f_remote << indent() << " protocolFactory = thrift.NewTSimpleJSONProtocolFactory()" << endl; + f_remote << indent() << " break" << endl; + f_remote << indent() << "case \"json\":" << endl; + f_remote << indent() << " protocolFactory = thrift.NewTJSONProtocolFactory()" << endl; + f_remote << indent() << " break" << endl; + f_remote << indent() << "case \"binary\", \"\":" << endl; + f_remote << indent() << " protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()" << endl; + f_remote << indent() << " break" << endl; + f_remote << indent() << "default:" << endl; + f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Invalid protocol specified: \", protocol)" + << endl; + f_remote << indent() << " Usage()" << endl; + f_remote << indent() << " os.Exit(1)" << endl; + f_remote << indent() << "}" << endl; + f_remote << indent() << "iprot := protocolFactory.GetProtocol(trans)" << endl; + f_remote << indent() << "oprot := protocolFactory.GetProtocol(trans)" << endl; + f_remote << indent() << "client := " << package_name_ << ".New" << publicize(service_name_) + << "Client(thrift.NewTStandardClient(iprot, oprot))" << endl; + f_remote << indent() << "if err := trans.Open(); err != nil {" << endl; + f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Error opening socket to \", " + "host, \":\", port, \" \", err)" << endl; + f_remote << indent() << " os.Exit(1)" << endl; + f_remote << indent() << "}" << endl; + f_remote << indent() << endl; + f_remote << indent() << "switch cmd {" << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* arg_struct = (*f_iter)->get_arglist(); + const std::vector& args = arg_struct->get_members(); + vector::const_iterator a_iter; + std::vector::size_type num_args = args.size(); + string funcName((*f_iter)->get_name()); + string pubName(publicize(funcName)); + string argumentsName(publicize(funcName + "_args", true)); + f_remote << indent() << "case \"" << escape_string(funcName) << "\":" << endl; + indent_up(); + f_remote << indent() << "if flag.NArg() - 1 != " << num_args << " {" << endl; + f_remote << indent() << " fmt.Fprintln(os.Stderr, \"" << escape_string(pubName) << " requires " + << num_args << " args\")" << endl; + f_remote << indent() << " flag.Usage()" << endl; + f_remote << indent() << "}" << endl; + + for (std::vector::size_type i = 0; i < num_args; ++i) { + std::vector::size_type flagArg = i + 1; + t_type* the_type(args[i]->get_type()); + t_type* the_type2(get_true_type(the_type)); + + if (the_type2->is_enum()) { + f_remote << indent() << "tmp" << i << ", err := (strconv.Atoi(flag.Arg(" << flagArg << ")))" + << endl; + f_remote << indent() << "if err != nil {" << endl; + f_remote << indent() << " Usage()" << endl; + f_remote << indent() << " return" << endl; + f_remote << indent() << "}" << endl; + f_remote << indent() << "argvalue" << i << " := " << package_name_ << "." + << publicize(the_type->get_name()) << "(tmp" << i << ")" << endl; + } else if (the_type2->is_base_type()) { + t_base_type::t_base e = ((t_base_type*)the_type2)->get_base(); + string err(tmp("err")); + + switch (e) { + case t_base_type::TYPE_VOID: + break; + + case t_base_type::TYPE_STRING: + if (the_type2->is_binary()) { + f_remote << indent() << "argvalue" << i << " := []byte(flag.Arg(" << flagArg << "))" + << endl; + } else { + f_remote << indent() << "argvalue" << i << " := flag.Arg(" << flagArg << ")" << endl; + } + break; + + case t_base_type::TYPE_BOOL: + f_remote << indent() << "argvalue" << i << " := flag.Arg(" << flagArg << ") == \"true\"" + << endl; + break; + + case t_base_type::TYPE_I8: + f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg(" + << flagArg << ")))" << endl; + f_remote << indent() << "if " << err << " != nil {" << endl; + f_remote << indent() << " Usage()" << endl; + f_remote << indent() << " return" << endl; + f_remote << indent() << "}" << endl; + f_remote << indent() << "argvalue" << i << " := int8(tmp" << i << ")" << endl; + break; + + case t_base_type::TYPE_I16: + f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg(" + << flagArg << ")))" << endl; + f_remote << indent() << "if " << err << " != nil {" << endl; + f_remote << indent() << " Usage()" << endl; + f_remote << indent() << " return" << endl; + f_remote << indent() << "}" << endl; + f_remote << indent() << "argvalue" << i << " := int16(tmp" << i << ")" << endl; + break; + + case t_base_type::TYPE_I32: + f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg(" + << flagArg << ")))" << endl; + f_remote << indent() << "if " << err << " != nil {" << endl; + f_remote << indent() << " Usage()" << endl; + f_remote << indent() << " return" << endl; + f_remote << indent() << "}" << endl; + f_remote << indent() << "argvalue" << i << " := int32(tmp" << i << ")" << endl; + break; + + case t_base_type::TYPE_I64: + f_remote << indent() << "argvalue" << i << ", " << err + << " := (strconv.ParseInt(flag.Arg(" << flagArg << "), 10, 64))" << endl; + f_remote << indent() << "if " << err << " != nil {" << endl; + f_remote << indent() << " Usage()" << endl; + f_remote << indent() << " return" << endl; + f_remote << indent() << "}" << endl; + break; + + case t_base_type::TYPE_DOUBLE: + f_remote << indent() << "argvalue" << i << ", " << err + << " := (strconv.ParseFloat(flag.Arg(" << flagArg << "), 64))" << endl; + f_remote << indent() << "if " << err << " != nil {" << endl; + f_remote << indent() << " Usage()" << endl; + f_remote << indent() << " return" << endl; + f_remote << indent() << "}" << endl; + break; + + default: + throw("Invalid base type in generate_service_remote"); + } + + // f_remote << publicize(args[i]->get_name()) << "(strconv.Atoi(flag.Arg(" << flagArg << + // ")))"; + } else if (the_type2->is_struct()) { + string arg(tmp("arg")); + string mbTrans(tmp("mbTrans")); + string err1(tmp("err")); + string factory(tmp("factory")); + string jsProt(tmp("jsProt")); + string err2(tmp("err")); + std::string tstruct_name(publicize(the_type->get_name())); + std::string tstruct_module( module_name(the_type)); + if(tstruct_module.empty()) { + tstruct_module = package_name_; + } + + f_remote << indent() << arg << " := flag.Arg(" << flagArg << ")" << endl; + f_remote << indent() << mbTrans << " := thrift.NewTMemoryBufferLen(len(" << arg << "))" + << endl; + f_remote << indent() << "defer " << mbTrans << ".Close()" << endl; + f_remote << indent() << "_, " << err1 << " := " << mbTrans << ".WriteString(" << arg << ")" + << endl; + f_remote << indent() << "if " << err1 << " != nil {" << endl; + f_remote << indent() << " Usage()" << endl; + f_remote << indent() << " return" << endl; + f_remote << indent() << "}" << endl; + f_remote << indent() << factory << " := thrift.NewTSimpleJSONProtocolFactory()" << endl; + f_remote << indent() << jsProt << " := " << factory << ".GetProtocol(" << mbTrans << ")" + << endl; + f_remote << indent() << "argvalue" << i << " := " << tstruct_module << ".New" << tstruct_name + << "()" << endl; + f_remote << indent() << err2 << " := argvalue" << i << "." << read_method_name_ << "(" << jsProt << ")" << endl; + f_remote << indent() << "if " << err2 << " != nil {" << endl; + f_remote << indent() << " Usage()" << endl; + f_remote << indent() << " return" << endl; + f_remote << indent() << "}" << endl; + } else if (the_type2->is_container() || the_type2->is_xception()) { + string arg(tmp("arg")); + string mbTrans(tmp("mbTrans")); + string err1(tmp("err")); + string factory(tmp("factory")); + string jsProt(tmp("jsProt")); + string err2(tmp("err")); + std::string argName(publicize(args[i]->get_name())); + f_remote << indent() << arg << " := flag.Arg(" << flagArg << ")" << endl; + f_remote << indent() << mbTrans << " := thrift.NewTMemoryBufferLen(len(" << arg << "))" + << endl; + f_remote << indent() << "defer " << mbTrans << ".Close()" << endl; + f_remote << indent() << "_, " << err1 << " := " << mbTrans << ".WriteString(" << arg << ")" + << endl; + f_remote << indent() << "if " << err1 << " != nil { " << endl; + f_remote << indent() << " Usage()" << endl; + f_remote << indent() << " return" << endl; + f_remote << indent() << "}" << endl; + f_remote << indent() << factory << " := thrift.NewTSimpleJSONProtocolFactory()" << endl; + f_remote << indent() << jsProt << " := " << factory << ".GetProtocol(" << mbTrans << ")" + << endl; + f_remote << indent() << "containerStruct" << i << " := " << package_name_ << ".New" + << argumentsName << "()" << endl; + f_remote << indent() << err2 << " := containerStruct" << i << ".ReadField" << (i + 1) << "(" + << jsProt << ")" << endl; + f_remote << indent() << "if " << err2 << " != nil {" << endl; + f_remote << indent() << " Usage()" << endl; + f_remote << indent() << " return" << endl; + f_remote << indent() << "}" << endl; + f_remote << indent() << "argvalue" << i << " := containerStruct" << i << "." << argName + << endl; + } else { + throw("Invalid argument type in generate_service_remote"); + } + + if (the_type->is_typedef()) { + std::string typedef_module( module_name(the_type)); + if(typedef_module.empty()) { + typedef_module = package_name_; + } + f_remote << indent() << "value" << i << " := " << typedef_module << "." + << publicize(the_type->get_name()) << "(argvalue" << i << ")" << endl; + } else { + f_remote << indent() << "value" << i << " := argvalue" << i << endl; + } + } + + f_remote << indent() << "fmt.Print(client." << pubName << "("; + bool argFirst = true; + + f_remote << "context.Background()"; + for (std::vector::size_type i = 0; i < num_args; ++i) { + if (argFirst) { + argFirst = false; + f_remote << ", "; + } else { + f_remote << ", "; + } + + if (args[i]->get_type()->is_enum()) { + f_remote << "value" << i; + } else if (args[i]->get_type()->is_base_type()) { + t_base_type::t_base e = ((t_base_type*)(args[i]->get_type()))->get_base(); + + switch (e) { + case t_base_type::TYPE_VOID: + break; + + case t_base_type::TYPE_STRING: + case t_base_type::TYPE_BOOL: + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + case t_base_type::TYPE_DOUBLE: + f_remote << "value" << i; + break; + + default: + throw("Invalid base type in generate_service_remote"); + } + + // f_remote << publicize(args[i]->get_name()) << "(strconv.Atoi(flag.Arg(" << flagArg << + // ")))"; + } else { + f_remote << "value" << i; + } + } + + f_remote << "))" << endl; + f_remote << indent() << "fmt.Print(\"\\n\")" << endl; + f_remote << indent() << "break" << endl; + indent_down(); + } + + f_remote << indent() << "case \"\":" << endl; + f_remote << indent() << " Usage()" << endl; + f_remote << indent() << " break" << endl; + f_remote << indent() << "default:" << endl; + f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Invalid function \", cmd)" << endl; + f_remote << indent() << "}" << endl; + indent_down(); + f_remote << indent() << "}" << endl; + // Close service file + f_remote.close(); + format_go_output(f_remote_name); +#ifndef _MSC_VER + // Make file executable, love that bitwise OR action + chmod(f_remote_name.c_str(), + S_IRUSR | S_IWUSR | S_IXUSR +#ifndef _WIN32 + | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH +#endif + ); +#endif +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_go_generator::generate_service_server(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + string extends = ""; + string extends_processor = ""; + string extends_processor_new = ""; + string serviceName(publicize(tservice->get_name())); + + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + size_t index = extends.rfind("."); + + if (index != string::npos) { + extends_processor = extends.substr(0, index + 1) + publicize(extends.substr(index + 1)) + + "Processor"; + extends_processor_new = extends.substr(0, index + 1) + "New" + + publicize(extends.substr(index + 1)) + "Processor"; + } else { + extends_processor = publicize(extends) + "Processor"; + extends_processor_new = "New" + extends_processor; + } + } + + string pServiceName(privatize(tservice->get_name())); + // Generate the header portion + string self(tmp("self")); + + if (extends_processor.empty()) { + f_types_ << indent() << "type " << serviceName << "Processor struct {" << endl; + f_types_ << indent() << " processorMap map[string]thrift.TProcessorFunction" << endl; + f_types_ << indent() << " handler " << serviceName << endl; + f_types_ << indent() << "}" << endl << endl; + f_types_ << indent() << "func (p *" << serviceName + << "Processor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {" + << endl; + f_types_ << indent() << " p.processorMap[key] = processor" << endl; + f_types_ << indent() << "}" << endl << endl; + f_types_ << indent() << "func (p *" << serviceName + << "Processor) GetProcessorFunction(key string) " + "(processor thrift.TProcessorFunction, ok bool) {" << endl; + f_types_ << indent() << " processor, ok = p.processorMap[key]" << endl; + f_types_ << indent() << " return processor, ok" << endl; + f_types_ << indent() << "}" << endl << endl; + f_types_ << indent() << "func (p *" << serviceName + << "Processor) ProcessorMap() map[string]thrift.TProcessorFunction {" << endl; + f_types_ << indent() << " return p.processorMap" << endl; + f_types_ << indent() << "}" << endl << endl; + f_types_ << indent() << "func New" << serviceName << "Processor(handler " << serviceName + << ") *" << serviceName << "Processor {" << endl << endl; + f_types_ + << indent() << " " << self << " := &" << serviceName + << "Processor{handler:handler, processorMap:make(map[string]thrift.TProcessorFunction)}" + << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string escapedFuncName(escape_string((*f_iter)->get_name())); + f_types_ << indent() << " " << self << ".processorMap[\"" << escapedFuncName << "\"] = &" + << pServiceName << "Processor" << publicize((*f_iter)->get_name()) + << "{handler:handler}" << endl; + } + + string x(tmp("x")); + f_types_ << indent() << "return " << self << endl; + f_types_ << indent() << "}" << endl << endl; + f_types_ << indent() << "func (p *" << serviceName + << "Processor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err " + "thrift.TException) {" << endl; + f_types_ << indent() << " name, _, seqId, err := iprot.ReadMessageBegin()" << endl; + f_types_ << indent() << " if err != nil { return false, err }" << endl; + f_types_ << indent() << " if processor, ok := p.GetProcessorFunction(name); ok {" << endl; + f_types_ << indent() << " return processor.Process(ctx, seqId, iprot, oprot)" << endl; + f_types_ << indent() << " }" << endl; + f_types_ << indent() << " iprot.Skip(thrift.STRUCT)" << endl; + f_types_ << indent() << " iprot.ReadMessageEnd()" << endl; + f_types_ << indent() << " " << x + << " := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, \"Unknown function " + "\" + name)" << endl; + f_types_ << indent() << " oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId)" << endl; + f_types_ << indent() << " " << x << ".Write(oprot)" << endl; + f_types_ << indent() << " oprot.WriteMessageEnd()" << endl; + f_types_ << indent() << " oprot.Flush()" << endl; + f_types_ << indent() << " return false, " << x << endl; + f_types_ << indent() << "" << endl; + f_types_ << indent() << "}" << endl << endl; + } else { + f_types_ << indent() << "type " << serviceName << "Processor struct {" << endl; + f_types_ << indent() << " *" << extends_processor << endl; + f_types_ << indent() << "}" << endl << endl; + f_types_ << indent() << "func New" << serviceName << "Processor(handler " << serviceName + << ") *" << serviceName << "Processor {" << endl; + f_types_ << indent() << " " << self << " := &" << serviceName << "Processor{" + << extends_processor_new << "(handler)}" << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string escapedFuncName(escape_string((*f_iter)->get_name())); + f_types_ << indent() << " " << self << ".AddToProcessorMap(\"" << escapedFuncName + << "\", &" << pServiceName << "Processor" << publicize((*f_iter)->get_name()) + << "{handler:handler})" << endl; + } + + f_types_ << indent() << " return " << self << endl; + f_types_ << indent() << "}" << endl << endl; + } + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(tservice, *f_iter); + } + + f_types_ << endl; +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_go_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + // Open function + string processorName = privatize(tservice->get_name()) + "Processor" + + publicize(tfunction->get_name()); + string argsname = publicize(tfunction->get_name() + "_args", true); + string resultname = publicize(tfunction->get_name() + "_result", true); + + // t_struct* xs = tfunction->get_xceptions(); + // const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + f_types_ << indent() << "type " << processorName << " struct {" << endl; + f_types_ << indent() << " handler " << publicize(tservice->get_name()) << endl; + f_types_ << indent() << "}" << endl << endl; + f_types_ << indent() << "func (p *" << processorName + << ") Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err " + "thrift.TException) {" << endl; + indent_up(); + f_types_ << indent() << "args := " << argsname << "{}" << endl; + f_types_ << indent() << "if err = args." << read_method_name_ << "(iprot); err != nil {" << endl; + f_types_ << indent() << " iprot.ReadMessageEnd()" << endl; + if (!tfunction->is_oneway()) { + f_types_ << indent() + << " x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error())" + << endl; + f_types_ << indent() << " oprot.WriteMessageBegin(\"" << escape_string(tfunction->get_name()) + << "\", thrift.EXCEPTION, seqId)" << endl; + f_types_ << indent() << " x.Write(oprot)" << endl; + f_types_ << indent() << " oprot.WriteMessageEnd()" << endl; + f_types_ << indent() << " oprot.Flush()" << endl; + } + f_types_ << indent() << " return false, err" << endl; + f_types_ << indent() << "}" << endl << endl; + f_types_ << indent() << "iprot.ReadMessageEnd()" << endl; + + if (!tfunction->is_oneway()) { + f_types_ << indent() << "result := " << resultname << "{}" << endl; + } + bool need_reference = type_need_reference(tfunction->get_returntype()); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + f_types_ << "var retval " << type_to_go_type(tfunction->get_returntype()) << endl; + } + + f_types_ << indent() << "var err2 error" << endl; + f_types_ << indent() << "if "; + + if (!tfunction->is_oneway()) { + if (!tfunction->get_returntype()->is_void()) { + f_types_ << "retval, "; + } + } + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + f_types_ << "err2 = p.handler." << publicize(tfunction->get_name()) << "("; + bool first = true; + + f_types_ << "ctx"; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + f_types_ << ", "; + } else { + f_types_ << ", "; + } + + f_types_ << "args." << publicize((*f_iter)->get_name()); + } + + f_types_ << "); err2 != nil {" << endl; + + t_struct* exceptions = tfunction->get_xceptions(); + const vector& x_fields = exceptions->get_members(); + if (!x_fields.empty()) { + f_types_ << indent() << "switch v := err2.(type) {" << endl; + + vector::const_iterator xf_iter; + + for (xf_iter = x_fields.begin(); xf_iter != x_fields.end(); ++xf_iter) { + f_types_ << indent() << " case " << type_to_go_type(((*xf_iter)->get_type())) << ":" + << endl; + f_types_ << indent() << "result." << publicize((*xf_iter)->get_name()) << " = v" << endl; + } + + f_types_ << indent() << " default:" << endl; + } + + if (!tfunction->is_oneway()) { + f_types_ << indent() << " x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, " + "\"Internal error processing " << escape_string(tfunction->get_name()) + << ": \" + err2.Error())" << endl; + f_types_ << indent() << " oprot.WriteMessageBegin(\"" << escape_string(tfunction->get_name()) + << "\", thrift.EXCEPTION, seqId)" << endl; + f_types_ << indent() << " x.Write(oprot)" << endl; + f_types_ << indent() << " oprot.WriteMessageEnd()" << endl; + f_types_ << indent() << " oprot.Flush()" << endl; + } + + f_types_ << indent() << " return true, err2" << endl; + + if (!x_fields.empty()) { + f_types_ << indent() << "}" << endl; + } + + f_types_ << indent() << "}"; // closes err2 != nil + + if (!tfunction->is_oneway()) { + if (!tfunction->get_returntype()->is_void()) { + f_types_ << " else {" << endl; // make sure we set Success retval only on success + indent_up(); + f_types_ << indent() << "result.Success = "; + if (need_reference) { + f_types_ << "&"; + } + f_types_ << "retval" << endl; + indent_down(); + f_types_ << "}" << endl; + } else { + f_types_ << endl; + } + f_types_ << indent() << "if err2 = oprot.WriteMessageBegin(\"" + << escape_string(tfunction->get_name()) << "\", thrift.REPLY, seqId); err2 != nil {" + << endl; + f_types_ << indent() << " err = err2" << endl; + f_types_ << indent() << "}" << endl; + f_types_ << indent() << "if err2 = result." << write_method_name_ << "(oprot); err == nil && err2 != nil {" << endl; + f_types_ << indent() << " err = err2" << endl; + f_types_ << indent() << "}" << endl; + f_types_ << indent() << "if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil {" + << endl; + f_types_ << indent() << " err = err2" << endl; + f_types_ << indent() << "}" << endl; + f_types_ << indent() << "if err2 = oprot.Flush(); err == nil && err2 != nil {" << endl; + f_types_ << indent() << " err = err2" << endl; + f_types_ << indent() << "}" << endl; + f_types_ << indent() << "if err != nil {" << endl; + f_types_ << indent() << " return" << endl; + f_types_ << indent() << "}" << endl; + f_types_ << indent() << "return true, err" << endl; + } else { + f_types_ << endl; + f_types_ << indent() << "return true, nil" << endl; + } + indent_down(); + f_types_ << indent() << "}" << endl << endl; +} + +/** + * Deserializes a field of any type. + */ +void t_go_generator::generate_deserialize_field(ofstream& out, + t_field* tfield, + bool declare, + string prefix, + bool inclass, + bool coerceData, + bool inkey, + bool in_container_value) { + (void)inclass; + (void)coerceData; + t_type* orig_type = tfield->get_type(); + t_type* type = get_true_type(orig_type); + string name(prefix + publicize(tfield->get_name())); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + name; + } + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, + (t_struct*)type, + is_pointer_field(tfield, in_container_value), + declare, + name); + } else if (type->is_container()) { + generate_deserialize_container(out, orig_type, is_pointer_field(tfield), declare, name); + } else if (type->is_base_type() || type->is_enum()) { + + if (declare) { + string type_name = inkey ? type_to_go_key_type(tfield->get_type()) + : type_to_go_type(tfield->get_type()); + + out << "var " << tfield->get_name() << " " << type_name << endl; + } + + indent(out) << "if v, err := iprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + + case t_base_type::TYPE_STRING: + if (type->is_binary() && !inkey) { + out << "ReadBinary()"; + } else { + out << "ReadString()"; + } + + break; + + case t_base_type::TYPE_BOOL: + out << "ReadBool()"; + break; + + case t_base_type::TYPE_I8: + out << "ReadByte()"; + break; + + case t_base_type::TYPE_I16: + out << "ReadI16()"; + break; + + case t_base_type::TYPE_I32: + out << "ReadI32()"; + break; + + case t_base_type::TYPE_I64: + out << "ReadI64()"; + break; + + case t_base_type::TYPE_DOUBLE: + out << "ReadDouble()"; + break; + + default: + throw "compiler error: no Go name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "ReadI32()"; + } + + out << "; err != nil {" << endl; + out << indent() << "return thrift.PrependError(\"error reading field " << tfield->get_key() + << ": \", err)" << endl; + + out << "} else {" << endl; + string wrap; + + if (type->is_enum() || orig_type->is_typedef()) { + wrap = publicize(type_name(orig_type)); + } else if (((t_base_type*)type)->get_base() == t_base_type::TYPE_I8) { + wrap = "int8"; + } + + string maybe_address = (is_pointer_field(tfield) ? "&" : ""); + if (wrap == "") { + indent(out) << name << " = " << maybe_address << "v" << endl; + } else { + indent(out) << "temp := " << wrap << "(v)" << endl; + indent(out) << name << " = " << maybe_address << "temp" << endl; + } + + out << "}" << endl; + } else { + throw "INVALID TYPE IN generate_deserialize_field '" + type->get_name() + "' for field '" + + tfield->get_name() + "'"; + } +} + +/** + * Generates an unserializer for a struct, calling read() + */ +void t_go_generator::generate_deserialize_struct(ofstream& out, + t_struct* tstruct, + bool pointer_field, + bool declare, + string prefix) { + string eq(declare ? " := " : " = "); + + out << indent() << prefix << eq << (pointer_field ? "&" : ""); + generate_go_struct_initializer(out, tstruct); + out << indent() << "if err := " << prefix << "." << read_method_name_ << "(iprot); err != nil {" << endl; + out << indent() << " return thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", " + << prefix << "), err)" << endl; + out << indent() << "}" << endl; +} + +/** + * Serialize a container by writing out the header followed by + * data and then a footer. + */ +void t_go_generator::generate_deserialize_container(ofstream& out, + t_type* orig_type, + bool pointer_field, + bool declare, + string prefix) { + t_type* ttype = get_true_type(orig_type); + string eq(" = "); + + if (declare) { + eq = " := "; + } + + // Declare variables, read header + if (ttype->is_map()) { + out << indent() << "_, _, size, err := iprot.ReadMapBegin()" << endl; + out << indent() << "if err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"error reading map begin: \", err)" << endl; + out << indent() << "}" << endl; + out << indent() << "tMap := make(" << type_to_go_type(orig_type) << ", size)" << endl; + out << indent() << prefix << eq << " " << (pointer_field ? "&" : "") << "tMap" << endl; + } else if (ttype->is_set()) { + out << indent() << "_, size, err := iprot.ReadSetBegin()" << endl; + out << indent() << "if err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"error reading set begin: \", err)" << endl; + out << indent() << "}" << endl; + out << indent() << "tSet := make(" << type_to_go_type(orig_type) << ", 0, size)" << endl; + out << indent() << prefix << eq << " " << (pointer_field ? "&" : "") << "tSet" << endl; + } else if (ttype->is_list()) { + out << indent() << "_, size, err := iprot.ReadListBegin()" << endl; + out << indent() << "if err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"error reading list begin: \", err)" << endl; + out << indent() << "}" << endl; + out << indent() << "tSlice := make(" << type_to_go_type(orig_type) << ", 0, size)" << endl; + out << indent() << prefix << eq << " " << (pointer_field ? "&" : "") << "tSlice" << endl; + } else { + throw "INVALID TYPE IN generate_deserialize_container '" + ttype->get_name() + "' for prefix '" + + prefix + "'"; + } + + // For loop iterates over elements + out << indent() << "for i := 0; i < size; i ++ {" << endl; + indent_up(); + + if (pointer_field) { + prefix = "(*" + prefix + ")"; + } + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, declare, prefix); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, declare, prefix); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, declare, prefix); + } + + indent_down(); + out << indent() << "}" << endl; + + // Read container end + if (ttype->is_map()) { + out << indent() << "if err := iprot.ReadMapEnd(); err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"error reading map end: \", err)" << endl; + out << indent() << "}" << endl; + } else if (ttype->is_set()) { + out << indent() << "if err := iprot.ReadSetEnd(); err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"error reading set end: \", err)" << endl; + out << indent() << "}" << endl; + } else if (ttype->is_list()) { + out << indent() << "if err := iprot.ReadListEnd(); err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"error reading list end: \", err)" << endl; + out << indent() << "}" << endl; + } +} + +/** + * Generates code to deserialize a map + */ +void t_go_generator::generate_deserialize_map_element(ofstream& out, + t_map* tmap, + bool declare, + string prefix) { + (void)declare; + string key = tmp("_key"); + string val = tmp("_val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + fkey.set_req(t_field::T_OPT_IN_REQ_OUT); + fval.set_req(t_field::T_OPT_IN_REQ_OUT); + generate_deserialize_field(out, &fkey, true, "", false, false, true); + generate_deserialize_field(out, &fval, true, "", false, false, false, true); + indent(out) << prefix << "[" << key << "] = " << val << endl; +} + +/** + * Write a set element + */ +void t_go_generator::generate_deserialize_set_element(ofstream& out, + t_set* tset, + bool declare, + string prefix) { + (void)declare; + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); + felem.set_req(t_field::T_OPT_IN_REQ_OUT); + generate_deserialize_field(out, &felem, true, "", false, false, false, true); + indent(out) << prefix << " = append(" << prefix << ", " << elem << ")" << endl; +} + +/** + * Write a list element + */ +void t_go_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + bool declare, + string prefix) { + (void)declare; + string elem = tmp("_elem"); + t_field felem(((t_list*)tlist)->get_elem_type(), elem); + felem.set_req(t_field::T_OPT_IN_REQ_OUT); + generate_deserialize_field(out, &felem, true, "", false, false, false, true); + indent(out) << prefix << " = append(" << prefix << ", " << elem << ")" << endl; +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_go_generator::generate_serialize_field(ofstream& out, + t_field* tfield, + string prefix, + bool inkey) { + t_type* type = get_true_type(tfield->get_type()); + string name(prefix + publicize(tfield->get_name())); + + // Do nothing for void types + if (type->is_void()) { + throw "compiler error: cannot generate serialize for void type: " + name; + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, name); + } else if (type->is_container()) { + generate_serialize_container(out, type, is_pointer_field(tfield), name); + } else if (type->is_base_type() || type->is_enum()) { + indent(out) << "if err := oprot."; + + if (is_pointer_field(tfield)) { + name = "*" + name; + } + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + + case t_base_type::TYPE_STRING: + if (type->is_binary() && !inkey) { + out << "WriteBinary(" << name << ")"; + } else { + out << "WriteString(string(" << name << "))"; + } + + break; + + case t_base_type::TYPE_BOOL: + out << "WriteBool(bool(" << name << "))"; + break; + + case t_base_type::TYPE_I8: + out << "WriteByte(int8(" << name << "))"; + break; + + case t_base_type::TYPE_I16: + out << "WriteI16(int16(" << name << "))"; + break; + + case t_base_type::TYPE_I32: + out << "WriteI32(int32(" << name << "))"; + break; + + case t_base_type::TYPE_I64: + out << "WriteI64(int64(" << name << "))"; + break; + + case t_base_type::TYPE_DOUBLE: + out << "WriteDouble(float64(" << name << "))"; + break; + + default: + throw "compiler error: no Go name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "WriteI32(int32(" << name << "))"; + } + + out << "; err != nil {" << endl; + out << indent() << "return thrift.PrependError(fmt.Sprintf(\"%T." + << escape_string(tfield->get_name()) << " (" << tfield->get_key() + << ") field write error: \", p), err) }" << endl; + } else { + throw "compiler error: Invalid type in generate_serialize_field '" + type->get_name() + + "' for field '" + name + "'"; + } +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_go_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + (void)tstruct; + out << indent() << "if err := " << prefix << "." << write_method_name_ << "(oprot); err != nil {" << endl; + out << indent() << " return thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", " + << prefix << "), err)" << endl; + out << indent() << "}" << endl; +} + +void t_go_generator::generate_serialize_container(ofstream& out, + t_type* ttype, + bool pointer_field, + string prefix) { + if (pointer_field) { + prefix = "*" + prefix; + } + if (ttype->is_map()) { + out << indent() << "if err := oprot.WriteMapBegin(" + << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " + << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " + << "len(" << prefix << ")); err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"error writing map begin: \", err)" << endl; + out << indent() << "}" << endl; + } else if (ttype->is_set()) { + out << indent() << "if err := oprot.WriteSetBegin(" + << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " + << "len(" << prefix << ")); err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"error writing set begin: \", err)" << endl; + out << indent() << "}" << endl; + } else if (ttype->is_list()) { + out << indent() << "if err := oprot.WriteListBegin(" + << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " + << "len(" << prefix << ")); err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"error writing list begin: \", err)" << endl; + out << indent() << "}" << endl; + } else { + throw "compiler error: Invalid type in generate_serialize_container '" + ttype->get_name() + + "' for prefix '" + prefix + "'"; + } + + if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + out << indent() << "for k, v := range " << prefix << " {" << endl; + indent_up(); + generate_serialize_map_element(out, tmap, "k", "v"); + indent_down(); + indent(out) << "}" << endl; + } else if (ttype->is_set()) { + t_set* tset = (t_set*)ttype; + out << indent() << "for i := 0; iis_list()) { + t_list* tlist = (t_list*)ttype; + out << indent() << "for _, v := range " << prefix << " {" << endl; + + indent_up(); + generate_serialize_list_element(out, tlist, "v"); + indent_down(); + indent(out) << "}" << endl; + } + + if (ttype->is_map()) { + out << indent() << "if err := oprot.WriteMapEnd(); err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"error writing map end: \", err)" << endl; + out << indent() << "}" << endl; + } else if (ttype->is_set()) { + out << indent() << "if err := oprot.WriteSetEnd(); err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"error writing set end: \", err)" << endl; + out << indent() << "}" << endl; + } else if (ttype->is_list()) { + out << indent() << "if err := oprot.WriteListEnd(); err != nil {" << endl; + out << indent() << " return thrift.PrependError(\"error writing list end: \", err)" << endl; + out << indent() << "}" << endl; + } +} + +/** + * Serializes the members of a map. + * + */ +void t_go_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string kiter, + string viter) { + t_field kfield(tmap->get_key_type(), ""); + t_field vfield(tmap->get_val_type(), ""); + kfield.set_req(t_field::T_OPT_IN_REQ_OUT); + vfield.set_req(t_field::T_OPT_IN_REQ_OUT); + generate_serialize_field(out, &kfield, kiter, true); + generate_serialize_field(out, &vfield, viter); +} + +/** + * Serializes the members of a set. + */ +void t_go_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string prefix) { + t_field efield(tset->get_elem_type(), ""); + efield.set_req(t_field::T_OPT_IN_REQ_OUT); + generate_serialize_field(out, &efield, prefix); +} + +/** + * Serializes the members of a list. + */ +void t_go_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string prefix) { + t_field efield(tlist->get_elem_type(), ""); + efield.set_req(t_field::T_OPT_IN_REQ_OUT); + generate_serialize_field(out, &efield, prefix); +} + +/** + * Generates the docstring for a given struct. + */ +void t_go_generator::generate_go_docstring(ofstream& out, t_struct* tstruct) { + generate_go_docstring(out, tstruct, tstruct, "Attributes"); +} + +/** + * Generates the docstring for a given function. + */ +void t_go_generator::generate_go_docstring(ofstream& out, t_function* tfunction) { + generate_go_docstring(out, tfunction, tfunction->get_arglist(), "Parameters"); +} + +/** + * Generates the docstring for a struct or function. + */ +void t_go_generator::generate_go_docstring(ofstream& out, + t_doc* tdoc, + t_struct* tstruct, + const char* subheader) { + bool has_doc = false; + stringstream ss; + + if (tdoc->has_doc()) { + has_doc = true; + ss << tdoc->get_doc(); + } + + const vector& fields = tstruct->get_members(); + + if (fields.size() > 0) { + if (has_doc) { + ss << endl; + } + + has_doc = true; + ss << subheader << ":\n"; + vector::const_iterator p_iter; + + for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { + t_field* p = *p_iter; + ss << " - " << publicize(p->get_name()); + + if (p->has_doc()) { + ss << ": " << p->get_doc(); + } else { + ss << endl; + } + } + } + + if (has_doc) { + generate_docstring_comment(out, "", "// ", ss.str(), ""); + } +} + +/** + * Generates the docstring for a generic object. + */ +void t_go_generator::generate_go_docstring(ofstream& out, t_doc* tdoc) { + if (tdoc->has_doc()) { + generate_docstring_comment(out, "", "//", tdoc->get_doc(), ""); + } +} + +/** + * Declares an argument, which may include initialization as necessary. + * + * @param tfield The field + */ +string t_go_generator::declare_argument(t_field* tfield) { + std::ostringstream result; + result << publicize(tfield->get_name()) << "="; + + if (tfield->get_value() != NULL) { + result << "thrift_spec[" << tfield->get_key() << "][4]"; + } else { + result << "nil"; + } + + return result.str(); +} + +/** + * Renders a struct field initial value. + * + * @param tfield The field, which must have `tfield->get_value() != NULL` + */ +string t_go_generator::render_field_initial_value(t_field* tfield, + const string& name, + bool optional_field) { + t_type* type = get_true_type(tfield->get_type()); + + if (optional_field) { + // The caller will make a second pass for optional fields, + // assigning the result of render_const_value to "*field_name". It + // is maddening that Go syntax does not allow for a type-agnostic + // way to initialize a pointer to a const value, but so it goes. + // The alternative would be to write type specific functions that + // convert from const values to pointer types, but given the lack + // of overloading it would be messy. + return "new(" + type_to_go_type(tfield->get_type()) + ")"; + } else { + return render_const_value(type, tfield->get_value(), name); + } +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_go_generator::function_signature(t_function* tfunction, string prefix) { + // TODO(mcslee): Nitpicky, no ',' if argument_list is empty + return publicize(prefix + tfunction->get_name()) + "(" + argument_list(tfunction->get_arglist()) + + ")"; +} + +/** + * Renders an interface function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_go_generator::function_signature_if(t_function* tfunction, string prefix, bool addError) { + string signature = publicize(prefix + tfunction->get_name()) + "("; + signature += "ctx context.Context"; + if (!tfunction->get_arglist()->get_members().empty()) { + signature += ", " + argument_list(tfunction->get_arglist()); + } + signature += ") ("; + + t_type* ret = tfunction->get_returntype(); + t_struct* exceptions = tfunction->get_xceptions(); + string errs = argument_list(exceptions); + + if (!ret->is_void()) { + signature += "r " + type_to_go_type(ret); + + if (addError || errs.size() == 0) { + signature += ", "; + } + } + + if (addError) { + signature += "err error"; + } + + signature += ")"; + return signature; +} + +/** + * Renders a field list + */ +string t_go_generator::argument_list(t_struct* tstruct) { + string result = ""; + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + + result += variable_name_to_go_name((*f_iter)->get_name()) + " " + + type_to_go_type((*f_iter)->get_type()); + } + + return result; +} + +string t_go_generator::type_name(t_type* ttype) { + string module( module_name(ttype)); + if( ! module.empty()) { + return module + "." + ttype->get_name(); + } + + return ttype->get_name(); +} + +string t_go_generator::module_name(t_type* ttype) { + t_program* program = ttype->get_program(); + + if (program != NULL && program != program_) { + if (program->get_namespace("go").empty() || + program_->get_namespace("go").empty() || + program->get_namespace("go") != program_->get_namespace("go")) { + string module(get_real_go_module(program)); + // for namespaced includes, only keep part after dot. + size_t dot = module.rfind('.'); + if (dot != string::npos) { + module = module.substr(dot + 1); + } + return module; + } + } + + return ""; +} + +/** + * Converts the parse type to a go tyoe + */ +string t_go_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + + case t_base_type::TYPE_STRING: + /* this is wrong, binary is still a string type internally + if (type->is_binary()) { + return "thrift.BINARY"; + } + */ + return "thrift.STRING"; + + case t_base_type::TYPE_BOOL: + return "thrift.BOOL"; + + case t_base_type::TYPE_I8: + return "thrift.BYTE"; + + case t_base_type::TYPE_I16: + return "thrift.I16"; + + case t_base_type::TYPE_I32: + return "thrift.I32"; + + case t_base_type::TYPE_I64: + return "thrift.I64"; + + case t_base_type::TYPE_DOUBLE: + return "thrift.DOUBLE"; + } + } else if (type->is_enum()) { + return "thrift.I32"; + } else if (type->is_struct() || type->is_xception()) { + return "thrift.STRUCT"; + } else if (type->is_map()) { + return "thrift.MAP"; + } else if (type->is_set()) { + return "thrift.SET"; + } else if (type->is_list()) { + return "thrift.LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** + * Converts the parse type to a go map type, will throw an exception if it will + * not produce a valid go map type. + */ +string t_go_generator::type_to_go_key_type(t_type* type) { + t_type* resolved_type = type; + + while (resolved_type->is_typedef()) { + resolved_type = ((t_typedef*)resolved_type)->get_type()->get_true_type(); + } + + if (resolved_type->is_map() || resolved_type->is_list() || resolved_type->is_set()) { + throw "Cannot produce a valid type for a Go map key: " + type_to_go_type(type) + " - aborting."; + } + + if (resolved_type->is_binary()) + return "string"; + + return type_to_go_type(type); +} + +/** + * Converts the parse type to a go type + */ +string t_go_generator::type_to_go_type(t_type* type) { + return type_to_go_type_with_opt(type, false); +} + +/** + * Converts the parse type to a go type, taking into account whether the field + * associated with the type is T_OPTIONAL. + */ +string t_go_generator::type_to_go_type_with_opt(t_type* type, + bool optional_field) { + string maybe_pointer(optional_field ? "*" : ""); + + if (type->is_typedef() && ((t_typedef*)type)->is_forward_typedef()) { + type = ((t_typedef*)type)->get_true_type(); + } + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + throw ""; + + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + return maybe_pointer + "[]byte"; + } + + return maybe_pointer + "string"; + + case t_base_type::TYPE_BOOL: + return maybe_pointer + "bool"; + + case t_base_type::TYPE_I8: + return maybe_pointer + "int8"; + + case t_base_type::TYPE_I16: + return maybe_pointer + "int16"; + + case t_base_type::TYPE_I32: + return maybe_pointer + "int32"; + + case t_base_type::TYPE_I64: + return maybe_pointer + "int64"; + + case t_base_type::TYPE_DOUBLE: + return maybe_pointer + "float64"; + } + } else if (type->is_enum()) { + return maybe_pointer + publicize(type_name(type)); + } else if (type->is_struct() || type->is_xception()) { + return "*" + publicize(type_name(type)); + } else if (type->is_map()) { + t_map* t = (t_map*)type; + string keyType = type_to_go_key_type(t->get_key_type()); + string valueType = type_to_go_type(t->get_val_type()); + return maybe_pointer + string("map[") + keyType + "]" + valueType; + } else if (type->is_set()) { + t_set* t = (t_set*)type; + string elemType = type_to_go_type(t->get_elem_type()); + return maybe_pointer + string("[]") + elemType; + } else if (type->is_list()) { + t_list* t = (t_list*)type; + string elemType = type_to_go_type(t->get_elem_type()); + return maybe_pointer + string("[]") + elemType; + } else if (type->is_typedef()) { + return maybe_pointer + publicize(type_name(type)); + } + + throw "INVALID TYPE IN type_to_go_type: " + type->get_name(); +} + +/** See the comment inside generate_go_struct_definition for what this is. */ +string t_go_generator::type_to_spec_args(t_type* ttype) { + while (ttype->is_typedef()) { + ttype = ((t_typedef*)ttype)->get_type(); + } + + if (ttype->is_base_type() || ttype->is_enum()) { + return "nil"; + } else if (ttype->is_struct() || ttype->is_xception()) { + return "(" + type_name(ttype) + ", " + type_name(ttype) + ".thrift_spec)"; + } else if (ttype->is_map()) { + return "(" + type_to_enum(((t_map*)ttype)->get_key_type()) + "," + + type_to_spec_args(((t_map*)ttype)->get_key_type()) + "," + + type_to_enum(((t_map*)ttype)->get_val_type()) + "," + + type_to_spec_args(((t_map*)ttype)->get_val_type()) + ")"; + } else if (ttype->is_set()) { + return "(" + type_to_enum(((t_set*)ttype)->get_elem_type()) + "," + + type_to_spec_args(((t_set*)ttype)->get_elem_type()) + ")"; + } else if (ttype->is_list()) { + return "(" + type_to_enum(((t_list*)ttype)->get_elem_type()) + "," + + type_to_spec_args(((t_list*)ttype)->get_elem_type()) + ")"; + } + + throw "INVALID TYPE IN type_to_spec_args: " + ttype->get_name(); +} + +bool format_go_output(const string& file_path) { + + // formatting via gofmt deactivated due to THRIFT-3893 + // Please look at the ticket and make sure you fully understand all the implications + // before submitting a patch that enables this feature again. Thank you. + (void) file_path; + return false; + + /* + const string command = "gofmt -w " + file_path; + + if (system(command.c_str()) == 0) { + return true; + } + + fprintf(stderr, "WARNING - Running '%s' failed.\n", command.c_str()); + return false; + */ + } + +THRIFT_REGISTER_GENERATOR(go, "Go", + " package_prefix= Package prefix for generated files.\n" \ + " thrift_import= Override thrift package import path (default:" + DEFAULT_THRIFT_IMPORT + ")\n" \ + " package= Package name (default: inferred from thrift file name)\n" \ + " ignore_initialisms\n" + " Disable automatic spelling correction of initialisms (e.g. \"URL\")\n" \ + " read_write_private\n" + " Make read/write methods private, default is public Read/Write\n" \ + " legacy_context\n" + " Use legacy x/net/context instead of context in go<1.7.\n") diff --git a/compiler/cpp/src/thrift/generate/t_gv_generator.cc b/compiler/cpp/src/thrift/generate/t_gv_generator.cc new file mode 100644 index 0000000..14b5377 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_gv_generator.cc @@ -0,0 +1,345 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "thrift/platform.h" +#include "thrift/generate/t_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::pair; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * Graphviz code generator + */ +class t_gv_generator : public t_generator { +public: + t_gv_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + exception_arrows = false; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("exceptions") == 0) { + exception_arrows = true; + } else { + throw "unknown option gv:" + iter->first; + } + } + + out_dir_base_ = "gen-gv"; + } + + /** + * Init and end of generator + */ + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_service(t_service* tservice); + +protected: + /** + * Helpers + */ + void print_type(t_type* ttype, string struct_field_ref); + void print_const_value(t_type* type, t_const_value* tvalue); + +private: + std::ofstream f_out_; + std::list edges; + bool exception_arrows; +}; + +/** + * Init generator: + * - Adds some escaping for the Graphviz domain. + * - Create output directory and open file for writting. + * - Write the file header. + */ +void t_gv_generator::init_generator() { + escape_['{'] = "\\{"; + escape_['}'] = "\\}"; + + // Make output directory + MKDIR(get_out_dir().c_str()); + string fname = get_out_dir() + program_->get_name() + ".gv"; + f_out_.open(fname.c_str()); + f_out_ << "digraph \"" << escape_string(program_name_) << "\" {" << endl; + f_out_ << "node [style=filled, shape=record];" << endl; + f_out_ << "edge [arrowsize=0.5];" << endl; + f_out_ << "rankdir=LR" << endl; +} + +/** + * Closes generator: + * - Print accumulated nodes connections. + * - Print footnote. + * - Closes file. + */ +void t_gv_generator::close_generator() { + // Print edges + std::list::iterator iter = edges.begin(); + for (; iter != edges.end(); iter++) { + f_out_ << (*iter) << endl; + } + + // Print graph end } and close file + f_out_ << "}" << endl; + f_out_.close(); +} + +void t_gv_generator::generate_typedef(t_typedef* ttypedef) { + string name = ttypedef->get_name(); + f_out_ << "node [fillcolor=azure];" << endl; + f_out_ << name << " [label=\""; + + f_out_ << escape_string(name); + f_out_ << " :: "; + print_type(ttypedef->get_type(), name); + + f_out_ << "\"];" << endl; +} + +void t_gv_generator::generate_enum(t_enum* tenum) { + string name = tenum->get_name(); + f_out_ << "node [fillcolor=white];" << endl; + f_out_ << name << " [label=\"enum " << escape_string(name); + + vector values = tenum->get_constants(); + vector::iterator val_iter; + for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) { + f_out_ << '|' << (*val_iter)->get_name(); + f_out_ << " = "; + f_out_ << (*val_iter)->get_value(); + } + + f_out_ << "\"];" << endl; +} + +void t_gv_generator::generate_const(t_const* tconst) { + string name = tconst->get_name(); + + f_out_ << "node [fillcolor=aliceblue];" << endl; + f_out_ << "const_" << name << " [label=\""; + + f_out_ << escape_string(name); + f_out_ << " = "; + print_const_value(tconst->get_type(), tconst->get_value()); + f_out_ << " :: "; + print_type(tconst->get_type(), "const_" + name); + + f_out_ << "\"];" << endl; +} + +void t_gv_generator::generate_struct(t_struct* tstruct) { + string name = tstruct->get_name(); + + if (tstruct->is_xception()) { + f_out_ << "node [fillcolor=lightpink];" << endl; + f_out_ << name << " [label=\""; + f_out_ << "exception " << escape_string(name); + } else if (tstruct->is_union()) { + f_out_ << "node [fillcolor=lightcyan];" << endl; + f_out_ << name << " [label=\""; + f_out_ << "union " << escape_string(name); + } else { + f_out_ << "node [fillcolor=beige];" << endl; + f_out_ << name << " [label=\""; + f_out_ << "struct " << escape_string(name); + } + + vector members = tstruct->get_members(); + vector::iterator mem_iter = members.begin(); + for (; mem_iter != members.end(); mem_iter++) { + string field_name = (*mem_iter)->get_name(); + + // print port (anchor reference) + f_out_ << "|'; + + // field name :: field type + f_out_ << (*mem_iter)->get_name(); + f_out_ << " :: "; + print_type((*mem_iter)->get_type(), name + ":field_" + field_name); + } + + f_out_ << "\"];" << endl; +} + +void t_gv_generator::print_type(t_type* ttype, string struct_field_ref) { + if (ttype->is_container()) { + if (ttype->is_list()) { + f_out_ << "list\\<"; + print_type(((t_list*)ttype)->get_elem_type(), struct_field_ref); + f_out_ << "\\>"; + } else if (ttype->is_set()) { + f_out_ << "set\\<"; + print_type(((t_set*)ttype)->get_elem_type(), struct_field_ref); + f_out_ << "\\>"; + } else if (ttype->is_map()) { + f_out_ << "map\\<"; + print_type(((t_map*)ttype)->get_key_type(), struct_field_ref); + f_out_ << ", "; + print_type(((t_map*)ttype)->get_val_type(), struct_field_ref); + f_out_ << "\\>"; + } + } else if (ttype->is_base_type()) { + f_out_ << (ttype->is_binary() ? "binary" : ttype->get_name()); + } else { + f_out_ << ttype->get_name(); + edges.push_back(struct_field_ref + " -> " + ttype->get_name()); + } +} + +/** + * Prints out an string representation of the provided constant value + */ +void t_gv_generator::print_const_value(t_type* type, t_const_value* tvalue) { + bool first = true; + switch (tvalue->get_type()) { + case t_const_value::CV_INTEGER: + f_out_ << tvalue->get_integer(); + break; + case t_const_value::CV_DOUBLE: + f_out_ << tvalue->get_double(); + break; + case t_const_value::CV_STRING: + f_out_ << "\\\"" << get_escaped_string(tvalue) << "\\\""; + break; + case t_const_value::CV_MAP: { + f_out_ << "\\{ "; + map map_elems = tvalue->get_map(); + map::iterator map_iter; + for (map_iter = map_elems.begin(); map_iter != map_elems.end(); map_iter++) { + if (!first) { + f_out_ << ", "; + } + first = false; + print_const_value(((t_map*)type)->get_key_type(), map_iter->first); + f_out_ << " = "; + print_const_value(((t_map*)type)->get_val_type(), map_iter->second); + } + f_out_ << " \\}"; + } break; + case t_const_value::CV_LIST: { + f_out_ << "\\{ "; + vector list_elems = tvalue->get_list(); + ; + vector::iterator list_iter; + for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) { + if (!first) { + f_out_ << ", "; + } + first = false; + if (type->is_list()) { + print_const_value(((t_list*)type)->get_elem_type(), *list_iter); + } else { + print_const_value(((t_set*)type)->get_elem_type(), *list_iter); + } + } + f_out_ << " \\}"; + } break; + case t_const_value::CV_IDENTIFIER: + f_out_ << escape_string(type->get_name()) << "." + << escape_string(tvalue->get_identifier_name()); + break; + default: + f_out_ << "UNKNOWN"; + break; + } +} + +void t_gv_generator::generate_service(t_service* tservice) { + string service_name = get_service_name(tservice); + f_out_ << "subgraph cluster_" << service_name << " {" << endl; + f_out_ << "node [fillcolor=bisque];" << endl; + f_out_ << "style=dashed;" << endl; + f_out_ << "label = \"" << escape_string(service_name) << " service\";" << endl; + + // TODO: service extends + + vector functions = tservice->get_functions(); + vector::iterator fn_iter = functions.begin(); + for (; fn_iter != functions.end(); fn_iter++) { + string fn_name = (*fn_iter)->get_name(); + + f_out_ << "function_" << service_name << fn_name; + f_out_ << "[label=\"function " << escape_string(fn_name); + f_out_ << " :: "; + print_type((*fn_iter)->get_returntype(), "function_" + service_name + fn_name + ":return_type"); + + vector args = (*fn_iter)->get_arglist()->get_members(); + vector::iterator arg_iter = args.begin(); + for (; arg_iter != args.end(); arg_iter++) { + f_out_ << "|get_name() << ">"; + f_out_ << (*arg_iter)->get_name(); + if ((*arg_iter)->get_value() != NULL) { + f_out_ << " = "; + print_const_value((*arg_iter)->get_type(), (*arg_iter)->get_value()); + } + f_out_ << " :: "; + print_type((*arg_iter)->get_type(), + "function_" + service_name + fn_name + ":param_" + (*arg_iter)->get_name()); + } + // end of node + f_out_ << "\"];" << endl; + + // Exception edges + if (exception_arrows) { + vector excepts = (*fn_iter)->get_xceptions()->get_members(); + vector::iterator ex_iter = excepts.begin(); + for (; ex_iter != excepts.end(); ex_iter++) { + edges.push_back("function_" + service_name + fn_name + " -> " + + (*ex_iter)->get_type()->get_name() + " [color=red]"); + } + } + } + + f_out_ << " }" << endl; +} + +THRIFT_REGISTER_GENERATOR( + gv, + "Graphviz", + " exceptions: Whether to draw arrows from functions to exception.\n") diff --git a/compiler/cpp/src/thrift/generate/t_haxe_generator.cc b/compiler/cpp/src/thrift/generate/t_haxe_generator.cc new file mode 100644 index 0000000..97c7d19 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_haxe_generator.cc @@ -0,0 +1,2983 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * Haxe code generator. + * + */ +class t_haxe_generator : public t_oop_generator { +public: + t_haxe_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + callbacks_ = false; + rtti_ = false; + buildmacro_ = ""; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("callbacks") == 0) { + callbacks_ = true; + } else if( iter->first.compare("rtti") == 0) { + rtti_ = true; + } else if( iter->first.compare("buildmacro") == 0) { + buildmacro_ = (iter->second); + } else { + throw "unknown option haxe:" + iter->first; + } + } + + out_dir_base_ = "gen-haxe"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + void generate_consts(std::vector consts); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + void print_const_value(std::ofstream& out, + std::string name, + t_type* type, + t_const_value* value, + bool in_static, + bool defval = false); + std::string render_const_value(ofstream& out, + std::string name, + t_type* type, + t_const_value* value); + + /** + * Service-level generation functions + */ + + void generate_haxe_struct(t_struct* tstruct, bool is_exception, bool is_result = false); + + void generate_haxe_struct_definition(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false, + bool is_result = false); + // removed -- equality,compare_to + void generate_haxe_struct_reader(std::ofstream& out, t_struct* tstruct); + void generate_haxe_validator(std::ofstream& out, t_struct* tstruct); + void generate_haxe_struct_result_writer(std::ofstream& out, t_struct* tstruct); + void generate_haxe_struct_writer(std::ofstream& out, t_struct* tstruct); + void generate_haxe_struct_tostring(std::ofstream& out, t_struct* tstruct); + void generate_haxe_meta_data_map(std::ofstream& out, t_struct* tstruct); + void generate_field_value_meta_data(std::ofstream& out, t_type* type); + std::string get_haxe_type_string(t_type* type); + void generate_reflection_setters(std::ostringstream& out, + t_type* type, + std::string field_name, + std::string cap_name); + void generate_reflection_getters(std::ostringstream& out, + t_type* type, + std::string field_name, + std::string cap_name); + void generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct); + void generate_generic_isset_method(std::ofstream& out, t_struct* tstruct); + void generate_property_getters_setters(std::ofstream& out, t_struct* tstruct); + + void generate_function_helpers(t_function* tfunction); + std::string get_cap_name(std::string name); + std::string generate_isset_check(t_field* field); + std::string generate_isset_check(std::string field); + void generate_isset_set(ofstream& out, t_field* field); + // removed std::string isset_field_id(t_field* field); + + void generate_service_interface(t_service* tservice); + void generate_service_helpers(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* tfunction); + void generate_service_method_signature(t_function* tfunction, bool is_interface); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + void generate_deserialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + void generate_deserialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + void generate_deserialize_set_element(std::ofstream& out, t_set* tset, std::string prefix = ""); + void generate_deserialize_map_element(std::ofstream& out, t_map* tmap, std::string prefix = ""); + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix = ""); + + void generate_serialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string iter, + std::string map); + + void generate_haxe_doc(std::ofstream& out, t_doc* tdoc); + void generate_haxe_doc(std::ofstream& out, t_function* tdoc); + + void generate_rtti_decoration(std::ofstream& out); + void generate_macro_decoration(std::ofstream& out); + + /** + * Helper rendering functions + */ + + std::string haxe_package(); + std::string haxe_type_imports(); + std::string haxe_thrift_imports(); + std::string haxe_thrift_gen_imports(t_struct* tstruct, string& imports); + std::string haxe_thrift_gen_imports(t_service* tservice); + std::string type_name(t_type* ttype, bool in_container = false, bool in_init = false); + std::string base_type_name(t_base_type* tbase, bool in_container = false); + std::string declare_field(t_field* tfield, bool init = false); + std::string function_signature_callback(t_function* tfunction); + std::string function_signature_normal(t_function* tfunction); + std::string argument_list(t_struct* tstruct); + std::string type_to_enum(t_type* ttype); + std::string get_enum_class_name(t_type* type); + string generate_service_method_onsuccess(t_function* tfunction, bool as_type, bool omit_name); + void generate_service_method_signature_callback(t_function* tfunction, bool is_interface); + void generate_service_method_signature_normal(t_function* tfunction, bool is_interface); + + bool type_can_be_null(t_type* ttype) { + ttype = get_true_type(ttype); + + if (ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string()) { + return true; + } + + if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + // case t_base_type::TYPE_I64: - Int64 is not really nullable, even though it behaved that + // way before Haxe 3.2.0 + return true; + default: + return false; + } + } + + return false; + } + + std::string constant_name(std::string name); + +private: + bool callbacks_; + bool rtti_; + string buildmacro_; + + /** + * File streams + */ + + std::string package_name_; + std::ofstream f_service_; + std::string package_dir_; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_haxe_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + package_name_ = program_->get_namespace("haxe"); + + // Haxe package names are lowercase + if (package_name_.length() > 0) { + package_name_[0] = tolower(package_name_[0]); + size_t index = package_name_.find('.'); + while (index != std::string::npos) { + if (++index < package_name_.length()) { + package_name_[index] = tolower(package_name_[index]); + } + index = package_name_.find('.', index); + } + } + + string dir = package_name_; + string subdir = get_out_dir(); + string::size_type loc; + while ((loc = dir.find(".")) != string::npos) { + subdir = subdir + "/" + dir.substr(0, loc); + MKDIR(subdir.c_str()); + dir = dir.substr(loc + 1); + } + if (dir.size() > 0) { + subdir = subdir + "/" + dir; + MKDIR(subdir.c_str()); + } + + package_dir_ = subdir; +} + +/** + * Packages the generated file + * + * @return String of the package, i.e. "package org.apache.thriftdemo;" + */ +string t_haxe_generator::haxe_package() { + if (!package_name_.empty()) { + return string("package ") + package_name_; + } + return "package"; +} + +/** + * Prints standard haxe imports + * + * @return List of imports for haxe types that are used in here + */ +string t_haxe_generator::haxe_type_imports() { + return string() + "import org.apache.thrift.helper.*;\n" + "import haxe.io.Bytes;\n" + + "import haxe.ds.IntMap;\n" + "import haxe.ds.StringMap;\n" + + "import haxe.ds.ObjectMap;\n" + "\n" + "#if flash\n" + + "import flash.errors.ArgumentError;\n" + "#end\n" + "\n"; +} + +/** + * Prints standard haxe imports + * + * @return List of imports necessary for thrift + */ +string t_haxe_generator::haxe_thrift_imports() { + return string() + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n" + + "import org.apache.thrift.protocol.*;\n" + "\n"; +} + +/** + * Prints imports needed for a given type + * + * @return List of imports necessary for a given t_struct + */ +string t_haxe_generator::haxe_thrift_gen_imports(t_struct* tstruct, string& imports) { + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + // For each type check if it is from a different namespace + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_program* program = (*m_iter)->get_type()->get_program(); + if (program != NULL && program != program_) { + string package = program->get_namespace("haxe"); + if (!package.empty()) { + if (imports.find(package + "." + (*m_iter)->get_type()->get_name()) == string::npos) { + imports.append("import " + package + "." + (*m_iter)->get_type()->get_name() + ";\n"); + } + } + } + } + return imports; +} + +/** + * Prints imports needed for a given type + * + * @return List of imports necessary for a given t_service + */ +string t_haxe_generator::haxe_thrift_gen_imports(t_service* tservice) { + string imports; + const vector& functions = tservice->get_functions(); + vector::const_iterator f_iter; + + // For each type check if it is from a different namespace + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_program* program = (*f_iter)->get_returntype()->get_program(); + if (program != NULL && program != program_) { + string package = program->get_namespace("haxe"); + if (!package.empty()) { + if (imports.find(package + "." + (*f_iter)->get_returntype()->get_name()) == string::npos) { + imports.append("import " + package + "." + (*f_iter)->get_returntype()->get_name() + + ";\n"); + } + } + } + + haxe_thrift_gen_imports((*f_iter)->get_arglist(), imports); + haxe_thrift_gen_imports((*f_iter)->get_xceptions(), imports); + } + + return imports; +} + +/** + * Nothing in haxe + */ +void t_haxe_generator::close_generator() { +} + +/** + * Generates a typedef. This is not done in haxe, since it does + * not support arbitrary name replacements, and it'd be a wacky waste + * of overhead to make wrapper classes. + * + * @param ttypedef The type definition + */ +void t_haxe_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + +/** + * Enums are a class with a set of static constants. + * + * @param tenum The enumeration + */ +void t_haxe_generator::generate_enum(t_enum* tenum) { + // Make output file + string f_enum_name = package_dir_ + "/" + get_cap_name(tenum->get_name()) + ".hx"; + ofstream f_enum; + f_enum.open(f_enum_name.c_str()); + + // Comment and package it + f_enum << autogen_comment() << haxe_package() << ";" << endl << endl; + + // Add haxe imports + f_enum << string() + "import org.apache.thrift.helper.*;" << endl << endl; + + generate_rtti_decoration(f_enum); + generate_macro_decoration(f_enum); + indent(f_enum) << "class " << get_cap_name(tenum->get_name()) << " "; + scope_up(f_enum); + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + indent(f_enum) << "public static inline var " << (*c_iter)->get_name() << " : Int = " << value + << ";" << endl; + } + + // Create a static Set with all valid values for this enum + f_enum << endl; + + indent(f_enum) << "public static var VALID_VALUES = { new IntSet( ["; + indent_up(); + bool firstValue = true; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + // populate set + f_enum << (firstValue ? "" : ", ") << (*c_iter)->get_name(); + firstValue = false; + } + indent_down(); + f_enum << "]); };" << endl; + + indent(f_enum) << "public static var VALUES_TO_NAMES = { ["; + indent_up(); + firstValue = true; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + f_enum << (firstValue ? "" : ",") << endl; + indent(f_enum) << (*c_iter)->get_name() << " => \"" << (*c_iter)->get_name() << "\""; + firstValue = false; + } + f_enum << endl; + indent_down(); + indent(f_enum) << "]; };" << endl; + + scope_down(f_enum); // end class + + f_enum.close(); +} + +/** + * Generates a class that holds all the constants. + */ +void t_haxe_generator::generate_consts(std::vector consts) { + if (consts.empty()) { + return; + } + + string f_consts_name = package_dir_ + "/" + get_cap_name(program_name_) + "Constants.hx"; + ofstream f_consts; + f_consts.open(f_consts_name.c_str()); + + // Print header + f_consts << autogen_comment() << haxe_package() << ";" << endl << endl; + + f_consts << endl; + + f_consts << haxe_type_imports(); + + generate_rtti_decoration(f_consts); + generate_macro_decoration(f_consts); + indent(f_consts) << "class " << get_cap_name(program_name_) << "Constants {" << endl << endl; + indent_up(); + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + print_const_value(f_consts, + (*c_iter)->get_name(), + (*c_iter)->get_type(), + (*c_iter)->get_value(), + false); + } + indent_down(); + indent(f_consts) << "}" << endl; + f_consts.close(); +} + +void t_haxe_generator::print_const_value(std::ofstream& out, + string name, + t_type* type, + t_const_value* value, + bool in_static, + bool defval) { + type = get_true_type(type); + + indent(out); + if (!defval) { + out << (in_static ? "var " : "public static inline var "); + } + if (type->is_base_type()) { + string v2 = render_const_value(out, name, type, value); + out << name; + if (!defval) { + out << ":" << type_name(type); + } + out << " = " << v2 << ";" << endl << endl; + } else if (type->is_enum()) { + out << name; + if (!defval) { + out << ":" << type_name(type); + } + out << " = " << value->get_integer() << ";" << endl << endl; + } else if (type->is_struct() || type->is_xception()) { + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + out << name << ":" << type_name(type) << " = new " << type_name(type, false, true) << "();" + << endl; + if (!in_static) { + indent(out) << "{" << endl; + indent_up(); + indent(out) << "new function() : Void {" << endl; + indent_up(); + } + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + string val = render_const_value(out, name, field_type, v_iter->second); + indent(out) << name << "."; + out << v_iter->first->get_string() << " = " << val << ";" << endl; + } + if (!in_static) { + indent_down(); + indent(out) << "}();" << endl; + indent_down(); + indent(out) << "}" << endl; + } + out << endl; + } else if (type->is_map()) { + out << name; + if (!defval) { + out << ":" << type_name(type); + } + out << " = new " << type_name(type, false, true) << "();" << endl; + if (!in_static) { + indent(out) << "{" << endl; + indent_up(); + indent(out) << "new function() : Void {" << endl; + indent_up(); + } + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string key = render_const_value(out, name, ktype, v_iter->first); + string val = render_const_value(out, name, vtype, v_iter->second); + indent(out) << name << "[" << key << "] = " << val << ";" << endl; + } + if (!in_static) { + indent_down(); + indent(out) << "}();" << endl; + indent_down(); + indent(out) << "}" << endl; + } + out << endl; + } else if (type->is_list() || type->is_set()) { + out << name; + if (!defval) { + out << ":" << type_name(type); + } + out << " = new " << type_name(type, false, true) << "();" << endl; + if (!in_static) { + indent(out) << "{" << endl; + indent_up(); + indent(out) << "new function() : Void {" << endl; + indent_up(); + } + t_type* etype; + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(out, name, etype, *v_iter); + indent(out) << name << "." << (type->is_list() ? "push" : "add") << "(" << val << ");" + << endl; + } + if (!in_static) { + indent_down(); + indent(out) << "}();" << endl; + indent_down(); + indent(out) << "}" << endl; + } + out << endl; + } else { + throw "compiler error: no const of type " + type->get_name(); + } +} + +string t_haxe_generator::render_const_value(ofstream& out, + string name, + t_type* type, + t_const_value* value) { + (void)name; + type = get_true_type(type); + std::ostringstream render; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + render << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() > 0) ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + render << "(byte)" << value->get_integer(); + break; + case t_base_type::TYPE_I16: + render << "(short)" << value->get_integer(); + break; + case t_base_type::TYPE_I32: + render << value->get_integer(); + break; + case t_base_type::TYPE_I64: + render << value->get_integer() << "L"; + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + render << "(double)" << value->get_integer(); + } else { + render << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + render << value->get_integer(); + } else { + string t = tmp("tmp"); + print_const_value(out, t, type, value, true); + render << t; + } + + return render.str(); +} + +/** + * Generates a struct definition for a thrift data type. This is a class + * with data members, read(), write(), and an inner Isset class. + * + * @param tstruct The struct definition + */ +void t_haxe_generator::generate_struct(t_struct* tstruct) { + generate_haxe_struct(tstruct, false); +} + +/** + * Exceptions are structs, but they inherit from Exception + * + * @param tstruct The struct definition + */ +void t_haxe_generator::generate_xception(t_struct* txception) { + generate_haxe_struct(txception, true); +} + +/** + * Haxe struct definition. + * + * @param tstruct The struct definition + */ +void t_haxe_generator::generate_haxe_struct(t_struct* tstruct, bool is_exception, bool is_result) { + // Make output file + string f_struct_name = package_dir_ + "/" + get_cap_name(tstruct->get_name()) + ".hx"; + ofstream f_struct; + f_struct.open(f_struct_name.c_str()); + + f_struct << autogen_comment() << haxe_package() << ";" << endl; + + f_struct << endl; + + string imports; + + f_struct << haxe_type_imports() << haxe_thrift_imports() + << haxe_thrift_gen_imports(tstruct, imports) << endl; + + generate_haxe_struct_definition(f_struct, tstruct, is_exception, is_result); + + f_struct.close(); +} + +/** + * haxe struct definition. This has various parameters, as it could be + * generated standalone or inside another class as a helper. If it + * is a helper than it is a static class. + * + * @param tstruct The struct definition + * @param is_exception Is this an exception? + * @param in_class If inside a class, needs to be static class + * @param is_result If this is a result it needs a different writer + */ +void t_haxe_generator::generate_haxe_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool is_result) { + generate_haxe_doc(out, tstruct); + + string clsname = get_cap_name(tstruct->get_name()); + + generate_rtti_decoration(out); + generate_macro_decoration(out); + indent(out) << "class " << clsname << " "; + + if (is_exception) { + out << "extends TException "; + } + out << "implements TBase "; + + scope_up(out); + indent(out) << endl; + + indent(out) << "static var STRUCT_DESC = { new TStruct(\"" << tstruct->get_name() << "\"); };" + << endl; + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << "static var " << constant_name((*m_iter)->get_name()) + << "_FIELD_DESC = { new TField(\"" << (*m_iter)->get_name() << "\", " + << type_to_enum((*m_iter)->get_type()) << ", " << (*m_iter)->get_key() << "); };" + << endl; + } + out << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + generate_haxe_doc(out, *m_iter); + // indent(out) << "private var _" << (*m_iter)->get_name() + " : " + + // type_name((*m_iter)->get_type()) << ";" << endl; + indent(out) << "@:isVar" << endl; + indent(out) << "public var " + << (*m_iter)->get_name() + "(get,set) : " + + get_cap_name(type_name((*m_iter)->get_type())) << ";" << endl; + } + + out << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << "inline static var " << upcase_string((*m_iter)->get_name()) + << "_FIELD_ID : Int = " << (*m_iter)->get_key() << ";" << endl; + } + + out << endl; + + // Inner Isset class + if (members.size() > 0) { + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (!type_can_be_null((*m_iter)->get_type())) { + indent(out) << "private var __isset_" << (*m_iter)->get_name() << " : Bool = false;" + << endl; + } + } + } + + out << endl; + + // Static initializer to populate global class to struct metadata map + if (false) { + // TODO: reactivate when needed + generate_haxe_meta_data_map(out, tstruct); + indent(out) << "{" << endl; + indent_up(); + indent(out) << "FieldMetaData.addStructMetaDataMap(" << type_name(tstruct) << ", metaDataMap);" + << endl; + indent_down(); + indent(out) << "}" << endl; + indent(out) << "}" << endl; + } + + // Default constructor + indent(out) << "public function new() {" << endl; + indent_up(); + if (is_exception) { + indent(out) << "super();" << endl; + } + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_value() != NULL) { + indent(out) << "this." << (*m_iter)->get_name() << " = " + << (*m_iter)->get_value()->get_integer() << ";" << endl; + } + } + indent_down(); + indent(out) << "}" << endl << endl; + + generate_property_getters_setters(out, tstruct); + generate_generic_field_getters_setters(out, tstruct); + generate_generic_isset_method(out, tstruct); + + generate_haxe_struct_reader(out, tstruct); + if (is_result) { + generate_haxe_struct_result_writer(out, tstruct); + } else { + generate_haxe_struct_writer(out, tstruct); + } + generate_haxe_struct_tostring(out, tstruct); + generate_haxe_validator(out, tstruct); + scope_down(out); + out << endl; +} + +/** + * Generates a function to read all the fields of the struct. + * + * @param tstruct The struct definition + */ +void t_haxe_generator::generate_haxe_struct_reader(ofstream& out, t_struct* tstruct) { + out << indent() << "public function read( iprot : TProtocol) : Void {" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + indent(out) << "iprot.IncrementRecursionDepth();" << endl; + indent(out) << "try" << endl; + scope_up(out); + + // Declare stack tmp variables and read struct header + out << indent() << "var field : TField;" << endl << indent() << "iprot.readStructBegin();" + << endl; + + // Loop over reading in fields + indent(out) << "while (true)" << endl; + scope_up(out); + + // Read beginning field marker + indent(out) << "field = iprot.readFieldBegin();" << endl; + + // Check for field STOP marker and break + indent(out) << "if (field.type == TType.STOP) { " << endl; + indent_up(); + indent(out) << "break;" << endl; + indent_down(); + indent(out) << "}" << endl; + + // Switch statement on the field we are reading + indent(out) << "switch (field.id)" << endl; + + scope_up(out); + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << "case " << upcase_string((*f_iter)->get_name()) << "_FIELD_ID:" << endl; + indent_up(); + indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; + indent_up(); + + generate_deserialize_field(out, *f_iter, "this."); + generate_isset_set(out, *f_iter); + indent_down(); + out << indent() << "} else { " << endl << indent() << " TProtocolUtil.skip(iprot, field.type);" + << endl << indent() << "}" << endl; + indent_down(); + } + + // In the default case we skip the field + out << indent() << "default:" << endl << indent() << " TProtocolUtil.skip(iprot, field.type);" + << endl; + + scope_down(out); + + // Read field end marker + indent(out) << "iprot.readFieldEnd();" << endl; + + scope_down(out); + + out << indent() << "iprot.readStructEnd();" << endl << endl; + + indent(out) << "iprot.DecrementRecursionDepth();" << endl; + scope_down(out); + indent(out) << "catch(e:Dynamic)" << endl; + scope_up(out); + indent(out) << "iprot.DecrementRecursionDepth();" << endl; + indent(out) << "throw e;" << endl; + scope_down(out); + + // check for required fields of primitive type + // (which can be checked here but not in the general validate method) + out << endl << indent() << "// check for required fields of primitive type, which can't be " + "checked in the validate method" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) { + out << indent() << "if (!__isset_" << (*f_iter)->get_name() << ") {" << endl << indent() + << " throw new TProtocolException(TProtocolException.UNKNOWN, \"Required field '" + << (*f_iter)->get_name() + << "' was not found in serialized data! Struct: \" + toString());" << endl << indent() + << "}" << endl; + } + } + + // performs various checks (e.g. check that all required fields are set) + indent(out) << "validate();" << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +// generates haxe method to perform various checks +// (e.g. check that all required fields are set) +void t_haxe_generator::generate_haxe_validator(ofstream& out, t_struct* tstruct) { + indent(out) << "public function validate() : Void {" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out << indent() << "// check for required fields" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + if (type_can_be_null((*f_iter)->get_type())) { + indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl; + indent(out) + << " throw new TProtocolException(TProtocolException.UNKNOWN, \"Required field '" + << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" << endl; + indent(out) << "}" << endl; + } else { + indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name() + << "' because it's a primitive." << endl; + } + } + } + + // check that fields of type enum have valid values + out << indent() << "// check that fields of type enum have valid values" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = (*f_iter); + t_type* type = field->get_type(); + // if field is an enum, check that its value is valid + if (type->is_enum()) { + indent(out) << "if (" << generate_isset_check(field) << " && !" + << get_cap_name(get_enum_class_name(type)) << ".VALID_VALUES.contains(" + << field->get_name() << ")){" << endl; + indent_up(); + indent(out) << "throw new TProtocolException(TProtocolException.UNKNOWN, \"The field '" + << field->get_name() << "' has been assigned the invalid value \" + " + << field->get_name() << ");" << endl; + indent_down(); + indent(out) << "}" << endl; + } + } + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a function to write all the fields of the struct + * + * @param tstruct The struct definition + */ +void t_haxe_generator::generate_haxe_struct_writer(ofstream& out, t_struct* tstruct) { + out << indent() << "public function write(oprot:TProtocol) : Void {" << endl; + indent_up(); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + // performs various checks (e.g. check that all required fields are set) + indent(out) << "validate();" << endl; + indent(out) << "oprot.IncrementRecursionDepth();" << endl; + indent(out) << "try" << endl; + scope_up(out); + + indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; + if (could_be_unset) { + indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl; + indent_up(); + } + bool null_allowed = type_can_be_null((*f_iter)->get_type()); + if (null_allowed) { + out << indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl; + indent_up(); + } + + indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) + << "_FIELD_DESC);" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "this."); + + // Write field closer + indent(out) << "oprot.writeFieldEnd();" << endl; + + if (null_allowed) { + indent_down(); + indent(out) << "}" << endl; + } + if (could_be_unset) { + indent_down(); + indent(out) << "}" << endl; + } + } + + indent(out) << "oprot.writeFieldStop();" << endl; + indent(out) << "oprot.writeStructEnd();" << endl; + + indent(out) << "oprot.DecrementRecursionDepth();" << endl; + scope_down(out); + indent(out) << "catch(e:Dynamic)" << endl; + scope_up(out); + indent(out) << "oprot.DecrementRecursionDepth();" << endl; + indent(out) << "throw e;" << endl; + scope_down(out); + + indent_down(); + out << indent() << "}" << endl << endl; +} + +/** + * Generates a function to write all the fields of the struct, + * which is a function result. These fields are only written + * if they are set in the Isset array, and only one of them + * can be set at a time. + * + * @param tstruct The struct definition + */ +void t_haxe_generator::generate_haxe_struct_result_writer(ofstream& out, t_struct* tstruct) { + out << indent() << "public function write(oprot:TProtocol) : Void {" << endl; + indent_up(); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + indent(out) << "oprot.IncrementRecursionDepth();" << endl; + indent(out) << "try" << endl; + scope_up(out); + + indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; + + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + out << endl << indent() << "if "; + } else { + out << " else if "; + } + + out << "(this." << generate_isset_check(*f_iter) << ") {" << endl; + + indent_up(); + + indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) + << "_FIELD_DESC);" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "this."); + + // Write field closer + indent(out) << "oprot.writeFieldEnd();" << endl; + + indent_down(); + indent(out) << "}"; + } + + indent(out) << endl; + indent(out) << "oprot.writeFieldStop();" << endl; + indent(out) << "oprot.writeStructEnd();" << endl; + + indent(out) << "oprot.DecrementRecursionDepth();" << endl; + scope_down(out); + indent(out) << "catch(e:Dynamic)" << endl; + scope_up(out); + indent(out) << "oprot.DecrementRecursionDepth();" << endl; + indent(out) << "throw e;" << endl; + scope_down(out); + + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_haxe_generator::generate_reflection_getters(ostringstream& out, + t_type* type, + string field_name, + string cap_name) { + (void)type; + (void)cap_name; + indent(out) << "case " << upcase_string(field_name) << "_FIELD_ID:" << endl; + indent_up(); + indent(out) << "return this." << field_name << ";" << endl; + indent_down(); +} + +void t_haxe_generator::generate_reflection_setters(ostringstream& out, + t_type* type, + string field_name, + string cap_name) { + (void)type; + (void)cap_name; + indent(out) << "case " << upcase_string(field_name) << "_FIELD_ID:" << endl; + indent_up(); + indent(out) << "if (value == null) {" << endl; + indent(out) << " unset" << get_cap_name(field_name) << "();" << endl; + indent(out) << "} else {" << endl; + indent(out) << " this." << field_name << " = value;" << endl; + indent(out) << "}" << endl << endl; + + indent_down(); +} + +void t_haxe_generator::generate_generic_field_getters_setters(std::ofstream& out, + t_struct* tstruct) { + + std::ostringstream getter_stream; + std::ostringstream setter_stream; + + // build up the bodies of both the getter and setter at once + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + t_type* type = get_true_type(field->get_type()); + std::string field_name = field->get_name(); + std::string cap_name = get_cap_name(field_name); + + indent_up(); + generate_reflection_setters(setter_stream, type, field_name, cap_name); + generate_reflection_getters(getter_stream, type, field_name, cap_name); + indent_down(); + } + + // create the setter + indent(out) << "public function setFieldValue(fieldID : Int, value : Dynamic) : Void {" << endl; + indent_up(); + + if (fields.size() > 0) { + indent(out) << "switch (fieldID) {" << endl; + out << setter_stream.str(); + indent(out) << "default:" << endl; + indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; + indent(out) << "}" << endl; + } else { + indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; + } + + indent_down(); + indent(out) << "}" << endl << endl; + + // create the getter + indent(out) << "public function getFieldValue(fieldID : Int) : Dynamic {" << endl; + indent_up(); + + if (fields.size() > 0) { + indent(out) << "switch (fieldID) {" << endl; + out << getter_stream.str(); + indent(out) << "default:" << endl; + indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; + indent(out) << "}" << endl; + } else { + indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; + } + + indent_down(); + + indent(out) << "}" << endl << endl; +} + +// Creates a generic isSet method that takes the field number as argument +void t_haxe_generator::generate_generic_isset_method(std::ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // create the isSet method + indent(out) << "// Returns true if field corresponding to fieldID is set (has been assigned a " + "value) and false otherwise" << endl; + indent(out) << "public function isSet(fieldID : Int) : Bool {" << endl; + indent_up(); + if (fields.size() > 0) { + indent(out) << "switch (fieldID) {" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + indent(out) << "case " << upcase_string(field->get_name()) << "_FIELD_ID:" << endl; + indent_up(); + indent(out) << "return " << generate_isset_check(field) << ";" << endl; + indent_down(); + } + + indent(out) << "default:" << endl; + indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; + indent(out) << "}" << endl; + } else { + indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; + } + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a set of property setters/getters for the given struct. + * + * @param tstruct The struct definition + */ +void t_haxe_generator::generate_property_getters_setters(ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + t_type* type = get_true_type(field->get_type()); + std::string field_name = field->get_name(); + std::string cap_name = get_cap_name(field_name); + + // Simple getter + generate_haxe_doc(out, field); + indent(out) << "public function get_" << field_name << "() : " << get_cap_name(type_name(type)) + << " {" << endl; + indent_up(); + indent(out) << "return this." << field_name << ";" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + + // Simple setter + generate_haxe_doc(out, field); + indent(out) << "public function set_" << field_name << "(" << field_name << ":" + << get_cap_name(type_name(type)) << ") : " << get_cap_name(type_name(type)) << " {" + << endl; + indent_up(); + indent(out) << "this." << field_name << " = " << field_name << ";" << endl; + generate_isset_set(out, field); + indent(out) << "return this." << field_name << ";" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; + + // Unsetter + indent(out) << "public function unset" << cap_name << "() : Void {" << endl; + indent_up(); + if (type_can_be_null(type)) { + indent(out) << "this." << field_name << " = null;" << endl; + } else { + indent(out) << "this.__isset_" << field_name << " = false;" << endl; + } + indent_down(); + indent(out) << "}" << endl << endl; + + // isSet method + indent(out) << "// Returns true if field " << field_name + << " is set (has been assigned a value) and false otherwise" << endl; + indent(out) << "public function is" << get_cap_name("set") << cap_name << "() : Bool {" << endl; + indent_up(); + if (type_can_be_null(type)) { + indent(out) << "return this." << field_name << " != null;" << endl; + } else { + indent(out) << "return this.__isset_" << field_name << ";" << endl; + } + indent_down(); + indent(out) << "}" << endl << endl; + } +} + +/** + * Generates a toString() method for the given struct + * + * @param tstruct The struct definition + */ +void t_haxe_generator::generate_haxe_struct_tostring(ofstream& out, t_struct* tstruct) { + out << indent() << "public " + << "function toString() : String {" << endl; + indent_up(); + + out << indent() << "var ret : String = \"" << tstruct->get_name() << "(\";" << endl; + out << indent() << "var first : Bool = true;" << endl << endl; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; + if (could_be_unset) { + indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl; + indent_up(); + } + + t_field* field = (*f_iter); + + if (!first) { + indent(out) << "if (!first) ret += \", \";" << endl; + } + indent(out) << "ret += \"" << (*f_iter)->get_name() << ":\";" << endl; + bool can_be_null = type_can_be_null(field->get_type()); + if (can_be_null) { + indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl; + indent(out) << " ret += \"null\";" << endl; + indent(out) << "} else {" << endl; + indent_up(); + } + + if (field->get_type()->is_binary()) { + indent(out) << " ret += \"BINARY\";" << endl; + } else if (field->get_type()->is_enum()) { + indent(out) << "var " << field->get_name() + << "_name : String = " << get_cap_name(get_enum_class_name(field->get_type())) + << ".VALUES_TO_NAMES[this." << (*f_iter)->get_name() << "];" << endl; + indent(out) << "if (" << field->get_name() << "_name != null) {" << endl; + indent(out) << " ret += " << field->get_name() << "_name;" << endl; + indent(out) << " ret += \" (\";" << endl; + indent(out) << "}" << endl; + indent(out) << "ret += this." << field->get_name() << ";" << endl; + indent(out) << "if (" << field->get_name() << "_name != null) {" << endl; + indent(out) << " ret += \")\";" << endl; + indent(out) << "}" << endl; + } else { + indent(out) << "ret += this." << (*f_iter)->get_name() << ";" << endl; + } + + if (can_be_null) { + indent_down(); + indent(out) << "}" << endl; + } + indent(out) << "first = false;" << endl; + + if (could_be_unset) { + indent_down(); + indent(out) << "}" << endl; + } + first = false; + } + out << indent() << "ret += \")\";" << endl << indent() << "return ret;" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a static map with meta data to store information such as fieldID to + * fieldName mapping + * + * @param tstruct The struct definition + */ +void t_haxe_generator::generate_haxe_meta_data_map(ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Static Map with fieldID -> FieldMetaData mappings + indent(out) << "inline static var metaDataMap : IntMap = new IntMap();" << endl; + + if (fields.size() > 0) { + // Populate map + scope_up(out); + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + std::string field_name = field->get_name(); + indent(out) << "metaDataMap[" << upcase_string(field_name) + << "_FIELD_ID] = new FieldMetaData(\"" << field_name << "\", "; + + // Set field requirement type (required, optional, etc.) + if (field->get_req() == t_field::T_REQUIRED) { + out << "TFieldRequirementType.REQUIRED, "; + } else if (field->get_req() == t_field::T_OPTIONAL) { + out << "TFieldRequirementType.OPTIONAL, "; + } else { + out << "TFieldRequirementType.DEFAULT, "; + } + + // Create value meta data + generate_field_value_meta_data(out, field->get_type()); + out << ");" << endl; + } + scope_down(out); + } +} + +/** + * Returns a string with the haxe representation of the given thrift type + * (e.g. for the type struct it returns "TType.STRUCT") + */ +std::string t_haxe_generator::get_haxe_type_string(t_type* type) { + if (type->is_list()) { + return "TType.LIST"; + } else if (type->is_map()) { + return "TType.MAP"; + } else if (type->is_set()) { + return "TType.SET"; + } else if (type->is_struct() || type->is_xception()) { + return "TType.STRUCT"; + } else if (type->is_enum()) { + return "TType.I32"; + } else if (type->is_typedef()) { + return get_haxe_type_string(((t_typedef*)type)->get_type()); + } else if (type->is_base_type()) { + switch (((t_base_type*)type)->get_base()) { + case t_base_type::TYPE_VOID: + return "TType.VOID"; + break; + case t_base_type::TYPE_STRING: + return "TType.STRING"; + break; + case t_base_type::TYPE_BOOL: + return "TType.BOOL"; + break; + case t_base_type::TYPE_I8: + return "TType.BYTE"; + break; + case t_base_type::TYPE_I16: + return "TType.I16"; + break; + case t_base_type::TYPE_I32: + return "TType.I32"; + break; + case t_base_type::TYPE_I64: + return "TType.I64"; + break; + case t_base_type::TYPE_DOUBLE: + return "TType.DOUBLE"; + break; + default: + throw std::runtime_error("Unknown thrift type \"" + type->get_name() + + "\" passed to t_haxe_generator::get_haxe_type_string!"); + break; // This should never happen! + } + } else { + throw std::runtime_error( + "Unknown thrift type \"" + type->get_name() + + "\" passed to t_haxe_generator::get_haxe_type_string!"); // This should never happen! + } +} + +void t_haxe_generator::generate_field_value_meta_data(std::ofstream& out, t_type* type) { + out << endl; + indent_up(); + indent_up(); + if (type->is_struct()) { + indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type); + } else if (type->is_container()) { + if (type->is_list()) { + indent(out) << "new ListMetaData(TType.LIST, "; + t_type* elem_type = ((t_list*)type)->get_elem_type(); + generate_field_value_meta_data(out, elem_type); + } else if (type->is_set()) { + indent(out) << "new SetMetaData(TType.SET, "; + t_type* elem_type = ((t_list*)type)->get_elem_type(); + generate_field_value_meta_data(out, elem_type); + } else { // map + indent(out) << "new MapMetaData(TType.MAP, "; + t_type* key_type = ((t_map*)type)->get_key_type(); + t_type* val_type = ((t_map*)type)->get_val_type(); + generate_field_value_meta_data(out, key_type); + out << ", "; + generate_field_value_meta_data(out, val_type); + } + } else { + indent(out) << "new FieldValueMetaData(" << get_haxe_type_string(type); + } + out << ")"; + indent_down(); + indent_down(); +} + +/** + * Generates a thrift service. In C++, this comprises an entirely separate + * header and source file. The header file defines the methods and includes + * the data types defined in the main header file, and the implementation + * file contains implementations of the basic printer and default interfaces. + * + * @param tservice The service definition + */ +void t_haxe_generator::generate_service(t_service* tservice) { + // Make interface file + string f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + ".hx"; + f_service_.open(f_service_name.c_str()); + + f_service_ << autogen_comment() << haxe_package() << ";" << endl; + + f_service_ << endl << haxe_type_imports() << haxe_thrift_imports() + << haxe_thrift_gen_imports(tservice); + + if (tservice->get_extends() != NULL) { + t_type* parent = tservice->get_extends(); + string parent_namespace = parent->get_program()->get_namespace("haxe"); + if (!parent_namespace.empty() && parent_namespace != package_name_) { + f_service_ << "import " << type_name(parent) << ";" << endl; + } + } + + f_service_ << endl; + + generate_service_interface(tservice); + + f_service_.close(); + + // Now make the implementation/client file + f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + "Impl.hx"; + f_service_.open(f_service_name.c_str()); + + f_service_ << autogen_comment() << haxe_package() << ";" << endl << endl << haxe_type_imports() + << haxe_thrift_imports() << haxe_thrift_gen_imports(tservice) << endl; + + if (tservice->get_extends() != NULL) { + t_type* parent = tservice->get_extends(); + string parent_namespace = parent->get_program()->get_namespace("haxe"); + if (!parent_namespace.empty() && parent_namespace != package_name_) { + f_service_ << "import " << type_name(parent) << "Impl;" << endl; + } + } + + f_service_ << endl; + + generate_service_client(tservice); + + f_service_.close(); + + // Now make the helper class files + generate_service_helpers(tservice); + + // Now make the processor/server file + f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + "Processor.hx"; + f_service_.open(f_service_name.c_str()); + + f_service_ << autogen_comment() << haxe_package() << ";" << endl << endl << haxe_type_imports() + << haxe_thrift_imports() << haxe_thrift_gen_imports(tservice) << endl; + + if (!package_name_.empty()) { + f_service_ << "import " << package_name_ << ".*;" << endl; + f_service_ << "import " << package_name_ << "." << get_cap_name(service_name_).c_str() + << "Impl;" << endl; + f_service_ << endl; + } + + generate_service_server(tservice); + + f_service_.close(); +} + +/** + * Generates the code snippet for the onSuccess callbacks + * + * @param tfunction The service function to generate code for. + */ +string t_haxe_generator::generate_service_method_onsuccess(t_function* tfunction, + bool as_type, + bool omit_name) { + if (tfunction->is_oneway()) { + return ""; + } + + string name = ""; + if (!omit_name) { + name = "onSuccess"; + if (as_type) { + name += " : "; + } + } + + if (tfunction->get_returntype()->is_void()) { + if (as_type) { + return name + "Void->Void = null"; + } else { + return name + "() : Void"; + } + } + + if (as_type) { + return name + type_name(tfunction->get_returntype()) + "->Void = null"; + } else { + return name + "( retval : " + type_name(tfunction->get_returntype()) + ")"; + } +} + +/** + * Generates a service method header + * + * @param tfunction The service function to generate code for. + */ +void t_haxe_generator::generate_service_method_signature(t_function* tfunction, bool is_interface) { + if (callbacks_) { + generate_service_method_signature_callback(tfunction, is_interface); + } else { + generate_service_method_signature_normal(tfunction, is_interface); + } +} + +/** + * Generates a service method header in "normal" style + * + * @param tfunction The service function to generate code for. + */ +void t_haxe_generator::generate_service_method_signature_normal(t_function* tfunction, + bool is_interface) { + if (is_interface) { + indent(f_service_) << function_signature_normal(tfunction) << ";" << endl << endl; + } else { + indent(f_service_) << "public " << function_signature_normal(tfunction) << " {" << endl; + } +} + +/** + * Generates a service method header in "callback" style + * + * @param tfunction The service function to generate code for. + */ +void t_haxe_generator::generate_service_method_signature_callback(t_function* tfunction, + bool is_interface) { + if (!tfunction->is_oneway()) { + std::string on_success_impl = generate_service_method_onsuccess(tfunction, false, false); + indent(f_service_) << "// function onError(Dynamic) : Void;" << endl; + indent(f_service_) << "// function " << on_success_impl.c_str() << ";" << endl; + } + + if (is_interface) { + indent(f_service_) << function_signature_callback(tfunction) << ";" << endl << endl; + } else { + indent(f_service_) << "public " << function_signature_callback(tfunction) << " {" << endl; + } +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_haxe_generator::generate_service_interface(t_service* tservice) { + string extends_iface = ""; + if (tservice->get_extends() != NULL) { + extends_iface = " extends " + tservice->get_extends()->get_name(); + } + + generate_haxe_doc(f_service_, tservice); + // generate_rtti_decoration(f_service_); - not yet, because of + // https://github.com/HaxeFoundation/haxe/issues/3626 + generate_macro_decoration(f_service_); + f_service_ << indent() << "interface " << get_cap_name(service_name_) << extends_iface << " {" + << endl << endl; + indent_up(); + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_haxe_doc(f_service_, *f_iter); + generate_service_method_signature(*f_iter, true); + } + indent_down(); + f_service_ << indent() << "}" << endl << endl; +} + +/** + * Generates structs for all the service args and return types + * + * @param tservice The service + */ +void t_haxe_generator::generate_service_helpers(t_service* tservice) { + f_service_ << endl << endl; + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_haxe_struct(ts, false); + generate_function_helpers(*f_iter); + } +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_haxe_generator::generate_service_client(t_service* tservice) { + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() != NULL) { + extends = get_cap_name(tservice->get_extends()->get_name()); + extends_client = " extends " + extends + "Impl"; + } + + generate_rtti_decoration(f_service_); + // build macro is inherited from interface + indent(f_service_) << "class " << get_cap_name(service_name_) << "Impl" << extends_client + << " implements " << get_cap_name(service_name_) << " {" << endl << endl; + indent_up(); + + indent(f_service_) << "public function new( iprot : TProtocol, oprot : TProtocol = null)" << endl; + scope_up(f_service_); + if (extends.empty()) { + f_service_ << indent() << "iprot_ = iprot;" << endl; + f_service_ << indent() << "if (oprot == null) {" << endl; + indent_up(); + f_service_ << indent() << "oprot_ = iprot;" << endl; + indent_down(); + f_service_ << indent() << "} else {" << endl; + indent_up(); + f_service_ << indent() << "oprot_ = oprot;" << endl; + indent_down(); + f_service_ << indent() << "}" << endl; + } else { + f_service_ << indent() << "super(iprot, oprot);" << endl; + } + scope_down(f_service_); + f_service_ << endl; + + if (extends.empty()) { + f_service_ << indent() << "private var iprot_ : TProtocol;" << endl << indent() + << "private var oprot_ : TProtocol;" << endl << indent() + << "private var seqid_ : Int;" << endl << endl; + + indent(f_service_) << "public function getInputProtocol() : TProtocol" << endl; + scope_up(f_service_); + indent(f_service_) << "return this.iprot_;" << endl; + scope_down(f_service_); + f_service_ << endl; + + indent(f_service_) << "public function getOutputProtocol() : TProtocol" << endl; + scope_up(f_service_); + indent(f_service_) << "return this.oprot_;" << endl; + scope_down(f_service_); + f_service_ << endl; + } + + // Generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string funname = (*f_iter)->get_name(); + + // Open function + generate_service_method_signature(*f_iter, false); + + indent_up(); + + // Get the struct of function call params + t_struct* arg_struct = (*f_iter)->get_arglist(); + + string argsname = get_cap_name((*f_iter)->get_name() + "_args"); + vector::const_iterator fld_iter; + const vector& fields = arg_struct->get_members(); + + // Serialize the request + string calltype = (*f_iter)->is_oneway() ? "ONEWAY" : "CALL"; + f_service_ << indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname + << "\", TMessageType." << calltype << ", seqid_));" << endl << indent() + << "var args : " << argsname << " = new " << argsname << "();" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << indent() << "args." << (*fld_iter)->get_name() << " = " + << (*fld_iter)->get_name() << ";" << endl; + } + + f_service_ << indent() << "args.write(oprot_);" << endl << indent() + << "oprot_.writeMessageEnd();" << endl; + + if (!((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) { + f_service_ << indent() << "var retval : " << type_name((*f_iter)->get_returntype()) << ";" + << endl; + } + + if ((*f_iter)->is_oneway()) { + f_service_ << indent() << "oprot_.getTransport().flush();" << endl; + } else { + indent(f_service_) << "oprot_.getTransport().flush(function(error:Dynamic) : Void {" << endl; + indent_up(); + if (callbacks_) { + indent(f_service_) << "try {" << endl; + indent_up(); + } + string resultname = get_cap_name((*f_iter)->get_name() + "_result"); + indent(f_service_) << "if (error != null) {" << endl; + indent_up(); + if (callbacks_) { + indent(f_service_) << "if (onError != null) onError(error);" << endl; + indent(f_service_) << "return;" << endl; + } else { + indent(f_service_) << "throw error;" << endl; + } + indent_down(); + indent(f_service_) << "}" << endl; + indent(f_service_) << "var msg : TMessage = iprot_.readMessageBegin();" << endl; + indent(f_service_) << "if (msg.type == TMessageType.EXCEPTION) {" << endl; + indent_up(); + indent(f_service_) << "var x = TApplicationException.read(iprot_);" << endl; + indent(f_service_) << "iprot_.readMessageEnd();" << endl; + if (callbacks_) { + indent(f_service_) << "if (onError != null) onError(x);" << endl; + indent(f_service_) << "return;" << endl; + } else { + indent(f_service_) << "throw x;" << endl; + } + indent_down(); + indent(f_service_) << "}" << endl; + indent(f_service_) << "var result : " << resultname << " = new " << resultname << "();" + << endl; + indent(f_service_) << "result.read(iprot_);" << endl; + indent(f_service_) << "iprot_.readMessageEnd();" << endl; + + // Careful, only return _result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << "if (result." << generate_isset_check("success") << ") {" << endl; + indent_up(); + if (callbacks_) { + indent(f_service_) << "if (onSuccess != null) onSuccess(result.success);" << endl; + indent(f_service_) << "return;" << endl; + } else { + indent(f_service_) << "retval = result.success;" << endl; + indent(f_service_) << "return;" << endl; + } + indent_down(); + indent(f_service_) << "}" << endl; + } + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + indent(f_service_) << "if (result." << (*x_iter)->get_name() << " != null) {" << endl; + indent_up(); + if (callbacks_) { + indent(f_service_) << "if (onError != null) onError(result." << (*x_iter)->get_name() + << ");" << endl; + indent(f_service_) << "return;" << endl; + } else { + indent(f_service_) << "throw result." << (*x_iter)->get_name() << ";" << endl; + } + indent_down(); + indent(f_service_) << "}" << endl; + } + + // If you get here it's an exception, unless a void function + if ((*f_iter)->get_returntype()->is_void()) { + if (callbacks_) { + indent(f_service_) << "if (onSuccess != null) onSuccess();" << endl; + } + indent(f_service_) << "return;" << endl; + } else { + if (callbacks_) { + indent(f_service_) << "if (onError != null)" << endl; + indent_up(); + indent(f_service_) + << "onError( new TApplicationException(TApplicationException.MISSING_RESULT," << endl; + indent(f_service_) << " \"" << (*f_iter)->get_name() + << " failed: unknown result\"));" << endl; + indent_down(); + } else { + indent(f_service_) + << "throw new TApplicationException(TApplicationException.MISSING_RESULT," << endl; + indent(f_service_) << " \"" << (*f_iter)->get_name() + << " failed: unknown result\");" << endl; + } + } + + if (callbacks_) { + indent_down(); + indent(f_service_) << "} catch( e : TException) {" << endl; + indent_up(); + indent(f_service_) << "if (onError != null) onError(e);" << endl; + indent_down(); + indent(f_service_) << "}" << endl; + } + + indent_down(); + indent(f_service_) << "});" << endl; + } + + if (!((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) { + f_service_ << indent() << "return retval;" << endl; + } + + // Close function + scope_down(f_service_); + f_service_ << endl; + } + + indent_down(); + indent(f_service_) << "}" << endl; +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_haxe_generator::generate_service_server(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + // Extends stuff + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() != NULL) { + extends = get_cap_name(type_name(tservice->get_extends())); + extends_processor = " extends " + extends + "Processor"; + } + + // Generate the header portion + generate_rtti_decoration(f_service_); + generate_macro_decoration(f_service_); + indent(f_service_) << "class " << get_cap_name(service_name_) << "Processor" << extends_processor + << " implements TProcessor {" << endl << endl; + indent_up(); + + f_service_ << indent() << "private var " << get_cap_name(service_name_) + << "_iface_ : " << get_cap_name(service_name_) << ";" << endl; + + if (extends.empty()) { + f_service_ << indent() + << "private var PROCESS_MAP = new StringMap< Int->TProtocol->TProtocol->Void >();" + << endl; + } + + f_service_ << endl; + + indent(f_service_) << "public function new( iface : " << get_cap_name(service_name_) << ")" + << endl; + scope_up(f_service_); + if (!extends.empty()) { + f_service_ << indent() << "super(iface);" << endl; + } + f_service_ << indent() << get_cap_name(service_name_) << "_iface_ = iface;" << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << indent() << "PROCESS_MAP.set(\"" << (*f_iter)->get_name() << "\", " + << (*f_iter)->get_name() << "());" << endl; + } + + scope_down(f_service_); + f_service_ << endl; + + // Generate the server implementation + string override = ""; + if (tservice->get_extends() != NULL) { + override = "override "; + } + indent(f_service_) << override + << "public function process( iprot : TProtocol, oprot : TProtocol) : Bool" + << endl; + scope_up(f_service_); + + f_service_ << indent() << "var msg : TMessage = iprot.readMessageBegin();" << endl; + + // TODO(mcslee): validate message, was the seqid etc. legit? + // AS- If all method is oneway: + // do you have an oprot? + // do you you need nullcheck? + f_service_ + << indent() << "var fn = PROCESS_MAP.get(msg.name);" << endl << indent() + << "if (fn == null) {" << endl << indent() << " TProtocolUtil.skip(iprot, TType.STRUCT);" + << endl << indent() << " iprot.readMessageEnd();" << endl << indent() + << " var x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, \"Invalid " + "method name: '\"+msg.name+\"'\");" << endl << indent() + << " oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" + << endl << indent() << " x.write(oprot);" << endl << indent() << " oprot.writeMessageEnd();" + << endl << indent() << " oprot.getTransport().flush();" << endl << indent() + << " return true;" << endl << indent() << "}" << endl << indent() + << "fn( msg.seqid, iprot, oprot);" << endl; + + f_service_ << indent() << "return true;" << endl; + + scope_down(f_service_); + f_service_ << endl; + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(tservice, *f_iter); + } + + indent_down(); + indent(f_service_) << "}" << endl << endl; +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_haxe_generator::generate_function_helpers(t_function* tfunction) { + if (tfunction->is_oneway()) { + return; + } + + string resultname = get_cap_name(tfunction->get_name() + "_result"); + t_struct result(program_, resultname); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + generate_haxe_struct(&result, false, true); +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_haxe_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + (void)tservice; + // Open class + indent(f_service_) << "private function " << tfunction->get_name() + << "() : Int->TProtocol->TProtocol->Void {" << endl; + indent_up(); + + // Open function + indent(f_service_) << "return function( seqid : Int, iprot : TProtocol, oprot : TProtocol) : Void" + << endl; + scope_up(f_service_); + + string argsname = get_cap_name(tfunction->get_name() + "_args"); + string resultname = get_cap_name(tfunction->get_name() + "_result"); + + f_service_ << indent() << "var args : " << argsname << " = new " << argsname << "();" << endl + << indent() << "args.read(iprot);" << endl << indent() << "iprot.readMessageEnd();" + << endl; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + // Declare result for non oneway function + if (!tfunction->is_oneway()) { + f_service_ << indent() << "var result : " << resultname << " = new " << resultname << "();" + << endl; + } + + // Try block for any function to catch (defined or undefined) exceptions + f_service_ << indent() << "try {" << endl; + indent_up(); + + if (callbacks_) { + // callback function style onError/onSuccess + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + f_service_ << indent(); + f_service_ << get_cap_name(service_name_) << "_iface_." << tfunction->get_name() << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "args." << (*f_iter)->get_name(); + } + + if (tfunction->is_oneway()) { + f_service_ << ");" << endl; + } else { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + string on_success = generate_service_method_onsuccess(tfunction, false, true); + indent_up(); + f_service_ << endl; + indent(f_service_) << "null, // errors are thrown by the handler" << endl; + if (tfunction->get_returntype()->is_void()) { + indent(f_service_) << "null); // no retval" << endl; + } else { + indent(f_service_) << "function" << on_success.c_str() << " {" << endl; + if (!tfunction->get_returntype()->is_void()) { + indent_up(); + indent(f_service_) << "result.success = retval;" << endl; + indent_down(); + } + indent(f_service_) << "});" << endl; + } + indent_down(); + } + + } else { + // normal function():result style + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + f_service_ << indent(); + if (!(tfunction->is_oneway() || tfunction->get_returntype()->is_void())) { + f_service_ << "result.success = "; + } + f_service_ << get_cap_name(service_name_) << "_iface_." << tfunction->get_name() << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "args." << (*f_iter)->get_name(); + } + f_service_ << ");" << endl; + } + + indent_down(); + f_service_ << indent() << "}"; + if (!tfunction->is_oneway()) { + // catch exceptions defined in the IDL + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << " catch (" << (*x_iter)->get_name() << ":" + << get_cap_name(type_name((*x_iter)->get_type(), false, false)) << ") {" << endl; + if (!tfunction->is_oneway()) { + indent_up(); + f_service_ << indent() << "result." << (*x_iter)->get_name() << " = " + << (*x_iter)->get_name() << ";" << endl; + indent_down(); + f_service_ << indent() << "}"; + } else { + f_service_ << "}"; + } + } + } + + // always catch all exceptions to prevent from service denial + f_service_ << " catch (th : Dynamic) {" << endl; + indent_up(); + indent(f_service_) << "trace(\"Internal error processing " << tfunction->get_name() << "\", th);" + << endl; + if (!tfunction->is_oneway()) { + indent(f_service_) << "var x = new TApplicationException(TApplicationException.INTERNAL_ERROR, " + "\"Internal error processing " << tfunction->get_name() << "\");" << endl; + indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() + << "\", TMessageType.EXCEPTION, seqid));" << endl; + indent(f_service_) << "x.write(oprot);" << endl; + indent(f_service_) << "oprot.writeMessageEnd();" << endl; + indent(f_service_) << "oprot.getTransport().flush();" << endl; + } + indent(f_service_) << "return;" << endl; + indent_down(); + f_service_ << indent() << "}" << endl; + + // Shortcut out here for oneway functions + if (tfunction->is_oneway()) { + f_service_ << indent() << "return;" << endl; + scope_down(f_service_); + + // Close class + indent_down(); + f_service_ << indent() << "}" << endl << endl; + return; + } + + f_service_ << indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() + << "\", TMessageType.REPLY, seqid));" << endl << indent() << "result.write(oprot);" + << endl << indent() << "oprot.writeMessageEnd();" << endl << indent() + << "oprot.getTransport().flush();" << endl; + + // Close function + scope_down(f_service_); + f_service_ << endl; + + // Close class + indent_down(); + f_service_ << indent() << "}" << endl << endl; +} + +/** + * Deserializes a field of any type. + * + * @param tfield The field + * @param prefix The variable name or container for this field + */ +void t_haxe_generator::generate_deserialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = prefix + tfield->get_name(); + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name); + } else if (type->is_container()) { + generate_deserialize_container(out, type, name); + } else if (type->is_base_type() || type->is_enum()) { + + indent(out) << name << " = iprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "readBinary();"; + } else { + out << "readString();"; + } + break; + case t_base_type::TYPE_BOOL: + out << "readBool();"; + break; + case t_base_type::TYPE_I8: + out << "readByte();"; + break; + case t_base_type::TYPE_I16: + out << "readI16();"; + break; + case t_base_type::TYPE_I32: + out << "readI32();"; + break; + case t_base_type::TYPE_I64: + out << "readI64();"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble();"; + break; + default: + throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "readI32();"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +/** + * Generates an unserializer for a struct, invokes read() + */ +void t_haxe_generator::generate_deserialize_struct(ofstream& out, + t_struct* tstruct, + string prefix) { + out << indent() << prefix << " = new " << get_cap_name(type_name(tstruct)) << "();" << endl + << indent() << prefix << ".read(iprot);" << endl; +} + +/** + * Deserializes a container by reading its size and then iterating + */ +void t_haxe_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) { + scope_up(out); + + string obj; + + if (ttype->is_map()) { + obj = tmp("_map"); + } else if (ttype->is_set()) { + obj = tmp("_set"); + } else if (ttype->is_list()) { + obj = tmp("_list"); + } + + // Declare variables, read header + if (ttype->is_map()) { + indent(out) << "var " << obj << " = iprot.readMapBegin();" << endl; + } else if (ttype->is_set()) { + indent(out) << "var " << obj << " = iprot.readSetBegin();" << endl; + } else if (ttype->is_list()) { + indent(out) << "var " << obj << " = iprot.readListBegin();" << endl; + } + + indent(out) << prefix << " = new " << type_name(ttype, false, true) + // size the collection correctly + << "(" + << ");" << endl; + + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << "for( " << i << " in 0 ... " << obj << ".size)" << endl; + + scope_up(out); + + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, prefix); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, prefix); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, prefix); + } + + scope_down(out); + + // Read container end + if (ttype->is_map()) { + indent(out) << "iprot.readMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "iprot.readSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "iprot.readListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Generates code to deserialize a map + */ +void t_haxe_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) { + string key = tmp("_key"); + string val = tmp("_val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + indent(out) << declare_field(&fkey) << endl; + indent(out) << declare_field(&fval) << endl; + + generate_deserialize_field(out, &fkey); + generate_deserialize_field(out, &fval); + + indent(out) << prefix << ".set( " << key << ", " << val << ");" << endl; +} + +/** + * Deserializes a set element + */ +void t_haxe_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) { + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); + + indent(out) << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".add(" << elem << ");" << endl; +} + +/** + * Deserializes a list element + */ +void t_haxe_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix) { + string elem = tmp("_elem"); + t_field felem(tlist->get_elem_type(), elem); + + indent(out) << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".add(" << elem << ");" << endl; +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_haxe_generator::generate_serialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = get_true_type(tfield->get_type()); + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); + } else if (type->is_container()) { + generate_serialize_container(out, type, prefix + tfield->get_name()); + } else if (type->is_base_type() || type->is_enum()) { + + string name = prefix + tfield->get_name(); + indent(out) << "oprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "writeBinary(" << name << ");"; + } else { + out << "writeString(" << name << ");"; + } + break; + case t_base_type::TYPE_BOOL: + out << "writeBool(" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "writeByte(" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "writeI16(" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "writeI32(" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "writeI64(" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble(" << name << ");"; + break; + default: + throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "writeI32(" << name << ");"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", + prefix.c_str(), + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_haxe_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + (void)tstruct; + out << indent() << prefix << ".write(oprot);" << endl; +} + +/** + * Serializes a container by writing its size then the elements. + * + * @param ttype The type of container + * @param prefix String prefix for fields + */ +void t_haxe_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + scope_up(out); + + if (ttype->is_map()) { + string iter = tmp("_key"); + string counter = tmp("_sizeCounter"); + indent(out) << "var " << counter << " : Int = 0;" << endl; + indent(out) << "for( " << iter << " in " << prefix << ") {" << endl; + indent(out) << " " << counter << +"++;" << endl; + indent(out) << "}" << endl; + + indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type()) + << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << counter << "));" + << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type()) + << ", " << prefix << ".size));" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.writeListBegin(new TList(" + << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".length));" + << endl; + } + + string iter = tmp("elem"); + if (ttype->is_map()) { + indent(out) << "for( " << iter << " in " << prefix << ".keys())" << endl; + } else if (ttype->is_set()) { + indent(out) << "for( " << iter << " in " << prefix << ".toArray())" << endl; + } else if (ttype->is_list()) { + indent(out) << "for( " << iter << " in " << prefix << ")" << endl; + } + + scope_up(out); + + if (ttype->is_map()) { + generate_serialize_map_element(out, (t_map*)ttype, iter, prefix); + } else if (ttype->is_set()) { + generate_serialize_set_element(out, (t_set*)ttype, iter); + } else if (ttype->is_list()) { + generate_serialize_list_element(out, (t_list*)ttype, iter); + } + + scope_down(out); + + if (ttype->is_map()) { + indent(out) << "oprot.writeMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.writeSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.writeListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Serializes the members of a map. + */ +void t_haxe_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string iter, + string map) { + t_field kfield(tmap->get_key_type(), iter); + generate_serialize_field(out, &kfield, ""); + t_field vfield(tmap->get_val_type(), map + ".get(" + iter + ")"); + generate_serialize_field(out, &vfield, ""); +} + +/** + * Serializes the members of a set. + */ +void t_haxe_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) { + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +/** + * Serializes the members of a list. + */ +void t_haxe_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) { + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +/** + * Returns a haxe type name + * + * @param ttype The type + * @param container Is the type going inside a container? + * @return haxe type name, i.e. HashMap + */ +string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_init) { + (void)in_init; + + // typedefs are just resolved to their real type + ttype = get_true_type(ttype); + string prefix; + + if (ttype->is_base_type()) { + return base_type_name((t_base_type*)ttype, in_container); + } + + if (ttype->is_enum()) { + return "Int"; + } + + if (ttype->is_map()) { + t_type* tkey = get_true_type(((t_map*)ttype)->get_key_type()); + t_type* tval = get_true_type(((t_map*)ttype)->get_val_type()); + if (tkey->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)tkey)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + if (!(tkey->is_binary())) { + return "StringMap< " + type_name(tval) + ">"; + } + break; // default to ObjectMap<> + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + return "IntMap< " + type_name(tval) + ">"; + case t_base_type::TYPE_I64: + return "Int64Map< " + type_name(tval) + ">"; + default: + break; // default to ObjectMap<> + } + } + if (tkey->is_enum()) { + return "IntMap< " + type_name(tval) + ">"; + } + return "ObjectMap< " + type_name(tkey) + ", " + type_name(tval) + ">"; + } + + if (ttype->is_set()) { + t_type* tkey = get_true_type(((t_set*)ttype)->get_elem_type()); + if (tkey->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)tkey)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + if (!(tkey->is_binary())) { + return "StringSet"; + } + break; // default to ObjectSet + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + return "IntSet"; + case t_base_type::TYPE_I64: + return "Int64Set"; + default: + break; // default to ObjectSet + } + } + if (tkey->is_enum()) { + return "IntSet"; + } + return "ObjectSet< " + type_name(tkey) + ">"; + } + + if (ttype->is_list()) { + t_type* telm = ((t_list*)ttype)->get_elem_type(); + return "List< " + type_name(telm) + ">"; + } + + // Check for namespacing + t_program* program = ttype->get_program(); + if (program != NULL && program != program_) { + string package = program->get_namespace("haxe"); + if (!package.empty()) { + return package + "." + ttype->get_name(); + } + } + + return ttype->get_name(); +} + +/** + * Returns the haxe type that corresponds to the thrift type. + * + * @param tbase The base type + * @param container Is it going in a haxe container? + */ +string t_haxe_generator::base_type_name(t_base_type* type, bool in_container) { + (void)in_container; + t_base_type::t_base tbase = type->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + return "Void"; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + return "haxe.io.Bytes"; + } else { + return "String"; + } + case t_base_type::TYPE_BOOL: + return "Bool"; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + return "haxe.Int32"; + case t_base_type::TYPE_I64: + return "haxe.Int64"; + case t_base_type::TYPE_DOUBLE: + return "Float"; + default: + throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase); + } +} + +/** + * Declares a field, which may include initialization as necessary. + * + * @param ttype The type + */ +string t_haxe_generator::declare_field(t_field* tfield, bool init) { + // TODO(mcslee): do we ever need to initialize the field? + string result = "var " + tfield->get_name() + " : " + type_name(tfield->get_type()); + if (init) { + t_type* ttype = get_true_type(tfield->get_type()); + if (ttype->is_base_type() && tfield->get_value() != NULL) { + ofstream dummy; + result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value()); + } else if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + result += " = null"; + break; + case t_base_type::TYPE_BOOL: + result += " = false"; + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + result += " = 0"; + break; + case t_base_type::TYPE_DOUBLE: + result += " = (double)0"; + break; + } + + } else if (ttype->is_enum()) { + result += " = 0"; + } else if (ttype->is_container()) { + result += " = new " + type_name(ttype, false, true) + "()"; + } else { + result += " = new " + type_name(ttype, false, true) + "()"; + } + } + return result + ";"; +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_haxe_generator::function_signature_callback(t_function* tfunction) { + std::string on_error_success = "onError : Dynamic->Void = null, " + + generate_service_method_onsuccess(tfunction, true, false); + + std::string arguments = argument_list(tfunction->get_arglist()); + if (!tfunction->is_oneway()) { + if (arguments != "") { + arguments += ", "; + } + arguments += on_error_success; //"onError : Function, onSuccess : Function"; + } + + std::string result = "function " + tfunction->get_name() + "(" + arguments + ") : Void"; + return result; +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_haxe_generator::function_signature_normal(t_function* tfunction) { + std::string arguments = argument_list(tfunction->get_arglist()); + + std::string resulttype; + if (tfunction->is_oneway() || tfunction->get_returntype()->is_void()) { + resulttype = "Void"; + } else { + resulttype = type_name(tfunction->get_returntype()); + } + + std::string result = "function " + tfunction->get_name() + "(" + arguments + ") : " + resulttype; + return result; +} + +/** + * Renders a comma separated field list, with type names + */ +string t_haxe_generator::argument_list(t_struct* tstruct) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + result += (*f_iter)->get_name() + " : " + type_name((*f_iter)->get_type()); + } + return result; +} + +/** + * Converts the parse type to a C++ enum string for the given type. + */ +string t_haxe_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "TType.STRING"; + case t_base_type::TYPE_BOOL: + return "TType.BOOL"; + case t_base_type::TYPE_I8: + return "TType.BYTE"; + case t_base_type::TYPE_I16: + return "TType.I16"; + case t_base_type::TYPE_I32: + return "TType.I32"; + case t_base_type::TYPE_I64: + return "TType.I64"; + case t_base_type::TYPE_DOUBLE: + return "TType.DOUBLE"; + } + } else if (type->is_enum()) { + return "TType.I32"; + } else if (type->is_struct() || type->is_xception()) { + return "TType.STRUCT"; + } else if (type->is_map()) { + return "TType.MAP"; + } else if (type->is_set()) { + return "TType.SET"; + } else if (type->is_list()) { + return "TType.LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** + * Haxe class names must start with uppercase letter, but Haxe namespaces must not. + */ +std::string t_haxe_generator::get_cap_name(std::string name) { + if (name.length() == 0) { + return name; + } + + // test.for.Generic< data.Type, or.the.Like> and handle it recursively + size_t generic_first = name.find('<'); + size_t generic_last = name.rfind('>'); + if ((generic_first != std::string::npos) && (generic_last != std::string::npos)) { + string outer_type = name.substr(0, generic_first); + string inner_types = name.substr(generic_first + 1, generic_last - generic_first - 1); + + string new_inner = ""; + size_t comma_start = 0; + while (comma_start < inner_types.length()) { + size_t comma_pos = comma_start; + int nested = 0; + + while (comma_pos < inner_types.length()) { + bool found = false; + switch (inner_types[comma_pos]) { + case '<': + ++nested; + break; + case '>': + --nested; + break; + case ',': + found = (nested == 0); + break; + } + if (found) { + break; + } + ++comma_pos; + } + + if (new_inner.length() > 0) { + new_inner += ","; + } + + string inner = inner_types.substr(comma_start, comma_pos - comma_start); + new_inner += get_cap_name(inner); + comma_start = ++comma_pos; + } + + return get_cap_name(outer_type) + "<" + new_inner + ">"; + } + + // package name + size_t index = name.find_first_not_of(" \n\r\t"); + if (index < name.length()) { + name[index] = tolower(name[index]); + index = name.find('.'); + while (index != std::string::npos) { + if (++index < name.length()) { + name[index] = tolower(name[index]); + } + index = name.find('.', index); + } + } + + // class name + index = name.rfind('.'); + if (index != std::string::npos) { + ++index; + } else { + index = name.find_first_not_of(" \n\r\t"); + } + + if (index < name.length()) { + name[index] = toupper(name[index]); + } + + return name; +} + +string t_haxe_generator::constant_name(string name) { + string constant_name; + + bool is_first = true; + bool was_previous_char_upper = false; + for (string::iterator iter = name.begin(); iter != name.end(); ++iter) { + string::value_type character = (*iter); + + bool is_upper = isupper(character); + + if (is_upper && !is_first && !was_previous_char_upper) { + constant_name += '_'; + } + constant_name += toupper(character); + + is_first = false; + was_previous_char_upper = is_upper; + } + + return constant_name; +} + +/** + * Enables RTTI for a class or interface + */ +void t_haxe_generator::generate_rtti_decoration(ofstream& out) { + if (rtti_) { + out << "@:rtti" << endl; + } +} + +/** + * Adds build macros to a class or interface + */ +void t_haxe_generator::generate_macro_decoration(ofstream& out) { + if (!buildmacro_.empty()) { + out << "#if ! macro" << endl; + out << "@:build( " << buildmacro_ << ")" << endl; // current class/interface + out << "@:autoBuild( " << buildmacro_ << ")" << endl; // inherited classes/interfaces + out << "#end" << endl; + } +} + +/** + * Emits a haxeDoc comment if the provided object has a doc in Thrift + */ +void t_haxe_generator::generate_haxe_doc(ofstream& out, t_doc* tdoc) { + if (tdoc->has_doc()) { + generate_docstring_comment(out, "/**\n", " * ", tdoc->get_doc(), " */\n"); + } +} + +/** + * Emits a haxeDoc comment if the provided function object has a doc in Thrift + */ +void t_haxe_generator::generate_haxe_doc(ofstream& out, t_function* tfunction) { + if (tfunction->has_doc()) { + stringstream ss; + ss << tfunction->get_doc(); + const vector& fields = tfunction->get_arglist()->get_members(); + vector::const_iterator p_iter; + for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { + t_field* p = *p_iter; + ss << "\n@param " << p->get_name(); + if (p->has_doc()) { + ss << " " << p->get_doc(); + } + } + generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n"); + } +} + +std::string t_haxe_generator::generate_isset_check(t_field* field) { + return generate_isset_check(field->get_name()); +} + +std::string t_haxe_generator::generate_isset_check(std::string field_name) { + return "is" + get_cap_name("set") + get_cap_name(field_name) + "()"; +} + +void t_haxe_generator::generate_isset_set(ofstream& out, t_field* field) { + if (!type_can_be_null(field->get_type())) { + indent(out) << "this.__isset_" << field->get_name() << " = true;" << endl; + } +} + +std::string t_haxe_generator::get_enum_class_name(t_type* type) { + string package = ""; + t_program* program = type->get_program(); + if (program != NULL /*&& program != program_*/) { + package = program->get_namespace("haxe") + "."; + } + return package + type->get_name(); +} + +THRIFT_REGISTER_GENERATOR( + haxe, + "Haxe", + " callbacks Use onError()/onSuccess() callbacks for service methods (like AS3)\n" + " rtti Enable @:rtti for generated classes and interfaces\n" + " buildmacro=my.macros.Class.method(args)\n" + " Add @:build macro calls to generated classes and interfaces\n") diff --git a/compiler/cpp/src/thrift/generate/t_hs_generator.cc b/compiler/cpp/src/thrift/generate/t_hs_generator.cc new file mode 100644 index 0000000..d0a8cb2 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_hs_generator.cc @@ -0,0 +1,1732 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "thrift/platform.h" +#include "thrift/version.h" + +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * Haskell code generator. + * + */ +class t_hs_generator : public t_oop_generator { +public: + t_hs_generator(t_program* program, + const map& parsed_options, + const string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + /* no options yet */ + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + throw "unknown option hs:" + iter->first; + } + + out_dir_base_ = "gen-hs"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + string render_const_value(t_type* type, t_const_value* value); + + /** + * Struct generation code + */ + + void generate_hs_struct(t_struct* tstruct, bool is_exception); + + void generate_hs_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_xception = false, + bool helper = false); + + void generate_hs_struct_reader(ofstream& out, t_struct* tstruct); + + void generate_hs_struct_writer(ofstream& out, t_struct* tstruct); + + void generate_hs_struct_arbitrary(ofstream& out, t_struct* tstruct); + + void generate_hs_function_helpers(t_function* tfunction); + + void generate_hs_typemap(ofstream& out, t_struct* tstruct); + + void generate_hs_default(ofstream& out, t_struct* tstruct); + + /** + * Service-level generation functions + */ + + void generate_service_helpers(t_service* tservice); + void generate_service_interface(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* tfunction); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(ofstream& out, t_field* tfield, string prefix); + + void generate_deserialize_struct(ofstream& out, t_struct* tstruct, string name = ""); + + void generate_deserialize_container(ofstream& out, t_type* ttype, string arg = ""); + + void generate_deserialize_set_element(ofstream& out, t_set* tset); + + void generate_deserialize_list_element(ofstream& out, t_list* tlist, string prefix = ""); + + void generate_deserialize_type(ofstream& out, t_type* type, string arg = ""); + + void generate_serialize_type(ofstream& out, t_type* type, string name = ""); + + void generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix = ""); + + void generate_serialize_container(ofstream& out, t_type* ttype, string prefix = ""); + + void generate_serialize_map_element(ofstream& out, t_map* tmap, string kiter, string viter); + + void generate_serialize_set_element(ofstream& out, t_set* tmap, string iter); + + void generate_serialize_list_element(ofstream& out, t_list* tlist, string iter); + + /** + * Helper rendering functions + */ + + string hs_autogen_comment(); + string hs_language_pragma(); + string hs_imports(); + + string type_name(t_type* ttype, string function_prefix = ""); + + string field_name(string tname, string fname); + + string function_type(t_function* tfunc, + bool options = false, + bool io = false, + bool method = false); + + string type_to_enum(t_type* ttype); + + string type_to_default(t_type* ttype); + + string render_hs_type(t_type* type, bool needs_parens); + + string type_to_constructor(t_type* ttype); + + string render_hs_type_for_function_name(t_type* type); + +private: + ofstream f_types_; + ofstream f_consts_; + ofstream f_service_; + ofstream f_iface_; + ofstream f_client_; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_hs_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + + // Make output file + string pname = capitalize(program_name_); + string f_types_name = get_out_dir() + pname + "_Types.hs"; + f_types_.open(f_types_name.c_str()); + + string f_consts_name = get_out_dir() + pname + "_Consts.hs"; + f_consts_.open(f_consts_name.c_str()); + + // Print header + f_types_ << hs_language_pragma() << endl; + f_types_ << hs_autogen_comment() << endl; + f_types_ << "module " << pname << "_Types where" << endl; + f_types_ << hs_imports() << endl; + + f_consts_ << hs_language_pragma() << endl; + f_consts_ << hs_autogen_comment() << endl; + f_consts_ << "module " << pname << "_Consts where" << endl; + f_consts_ << hs_imports() << endl; + f_consts_ << "import " << pname << "_Types" << endl; +} + +string t_hs_generator::hs_language_pragma() { + return string( + "{-# LANGUAGE DeriveDataTypeable #-}\n" + "{-# LANGUAGE DeriveGeneric #-}\n" + "{-# LANGUAGE OverloadedStrings #-}\n" + "{-# OPTIONS_GHC -fno-warn-missing-fields #-}\n" + "{-# OPTIONS_GHC -fno-warn-missing-signatures #-}\n" + "{-# OPTIONS_GHC -fno-warn-name-shadowing #-}\n" + "{-# OPTIONS_GHC -fno-warn-unused-imports #-}\n" + "{-# OPTIONS_GHC -fno-warn-unused-matches #-}\n"); +} + +/** + * Autogen'd comment + */ +string t_hs_generator::hs_autogen_comment() { + return string("-----------------------------------------------------------------\n") + + "-- Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ") --\n" + + "-- --\n" + + "-- DO NOT EDIT UNLESS YOU ARE SURE YOU KNOW WHAT YOU ARE DOING --\n" + + "-----------------------------------------------------------------\n"; +} + +/** + * Prints standard thrift imports + */ +string t_hs_generator::hs_imports() { + const vector& includes = program_->get_includes(); + string result = string( + "import Prelude (($), (.), (>>=), (==), (++))\n" + "import qualified Prelude as P\n" + "import qualified Control.Exception as X\n" + "import qualified Control.Monad as M ( liftM, ap, when )\n" + "import Data.Functor ( (<$>) )\n" + "import qualified Data.ByteString.Lazy as LBS\n" + "import qualified Data.Hashable as H\n" + "import qualified Data.Int as I\n" + "import qualified Data.Maybe as M (catMaybes)\n" + "import qualified Data.Text.Lazy.Encoding as E ( decodeUtf8, encodeUtf8 )\n" + "import qualified Data.Text.Lazy as LT\n" + "import qualified GHC.Generics as G (Generic)\n" + "import qualified Data.Typeable as TY ( Typeable )\n" + "import qualified Data.HashMap.Strict as Map\n" + "import qualified Data.HashSet as Set\n" + "import qualified Data.Vector as Vector\n" + "import qualified Test.QuickCheck.Arbitrary as QC ( Arbitrary(..) )\n" + "import qualified Test.QuickCheck as QC ( elements )\n" + "\n" + "import qualified Thrift as T\n" + "import qualified Thrift.Types as T\n" + "import qualified Thrift.Arbitraries as T\n" + "\n"); + + for (size_t i = 0; i < includes.size(); ++i) + result += "import qualified " + capitalize(includes[i]->get_name()) + "_Types\n"; + + if (includes.size() > 0) + result += "\n"; + + return result; +} + +/** + * Closes the type files + */ +void t_hs_generator::close_generator() { + // Close types file + f_types_.close(); + f_consts_.close(); +} + +/** + * Generates a typedef. Ez. + * + * @param ttypedef The type definition + */ +void t_hs_generator::generate_typedef(t_typedef* ttypedef) { + string tname = capitalize(ttypedef->get_symbolic()); + string tdef = render_hs_type(ttypedef->get_type(), false); + indent(f_types_) << "type " << tname << " = " << tdef << endl; + f_types_ << endl; +} + +/** + * Generates code for an enumerated type. + * the values. + * + * @param tenum The enumeration + */ +void t_hs_generator::generate_enum(t_enum* tenum) { + indent(f_types_) << "data " << capitalize(tenum->get_name()) << " = "; + indent_up(); + vector constants = tenum->get_constants(); + vector::iterator c_iter; + + bool first = true; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + string name = capitalize((*c_iter)->get_name()); + f_types_ << (first ? "" : "|"); + f_types_ << name; + first = false; + } + indent(f_types_) << "deriving (P.Show, P.Eq, G.Generic, TY.Typeable, P.Ord, P.Bounded)" << endl; + indent_down(); + + string ename = capitalize(tenum->get_name()); + + indent(f_types_) << "instance P.Enum " << ename << " where" << endl; + indent_up(); + indent(f_types_) << "fromEnum t = case t of" << endl; + indent_up(); + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + string name = capitalize((*c_iter)->get_name()); + indent(f_types_) << name << " -> " << value << endl; + } + indent_down(); + indent(f_types_) << "toEnum t = case t of" << endl; + indent_up(); + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + string name = capitalize((*c_iter)->get_name()); + indent(f_types_) << value << " -> " << name << endl; + } + indent(f_types_) << "_ -> X.throw T.ThriftException" << endl; + indent_down(); + indent_down(); + + indent(f_types_) << "instance H.Hashable " << ename << " where" << endl; + indent_up(); + indent(f_types_) << "hashWithSalt salt = H.hashWithSalt salt P.. P.fromEnum" << endl; + indent_down(); + + indent(f_types_) << "instance QC.Arbitrary " << ename << " where" << endl; + indent_up(); + indent(f_types_) << "arbitrary = QC.elements (P.enumFromTo P.minBound P.maxBound)" << endl; + indent_down(); +} + +/** + * Generate a constant value + */ +void t_hs_generator::generate_const(t_const* tconst) { + t_type* type = tconst->get_type(); + string name = decapitalize(tconst->get_name()); + + t_const_value* value = tconst->get_value(); + + indent(f_consts_) << name << " :: " << render_hs_type(type, false) << endl; + indent(f_consts_) << name << " = " << render_const_value(type, value) << endl; + f_consts_ << endl; +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +string t_hs_generator::render_const_value(t_type* type, t_const_value* value) { + if (value == NULL) + return type_to_default(type); + + type = get_true_type(type); + ostringstream out; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + + case t_base_type::TYPE_STRING: + out << '"' << get_escaped_string(value) << '"'; + break; + + case t_base_type::TYPE_BOOL: + out << (value->get_integer() > 0 ? "P.True" : "P.False"); + break; + + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + out << "(" << value->get_integer() << ")"; + break; + + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + out << "(" << value->get_integer() << ")"; + } else { + out << "(" << value->get_double() << ")"; + } + break; + + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + + } else if (type->is_enum()) { + t_enum* tenum = (t_enum*)type; + vector constants = tenum->get_constants(); + for (vector::iterator c_iter = constants.begin(); c_iter != constants.end(); + ++c_iter) { + int val = (*c_iter)->get_value(); + if (val == value->get_integer()) { + t_program* prog = type->get_program(); + if (prog != NULL && prog != program_) + out << capitalize(prog->get_name()) << "_Types."; + out << capitalize((*c_iter)->get_name()); + break; + } + } + + } else if (type->is_struct() || type->is_xception()) { + string cname = type_name(type); + out << "default_" << cname << "{"; + + const vector& fields = ((t_struct*)type)->get_members(); + const map& val = value->get_map(); + + bool first = true; + for (map::const_iterator v_iter = val.begin(); + v_iter != val.end(); + ++v_iter) { + t_field* field = NULL; + + for (vector::const_iterator f_iter = fields.begin(); f_iter != fields.end(); + ++f_iter) + if ((*f_iter)->get_name() == v_iter->first->get_string()) + field = (*f_iter); + + if (field == NULL) + throw "type error: " + cname + " has no field " + v_iter->first->get_string(); + + string fname = v_iter->first->get_string(); + string const_value = render_const_value(field->get_type(), v_iter->second); + + out << (first ? "" : ", "); + out << field_name(cname, fname) << " = "; + if (field->get_req() == t_field::T_OPTIONAL || ((t_type*)field->get_type())->is_xception()) { + out << "P.Just "; + } + out << const_value; + first = false; + } + + out << "}"; + + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + + const map& val = value->get_map(); + map::const_iterator v_iter; + + out << "(Map.fromList ["; + + bool first = true; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string key = render_const_value(ktype, v_iter->first); + string val = render_const_value(vtype, v_iter->second); + out << (first ? "" : ","); + out << "(" << key << "," << val << ")"; + first = false; + } + out << "])"; + + } else if (type->is_list() || type->is_set()) { + t_type* etype = type->is_list() ? ((t_list*)type)->get_elem_type() + : ((t_set*)type)->get_elem_type(); + + const vector& val = value->get_list(); + vector::const_iterator v_iter; + + if (type->is_set()) + out << "(Set.fromList ["; + else + out << "(Vector.fromList ["; + + bool first = true; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + out << (first ? "" : ","); + out << render_const_value(etype, *v_iter); + first = false; + } + + out << "])"; + + } else { + throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); + } + + return out.str(); +} + +/** + * Generates a "struct" + */ +void t_hs_generator::generate_struct(t_struct* tstruct) { + generate_hs_struct(tstruct, false); +} + +/** + * Generates a struct definition for a thrift exception. Basically the same + * as a struct, but also has an exception declaration. + * + * @param txception The struct definition + */ +void t_hs_generator::generate_xception(t_struct* txception) { + generate_hs_struct(txception, true); +} + +/** + * Generates a Haskell struct + */ +void t_hs_generator::generate_hs_struct(t_struct* tstruct, bool is_exception) { + generate_hs_struct_definition(f_types_, tstruct, is_exception, false); +} + +/** + * Generates a struct definition for a thrift data type. + * + * @param tstruct The struct definition + */ +void t_hs_generator::generate_hs_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool helper) { + (void)helper; + string tname = type_name(tstruct); + string name = tstruct->get_name(); + const vector& members = tstruct->get_members(); + + indent(out) << "data " << tname << " = " << tname; + if (members.size() > 0) { + indent_up(); + bool first = true; + for (vector::const_iterator m_iter = members.begin(); m_iter != members.end(); + ++m_iter) { + if (first) { + indent(out) << "{ "; + first = false; + } else { + indent(out) << ", "; + } + string mname = (*m_iter)->get_name(); + out << field_name(tname, mname) << " :: "; + if ((*m_iter)->get_req() == t_field::T_OPTIONAL + || ((t_type*)(*m_iter)->get_type())->is_xception()) { + out << "P.Maybe "; + } + out << render_hs_type((*m_iter)->get_type(), true) << endl; + } + indent(out) << "}"; + indent_down(); + } + + out << " deriving (P.Show,P.Eq,G.Generic,TY.Typeable)" << endl; + + if (is_exception) + out << "instance X.Exception " << tname << endl; + + indent(out) << "instance H.Hashable " << tname << " where" << endl; + indent_up(); + indent(out) << "hashWithSalt salt record = salt"; + for (vector::const_iterator m_iter = members.begin(); m_iter != members.end(); + ++m_iter) { + string mname = (*m_iter)->get_name(); + indent(out) << " `H.hashWithSalt` " << field_name(tname, mname) << " record"; + } + indent(out) << endl; + indent_down(); + + generate_hs_struct_arbitrary(out, tstruct); + generate_hs_struct_writer(out, tstruct); + generate_hs_struct_reader(out, tstruct); + generate_hs_typemap(out, tstruct); + generate_hs_default(out, tstruct); +} + +void t_hs_generator::generate_hs_struct_arbitrary(ofstream& out, t_struct* tstruct) { + string tname = type_name(tstruct); + string name = tstruct->get_name(); + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + indent(out) << "instance QC.Arbitrary " << tname << " where " << endl; + indent_up(); + if (members.size() > 0) { + indent(out) << "arbitrary = M.liftM " << tname; + indent_up(); + indent_up(); + indent_up(); + indent_up(); + bool first = true; + for (vector::const_iterator m_iter = members.begin(); m_iter != members.end(); + ++m_iter) { + if (first) { + first = false; + out << " "; + } else { + indent(out) << "`M.ap`"; + } + out << "("; + if ((*m_iter)->get_req() == t_field::T_OPTIONAL + || ((t_type*)(*m_iter)->get_type())->is_xception()) { + out << "M.liftM P.Just "; + } + out << "QC.arbitrary)" << endl; + } + indent_down(); + indent_down(); + indent_down(); + indent_down(); + + // Shrink + indent(out) << "shrink obj | obj == default_" << tname << " = []" << endl; + indent(out) << " | P.otherwise = M.catMaybes" << endl; + indent_up(); + first = true; + for (vector::const_iterator m_iter = members.begin(); m_iter != members.end(); + ++m_iter) { + if (first) { + first = false; + indent(out) << "[ "; + } else { + indent(out) << ", "; + } + string fname = field_name(tname, (*m_iter)->get_name()); + out << "if obj == default_" << tname; + out << "{" << fname << " = " << fname << " obj} "; + out << "then P.Nothing "; + out << "else P.Just $ default_" << tname; + out << "{" << fname << " = " << fname << " obj}" << endl; + } + indent(out) << "]" << endl; + indent_down(); + } else { /* 0 == members.size() */ + indent(out) << "arbitrary = QC.elements [" << tname << "]" << endl; + } + indent_down(); +} + +/** + * Generates the read method for a struct + */ +void t_hs_generator::generate_hs_struct_reader(ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + string sname = type_name(tstruct); + string id = tmp("_id"); + string val = tmp("_val"); + + indent(out) << "to_" << sname << " :: T.ThriftVal -> " << sname << endl; + indent(out) << "to_" << sname << " (T.TStruct fields) = " << sname << "{" << endl; + indent_up(); + + bool first = true; + + // Generate deserialization code for known cases + for (vector::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + int32_t key = (*f_iter)->get_key(); + string etype = type_to_enum((*f_iter)->get_type()); + string fname = (*f_iter)->get_name(); + + if (first) { + first = false; + } else { + out << "," << endl; + } + + // Fill in Field + indent(out) << field_name(sname, fname) << " = "; + + out << "P.maybe ("; + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + out << "P.error \"Missing required field: " << fname << "\""; + } else { + if (((*f_iter)->get_req() == t_field::T_OPTIONAL + || ((t_type*)(*f_iter)->get_type())->is_xception()) && (*f_iter)->get_value() == NULL) { + out << "P.Nothing"; + } else { + out << field_name(sname, fname) << " default_" << sname; + } + } + out << ") "; + + out << "(\\(_," << val << ") -> "; + if ((*f_iter)->get_req() == t_field::T_OPTIONAL + || ((t_type*)(*f_iter)->get_type())->is_xception()) + out << "P.Just "; + generate_deserialize_field(out, *f_iter, val); + out << ")"; + out << " (Map.lookup (" << key << ") fields)"; + } + + out << endl; + indent(out) << "}" << endl; + indent_down(); + + // read + string tmap = type_name(tstruct, "typemap_"); + indent(out) << "to_" << sname << " _ = P.error \"not a struct\"" << endl; + + indent(out) << "read_" << sname << " :: T.Protocol p => p -> P.IO " << sname + << endl; + indent(out) << "read_" << sname << " iprot = to_" << sname; + out << " <$> T.readVal iprot (T.T_STRUCT " << tmap << ")" << endl; + + indent(out) << "decode_" << sname + << " :: T.StatelessProtocol p => p -> LBS.ByteString -> " << sname << endl; + indent(out) << "decode_" << sname << " iprot bs = to_" << sname << " $ "; + out << "T.deserializeVal iprot (T.T_STRUCT " << tmap << ") bs" << endl; +} + +void t_hs_generator::generate_hs_struct_writer(ofstream& out, t_struct* tstruct) { + string name = type_name(tstruct); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + string str = tmp("_str"); + string f = tmp("_f"); + string v = tmp("_v"); + + indent(out) << "from_" << name << " :: " << name << " -> T.ThriftVal" << endl; + indent(out) << "from_" << name << " record = T.TStruct $ Map.fromList "; + indent_up(); + + // Get Exceptions + bool hasExn = false; + for (vector::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (((t_type*)(*f_iter)->get_type())->is_xception()) { + hasExn = true; + break; + } + } + + bool isfirst = true; + if (hasExn) { + out << endl; + indent(out) << "(let exns = M.catMaybes "; + indent_up(); + for (vector::const_iterator f_iter = fields.begin(); f_iter != fields.end(); + ++f_iter) { + if (((t_type*)(*f_iter)->get_type())->is_xception()) { + if (isfirst) { + out << "[ "; + isfirst = false; + } else { + out << ", "; + } + string mname = (*f_iter)->get_name(); + int32_t key = (*f_iter)->get_key(); + out << "(\\" << v << " -> (" << key << ", (\"" << mname << "\","; + generate_serialize_type(out, (*f_iter)->get_type(), v); + out << "))) <$> " << field_name(name, mname) << " record"; + } + } + if (!isfirst) { + out << "]" << endl; + } + indent_down(); + indent(out) << "in if P.not (P.null exns) then exns else "; + indent_up(); + } else { + out << "$ "; + } + + out << "M.catMaybes" << endl; + // Get the Rest + isfirst = true; + for (vector::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + // Write field header + if (isfirst) { + indent(out) << "[ "; + isfirst = false; + } else { + indent(out) << ", "; + } + string mname = (*f_iter)->get_name(); + int32_t key = (*f_iter)->get_key(); + out << "(\\"; + out << v << " -> "; + if ((*f_iter)->get_req() != t_field::T_OPTIONAL + && !((t_type*)(*f_iter)->get_type())->is_xception()) { + out << "P.Just "; + } + out << "(" << key << ", (\"" << mname << "\","; + generate_serialize_type(out, (*f_iter)->get_type(), v); + out << "))) "; + if ((*f_iter)->get_req() != t_field::T_OPTIONAL + && !((t_type*)(*f_iter)->get_type())->is_xception()) { + out << "$"; + } else { + out << "<$>"; + } + out << " " << field_name(name, mname) << " record" << endl; + } + + // Write the struct map + if (isfirst) { + indent(out) << "[]" << endl; + } else { + indent(out) << "]" << endl; + } + if (hasExn) { + indent(out) << ")" << endl; + indent_down(); + } + indent_down(); + + // write + indent(out) << "write_" << name << " :: T.Protocol p => p -> " << name + << " -> P.IO ()" << endl; + indent(out) << "write_" << name << " oprot record = T.writeVal oprot $ from_"; + out << name << " record" << endl; + + // encode + indent(out) << "encode_" << name << " :: T.StatelessProtocol p => p -> " << name + << " -> LBS.ByteString" << endl; + indent(out) << "encode_" << name << " oprot record = T.serializeVal oprot $ "; + out << "from_" << name << " record" << endl; +} + +/** + * Generates a thrift service. + * + * @param tservice The service definition + */ +void t_hs_generator::generate_service(t_service* tservice) { + string f_service_name = get_out_dir() + capitalize(service_name_) + ".hs"; + f_service_.open(f_service_name.c_str()); + + f_service_ << hs_language_pragma() << endl; + f_service_ << hs_autogen_comment() << endl; + f_service_ << "module " << capitalize(service_name_) << " where" << endl; + f_service_ << hs_imports() << endl; + + if (tservice->get_extends()) { + f_service_ << "import qualified " << capitalize(tservice->get_extends()->get_name()) << endl; + } + + f_service_ << "import " << capitalize(program_name_) << "_Types" << endl; + f_service_ << "import qualified " << capitalize(service_name_) << "_Iface as Iface" << endl; + + // Generate the three main parts of the service + generate_service_helpers(tservice); + generate_service_interface(tservice); + generate_service_client(tservice); + generate_service_server(tservice); + + // Close service file + f_service_.close(); +} + +/** + * Generates helper functions for a service. + * + * @param tservice The service to generate a header definition for + */ +void t_hs_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + indent(f_service_) << "-- HELPER FUNCTIONS AND STRUCTURES --" << endl; + indent(f_service_) << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_hs_struct_definition(f_service_, ts, false); + generate_hs_function_helpers(*f_iter); + } +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_hs_generator::generate_hs_function_helpers(t_function* tfunction) { + t_struct result(program_, field_name(tfunction->get_name(), "result")); + t_field success(tfunction->get_returntype(), "success", 0); + + if (!tfunction->get_returntype()->is_void()) + result.append(&success); + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + result.append(*f_iter); + + generate_hs_struct_definition(f_service_, &result, false); +} + +/** + * Generate the map from field names to (type, id) + * @param tstruct the Struct + */ +void t_hs_generator::generate_hs_typemap(ofstream& out, t_struct* tstruct) { + string name = type_name(tstruct); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + indent(out) << "typemap_" << name << " :: T.TypeMap" << endl; + indent(out) << "typemap_" << name << " = Map.fromList ["; + bool first = true; + for (vector::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + string mname = (*f_iter)->get_name(); + if (!first) { + out << ","; + } + + t_type* type = get_true_type((*f_iter)->get_type()); + int32_t key = (*f_iter)->get_key(); + out << "(" << key << ",(\"" << mname << "\"," << type_to_enum(type) << "))"; + first = false; + } + out << "]" << endl; +} + +/** + * generate the struct with default values filled in + * @param tstruct the Struct + */ +void t_hs_generator::generate_hs_default(ofstream& out, t_struct* tstruct) { + string name = type_name(tstruct); + string fname = type_name(tstruct, "default_"); + const vector& fields = tstruct->get_sorted_members(); + + indent(out) << fname << " :: " << name << endl; + indent(out) << fname << " = " << name << "{" << endl; + indent_up(); + bool first = true; + for (vector::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + string mname = (*f_iter)->get_name(); + if (first) { + first = false; + } else { + out << "," << endl; + } + + t_type* type = get_true_type((*f_iter)->get_type()); + t_const_value* value = (*f_iter)->get_value(); + indent(out) << field_name(name, mname) << " = "; + if ((*f_iter)->get_req() == t_field::T_OPTIONAL + || ((t_type*)(*f_iter)->get_type())->is_xception()) { + if (value == NULL) { + out << "P.Nothing"; + } else { + out << "P.Just " << render_const_value(type, value); + } + } else { + out << render_const_value(type, value); + } + } + out << "}" << endl; + indent_down(); +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_hs_generator::generate_service_interface(t_service* tservice) { + string f_iface_name = get_out_dir() + capitalize(service_name_) + "_Iface.hs"; + f_iface_.open(f_iface_name.c_str()); + + f_iface_ << hs_language_pragma() << endl; + f_iface_ << hs_autogen_comment() << endl; + + f_iface_ << "module " << capitalize(service_name_) << "_Iface where" << endl; + + f_iface_ << hs_imports() << endl; + f_iface_ << "import " << capitalize(program_name_) << "_Types" << endl; + f_iface_ << endl; + + string sname = capitalize(service_name_); + if (tservice->get_extends() != NULL) { + string extends = type_name(tservice->get_extends()); + + indent(f_iface_) << "import " << extends << "_Iface" << endl; + indent(f_iface_) << "class " << extends << "_Iface a => " << sname << "_Iface a where" << endl; + + } else { + indent(f_iface_) << "class " << sname << "_Iface a where" << endl; + } + + indent_up(); + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string ft = function_type(*f_iter, true, true, true); + indent(f_iface_) << decapitalize((*f_iter)->get_name()) << " :: a -> " << ft << endl; + } + + indent_down(); + f_iface_.close(); +} + +/** + * Generates a service client definition. Note that in Haskell, the client doesn't implement iface. + *This is because + * The client does not (and should not have to) deal with arguments being Nothing. + * + * @param tservice The service to generate a server for. + */ +void t_hs_generator::generate_service_client(t_service* tservice) { + string f_client_name = get_out_dir() + capitalize(service_name_) + "_Client.hs"; + f_client_.open(f_client_name.c_str()); + f_client_ << hs_language_pragma() << endl; + f_client_ << hs_autogen_comment() << endl; + + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + + string extends = ""; + string exports = ""; + + bool first = true; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + exports += (first ? "" : ","); + string funname = (*f_iter)->get_name(); + exports += decapitalize(funname); + first = false; + } + + string sname = capitalize(service_name_); + indent(f_client_) << "module " << sname << "_Client(" << exports << ") where" << endl; + + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + indent(f_client_) << "import " << extends << "_Client" << endl; + } + + indent(f_client_) << "import qualified Data.IORef as R" << endl; + indent(f_client_) << hs_imports() << endl; + indent(f_client_) << "import " << capitalize(program_name_) << "_Types" << endl; + indent(f_client_) << "import " << capitalize(service_name_) << endl; + + // DATS RITE A GLOBAL VAR + indent(f_client_) << "seqid = R.newIORef 0" << endl; + + // Generate client method implementations + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* arg_struct = (*f_iter)->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + string funname = (*f_iter)->get_name(); + + string fargs = ""; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) + fargs += " arg_" + (*fld_iter)->get_name(); + + // Open function + indent(f_client_) << decapitalize(funname) << " (ip,op)" << fargs << " = do" << endl; + indent_up(); + indent(f_client_) << "send_" << funname << " op" << fargs; + + f_client_ << endl; + + if (!(*f_iter)->is_oneway()) + indent(f_client_) << "recv_" << funname << " ip" << endl; + + indent_down(); + + indent(f_client_) << "send_" << funname << " op" << fargs << " = do" << endl; + indent_up(); + + indent(f_client_) << "seq <- seqid" << endl; + indent(f_client_) << "seqn <- R.readIORef seq" << endl; + string argsname = capitalize((*f_iter)->get_name() + "_args"); + + // Serialize the request header + string fname = (*f_iter)->get_name(); + string msgType = (*f_iter)->is_oneway() ? "T.M_ONEWAY" : "T.M_CALL"; + indent(f_client_) << "T.writeMessage op (\"" << fname << "\", " << msgType << ", seqn) $" + << endl; + indent_up(); + indent(f_client_) << "write_" << argsname << " op (" << argsname << "{"; + + bool first = true; + for (vector::const_iterator fld_iter = fields.begin(); fld_iter != fields.end(); + ++fld_iter) { + string fieldname = (*fld_iter)->get_name(); + f_client_ << (first ? "" : ","); + f_client_ << field_name(argsname, fieldname) << "="; + if ((*fld_iter)->get_req() == t_field::T_OPTIONAL + || ((t_type*)(*fld_iter)->get_type())->is_xception()) + f_client_ << "P.Just "; + f_client_ << "arg_" << fieldname; + first = false; + } + f_client_ << "})" << endl; + indent_down(); + indent_down(); + + if (!(*f_iter)->is_oneway()) { + string resultname = capitalize((*f_iter)->get_name() + "_result"); + t_struct noargs(program_); + + string funname = string("recv_") + (*f_iter)->get_name(); + t_function recv_function((*f_iter)->get_returntype(), funname, &noargs); + + // Open function + indent(f_client_) << funname << " ip = do" << endl; + indent_up(); + + indent(f_client_) << "T.readMessage ip $ \\(fname, mtype, rseqid) -> do" << endl; + indent_up(); + indent(f_client_) << "M.when (mtype == T.M_EXCEPTION) $ do { exn <- T.readAppExn ip ; " + "X.throw exn }" << endl; + + indent(f_client_) << "res <- read_" << resultname << " ip" << endl; + + t_struct* xs = (*f_iter)->get_xceptions(); + const vector& xceptions = xs->get_members(); + + for (vector::const_iterator x_iter = xceptions.begin(); x_iter != xceptions.end(); + ++x_iter) { + indent(f_client_) << "P.maybe (P.return ()) X.throw (" + << field_name(resultname, (*x_iter)->get_name()) << " res)" << endl; + } + + if (!(*f_iter)->get_returntype()->is_void()) + indent(f_client_) << "P.return $ " << field_name(resultname, "success") << " res" << endl; + else + indent(f_client_) << "P.return ()" << endl; + + // Close function + indent_down(); + indent_down(); + } + } + + f_client_.close(); +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_hs_generator::generate_service_server(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) + generate_process_function(tservice, *f_iter); + + indent(f_service_) << "proc_ handler (iprot,oprot) (name,typ,seqid) = case name of" << endl; + indent_up(); + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string fname = (*f_iter)->get_name(); + indent(f_service_) << "\"" << fname << "\" -> process_" << decapitalize(fname) + << " (seqid,iprot,oprot,handler)" << endl; + } + + indent(f_service_) << "_ -> "; + if (tservice->get_extends() != NULL) { + f_service_ << type_name(tservice->get_extends()) + << ".proc_ handler (iprot,oprot) (name,typ,seqid)" << endl; + + } else { + f_service_ << "do" << endl; + indent_up(); + indent(f_service_) << "_ <- T.readVal iprot (T.T_STRUCT Map.empty)" << endl; + indent(f_service_) << "T.writeMessage oprot (name,T.M_EXCEPTION,seqid) $" << endl; + indent_up(); + indent(f_service_) << "T.writeAppExn oprot (T.AppExn T.AE_UNKNOWN_METHOD (\"Unknown function " + "\" ++ LT.unpack name))" << endl; + indent_down(); + indent_down(); + } + + indent_down(); + + // Generate the server implementation + indent(f_service_) << "process handler (iprot, oprot) = do" << endl; + indent_up(); + + indent(f_service_) << "T.readMessage iprot (" << endl; + indent(f_service_) << " proc_ handler (iprot,oprot))" << endl; + indent(f_service_) << "P.return P.True" << endl; + indent_down(); +} + +bool hasNoArguments(t_function* func) { + return (func->get_arglist()->get_members().empty()); +} + +string t_hs_generator::render_hs_type_for_function_name(t_type* type) { + string type_str = render_hs_type(type, false); + std::string::size_type found = -1; + + while (true) { + found = type_str.find_first_of("[]. ", found + 1); + if (string::npos == size_t(found)) { + break; + } + + if (type_str[found] == '.') + type_str[found] = '_'; + else + type_str[found] = 'Z'; + } + return type_str; +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_hs_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + (void)tservice; + // Open function + string funname = decapitalize(tfunction->get_name()); + indent(f_service_) << "process_" << funname << " (seqid, iprot, oprot, handler) = do" << endl; + indent_up(); + + string argsname = capitalize(tfunction->get_name()) + "_args"; + string resultname = capitalize(tfunction->get_name()) + "_result"; + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + indent(f_service_) << "args <- read_" << argsname << " iprot" << endl; + + t_struct* xs = tfunction->get_xceptions(); + const vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + size_t n = xceptions.size() + 1; + // Try block for a function with exceptions + if (n > 0) { + for (size_t i = 0; i < n; i++) { + indent(f_service_) << "(X.catch" << endl; + indent_up(); + } + } + + if (n > 0) { + indent(f_service_) << "(do" << endl; + indent_up(); + } + indent(f_service_); + + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) + f_service_ << "val <- "; + + f_service_ << "Iface." << decapitalize(tfunction->get_name()) << " handler"; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + f_service_ << " (" << field_name(argsname, (*f_iter)->get_name()) << " args)"; + + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + f_service_ << endl; + indent(f_service_) << "let res = default_" << resultname << "{" + << field_name(resultname, "success") << " = val}"; + + } else if (!tfunction->is_oneway()) { + f_service_ << endl; + indent(f_service_) << "let res = default_" << resultname; + } + f_service_ << endl; + + // Shortcut out here for oneway functions + if (tfunction->is_oneway()) { + indent(f_service_) << "P.return ()"; + } else { + indent(f_service_) << "T.writeMessage oprot (\"" << tfunction->get_name() + << "\", T.M_REPLY, seqid) $" << endl; + indent_up(); + indent(f_service_) << "write_" << resultname << " oprot res"; + indent_down(); + } + if (n > 0) { + f_service_ << ")"; + indent_down(); + } + f_service_ << endl; + + if (n > 0) { + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + indent(f_service_) << "(\\e -> do" << endl; + indent_up(); + + if (!tfunction->is_oneway()) { + indent(f_service_) << "let res = default_" << resultname << "{" + << field_name(resultname, (*x_iter)->get_name()) << " = P.Just e}" + << endl; + indent(f_service_) << "T.writeMessage oprot (\"" << tfunction->get_name() + << "\", T.M_REPLY, seqid) $" << endl; + indent_up(); + indent(f_service_) << "write_" << resultname << " oprot res"; + indent_down(); + } else { + indent(f_service_) << "P.return ()"; + } + + f_service_ << "))" << endl; + indent_down(); + indent_down(); + } + indent(f_service_) << "((\\_ -> do" << endl; + indent_up(); + + if (!tfunction->is_oneway()) { + indent(f_service_) << "T.writeMessage oprot (\"" << tfunction->get_name() + << "\", T.M_EXCEPTION, seqid) $" << endl; + indent_up(); + indent(f_service_) << "T.writeAppExn oprot (T.AppExn T.AE_UNKNOWN \"\")"; + indent_down(); + } else { + indent(f_service_) << "P.return ()"; + } + + f_service_ << ") :: X.SomeException -> P.IO ()))" << endl; + indent_down(); + indent_down(); + } + // Close function + indent_down(); +} + +/** + * Deserializes a field of any type. + */ +void t_hs_generator::generate_deserialize_field(ofstream& out, t_field* tfield, string prefix) { + (void)prefix; + t_type* type = tfield->get_type(); + generate_deserialize_type(out, type, prefix); +} + +/** + * Deserializes a field of any type. + */ +void t_hs_generator::generate_deserialize_type(ofstream& out, t_type* type, string arg) { + type = get_true_type(type); + string val = tmp("_val"); + out << "(case " << arg << " of {" << type_to_constructor(type) << " " << val << " -> "; + + if (type->is_void()) + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE"; + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, val); + + } else if (type->is_container()) { + generate_deserialize_container(out, type, val); + + } else if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + if (tbase == t_base_type::TYPE_STRING && !type->is_binary()) { + out << "E.decodeUtf8 "; + } + out << val; + if (type->is_binary()) { + // Since wire type of binary is the same as string, we actually receive T.TString not + // T.TBinary + out << "; T.TString " << val << " -> " << val; + } + } else if (type->is_enum()) { + out << "P.toEnum $ P.fromIntegral " << val; + + } else { + throw "DO NOT KNOW HOW TO DESERIALIZE TYPE " + type->get_name(); + } + out << "; _ -> P.error \"wrong type\"})"; +} + +/** + * Generates an unserializer for a struct, calling read() + */ +void t_hs_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, string name) { + + out << "(" << type_name(tstruct, "to_") << " (T.TStruct " << name << "))"; +} + +/** + * Serialize a container by writing out the header followed by + * data and then a footer. + */ +void t_hs_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string arg) { + + string val = tmp("_v"); + // Declare variables, read header + if (ttype->is_map()) { + string key = tmp("_k"); + out << "(Map.fromList $ P.map (\\(" << key << "," << val << ") -> ("; + generate_deserialize_type(out, ((t_map*)ttype)->get_key_type(), key); + + out << ","; + generate_deserialize_type(out, ((t_map*)ttype)->get_val_type(), val); + + out << ")) " << arg << ")"; + + } else if (ttype->is_set()) { + out << "(Set.fromList $ P.map (\\" << val << " -> "; + generate_deserialize_type(out, ((t_set*)ttype)->get_elem_type(), val); + out << ") " << arg << ")"; + + } else if (ttype->is_list()) { + out << "(Vector.fromList $ P.map (\\" << val << " -> "; + generate_deserialize_type(out, ((t_list*)ttype)->get_elem_type(), val); + out << ") " << arg << ")"; + } +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_hs_generator::generate_serialize_type(ofstream& out, t_type* type, string name) { + + type = get_true_type(type); + // Do nothing for void types + if (type->is_void()) + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE"; + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, name); + + } else if (type->is_container()) { + generate_serialize_container(out, type, name); + + } else if (type->is_base_type() || type->is_enum()) { + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + out << type_to_constructor(type) << " "; + if (tbase == t_base_type::TYPE_STRING && !type->is_binary()) { + out << "$ E.encodeUtf8 "; + } + out << name; + + } else if (type->is_enum()) { + string ename = capitalize(type->get_name()); + out << "T.TI32 $ P.fromIntegral $ P.fromEnum " << name; + } + + } else { + throw "DO NOT KNOW HOW TO SERIALIZE FIELD OF TYPE " + type->get_name(); + } +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_hs_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + out << type_name(tstruct, "from_") << " " << prefix; +} + +void t_hs_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + string k = tmp("_k"); + string v = tmp("_v"); + + if (ttype->is_map()) { + t_type* ktype = ((t_map*)ttype)->get_key_type(); + t_type* vtype = ((t_map*)ttype)->get_val_type(); + out << "T.TMap " << type_to_enum(ktype) << " " << type_to_enum(vtype); + out << " $ P.map (\\(" << k << "," << v << ") -> ("; + generate_serialize_type(out, ktype, k); + out << ", "; + generate_serialize_type(out, vtype, v); + out << ")) $ Map.toList " << prefix; + + } else if (ttype->is_set()) { + out << "T.TSet " << type_to_enum(((t_set*)ttype)->get_elem_type()); + out << " $ P.map (\\" << v << " -> "; + generate_serialize_type(out, ((t_set*)ttype)->get_elem_type(), v); + out << ") $ Set.toList " << prefix; + + } else if (ttype->is_list()) { + out << "T.TList " << type_to_enum(((t_list*)ttype)->get_elem_type()); + out << " $ P.map (\\" << v << " -> "; + generate_serialize_type(out, ((t_list*)ttype)->get_elem_type(), v); + out << ") $ Vector.toList " << prefix; + } +} + +string t_hs_generator::function_type(t_function* tfunc, bool options, bool io, bool method) { + string result = ""; + + const vector& fields = tfunc->get_arglist()->get_members(); + for (vector::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_OPTIONAL + || ((t_type*)(*f_iter)->get_type())->is_xception()) + result += "P.Maybe "; + result += render_hs_type((*f_iter)->get_type(), options); + result += " -> "; + } + + if (fields.empty() && !method) + result += "() -> "; + + if (io) + result += "P.IO "; + + result += render_hs_type(tfunc->get_returntype(), io); + return result; +} + +string t_hs_generator::type_name(t_type* ttype, string function_prefix) { + string prefix = ""; + t_program* program = ttype->get_program(); + + if (program != NULL && program != program_) + if (!ttype->is_service()) + prefix = capitalize(program->get_name()) + "_Types."; + + return prefix + function_prefix + capitalize(ttype->get_name()); +} + +string t_hs_generator::field_name(string tname, string fname) { + return decapitalize(tname) + "_" + fname; +} + +/** + * Converts the parse type to a Protocol.t_type enum + */ +string t_hs_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + return "T.T_VOID"; + case t_base_type::TYPE_STRING: + return type->is_binary() ? "T.T_BINARY" : "T.T_STRING"; + case t_base_type::TYPE_BOOL: + return "T.T_BOOL"; + case t_base_type::TYPE_I8: + return "T.T_BYTE"; + case t_base_type::TYPE_I16: + return "T.T_I16"; + case t_base_type::TYPE_I32: + return "T.T_I32"; + case t_base_type::TYPE_I64: + return "T.T_I64"; + case t_base_type::TYPE_DOUBLE: + return "T.T_DOUBLE"; + } + + } else if (type->is_enum()) { + return "T.T_I32"; + + } else if (type->is_struct() || type->is_xception()) { + return "(T.T_STRUCT " + type_name((t_struct*)type, "typemap_") + ")"; + + } else if (type->is_map()) { + string ktype = type_to_enum(((t_map*)type)->get_key_type()); + string vtype = type_to_enum(((t_map*)type)->get_val_type()); + return "(T.T_MAP " + ktype + " " + vtype + ")"; + + } else if (type->is_set()) { + return "(T.T_SET " + type_to_enum(((t_set*)type)->get_elem_type()) + ")"; + + } else if (type->is_list()) { + return "(T.T_LIST " + type_to_enum(((t_list*)type)->get_elem_type()) + ")"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** + * Converts the parse type to a default value + */ +string t_hs_generator::type_to_default(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + return "P.error \"No default value for type T_VOID\""; + case t_base_type::TYPE_STRING: + return "\"\""; + case t_base_type::TYPE_BOOL: + return "P.False"; + case t_base_type::TYPE_I8: + return "0"; + case t_base_type::TYPE_I16: + return "0"; + case t_base_type::TYPE_I32: + return "0"; + case t_base_type::TYPE_I64: + return "0"; + case t_base_type::TYPE_DOUBLE: + return "0"; + } + + } else if (type->is_enum()) { + return "(P.toEnum 0)"; + + } else if (type->is_struct() || type->is_xception()) { + return type_name((t_struct*)type, "default_"); + + } else if (type->is_map()) { + return "Map.empty"; + + } else if (type->is_set()) { + return "Set.empty"; + + } else if (type->is_list()) { + return "Vector.empty"; + } + + throw "INVALID TYPE IN type_to_default: " + type->get_name(); +} + +/** + * Converts the parse type to an haskell type + */ +string t_hs_generator::render_hs_type(t_type* type, bool needs_parens) { + type = get_true_type(type); + string type_repr; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + return "()"; + case t_base_type::TYPE_STRING: + return (type->is_binary() ? "LBS.ByteString" : "LT.Text"); + case t_base_type::TYPE_BOOL: + return "P.Bool"; + case t_base_type::TYPE_I8: + return "I.Int8"; + case t_base_type::TYPE_I16: + return "I.Int16"; + case t_base_type::TYPE_I32: + return "I.Int32"; + case t_base_type::TYPE_I64: + return "I.Int64"; + case t_base_type::TYPE_DOUBLE: + return "P.Double"; + } + + } else if (type->is_enum()) { + return type_name((t_enum*)type); + + } else if (type->is_struct() || type->is_xception()) { + return type_name((t_struct*)type); + + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + type_repr = "Map.HashMap " + render_hs_type(ktype, true) + " " + render_hs_type(vtype, true); + + } else if (type->is_set()) { + t_type* etype = ((t_set*)type)->get_elem_type(); + type_repr = "Set.HashSet " + render_hs_type(etype, true); + + } else if (type->is_list()) { + t_type* etype = ((t_list*)type)->get_elem_type(); + type_repr = "Vector.Vector " + render_hs_type(etype, true); + + } else { + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); + } + + return needs_parens ? "(" + type_repr + ")" : type_repr; +} + +/** + * Converts the parse type to a haskell constructor + */ +string t_hs_generator::type_to_constructor(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "invalid type: T_VOID"; + case t_base_type::TYPE_STRING: + return type->is_binary() ? "T.TBinary" : "T.TString"; + case t_base_type::TYPE_BOOL: + return "T.TBool"; + case t_base_type::TYPE_I8: + return "T.TByte"; + case t_base_type::TYPE_I16: + return "T.TI16"; + case t_base_type::TYPE_I32: + return "T.TI32"; + case t_base_type::TYPE_I64: + return "T.TI64"; + case t_base_type::TYPE_DOUBLE: + return "T.TDouble"; + } + + } else if (type->is_enum()) { + return "T.TI32"; + + } else if (type->is_struct() || type->is_xception()) { + return "T.TStruct"; + + } else if (type->is_map()) { + return "T.TMap _ _"; + + } else if (type->is_set()) { + return "T.TSet _"; + + } else if (type->is_list()) { + return "T.TList _"; + } + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +THRIFT_REGISTER_GENERATOR(hs, "Haskell", "") diff --git a/compiler/cpp/src/thrift/generate/t_html_generator.cc b/compiler/cpp/src/thrift/generate/t_html_generator.cc new file mode 100644 index 0000000..dfd5df3 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_html_generator.cc @@ -0,0 +1,1088 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "thrift/platform.h" +#include "thrift/generate/t_generator.h" +#include "thrift/generate/t_html_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::pair; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +enum input_type { INPUT_UNKNOWN, INPUT_UTF8, INPUT_PLAIN }; + +/** + * HTML code generator + * + * mostly copy/pasting/tweaking from mcslee's work. + */ +class t_html_generator : public t_generator { +public: + t_html_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + standalone_ = false; + unsafe_ = false; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("standalone") == 0) { + standalone_ = true; + } else if( iter->first.compare("noescape") == 0) { + unsafe_ = true; + } else { + throw "unknown option html:" + iter->first; + } + } + + + out_dir_base_ = "gen-html"; + input_type_ = INPUT_UNKNOWN; + + escape_.clear(); + escape_['&'] = "&"; + escape_['<'] = "<"; + escape_['>'] = ">"; + escape_['"'] = """; + escape_['\''] = "'"; + + init_allowed__markup(); + } + + void generate_program(); + void generate_program_toc(); + void generate_program_toc_row(t_program* tprog); + void generate_program_toc_rows(t_program* tprog, std::vector& finished); + void generate_index(); + std::string escape_html(std::string const& str); + std::string escape_html_tags(std::string const& str); + void generate_css(); + void generate_css_content(std::ofstream& f_target); + void generate_style_tag(); + std::string make_file_link(std::string name); + bool is_utf8_sequence(std::string const& str, size_t firstpos); + void detect_input_encoding(std::string const& str, size_t firstpos); + void init_allowed__markup(); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_service(t_service* tservice); + void generate_xception(t_struct* txception); + + void print_doc(t_doc* tdoc); + int print_type(t_type* ttype); + void print_const_value(t_type* type, t_const_value* tvalue); + void print_fn_args_doc(t_function* tfunction); + +private: + std::ofstream f_out_; + std::string current_file_; + input_type input_type_; + std::map allowed_markup; + bool standalone_; + bool unsafe_; +}; + +/** + * Emits the Table of Contents links at the top of the module's page + */ +void t_html_generator::generate_program_toc() { + f_out_ << "" + << "" << endl; + generate_program_toc_row(program_); + f_out_ << "
ModuleServicesData typesConstants
" << endl; +} + +/** + * Recurses through from the provided program and generates a ToC row + * for each discovered program exactly once by maintaining the list of + * completed rows in 'finished' + */ +void t_html_generator::generate_program_toc_rows(t_program* tprog, + std::vector& finished) { + for (vector::iterator iter = finished.begin(); iter != finished.end(); iter++) { + if (tprog->get_path() == (*iter)->get_path()) { + return; + } + } + finished.push_back(tprog); + generate_program_toc_row(tprog); + vector includes = tprog->get_includes(); + for (vector::iterator iter = includes.begin(); iter != includes.end(); iter++) { + generate_program_toc_rows(*iter, finished); + } +} + +/** + * Emits the Table of Contents links at the top of the module's page + */ +void t_html_generator::generate_program_toc_row(t_program* tprog) { + string fname = tprog->get_name() + ".html"; + f_out_ << "" << endl << "" << tprog->get_name() << ""; + if (!tprog->get_services().empty()) { + vector services = tprog->get_services(); + vector::iterator sv_iter; + for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { + string name = get_service_name(*sv_iter); + f_out_ << "" << name + << "
" << endl; + f_out_ << "
    " << endl; + map fn_html; + vector functions = (*sv_iter)->get_functions(); + vector::iterator fn_iter; + for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) { + string fn_name = (*fn_iter)->get_name(); + string html = "
  • " + fn_name + "
  • "; + fn_html.insert(pair(fn_name, html)); + } + for (map::iterator html_iter = fn_html.begin(); html_iter != fn_html.end(); + html_iter++) { + f_out_ << html_iter->second << endl; + } + f_out_ << "
" << endl; + } + } + f_out_ << "" << endl << ""; + map data_types; + if (!tprog->get_enums().empty()) { + vector enums = tprog->get_enums(); + vector::iterator en_iter; + for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { + string name = (*en_iter)->get_name(); + // f_out_ << "" << name + // << "
" << endl; + string html = "" + name + ""; + data_types.insert(pair(name, html)); + } + } + if (!tprog->get_typedefs().empty()) { + vector typedefs = tprog->get_typedefs(); + vector::iterator td_iter; + for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { + string name = (*td_iter)->get_symbolic(); + // f_out_ << "" << name + // << "
" << endl; + string html = "" + name + + ""; + data_types.insert(pair(name, html)); + } + } + if (!tprog->get_objects().empty()) { + vector objects = tprog->get_objects(); + vector::iterator o_iter; + for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { + string name = (*o_iter)->get_name(); + // f_out_ << "" << name + //<< "
" << endl; + string html = "" + name + + ""; + data_types.insert(pair(name, html)); + } + } + for (map::iterator dt_iter = data_types.begin(); dt_iter != data_types.end(); + dt_iter++) { + f_out_ << dt_iter->second << "
" << endl; + } + f_out_ << "" << endl << ""; + if (!tprog->get_consts().empty()) { + map const_html; + vector consts = tprog->get_consts(); + vector::iterator con_iter; + for (con_iter = consts.begin(); con_iter != consts.end(); ++con_iter) { + string name = (*con_iter)->get_name(); + string html = "" + name + + ""; + const_html.insert(pair(name, html)); + } + for (map::iterator con_iter = const_html.begin(); con_iter != const_html.end(); + con_iter++) { + f_out_ << con_iter->second << "
" << endl; + } + } + f_out_ << "" << endl << ""; +} + +/** + * Prepares for file generation by opening up the necessary file output + * stream. + */ +void t_html_generator::generate_program() { + // Make output directory + MKDIR(get_out_dir().c_str()); + current_file_ = program_->get_name() + ".html"; + string fname = get_out_dir() + current_file_; + f_out_.open(fname.c_str()); + f_out_ << "" << endl; + f_out_ << "" << endl; + f_out_ << "" << endl; + f_out_ << "" << endl; + generate_style_tag(); + f_out_ << "Thrift module: " << program_->get_name() << "" << endl + << "
" << endl + << "

Thrift module: " << program_->get_name() << "

" << endl; + + print_doc(program_); + + generate_program_toc(); + + if (!program_->get_consts().empty()) { + f_out_ << "

Constants

" << endl; + vector consts = program_->get_consts(); + f_out_ << ""; + f_out_ << "" << endl; + generate_consts(consts); + f_out_ << "
ConstantTypeValue
"; + } + + if (!program_->get_enums().empty()) { + f_out_ << "

Enumerations

" << endl; + // Generate enums + vector enums = program_->get_enums(); + vector::iterator en_iter; + for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { + generate_enum(*en_iter); + } + } + + if (!program_->get_typedefs().empty()) { + f_out_ << "

Type declarations

" << endl; + // Generate typedefs + vector typedefs = program_->get_typedefs(); + vector::iterator td_iter; + for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { + generate_typedef(*td_iter); + } + } + + if (!program_->get_objects().empty()) { + f_out_ << "

Data structures

" << endl; + // Generate structs and exceptions in declared order + vector objects = program_->get_objects(); + vector::iterator o_iter; + for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { + if ((*o_iter)->is_xception()) { + generate_xception(*o_iter); + } else { + generate_struct(*o_iter); + } + } + } + + if (!program_->get_services().empty()) { + f_out_ << "

Services

" << endl; + // Generate services + vector services = program_->get_services(); + vector::iterator sv_iter; + for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { + service_name_ = get_service_name(*sv_iter); + generate_service(*sv_iter); + } + } + + f_out_ << "
" << endl; + f_out_.close(); + + generate_index(); + generate_css(); +} + +/** + * Emits the index.html file for the recursive set of Thrift programs + */ +void t_html_generator::generate_index() { + current_file_ = "index.html"; + string index_fname = get_out_dir() + current_file_; + f_out_.open(index_fname.c_str()); + f_out_ << "" << endl; + generate_style_tag(); + f_out_ << "All Thrift declarations" << endl + << "
" << endl << "

All Thrift declarations

" << endl; + f_out_ << "" + << "" << endl; + vector programs; + generate_program_toc_rows(program_, programs); + f_out_ << "
ModuleServicesData typesConstants
" << endl; + f_out_ << "
" << endl; + f_out_.close(); +} + +void t_html_generator::generate_css() { + if (!standalone_) { + current_file_ = "style.css"; + string css_fname = get_out_dir() + current_file_; + f_out_.open(css_fname.c_str()); + generate_css_content(f_out_); + f_out_.close(); + } +} + +void t_html_generator::generate_css_content(std::ofstream& f_target) { + f_target << BOOTSTRAP_CSS() << endl; + f_target << "/* Auto-generated CSS for generated Thrift docs */" << endl; + f_target << "h3, h4 { margin-bottom: 6px; }" << endl; + f_target << "div.definition { border: 1px solid #CCC; margin-bottom: 10px; padding: 10px; }" + << endl; + f_target << "div.extends { margin: -0.5em 0 1em 5em }" << endl; + f_target << "td { vertical-align: top; }" << endl; + f_target << "table { empty-cells: show; }" << endl; + f_target << "code { line-height: 20px; }" << endl; + f_target << ".table-bordered th, .table-bordered td { border-bottom: 1px solid #DDDDDD; }" + << endl; +} + +/** + * Generates the CSS tag. + * Depending on "standalone", either a CSS file link (default), or the entire CSS is embedded + * inline. + */ +void t_html_generator::generate_style_tag() { + if (!standalone_) { + f_out_ << "" << endl; + } else { + f_out_ << "" << endl; + } +} + +/** + * Returns the target file for a link + * The returned string is empty, whenever filename refers to the current file. + */ +std::string t_html_generator::make_file_link(std::string filename) { + return (current_file_.compare(filename) != 0) ? filename : ""; +} + +/** + * If the provided documentable object has documentation attached, this + * will emit it to the output stream in HTML format. + */ +void t_html_generator::print_doc(t_doc* tdoc) { + if (tdoc->has_doc()) { + if (unsafe_) { + f_out_ << tdoc->get_doc() << "
"; + } else { + f_out_ << "
" << escape_html(tdoc->get_doc()) << "

"; + } + } +} + +bool t_html_generator::is_utf8_sequence(std::string const& str, size_t firstpos) { + // leading char determines the length of the sequence + unsigned char c = str.at(firstpos); + int count = 0; + if ((c & 0xE0) == 0xC0) { + count = 1; + } else if ((c & 0xF0) == 0xE0) { + count = 2; + } else if ((c & 0xF8) == 0xF0) { + count = 3; + } else if ((c & 0xFC) == 0xF8) { + count = 4; + } else if ((c & 0xFE) == 0xFC) { + count = 5; + } else { + // pdebug("UTF-8 test: char '%c' (%d) is not a valid UTF-8 leading byte", c, int(c)); + return false; // no UTF-8 + } + + // following chars + size_t pos = firstpos + 1; + while ((pos < str.length()) && (0 < count)) { + c = str.at(pos); + if ((c & 0xC0) != 0x80) { + // pdebug("UTF-8 test: char '%c' (%d) is not a valid UTF-8 following byte", c, int(c)); + return false; // no UTF-8 + } + --count; + ++pos; + } + + // true if the sequence is complete + return (0 == count); +} + +void t_html_generator::detect_input_encoding(std::string const& str, size_t firstpos) { + if (is_utf8_sequence(str, firstpos)) { + pdebug("Input seems to be already UTF-8 encoded"); + input_type_ = INPUT_UTF8; + return; + } + + // fallback + pwarning(1, "Input is not UTF-8, treating as plain ANSI"); + input_type_ = INPUT_PLAIN; +} + +void t_html_generator::init_allowed__markup() { + allowed_markup.clear(); + // standalone tags + allowed_markup["br"] = 1; + allowed_markup["br/"] = 1; + allowed_markup["img"] = 1; + // paired tags + allowed_markup["b"] = 1; + allowed_markup["/b"] = 1; + allowed_markup["u"] = 1; + allowed_markup["/u"] = 1; + allowed_markup["i"] = 1; + allowed_markup["/i"] = 1; + allowed_markup["s"] = 1; + allowed_markup["/s"] = 1; + allowed_markup["big"] = 1; + allowed_markup["/big"] = 1; + allowed_markup["small"] = 1; + allowed_markup["/small"] = 1; + allowed_markup["sup"] = 1; + allowed_markup["/sup"] = 1; + allowed_markup["sub"] = 1; + allowed_markup["/sub"] = 1; + allowed_markup["pre"] = 1; + allowed_markup["/pre"] = 1; + allowed_markup["tt"] = 1; + allowed_markup["/tt"] = 1; + allowed_markup["ul"] = 1; + allowed_markup["/ul"] = 1; + allowed_markup["ol"] = 1; + allowed_markup["/ol"] = 1; + allowed_markup["li"] = 1; + allowed_markup["/li"] = 1; + allowed_markup["a"] = 1; + allowed_markup["/a"] = 1; + allowed_markup["p"] = 1; + allowed_markup["/p"] = 1; + allowed_markup["code"] = 1; + allowed_markup["/code"] = 1; + allowed_markup["dl"] = 1; + allowed_markup["/dl"] = 1; + allowed_markup["dt"] = 1; + allowed_markup["/dt"] = 1; + allowed_markup["dd"] = 1; + allowed_markup["/dd"] = 1; + allowed_markup["h1"] = 1; + allowed_markup["/h1"] = 1; + allowed_markup["h2"] = 1; + allowed_markup["/h2"] = 1; + allowed_markup["h3"] = 1; + allowed_markup["/h3"] = 1; + allowed_markup["h4"] = 1; + allowed_markup["/h4"] = 1; + allowed_markup["h5"] = 1; + allowed_markup["/h5"] = 1; + allowed_markup["h6"] = 1; + allowed_markup["/h6"] = 1; +} + +std::string t_html_generator::escape_html_tags(std::string const& str) { + std::ostringstream result; + + unsigned char c = '?'; + size_t lastpos; + size_t firstpos = 0; + while (firstpos < str.length()) { + + // look for non-ASCII char + lastpos = firstpos; + while (lastpos < str.length()) { + c = str.at(lastpos); + if (('<' == c) || ('>' == c)) { + break; + } + ++lastpos; + } + + // copy what we got so far + if (lastpos > firstpos) { + result << str.substr(firstpos, lastpos - firstpos); + firstpos = lastpos; + } + + // reached the end? + if (firstpos >= str.length()) { + break; + } + + // tag end without corresponding begin + ++firstpos; + if ('>' == c) { + result << ">"; + continue; + } + + // extract the tag + std::ostringstream tagstream; + while (firstpos < str.length()) { + c = str.at(firstpos); + ++firstpos; + if ('<' == c) { + tagstream << "<"; // nested begin? + } else if ('>' == c) { + break; + } else { + tagstream << c; // not very efficient, but tags should be quite short + } + } + + // we allow for several markup in docstrings, all else will become escaped + string tag_content = tagstream.str(); + string tag_key = tag_content; + size_t first_white = tag_key.find_first_of(" \t\f\v\n\r"); + if (first_white != string::npos) { + tag_key.erase(first_white); + } + for (std::string::size_type i = 0; i < tag_key.length(); ++i) { + tag_key[i] = tolower(tag_key[i]); + } + if (allowed_markup.find(tag_key) != allowed_markup.end()) { + result << "<" << tag_content << ">"; + } else { + result << "<" << tagstream.str() << ">"; + pverbose("illegal markup <%s> in doc-comment\n", tag_key.c_str()); + } + } + + return result.str(); +} + +std::string t_html_generator::escape_html(std::string const& str) { + // the generated HTML header says it is UTF-8 encoded + // if UTF-8 input has been detected before, we don't need to change anything + if (input_type_ == INPUT_UTF8) { + return escape_html_tags(str); + } + + // convert unsafe chars to their &#; equivalent + std::ostringstream result; + unsigned char c = '?'; + unsigned int ic = 0; + size_t lastpos; + size_t firstpos = 0; + while (firstpos < str.length()) { + + // look for non-ASCII char + lastpos = firstpos; + while (lastpos < str.length()) { + c = str.at(lastpos); + ic = c; + if ((32 > ic) || (127 < ic)) { + break; + } + ++lastpos; + } + + // copy what we got so far + if (lastpos > firstpos) { + result << str.substr(firstpos, lastpos - firstpos); + firstpos = lastpos; + } + + // reached the end? + if (firstpos >= str.length()) { + break; + } + + // some control code? + if (ic <= 31) { + switch (c) { + case '\r': + case '\n': + case '\t': + result << c; + break; + default: // silently consume all other ctrl chars + break; + } + ++firstpos; + continue; + } + + // reached the end? + if (firstpos >= str.length()) { + break; + } + + // try to detect input encoding + if (input_type_ == INPUT_UNKNOWN) { + detect_input_encoding(str, firstpos); + if (input_type_ == INPUT_UTF8) { + lastpos = str.length(); + result << str.substr(firstpos, lastpos - firstpos); + break; + } + } + + // convert the character to something useful based on the detected encoding + switch (input_type_) { + case INPUT_PLAIN: + result << "&#" << ic << ";"; + ++firstpos; + break; + default: + throw "Unexpected or unrecognized input encoding"; + } + } + + return escape_html_tags(result.str()); +} + +/** + * Prints out the provided type in HTML + */ +int t_html_generator::print_type(t_type* ttype) { + std::string::size_type len = 0; + f_out_ << ""; + if (ttype->is_container()) { + if (ttype->is_list()) { + f_out_ << "list<"; + len = 6 + print_type(((t_list*)ttype)->get_elem_type()); + f_out_ << ">"; + } else if (ttype->is_set()) { + f_out_ << "set<"; + len = 5 + print_type(((t_set*)ttype)->get_elem_type()); + f_out_ << ">"; + } else if (ttype->is_map()) { + f_out_ << "map<"; + len = 5 + print_type(((t_map*)ttype)->get_key_type()); + f_out_ << ", "; + len += print_type(((t_map*)ttype)->get_val_type()); + f_out_ << ">"; + } + } else if (ttype->is_base_type()) { + f_out_ << (ttype->is_binary() ? "binary" : ttype->get_name()); + len = ttype->get_name().size(); + } else { + string prog_name = ttype->get_program()->get_name(); + string type_name = ttype->get_name(); + f_out_ << "
is_typedef()) { + f_out_ << "Struct_"; + } else if (ttype->is_struct() || ttype->is_xception()) { + f_out_ << "Struct_"; + } else if (ttype->is_enum()) { + f_out_ << "Enum_"; + } else if (ttype->is_service()) { + f_out_ << "Svc_"; + } + f_out_ << type_name << "\">"; + len = type_name.size(); + if (ttype->get_program() != program_) { + f_out_ << prog_name << "."; + len += prog_name.size() + 1; + } + f_out_ << type_name << ""; + } + f_out_ << ""; + return (int)len; +} + +/** + * Prints out an HTML representation of the provided constant value + */ +void t_html_generator::print_const_value(t_type* type, t_const_value* tvalue) { + + // if tvalue is an identifier, the constant content is already shown elsewhere + if (tvalue->get_type() == t_const_value::CV_IDENTIFIER) { + string fname = program_->get_name() + ".html"; + string name = escape_html(tvalue->get_identifier()); + f_out_ << "" + name + + ""; + return; + } + + t_type* truetype = type; + while (truetype->is_typedef()) { + truetype = ((t_typedef*)truetype)->get_type(); + } + + bool first = true; + if (truetype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)truetype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + f_out_ << '"' << escape_html(get_escaped_string(tvalue)) << '"'; + break; + case t_base_type::TYPE_BOOL: + f_out_ << ((tvalue->get_integer() != 0) ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + f_out_ << tvalue->get_integer(); + break; + case t_base_type::TYPE_I16: + f_out_ << tvalue->get_integer(); + break; + case t_base_type::TYPE_I32: + f_out_ << tvalue->get_integer(); + break; + case t_base_type::TYPE_I64: + f_out_ << tvalue->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (tvalue->get_type() == t_const_value::CV_INTEGER) { + f_out_ << tvalue->get_integer(); + } else { + f_out_ << tvalue->get_double(); + } + break; + default: + f_out_ << "UNKNOWN BASE TYPE"; + break; + } + } else if (truetype->is_enum()) { + f_out_ << escape_html(truetype->get_name()) << "." + << escape_html(tvalue->get_identifier_name()); + } else if (truetype->is_struct() || truetype->is_xception()) { + f_out_ << "{ "; + const vector& fields = ((t_struct*)truetype)->get_members(); + vector::const_iterator f_iter; + const map& val = tvalue->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + truetype->get_name() + " has no field " + + v_iter->first->get_string(); + } + if (!first) { + f_out_ << ", "; + } + first = false; + f_out_ << escape_html(v_iter->first->get_string()) << " = "; + print_const_value(field_type, v_iter->second); + } + f_out_ << " }"; + } else if (truetype->is_map()) { + f_out_ << "{ "; + map map_elems = tvalue->get_map(); + map::iterator map_iter; + for (map_iter = map_elems.begin(); map_iter != map_elems.end(); map_iter++) { + if (!first) { + f_out_ << ", "; + } + first = false; + print_const_value(((t_map*)truetype)->get_key_type(), map_iter->first); + f_out_ << " = "; + print_const_value(((t_map*)truetype)->get_val_type(), map_iter->second); + } + f_out_ << " }"; + } else if (truetype->is_list()) { + f_out_ << "{ "; + vector list_elems = tvalue->get_list(); + ; + vector::iterator list_iter; + for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) { + if (!first) { + f_out_ << ", "; + } + first = false; + print_const_value(((t_list*)truetype)->get_elem_type(), *list_iter); + } + f_out_ << " }"; + } else if (truetype->is_set()) { + f_out_ << "{ "; + vector list_elems = tvalue->get_list(); + ; + vector::iterator list_iter; + for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) { + if (!first) { + f_out_ << ", "; + } + first = false; + print_const_value(((t_set*)truetype)->get_elem_type(), *list_iter); + } + f_out_ << " }"; + } else { + f_out_ << "UNKNOWN TYPE"; + } +} + +/** + * Prints out documentation for arguments/exceptions of a function, if any documentation has been + * supplied. + */ +void t_html_generator::print_fn_args_doc(t_function* tfunction) { + bool has_docs = false; + vector args = tfunction->get_arglist()->get_members(); + vector::iterator arg_iter = args.begin(); + if (arg_iter != args.end()) { + for (; arg_iter != args.end(); arg_iter++) { + if ((*arg_iter)->has_doc() && !(*arg_iter)->get_doc().empty()) + has_docs = true; + } + if (has_docs) { + arg_iter = args.begin(); + f_out_ << "

get_name() + << "\">Parameters

" << endl; + f_out_ << ""; + f_out_ << ""; + for (; arg_iter != args.end(); arg_iter++) { + f_out_ << "" << endl; + } + f_out_ << "
NameDescription
" << (*arg_iter)->get_name(); + f_out_ << ""; + f_out_ << escape_html((*arg_iter)->get_doc()); + f_out_ << "
"; + } + } + + has_docs = false; + vector excepts = tfunction->get_xceptions()->get_members(); + vector::iterator ex_iter = excepts.begin(); + if (ex_iter != excepts.end()) { + for (; ex_iter != excepts.end(); ex_iter++) { + if ((*ex_iter)->has_doc() && !(*ex_iter)->get_doc().empty()) + has_docs = true; + } + if (has_docs) { + ex_iter = excepts.begin(); + f_out_ << "

get_name() + << "\">Exceptions

" << endl; + f_out_ << ""; + f_out_ << ""; + for (; ex_iter != excepts.end(); ex_iter++) { + f_out_ << "" << endl; + } + f_out_ << "
TypeDescription
" << (*ex_iter)->get_type()->get_name(); + f_out_ << ""; + f_out_ << escape_html((*ex_iter)->get_doc()); + f_out_ << "
"; + } + } +} + +/** + * Generates a typedef. + * + * @param ttypedef The type definition + */ +void t_html_generator::generate_typedef(t_typedef* ttypedef) { + string name = ttypedef->get_name(); + f_out_ << "
"; + f_out_ << "

Typedef: " << name << "

" << endl; + f_out_ << "

Base type: "; + print_type(ttypedef->get_type()); + f_out_ << "

" << endl; + print_doc(ttypedef); + f_out_ << "
" << endl; +} + +/** + * Generates code for an enumerated type. + * + * @param tenum The enumeration + */ +void t_html_generator::generate_enum(t_enum* tenum) { + string name = tenum->get_name(); + f_out_ << "
"; + f_out_ << "

Enumeration: " << name << "

" << endl; + print_doc(tenum); + vector values = tenum->get_constants(); + vector::iterator val_iter; + f_out_ << "
" << endl; + for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) { + f_out_ << "" << endl; + } + f_out_ << "
"; + f_out_ << (*val_iter)->get_name(); + f_out_ << ""; + f_out_ << (*val_iter)->get_value(); + f_out_ << "" << endl; + print_doc((*val_iter)); + f_out_ << "
" << endl; +} + +/** + * Generates a constant value + */ +void t_html_generator::generate_const(t_const* tconst) { + string name = tconst->get_name(); + f_out_ << "" << name << ""; + print_type(tconst->get_type()); + f_out_ << ""; + print_const_value(tconst->get_type(), tconst->get_value()); + f_out_ << ""; + if (tconst->has_doc()) { + f_out_ << "
"; + print_doc(tconst); + f_out_ << "
"; + } +} + +/** + * Generates a struct definition for a thrift data type. + * + * @param tstruct The struct definition + */ +void t_html_generator::generate_struct(t_struct* tstruct) { + string name = tstruct->get_name(); + f_out_ << "
"; + f_out_ << "

"; + if (tstruct->is_xception()) { + f_out_ << "Exception: "; + } else if (tstruct->is_union()) { + f_out_ << "Union: "; + } else { + f_out_ << "Struct: "; + } + f_out_ << name << "

" << endl; + vector members = tstruct->get_members(); + vector::iterator mem_iter = members.begin(); + f_out_ << ""; + f_out_ << "" << endl; + for (; mem_iter != members.end(); mem_iter++) { + f_out_ << "" << endl; + } + f_out_ << "
KeyFieldTypeDescriptionRequirednessDefault value
" << (*mem_iter)->get_key() << ""; + f_out_ << (*mem_iter)->get_name(); + f_out_ << ""; + print_type((*mem_iter)->get_type()); + f_out_ << ""; + f_out_ << escape_html((*mem_iter)->get_doc()); + f_out_ << ""; + if ((*mem_iter)->get_req() == t_field::T_OPTIONAL) { + f_out_ << "optional"; + } else if ((*mem_iter)->get_req() == t_field::T_REQUIRED) { + f_out_ << "required"; + } else { + f_out_ << "default"; + } + f_out_ << ""; + t_const_value* default_val = (*mem_iter)->get_value(); + if (default_val != NULL) { + f_out_ << ""; + print_const_value((*mem_iter)->get_type(), default_val); + f_out_ << ""; + } + f_out_ << "

"; + print_doc(tstruct); + f_out_ << "
"; +} + +/** + * Exceptions are special structs + * + * @param tstruct The struct definition + */ +void t_html_generator::generate_xception(t_struct* txception) { + generate_struct(txception); +} + +/** + * Generates the HTML block for a Thrift service. + * + * @param tservice The service definition + */ +void t_html_generator::generate_service(t_service* tservice) { + f_out_ << "

Service: " << service_name_ << "

" << endl; + + if (tservice->get_extends()) { + f_out_ << "
extends "; + print_type(tservice->get_extends()); + f_out_ << "
\n"; + } + print_doc(tservice); + vector functions = tservice->get_functions(); + vector::iterator fn_iter = functions.begin(); + for (; fn_iter != functions.end(); fn_iter++) { + string fn_name = (*fn_iter)->get_name(); + f_out_ << "
"; + f_out_ << "

Function: " << service_name_ + << "." << fn_name << "

" << endl; + f_out_ << "
";
+    std::string::size_type offset = print_type((*fn_iter)->get_returntype());
+    bool first = true;
+    f_out_ << " " << fn_name << "(";
+    offset += fn_name.size() + 2;
+    vector args = (*fn_iter)->get_arglist()->get_members();
+    vector::iterator arg_iter = args.begin();
+    for (; arg_iter != args.end(); arg_iter++) {
+      if (!first) {
+        f_out_ << "," << endl;
+        for (std::string::size_type i = 0; i < offset; ++i) {
+          f_out_ << " ";
+        }
+      }
+      first = false;
+      print_type((*arg_iter)->get_type());
+      f_out_ << " " << (*arg_iter)->get_name();
+      if ((*arg_iter)->get_value() != NULL) {
+        f_out_ << " = ";
+        print_const_value((*arg_iter)->get_type(), (*arg_iter)->get_value());
+      }
+    }
+    f_out_ << ")" << endl;
+    first = true;
+    vector excepts = (*fn_iter)->get_xceptions()->get_members();
+    vector::iterator ex_iter = excepts.begin();
+    if (ex_iter != excepts.end()) {
+      f_out_ << "    throws ";
+      for (; ex_iter != excepts.end(); ex_iter++) {
+        if (!first) {
+          f_out_ << ", ";
+        }
+        first = false;
+        print_type((*ex_iter)->get_type());
+      }
+      f_out_ << endl;
+    }
+    f_out_ << "
"; + print_doc(*fn_iter); + print_fn_args_doc(*fn_iter); + f_out_ << "
"; + } +} + +THRIFT_REGISTER_GENERATOR( + html, + "HTML", + " standalone: Self-contained mode, includes all CSS in the HTML files.\n" + " Generates no style.css file, but HTML files will be larger.\n" + " noescape: Do not escape html in doc text.\n") diff --git a/compiler/cpp/src/thrift/generate/t_html_generator.h b/compiler/cpp/src/thrift/generate/t_html_generator.h new file mode 100644 index 0000000..600b17f --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_html_generator.h @@ -0,0 +1,240 @@ +#define BOOTSTRAP_CSS() \ + "/*!\n" \ + " * Bootstrap v2.0.3\n" \ + " *\n" \ + " * Copyright 2012 Twitter, Inc\n" \ + " * Licensed under the Apache License v2.0\n" \ + " * http://www.apache.org/licenses/LICENSE-2.0\n" \ + " *\n" \ + " * Designed and built with all the love in the world @twitter by @mdo and @fat.\n" \ + " */\n" \ + ".clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:\"\";}\n" \ + ".clearfix:after{clear:both;}\n" \ + ".hide-text{font:0/0 " \ + "a;color:transparent;text-shadow:none;background-color:transparent;border:0;}\n" \ + ".input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-" \ + "moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;}\n" \ + "article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}\n" \ + "audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}\n" \ + "audio:not([controls]){display:none;}\n" \ + "html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}\n" \ + "a:focus{outline:thin dotted #333;outline:5px auto " \ + "-webkit-focus-ring-color;outline-offset:-2px;}\n" \ + "a:hover,a:active{outline:0;}\n" \ + "sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}\n" \ + "sup{top:-0.5em;}\n" \ + "sub{bottom:-0.25em;}\n" \ + "img{max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;}\n" \ + "button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}\n" \ + "button,input{*overflow:visible;line-height:normal;}\n" \ + "button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}\n" \ + "button,input[type=\"button\"],input[type=\"reset\"],input[type=\"submit\"]{cursor:pointer;-" \ + "webkit-appearance:button;}\n" \ + "input[type=\"search\"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:" \ + "content-box;-webkit-appearance:textfield;}\n" \ + "input[type=\"search\"]::-webkit-search-decoration,input[type=\"search\"]::-webkit-search-" \ + "cancel-button{-webkit-appearance:none;}\n" \ + "textarea{overflow:auto;vertical-align:top;}\n" \ + "body{margin:0;font-family:\"Helvetica " \ + "Neue\",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-" \ + "color:#ffffff;}\n" \ + "a{color:#0088cc;text-decoration:none;}\n" \ + "a:hover{color:#005580;text-decoration:underline;}\n" \ + ".row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:\"\";}\n" \ + ".row:after{clear:both;}\n" \ + "[class*=\"span\"]{float:left;margin-left:20px;}\n" \ + ".container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}\n" \ + ".span12{width:940px;}\n" \ + ".span11{width:860px;}\n" \ + ".span10{width:780px;}\n" \ + ".span9{width:700px;}\n" \ + ".span8{width:620px;}\n" \ + ".span7{width:540px;}\n" \ + ".span6{width:460px;}\n" \ + ".span5{width:380px;}\n" \ + ".span4{width:300px;}\n" \ + ".span3{width:220px;}\n" \ + ".span2{width:140px;}\n" \ + ".span1{width:60px;}\n" \ + ".offset12{margin-left:980px;}\n" \ + ".offset11{margin-left:900px;}\n" \ + ".offset10{margin-left:820px;}\n" \ + ".offset9{margin-left:740px;}\n" \ + ".offset8{margin-left:660px;}\n" \ + ".offset7{margin-left:580px;}\n" \ + ".offset6{margin-left:500px;}\n" \ + ".offset5{margin-left:420px;}\n" \ + ".offset4{margin-left:340px;}\n" \ + ".offset3{margin-left:260px;}\n" \ + ".offset2{margin-left:180px;}\n" \ + ".offset1{margin-left:100px;}\n" \ + ".row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:\"\";}" \ + "\n" \ + ".row-fluid:after{clear:both;}\n" \ + ".row-fluid " \ + "[class*=\"span\"]{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-" \ + "box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:" \ + "2.127659574%;*margin-left:2.0744680846382977%;}\n" \ + ".row-fluid [class*=\"span\"]:first-child{margin-left:0;}\n" \ + ".row-fluid .span12{width:99.99999998999999%;*width:99.94680850063828%;}\n" \ + ".row-fluid .span11{width:91.489361693%;*width:91.4361702036383%;}\n" \ + ".row-fluid .span10{width:82.97872339599999%;*width:82.92553190663828%;}\n" \ + ".row-fluid .span9{width:74.468085099%;*width:74.4148936096383%;}\n" \ + ".row-fluid .span8{width:65.95744680199999%;*width:65.90425531263828%;}\n" \ + ".row-fluid .span7{width:57.446808505%;*width:57.3936170156383%;}\n" \ + ".row-fluid .span6{width:48.93617020799999%;*width:48.88297871863829%;}\n" \ + ".row-fluid .span5{width:40.425531911%;*width:40.3723404216383%;}\n" \ + ".row-fluid .span4{width:31.914893614%;*width:31.8617021246383%;}\n" \ + ".row-fluid .span3{width:23.404255317%;*width:23.3510638276383%;}\n" \ + ".row-fluid .span2{width:14.89361702%;*width:14.8404255306383%;}\n" \ + ".row-fluid .span1{width:6.382978723%;*width:6.329787233638298%;}\n" \ + ".container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{" \ + "display:table;content:\"\";}\n" \ + ".container:after{clear:both;}\n" \ + ".container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,." \ + "container-fluid:after{display:table;content:\"\";}\n" \ + ".container-fluid:after{clear:both;}\n" \ + "p{margin:0 0 9px;font-family:\"Helvetica " \ + "Neue\",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p " \ + "small{font-size:11px;color:#999999;}\n" \ + ".lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;}\n" \ + "h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:" \ + "optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 " \ + "small{font-weight:normal;color:#999999;}\n" \ + "h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;}\n" \ + "h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;}\n" \ + "h3{font-size:18px;line-height:27px;}h3 small{font-size:14px;}\n" \ + "h4,h5,h6{line-height:18px;}\n" \ + "h4{font-size:14px;}h4 small{font-size:12px;}\n" \ + "h5{font-size:12px;}\n" \ + "h6{font-size:11px;color:#999999;text-transform:uppercase;}\n" \ + ".page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;}\n" \ + ".page-header h1{line-height:1;}\n" \ + "ul,ol{padding:0;margin:0 0 9px 25px;}\n" \ + "ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}\n" \ + "ul{list-style:disc;}\n" \ + "ol{list-style:decimal;}\n" \ + "li{line-height:18px;}\n" \ + "ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}\n" \ + "dl{margin-bottom:18px;}\n" \ + "dt,dd{line-height:18px;}\n" \ + "dt{font-weight:bold;line-height:17px;}\n" \ + "dd{margin-left:9px;}\n" \ + ".dl-horizontal " \ + "dt{float:left;width:120px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;" \ + "white-space:nowrap;}\n" \ + ".dl-horizontal dd{margin-left:130px;}\n" \ + "hr{margin:18px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}\n" \ + "strong{font-weight:bold;}\n" \ + "em{font-style:italic;}\n" \ + ".muted{color:#999999;}\n" \ + "abbr[title]{cursor:help;border-bottom:1px dotted #ddd;}\n" \ + "abbr.initialism{font-size:90%;text-transform:uppercase;}\n" \ + "blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote " \ + "p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;}\n" \ + "blockquote small{display:block;line-height:18px;color:#999999;}blockquote " \ + "small:before{content:'\\2014 \\00A0';}\n" \ + "blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid " \ + "#eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right " \ + "small{text-align:right;}\n" \ + "q:before,q:after,blockquote:before,blockquote:after{content:\"\";}\n" \ + "address{display:block;margin-bottom:18px;font-style:normal;line-height:18px;}\n" \ + "small{font-size:100%;}\n" \ + "cite{font-style:normal;}\n" \ + "code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,Consolas,\"Courier " \ + "New\",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;" \ + "border-radius:3px;}\n" \ + "code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;}\n" \ + "pre{display:block;padding:8.5px;margin:0 0 " \ + "9px;font-size:12.025px;line-height:18px;word-break:break-all;word-wrap:break-word;white-space:" \ + "pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid " \ + "rgba(0, 0, 0, " \ + "0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}pre.prettyprint{" \ + "margin-bottom:18px;}\n" \ + "pre code{padding:0;color:inherit;background-color:transparent;border:0;}\n" \ + ".pre-scrollable{max-height:340px;overflow-y:scroll;}\n" \ + ".label,.badge{font-size:10.998px;font-weight:bold;line-height:14px;color:#ffffff;vertical-" \ + "align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, " \ + "0.25);background-color:#999999;}\n" \ + ".label{padding:1px 4px " \ + "2px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}\n" \ + ".badge{padding:1px 9px " \ + "2px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;}\n" \ + "a.label:hover,a.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;}\n" \ + ".label-important,.badge-important{background-color:#b94a48;}\n" \ + ".label-important[href],.badge-important[href]{background-color:#953b39;}\n" \ + ".label-warning,.badge-warning{background-color:#f89406;}\n" \ + ".label-warning[href],.badge-warning[href]{background-color:#c67605;}\n" \ + ".label-success,.badge-success{background-color:#468847;}\n" \ + ".label-success[href],.badge-success[href]{background-color:#356635;}\n" \ + ".label-info,.badge-info{background-color:#3a87ad;}\n" \ + ".label-info[href],.badge-info[href]{background-color:#2d6987;}\n" \ + ".label-inverse,.badge-inverse{background-color:#333333;}\n" \ + ".label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;}\n" \ + "table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;}" \ + "\n" \ + ".table{width:100%;margin-bottom:18px;}.table th,.table " \ + "td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid " \ + "#dddddd;}\n" \ + ".table th{font-weight:bold;}\n" \ + ".table thead th{vertical-align:bottom;}\n" \ + ".table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table " \ + "colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table " \ + "thead:first-child tr:first-child th,.table thead:first-child tr:first-child " \ + "td{border-top:0;}\n" \ + ".table tbody+tbody{border-top:2px solid #dddddd;}\n" \ + ".table-condensed th,.table-condensed td{padding:4px 5px;}\n" \ + ".table-bordered{border:1px solid " \ + "#dddddd;border-collapse:separate;*border-collapse:collapsed;border-left:0;-webkit-border-" \ + "radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered " \ + "td{border-left:1px solid #dddddd;}\n" \ + ".table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child " \ + "th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead " \ + "tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered " \ + "colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child " \ + "th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child " \ + "tr:first-child td{border-top:0;}\n" \ + ".table-bordered thead:first-child tr:first-child th:first-child,.table-bordered " \ + "tbody:first-child tr:first-child " \ + "td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-" \ + "radius-topleft:4px;}\n" \ + ".table-bordered thead:first-child tr:first-child th:last-child,.table-bordered " \ + "tbody:first-child tr:first-child " \ + "td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-" \ + "radius-topright:4px;}\n" \ + ".table-bordered thead:last-child tr:last-child th:first-child,.table-bordered " \ + "tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 " \ + "4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 " \ + "4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-" \ + "bottomleft:4px;}\n" \ + ".table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child " \ + "tr:last-child " \ + "td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-" \ + "border-radius-bottomright:4px;}\n" \ + ".table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) " \ + "th{background-color:#f9f9f9;}\n" \ + ".table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5;}\n" \ + "table .span1{float:none;width:44px;margin-left:0;}\n" \ + "table .span2{float:none;width:124px;margin-left:0;}\n" \ + "table .span3{float:none;width:204px;margin-left:0;}\n" \ + "table .span4{float:none;width:284px;margin-left:0;}\n" \ + "table .span5{float:none;width:364px;margin-left:0;}\n" \ + "table .span6{float:none;width:444px;margin-left:0;}\n" \ + "table .span7{float:none;width:524px;margin-left:0;}\n" \ + "table .span8{float:none;width:604px;margin-left:0;}\n" \ + "table .span9{float:none;width:684px;margin-left:0;}\n" \ + "table .span10{float:none;width:764px;margin-left:0;}\n" \ + "table .span11{float:none;width:844px;margin-left:0;}\n" \ + "table .span12{float:none;width:924px;margin-left:0;}\n" \ + "table .span13{float:none;width:1004px;margin-left:0;}\n" \ + "table .span14{float:none;width:1084px;margin-left:0;}\n" \ + "table .span15{float:none;width:1164px;margin-left:0;}\n" \ + "table .span16{float:none;width:1244px;margin-left:0;}\n" \ + "table .span17{float:none;width:1324px;margin-left:0;}\n" \ + "table .span18{float:none;width:1404px;margin-left:0;}\n" \ + "table .span19{float:none;width:1484px;margin-left:0;}\n" \ + "table .span20{float:none;width:1564px;margin-left:0;}\n" \ + "table .span21{float:none;width:1644px;margin-left:0;}\n" \ + "table .span22{float:none;width:1724px;margin-left:0;}\n" \ + "table .span23{float:none;width:1804px;margin-left:0;}\n" \ + "table .span24{float:none;width:1884px;margin-left:0;}" diff --git a/compiler/cpp/src/thrift/generate/t_java_generator.cc b/compiler/cpp/src/thrift/generate/t_java_generator.cc new file mode 100644 index 0000000..ebc8350 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_java_generator.cc @@ -0,0 +1,5381 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::setfill; +using std::setw; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * Java code generator. + * + */ +class t_java_generator : public t_oop_generator { +public: + t_java_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + bean_style_ = false; + android_style_ = false; + private_members_ = false; + nocamel_style_ = false; + fullcamel_style_ = false; + android_legacy_ = false; + sorted_containers_ = false; + java5_ = false; + reuse_objects_ = false; + use_option_type_ = false; + undated_generated_annotations_ = false; + suppress_generated_annotations_ = false; + handle_runtime_exceptions_ = false; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("beans") == 0) { + bean_style_ = true; + } else if( iter->first.compare("android") == 0) { + android_style_ = true; + } else if( iter->first.compare("private-members") == 0) { + private_members_ = true; + } else if( iter->first.compare("nocamel") == 0) { + nocamel_style_ = true; + } else if( iter->first.compare("fullcamel") == 0) { + fullcamel_style_ = true; + } else if( iter->first.compare("android_legacy") == 0) { + android_legacy_ = true; + } else if( iter->first.compare("sorted_containers") == 0) { + sorted_containers_ = true; + } else if( iter->first.compare("java5") == 0) { + java5_ = true; + } else if( iter->first.compare("reuse-objects") == 0) { + reuse_objects_ = true; + } else if( iter->first.compare("option_type") == 0) { + use_option_type_ = true; + } else if( iter->first.compare("handle_runtime_exceptions") == 0) { + handle_runtime_exceptions_ = true; + } else if( iter->first.compare("generated_annotations") == 0) { + if( iter->second.compare("undated") == 0) { + undated_generated_annotations_ = true; + } else if(iter->second.compare("suppress") == 0) { + suppress_generated_annotations_ = true; + } else { + throw "unknown option java:" + iter->first + "=" + iter->second; + } + } else { + throw "unknown option java:" + iter->first; + } + } + + if (java5_) { + android_legacy_ = true; + } + + out_dir_base_ = (bean_style_ ? "gen-javabean" : "gen-java"); + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + void generate_consts(std::vector consts); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_struct(t_struct* tstruct); + void generate_union(t_struct* tunion); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + void print_const_value(std::ofstream& out, + std::string name, + t_type* type, + t_const_value* value, + bool in_static, + bool defval = false); + std::string render_const_value(std::ofstream& out, t_type* type, t_const_value* value); + + /** + * Service-level generation functions + */ + + void generate_java_struct(t_struct* tstruct, bool is_exception); + + void generate_java_struct_definition(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false, + bool in_class = false, + bool is_result = false); + void generate_java_struct_parcelable(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_equality(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_compare_to(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_reader(std::ofstream& out, t_struct* tstruct); + void generate_java_validator(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_result_writer(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_writer(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_tostring(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_clear(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_write_object(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_read_object(std::ofstream& out, t_struct* tstruct); + void generate_java_meta_data_map(std::ofstream& out, t_struct* tstruct); + void generate_field_value_meta_data(std::ofstream& out, t_type* type); + std::string get_java_type_string(t_type* type); + void generate_java_struct_field_by_id(ofstream& out, t_struct* tstruct); + void generate_reflection_setters(std::ostringstream& out, + t_type* type, + std::string field_name, + std::string cap_name); + void generate_reflection_getters(std::ostringstream& out, + t_type* type, + std::string field_name, + std::string cap_name); + void generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct); + void generate_generic_isset_method(std::ofstream& out, t_struct* tstruct); + void generate_java_bean_boilerplate(std::ofstream& out, t_struct* tstruct); + + void generate_function_helpers(t_function* tfunction); + std::string as_camel_case(std::string name, bool ucfirst = true); + std::string get_rpc_method_name(std::string name); + std::string get_cap_name(std::string name); + std::string generate_isset_check(t_field* field); + std::string generate_isset_check(std::string field); + void generate_isset_set(ofstream& out, t_field* field, std::string prefix); + std::string isset_field_id(t_field* field); + + void generate_service_interface(t_service* tservice); + void generate_service_async_interface(t_service* tservice); + void generate_service_helpers(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_async_client(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_service_async_server(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* tfunction); + void generate_process_async_function(t_service* tservice, t_function* tfunction); + + void generate_java_union(t_struct* tstruct); + void generate_union_constructor(ofstream& out, t_struct* tstruct); + void generate_union_getters_and_setters(ofstream& out, t_struct* tstruct); + void generate_union_is_set_methods(ofstream& out, t_struct* tstruct); + void generate_union_abstract_methods(ofstream& out, t_struct* tstruct); + void generate_check_type(ofstream& out, t_struct* tstruct); + void generate_standard_scheme_read_value(ofstream& out, t_struct* tstruct); + void generate_standard_scheme_write_value(ofstream& out, t_struct* tstruct); + void generate_tuple_scheme_read_value(ofstream& out, t_struct* tstruct); + void generate_tuple_scheme_write_value(ofstream& out, t_struct* tstruct); + void generate_get_field_desc(ofstream& out, t_struct* tstruct); + void generate_get_struct_desc(ofstream& out, t_struct* tstruct); + void generate_get_field_name(ofstream& out, t_struct* tstruct); + + void generate_union_comparisons(ofstream& out, t_struct* tstruct); + void generate_union_hashcode(ofstream& out, t_struct* tstruct); + + void generate_scheme_map(ofstream& out, t_struct* tstruct); + void generate_standard_writer(ofstream& out, t_struct* tstruct, bool is_result); + void generate_standard_reader(ofstream& out, t_struct* tstruct); + void generate_java_struct_standard_scheme(ofstream& out, t_struct* tstruct, bool is_result); + + void generate_java_struct_tuple_scheme(ofstream& out, t_struct* tstruct); + void generate_java_struct_tuple_reader(ofstream& out, t_struct* tstruct); + void generate_java_struct_tuple_writer(ofstream& out, t_struct* tstruct); + + void generate_java_scheme_lookup(ofstream& out); + + void generate_javax_generated_annotation(ofstream& out); + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, + t_field* tfield, + std::string prefix = "", + bool has_metadata = true); + + void generate_deserialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_deserialize_container(std::ofstream& out, + t_type* ttype, + std::string prefix = "", + bool has_metadata = true); + + void generate_deserialize_set_element(std::ofstream& out, + t_set* tset, + std::string prefix = "", + std::string obj = "", + bool has_metadata = true); + + void generate_deserialize_map_element(std::ofstream& out, + t_map* tmap, + std::string prefix = "", + std::string obj = "", + bool has_metadata = true); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix = "", + std::string obj = "", + bool has_metadata = true); + + void generate_serialize_field(std::ofstream& out, + t_field* tfield, + std::string prefix = "", + bool has_metadata = true); + + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_serialize_container(std::ofstream& out, + t_type* ttype, + std::string prefix = "", + bool has_metadata = true); + + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string iter, + std::string map, + bool has_metadata = true); + + void generate_serialize_set_element(std::ofstream& out, + t_set* tmap, + std::string iter, + bool has_metadata = true); + + void generate_serialize_list_element(std::ofstream& out, + t_list* tlist, + std::string iter, + bool has_metadata = true); + + void generate_deep_copy_container(std::ofstream& out, + std::string source_name_p1, + std::string source_name_p2, + std::string result_name, + t_type* type); + void generate_deep_copy_non_container(std::ofstream& out, + std::string source_name, + std::string dest_name, + t_type* type); + + enum isset_type { ISSET_NONE, ISSET_PRIMITIVE, ISSET_BITSET }; + isset_type needs_isset(t_struct* tstruct, std::string* outPrimitiveType = NULL); + + /** + * Helper rendering functions + */ + + std::string java_package(); + std::string java_suppressions(); + std::string type_name(t_type* ttype, + bool in_container = false, + bool in_init = false, + bool skip_generic = false, + bool force_namespace = false); + std::string base_type_name(t_base_type* tbase, bool in_container = false); + std::string declare_field(t_field* tfield, bool init = false, bool comment = false); + std::string function_signature(t_function* tfunction, std::string prefix = ""); + std::string function_signature_async(t_function* tfunction, + bool use_base_method = false, + std::string prefix = ""); + std::string argument_list(t_struct* tstruct, bool include_types = true); + std::string async_function_call_arglist(t_function* tfunc, + bool use_base_method = true, + bool include_types = true); + std::string async_argument_list(t_function* tfunct, + t_struct* tstruct, + t_type* ttype, + bool include_types = false); + std::string type_to_enum(t_type* ttype); + void generate_struct_desc(ofstream& out, t_struct* tstruct); + void generate_field_descs(ofstream& out, t_struct* tstruct); + void generate_field_name_constants(ofstream& out, t_struct* tstruct); + + std::string make_valid_java_filename(std::string const& fromName); + std::string make_valid_java_identifier(std::string const& fromName); + + bool type_can_be_null(t_type* ttype) { + ttype = get_true_type(ttype); + + return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string() + || ttype->is_enum(); + } + + bool is_deprecated(const std::map& annotations) { + return annotations.find("deprecated") != annotations.end(); + } + + bool is_enum_set(t_type* ttype) { + if (!sorted_containers_) { + ttype = get_true_type(ttype); + if (ttype->is_set()) { + t_set* tset = (t_set*)ttype; + t_type* elem_type = get_true_type(tset->get_elem_type()); + return elem_type->is_enum(); + } + } + return false; + } + + bool is_enum_map(t_type* ttype) { + if (!sorted_containers_) { + ttype = get_true_type(ttype); + if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + t_type* key_type = get_true_type(tmap->get_key_type()); + return key_type->is_enum(); + } + } + return false; + } + + std::string inner_enum_type_name(t_type* ttype) { + ttype = get_true_type(ttype); + if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + t_type* key_type = get_true_type(tmap->get_key_type()); + return type_name(key_type, true) + ".class"; + } else if (ttype->is_set()) { + t_set* tset = (t_set*)ttype; + t_type* elem_type = get_true_type(tset->get_elem_type()); + return type_name(elem_type, true) + ".class"; + } + return ""; + } + + std::string constant_name(std::string name); + +private: + /** + * File streams + */ + + std::string package_name_; + std::ofstream f_service_; + std::string package_dir_; + + bool bean_style_; + bool android_style_; + bool private_members_; + bool nocamel_style_; + bool fullcamel_style_; + bool android_legacy_; + bool java5_; + bool sorted_containers_; + bool reuse_objects_; + bool use_option_type_; + bool undated_generated_annotations_; + bool suppress_generated_annotations_; + bool handle_runtime_exceptions_; + +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_java_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + package_name_ = program_->get_namespace("java"); + + string dir = package_name_; + string subdir = get_out_dir(); + string::size_type loc; + while ((loc = dir.find(".")) != string::npos) { + subdir = subdir + "/" + dir.substr(0, loc); + MKDIR(subdir.c_str()); + dir = dir.substr(loc + 1); + } + if (dir.size() > 0) { + subdir = subdir + "/" + dir; + MKDIR(subdir.c_str()); + } + + package_dir_ = subdir; +} + +/** + * Packages the generated file + * + * @return String of the package, i.e. "package org.apache.thriftdemo;" + */ +string t_java_generator::java_package() { + if (!package_name_.empty()) { + return string("package ") + package_name_ + ";\n\n"; + } + return ""; +} + +string t_java_generator::java_suppressions() { + return "@SuppressWarnings({\"cast\", \"rawtypes\", \"serial\", \"unchecked\", \"unused\"})\n"; +} + +/** + * Nothing in Java + */ +void t_java_generator::close_generator() { +} + +/** + * Generates a typedef. This is not done in Java, since it does + * not support arbitrary name replacements, and it'd be a wacky waste + * of overhead to make wrapper classes. + * + * @param ttypedef The type definition + */ +void t_java_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + +/** + * Enums are a class with a set of static constants. + * + * @param tenum The enumeration + */ +void t_java_generator::generate_enum(t_enum* tenum) { + bool is_deprecated = this->is_deprecated(tenum->annotations_); + // Make output file + string f_enum_name = package_dir_ + "/" + make_valid_java_filename(tenum->get_name()) + ".java"; + ofstream f_enum; + f_enum.open(f_enum_name.c_str()); + + // Comment and package it + f_enum << autogen_comment() << java_package() << endl; + + generate_java_doc(f_enum, tenum); + if (is_deprecated) { + indent(f_enum) << "@Deprecated" << endl; + } + indent(f_enum) << "public enum " << tenum->get_name() << " implements org.apache.thrift.TEnum "; + scope_up(f_enum); + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + bool first = true; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + + if (first) { + first = false; + } else { + f_enum << "," << endl; + } + + generate_java_doc(f_enum, *c_iter); + if (this->is_deprecated((*c_iter)->annotations_)) { + indent(f_enum) << "@Deprecated" << endl; + } + indent(f_enum) << (*c_iter)->get_name() << "(" << value << ")"; + } + f_enum << ";" << endl << endl; + + // Field for thriftCode + indent(f_enum) << "private final int value;" << endl << endl; + + indent(f_enum) << "private " << tenum->get_name() << "(int value) {" << endl; + indent(f_enum) << " this.value = value;" << endl; + indent(f_enum) << "}" << endl << endl; + + indent(f_enum) << "/**" << endl; + indent(f_enum) << " * Get the integer value of this enum value, as defined in the Thrift IDL." + << endl; + indent(f_enum) << " */" << endl; + indent(f_enum) << "public int getValue() {" << endl; + indent(f_enum) << " return value;" << endl; + indent(f_enum) << "}" << endl << endl; + + indent(f_enum) << "/**" << endl; + indent(f_enum) << " * Find a the enum type by its integer value, as defined in the Thrift IDL." + << endl; + indent(f_enum) << " * @return null if the value is not found." << endl; + indent(f_enum) << " */" << endl; + indent(f_enum) << "public static " + tenum->get_name() + " findByValue(int value) { " << endl; + + indent_up(); + + indent(f_enum) << "switch (value) {" << endl; + indent_up(); + + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + indent(f_enum) << "case " << value << ":" << endl; + indent(f_enum) << " return " << (*c_iter)->get_name() << ";" << endl; + } + + indent(f_enum) << "default:" << endl; + indent(f_enum) << " return null;" << endl; + + indent_down(); + + indent(f_enum) << "}" << endl; + + indent_down(); + + indent(f_enum) << "}" << endl; + + scope_down(f_enum); + + f_enum.close(); +} + +/** + * Generates a class that holds all the constants. + */ +void t_java_generator::generate_consts(std::vector consts) { + if (consts.empty()) { + return; + } + + string f_consts_name = package_dir_ + '/' + make_valid_java_filename(program_name_) + + "Constants.java"; + ofstream f_consts; + f_consts.open(f_consts_name.c_str()); + + // Print header + f_consts << autogen_comment() << java_package() << java_suppressions(); + + f_consts << "public class " << make_valid_java_identifier(program_name_) << "Constants {" << endl + << endl; + indent_up(); + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + generate_java_doc(f_consts, (*c_iter)); + print_const_value(f_consts, + (*c_iter)->get_name(), + (*c_iter)->get_type(), + (*c_iter)->get_value(), + false); + } + indent_down(); + indent(f_consts) << "}" << endl; + f_consts.close(); +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +void t_java_generator::print_const_value(std::ofstream& out, + string name, + t_type* type, + t_const_value* value, + bool in_static, + bool defval) { + type = get_true_type(type); + + indent(out); + if (!defval) { + out << (in_static ? "" : "public static final ") << type_name(type) << " "; + } + if (type->is_base_type()) { + string v2 = render_const_value(out, type, value); + out << name << " = " << v2 << ";" << endl << endl; + } else if (type->is_enum()) { + out << name << " = " << render_const_value(out, type, value) << ";" << endl << endl; + } else if (type->is_struct() || type->is_xception()) { + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + out << name << " = new " << type_name(type, false, true) << "();" << endl; + if (!in_static) { + indent(out) << "static {" << endl; + indent_up(); + } + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + string val = render_const_value(out, field_type, v_iter->second); + indent(out) << name << "."; + std::string cap_name = get_cap_name(v_iter->first->get_string()); + out << "set" << cap_name << "(" << val << ");" << endl; + } + if (!in_static) { + indent_down(); + indent(out) << "}" << endl; + } + out << endl; + } else if (type->is_map()) { + std::string constructor_args; + if (is_enum_map(type)) { + constructor_args = inner_enum_type_name(type); + } + out << name << " = new " << type_name(type, false, true) << "(" << constructor_args << ");" << endl; + if (!in_static) { + indent(out) << "static {" << endl; + indent_up(); + } + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string key = render_const_value(out, ktype, v_iter->first); + string val = render_const_value(out, vtype, v_iter->second); + indent(out) << name << ".put(" << key << ", " << val << ");" << endl; + } + if (!in_static) { + indent_down(); + indent(out) << "}" << endl; + } + out << endl; + } else if (type->is_list() || type->is_set()) { + if (is_enum_set(type)) { + out << name << " = " << type_name(type, false, true, true) << ".noneOf(" << inner_enum_type_name(type) << ");" << endl; + } else { + out << name << " = new " << type_name(type, false, true) << "();" << endl; + } + if (!in_static) { + indent(out) << "static {" << endl; + indent_up(); + } + t_type* etype; + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(out, etype, *v_iter); + indent(out) << name << ".add(" << val << ");" << endl; + } + if (!in_static) { + indent_down(); + indent(out) << "}" << endl; + } + out << endl; + } else { + throw "compiler error: no const of type " + type->get_name(); + } +} + +string t_java_generator::render_const_value(ofstream& out, t_type* type, t_const_value* value) { + type = get_true_type(type); + std::ostringstream render; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + render << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() > 0) ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + render << "(byte)" << value->get_integer(); + break; + case t_base_type::TYPE_I16: + render << "(short)" << value->get_integer(); + break; + case t_base_type::TYPE_I32: + render << value->get_integer(); + break; + case t_base_type::TYPE_I64: + render << value->get_integer() << "L"; + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + render << "(double)" << value->get_integer(); + } else { + render << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + std::string namespace_prefix = type->get_program()->get_namespace("java"); + if (namespace_prefix.length() > 0) { + namespace_prefix += "."; + } + render << namespace_prefix << value->get_identifier_with_parent(); + } else { + string t = tmp("tmp"); + print_const_value(out, t, type, value, true); + render << t; + } + + return render.str(); +} + +/** + * Generates a struct definition for a thrift data type. This will be a org.apache.thrift.TBase + * implementor. + * + * @param tstruct The struct definition + */ +void t_java_generator::generate_struct(t_struct* tstruct) { + if (tstruct->is_union()) { + generate_java_union(tstruct); + } else { + generate_java_struct(tstruct, false); + } +} + +/** + * Exceptions are structs, but they inherit from Exception + * + * @param tstruct The struct definition + */ +void t_java_generator::generate_xception(t_struct* txception) { + generate_java_struct(txception, true); +} + +/** + * Java struct definition. + * + * @param tstruct The struct definition + */ +void t_java_generator::generate_java_struct(t_struct* tstruct, bool is_exception) { + // Make output file + string f_struct_name = package_dir_ + "/" + make_valid_java_filename(tstruct->get_name()) + + ".java"; + ofstream f_struct; + f_struct.open(f_struct_name.c_str()); + + f_struct << autogen_comment() << java_package() << java_suppressions(); + + generate_java_struct_definition(f_struct, tstruct, is_exception); + f_struct.close(); +} + +/** + * Java union definition. + * + * @param tstruct The struct definition + */ +void t_java_generator::generate_java_union(t_struct* tstruct) { + // Make output file + string f_struct_name = package_dir_ + "/" + make_valid_java_filename(tstruct->get_name()) + + ".java"; + ofstream f_struct; + f_struct.open(f_struct_name.c_str()); + + f_struct << autogen_comment() << java_package() << java_suppressions(); + + generate_java_doc(f_struct, tstruct); + + bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); + bool is_deprecated = this->is_deprecated(tstruct->annotations_); + + if (is_deprecated) { + indent(f_struct) << "@Deprecated" << endl; + } + indent(f_struct) << "public " << (is_final ? "final " : "") << "class " << tstruct->get_name() + << " extends org.apache.thrift.TUnion<" << tstruct->get_name() << ", " + << tstruct->get_name() << "._Fields> "; + + scope_up(f_struct); + + generate_struct_desc(f_struct, tstruct); + generate_field_descs(f_struct, tstruct); + + f_struct << endl; + + generate_field_name_constants(f_struct, tstruct); + + f_struct << endl; + + generate_java_meta_data_map(f_struct, tstruct); + + generate_union_constructor(f_struct, tstruct); + + f_struct << endl; + + generate_union_abstract_methods(f_struct, tstruct); + + f_struct << endl; + + generate_java_struct_field_by_id(f_struct, tstruct); + + f_struct << endl; + + generate_union_getters_and_setters(f_struct, tstruct); + + f_struct << endl; + + generate_union_is_set_methods(f_struct, tstruct); + + f_struct << endl; + + generate_union_comparisons(f_struct, tstruct); + + f_struct << endl; + + generate_union_hashcode(f_struct, tstruct); + + f_struct << endl; + + generate_java_struct_write_object(f_struct, tstruct); + + f_struct << endl; + + generate_java_struct_read_object(f_struct, tstruct); + + f_struct << endl; + + scope_down(f_struct); + + f_struct.close(); +} + +void t_java_generator::generate_union_constructor(ofstream& out, t_struct* tstruct) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + indent(out) << "public " << type_name(tstruct) << "() {" << endl; + indent_up(); + bool default_value = false; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* type = get_true_type((*m_iter)->get_type()); + if ((*m_iter)->get_value() != NULL) { + indent(out) << "super(_Fields." << constant_name((*m_iter)->get_name()) << ", " + << render_const_value(out, type, (*m_iter)->get_value()) << ");" << endl; + default_value = true; + break; + } + } + if (default_value == false) { + indent(out) << "super();" << endl; + } + indent_down(); + indent(out) << "}" << endl << endl; + + indent(out) << "public " << type_name(tstruct) << "(_Fields setField, java.lang.Object value) {" << endl; + indent(out) << " super(setField, value);" << endl; + indent(out) << "}" << endl << endl; + + indent(out) << "public " << type_name(tstruct) << "(" << type_name(tstruct) << " other) {" + << endl; + indent(out) << " super(other);" << endl; + indent(out) << "}" << endl; + + indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl; + indent(out) << " return new " << tstruct->get_name() << "(this);" << endl; + indent(out) << "}" << endl << endl; + + // generate "constructors" for each field + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* type = (*m_iter)->get_type(); + indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() << "(" + << type_name(type) << " value) {" << endl; + indent(out) << " " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" << endl; + indent(out) << " x.set" << get_cap_name((*m_iter)->get_name()) << "(value);" << endl; + indent(out) << " return x;" << endl; + indent(out) << "}" << endl << endl; + + if (type->is_binary()) { + indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() + << "(byte[] value) {" << endl; + indent(out) << " " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" + << endl; + indent(out) << " x.set" << get_cap_name((*m_iter)->get_name()) + << "(java.nio.ByteBuffer.wrap(value.clone()));" << endl; + indent(out) << " return x;" << endl; + indent(out) << "}" << endl << endl; + } + } +} + +void t_java_generator::generate_union_getters_and_setters(ofstream& out, t_struct* tstruct) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + bool first = true; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (first) { + first = false; + } else { + out << endl; + } + + t_field* field = (*m_iter); + t_type* type = field->get_type(); + std::string cap_name = get_cap_name(field->get_name()); + bool is_deprecated = this->is_deprecated(field->annotations_); + + generate_java_doc(out, field); + if (type->is_binary()) { + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public byte[] get" << cap_name << "() {" << endl; + indent(out) << " set" << cap_name << "(org.apache.thrift.TBaseHelper.rightSize(buffer" + << get_cap_name("for") << cap_name << "()));" << endl; + indent(out) << " java.nio.ByteBuffer b = buffer" << get_cap_name("for") << cap_name << "();" << endl; + indent(out) << " return b == null ? null : b.array();" << endl; + indent(out) << "}" << endl; + + out << endl; + + indent(out) << "public java.nio.ByteBuffer buffer" << get_cap_name("for") + << get_cap_name(field->get_name()) << "() {" << endl; + indent(out) << " if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {" + << endl; + indent(out) + << " return org.apache.thrift.TBaseHelper.copyBinary((java.nio.ByteBuffer)getFieldValue());" + << endl; + indent(out) << " } else {" << endl; + indent(out) << " throw new java.lang.RuntimeException(\"Cannot get field '" << field->get_name() + << "' because union is currently set to \" + getFieldDesc(getSetField()).name);" + << endl; + indent(out) << " }" << endl; + indent(out) << "}" << endl; + } else { + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public " << type_name(field->get_type()) << " get" + << get_cap_name(field->get_name()) << "() {" << endl; + indent(out) << " if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {" + << endl; + indent(out) << " return (" << type_name(field->get_type(), true) << ")getFieldValue();" + << endl; + indent(out) << " } else {" << endl; + indent(out) << " throw new java.lang.RuntimeException(\"Cannot get field '" << field->get_name() + << "' because union is currently set to \" + getFieldDesc(getSetField()).name);" + << endl; + indent(out) << " }" << endl; + indent(out) << "}" << endl; + } + + out << endl; + + generate_java_doc(out, field); + if (type->is_binary()) { + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public void set" << get_cap_name(field->get_name()) << "(byte[] value) {" + << endl; + indent(out) << " set" << get_cap_name(field->get_name()) + << "(java.nio.ByteBuffer.wrap(value.clone()));" << endl; + indent(out) << "}" << endl; + + out << endl; + } + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public void set" << get_cap_name(field->get_name()) << "(" + << type_name(field->get_type()) << " value) {" << endl; + if (type_can_be_null(field->get_type())) { + indent(out) << " if (value == null) throw new java.lang.NullPointerException();" << endl; + } + indent(out) << " setField_ = _Fields." << constant_name(field->get_name()) << ";" << endl; + indent(out) << " value_ = value;" << endl; + indent(out) << "}" << endl; + } +} + +void t_java_generator::generate_union_is_set_methods(ofstream& out, t_struct* tstruct) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + bool first = true; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (first) { + first = false; + } else { + out << endl; + } + + std::string field_name = (*m_iter)->get_name(); + + indent(out) << "public boolean is" << get_cap_name("set") << get_cap_name(field_name) << "() {" + << endl; + indent_up(); + indent(out) << "return setField_ == _Fields." << constant_name(field_name) << ";" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } +} + +void t_java_generator::generate_union_abstract_methods(ofstream& out, t_struct* tstruct) { + generate_check_type(out, tstruct); + out << endl; + generate_standard_scheme_read_value(out, tstruct); + out << endl; + generate_standard_scheme_write_value(out, tstruct); + out << endl; + generate_tuple_scheme_read_value(out, tstruct); + out << endl; + generate_tuple_scheme_write_value(out, tstruct); + out << endl; + generate_get_field_desc(out, tstruct); + out << endl; + generate_get_struct_desc(out, tstruct); + out << endl; + indent(out) << "@Override" << endl; + indent(out) << "protected _Fields enumForId(short id) {" << endl; + indent(out) << " return _Fields.findByThriftIdOrThrow(id);" << endl; + indent(out) << "}" << endl; +} + +void t_java_generator::generate_check_type(ofstream& out, t_struct* tstruct) { + indent(out) << "@Override" << endl; + indent(out) + << "protected void checkType(_Fields setField, java.lang.Object value) throws java.lang.ClassCastException {" + << endl; + indent_up(); + + indent(out) << "switch (setField) {" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = (*m_iter); + + indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; + indent(out) << " if (value instanceof " << type_name(field->get_type(), true, false, true) + << ") {" << endl; + indent(out) << " break;" << endl; + indent(out) << " }" << endl; + indent(out) << " throw new java.lang.ClassCastException(\"Was expecting value of type " + << type_name(field->get_type(), true, false) << " for field '" << field->get_name() + << "', but got \" + value.getClass().getSimpleName());" << endl; + // do the real check here + } + + indent(out) << "default:" << endl; + indent(out) << " throw new java.lang.IllegalArgumentException(\"Unknown field id \" + setField);" << endl; + + indent_down(); + indent(out) << "}" << endl; + + indent_down(); + indent(out) << "}" << endl; +} + +void t_java_generator::generate_standard_scheme_read_value(ofstream& out, t_struct* tstruct) { + indent(out) << "@Override" << endl; + indent(out) << "protected java.lang.Object standardSchemeReadValue(org.apache.thrift.protocol.TProtocol " + "iprot, org.apache.thrift.protocol.TField field) throws " + "org.apache.thrift.TException {" << endl; + + indent_up(); + + indent(out) << "_Fields setField = _Fields.findByThriftId(field.id);" << endl; + indent(out) << "if (setField != null) {" << endl; + indent_up(); + indent(out) << "switch (setField) {" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = (*m_iter); + + indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; + indent_up(); + indent(out) << "if (field.type == " << constant_name(field->get_name()) << "_FIELD_DESC.type) {" + << endl; + indent_up(); + indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";" + << endl; + generate_deserialize_field(out, field, ""); + indent(out) << "return " << field->get_name() << ";" << endl; + indent_down(); + indent(out) << "} else {" << endl; + indent(out) << " org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);" << endl; + indent(out) << " return null;" << endl; + indent(out) << "}" << endl; + indent_down(); + } + + indent(out) << "default:" << endl; + indent(out) << " throw new java.lang.IllegalStateException(\"setField wasn't null, but didn't match any " + "of the case statements!\");" << endl; + + indent_down(); + indent(out) << "}" << endl; + + indent_down(); + indent(out) << "} else {" << endl; + indent_up(); + indent(out) << "org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);" << endl; + indent(out) << "return null;" << endl; + indent_down(); + indent(out) << "}" << endl; + + indent_down(); + indent(out) << "}" << endl; +} + +void t_java_generator::generate_standard_scheme_write_value(ofstream& out, t_struct* tstruct) { + indent(out) << "@Override" << endl; + indent(out) << "protected void standardSchemeWriteValue(org.apache.thrift.protocol.TProtocol " + "oprot) throws org.apache.thrift.TException {" << endl; + + indent_up(); + + indent(out) << "switch (setField_) {" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = (*m_iter); + + indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; + indent_up(); + indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << " = (" + << type_name(field->get_type(), true, false) << ")value_;" << endl; + generate_serialize_field(out, field, ""); + indent(out) << "return;" << endl; + indent_down(); + } + + indent(out) << "default:" << endl; + indent(out) << " throw new java.lang.IllegalStateException(\"Cannot write union with unknown field \" + " + "setField_);" << endl; + + indent_down(); + indent(out) << "}" << endl; + + indent_down(); + + indent(out) << "}" << endl; +} + +void t_java_generator::generate_tuple_scheme_read_value(ofstream& out, t_struct* tstruct) { + indent(out) << "@Override" << endl; + indent(out) << "protected java.lang.Object tupleSchemeReadValue(org.apache.thrift.protocol.TProtocol " + "iprot, short fieldID) throws org.apache.thrift.TException {" << endl; + + indent_up(); + + indent(out) << "_Fields setField = _Fields.findByThriftId(fieldID);" << endl; + indent(out) << "if (setField != null) {" << endl; + indent_up(); + indent(out) << "switch (setField) {" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = (*m_iter); + + indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; + indent_up(); + indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";" + << endl; + generate_deserialize_field(out, field, ""); + indent(out) << "return " << field->get_name() << ";" << endl; + indent_down(); + } + + indent(out) << "default:" << endl; + indent(out) << " throw new java.lang.IllegalStateException(\"setField wasn't null, but didn't match any " + "of the case statements!\");" << endl; + + indent_down(); + indent(out) << "}" << endl; + + indent_down(); + indent(out) << "} else {" << endl; + indent_up(); + indent(out) << "throw new org.apache.thrift.protocol.TProtocolException(\"Couldn't find a field with field id \" + fieldID);" + << endl; + indent_down(); + indent(out) << "}" << endl; + indent_down(); + indent(out) << "}" << endl; +} + +void t_java_generator::generate_tuple_scheme_write_value(ofstream& out, t_struct* tstruct) { + indent(out) << "@Override" << endl; + indent(out) << "protected void tupleSchemeWriteValue(org.apache.thrift.protocol.TProtocol oprot) " + "throws org.apache.thrift.TException {" << endl; + + indent_up(); + + indent(out) << "switch (setField_) {" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = (*m_iter); + + indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; + indent_up(); + indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << " = (" + << type_name(field->get_type(), true, false) << ")value_;" << endl; + generate_serialize_field(out, field, ""); + indent(out) << "return;" << endl; + indent_down(); + } + + indent(out) << "default:" << endl; + indent(out) << " throw new java.lang.IllegalStateException(\"Cannot write union with unknown field \" + " + "setField_);" << endl; + + indent_down(); + indent(out) << "}" << endl; + + indent_down(); + + indent(out) << "}" << endl; +} + +void t_java_generator::generate_get_field_desc(ofstream& out, t_struct* tstruct) { + indent(out) << "@Override" << endl; + indent(out) << "protected org.apache.thrift.protocol.TField getFieldDesc(_Fields setField) {" + << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + indent(out) << "switch (setField) {" << endl; + indent_up(); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = (*m_iter); + indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; + indent(out) << " return " << constant_name(field->get_name()) << "_FIELD_DESC;" << endl; + } + + indent(out) << "default:" << endl; + indent(out) << " throw new java.lang.IllegalArgumentException(\"Unknown field id \" + setField);" << endl; + + indent_down(); + indent(out) << "}" << endl; + + indent_down(); + indent(out) << "}" << endl; +} + +void t_java_generator::generate_get_struct_desc(ofstream& out, t_struct* tstruct) { + (void)tstruct; + indent(out) << "@Override" << endl; + indent(out) << "protected org.apache.thrift.protocol.TStruct getStructDesc() {" << endl; + indent(out) << " return STRUCT_DESC;" << endl; + indent(out) << "}" << endl; +} + +void t_java_generator::generate_union_comparisons(ofstream& out, t_struct* tstruct) { + // equality + indent(out) << "public boolean equals(java.lang.Object other) {" << endl; + indent(out) << " if (other instanceof " << tstruct->get_name() << ") {" << endl; + indent(out) << " return equals((" << tstruct->get_name() << ")other);" << endl; + indent(out) << " } else {" << endl; + indent(out) << " return false;" << endl; + indent(out) << " }" << endl; + indent(out) << "}" << endl; + + out << endl; + + indent(out) << "public boolean equals(" << tstruct->get_name() << " other) {" << endl; + indent(out) << " return other != null && getSetField() == other.getSetField() && " + "getFieldValue().equals(other.getFieldValue());" << endl; + indent(out) << "}" << endl; + out << endl; + + indent(out) << "@Override" << endl; + indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl; + indent(out) << " int lastComparison = org.apache.thrift.TBaseHelper.compareTo(getSetField(), " + "other.getSetField());" << endl; + indent(out) << " if (lastComparison == 0) {" << endl; + indent(out) << " return org.apache.thrift.TBaseHelper.compareTo(getFieldValue(), " + "other.getFieldValue());" << endl; + indent(out) << " }" << endl; + indent(out) << " return lastComparison;" << endl; + indent(out) << "}" << endl; + out << endl; +} + +void t_java_generator::generate_union_hashcode(ofstream& out, t_struct* tstruct) { + (void)tstruct; + indent(out) << "@Override" << endl; + indent(out) << "public int hashCode() {" << endl; + indent(out) << " java.util.List list = new java.util.ArrayList();" << endl; + indent(out) << " list.add(this.getClass().getName());" << endl; + indent(out) << " org.apache.thrift.TFieldIdEnum setField = getSetField();" << endl; + indent(out) << " if (setField != null) {" << endl; + indent(out) << " list.add(setField.getThriftFieldId());" << endl; + indent(out) << " java.lang.Object value = getFieldValue();" << endl; + indent(out) << " if (value instanceof org.apache.thrift.TEnum) {" << endl; + indent(out) << " list.add(((org.apache.thrift.TEnum)getFieldValue()).getValue());" << endl; + indent(out) << " } else {" << endl; + indent(out) << " list.add(value);" << endl; + indent(out) << " }" << endl; + indent(out) << " }" << endl; + indent(out) << " return list.hashCode();" << endl; + indent(out) << "}"; +} + +/** + * Java struct definition. This has various parameters, as it could be + * generated standalone or inside another class as a helper. If it + * is a helper than it is a static class. + * + * @param tstruct The struct definition + * @param is_exception Is this an exception? + * @param in_class If inside a class, needs to be static class + * @param is_result If this is a result it needs a different writer + */ +void t_java_generator::generate_java_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool in_class, + bool is_result) { + generate_java_doc(out, tstruct); + + bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); + bool is_deprecated = this->is_deprecated(tstruct->annotations_); + + if (!in_class && !suppress_generated_annotations_) { + generate_javax_generated_annotation(out); + } + + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public " << (is_final ? "final " : "") << (in_class ? "static " : "") << "class " + << tstruct->get_name() << " "; + + if (is_exception) { + out << "extends org.apache.thrift.TException "; + } + out << "implements org.apache.thrift.TBase<" << tstruct->get_name() << ", " << tstruct->get_name() + << "._Fields>, java.io.Serializable, Cloneable, Comparable<" << tstruct->get_name() << ">"; + + if (android_style_) { + out << ", android.os.Parcelable"; + } + + out << " "; + + scope_up(out); + + generate_struct_desc(out, tstruct); + + // Members are public for -java, private for -javabean + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + out << endl; + + generate_field_descs(out, tstruct); + + out << endl; + + generate_scheme_map(out, tstruct); + + out << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (bean_style_ || private_members_) { + indent(out) << "private "; + } else { + generate_java_doc(out, *m_iter); + indent(out) << "public "; + } + out << declare_field(*m_iter, false, true) << endl; + } + + out << endl; + + if (android_style_) { + generate_java_struct_parcelable(out, tstruct); + } + + generate_field_name_constants(out, tstruct); + + // isset data + if (members.size() > 0) { + out << endl; + + indent(out) << "// isset id assignments" << endl; + + int i = 0; + int optionals = 0; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() == t_field::T_OPTIONAL) { + optionals++; + } + if (!type_can_be_null((*m_iter)->get_type())) { + indent(out) << "private static final int " << isset_field_id(*m_iter) << " = " << i << ";" + << endl; + i++; + } + } + + std::string primitiveType; + switch (needs_isset(tstruct, &primitiveType)) { + case ISSET_NONE: + break; + case ISSET_PRIMITIVE: + indent(out) << "private " << primitiveType << " __isset_bitfield = 0;" << endl; + break; + case ISSET_BITSET: + indent(out) << "private java.util.BitSet __isset_bit_vector = new java.util.BitSet(" << i << ");" << endl; + break; + } + + if (optionals > 0) { + std::string output_string = "private static final _Fields optionals[] = {"; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() == t_field::T_OPTIONAL) { + output_string = output_string + "_Fields." + constant_name((*m_iter)->get_name()) + ","; + } + } + indent(out) << output_string.substr(0, output_string.length() - 1) << "};" << endl; + } + } + + generate_java_meta_data_map(out, tstruct); + + bool all_optional_members = true; + + // Default constructor + indent(out) << "public " << tstruct->get_name() << "() {" << endl; + indent_up(); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if ((*m_iter)->get_value() != NULL) { + print_const_value(out, + "this." + (*m_iter)->get_name(), + t, + (*m_iter)->get_value(), + true, + true); + } + if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { + all_optional_members = false; + } + } + indent_down(); + indent(out) << "}" << endl << endl; + + if (!members.empty() && !all_optional_members) { + // Full constructor for all fields + indent(out) << "public " << tstruct->get_name() << "(" << endl; + indent_up(); + bool first = true; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { + if (!first) { + out << "," << endl; + } + first = false; + indent(out) << type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name(); + } + } + out << ")" << endl; + indent_down(); + indent(out) << "{" << endl; + indent_up(); + indent(out) << "this();" << endl; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { + t_type* type = get_true_type((*m_iter)->get_type()); + if (type->is_binary()) { + indent(out) << "this." << (*m_iter)->get_name() + << " = org.apache.thrift.TBaseHelper.copyBinary(" << (*m_iter)->get_name() + << ");" << endl; + } else { + indent(out) << "this." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << ";" + << endl; + } + generate_isset_set(out, (*m_iter), ""); + } + } + + indent_down(); + indent(out) << "}" << endl << endl; + } + + // copy constructor + indent(out) << "/**" << endl; + indent(out) << " * Performs a deep copy on other." << endl; + indent(out) << " */" << endl; + indent(out) << "public " << tstruct->get_name() << "(" << tstruct->get_name() << " other) {" + << endl; + indent_up(); + + switch (needs_isset(tstruct)) { + case ISSET_NONE: + break; + case ISSET_PRIMITIVE: + indent(out) << "__isset_bitfield = other.__isset_bitfield;" << endl; + break; + case ISSET_BITSET: + indent(out) << "__isset_bit_vector.clear();" << endl; + indent(out) << "__isset_bit_vector.or(other.__isset_bit_vector);" << endl; + break; + } + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = (*m_iter); + std::string field_name = field->get_name(); + t_type* type = field->get_type()->get_true_type(); + bool can_be_null = type_can_be_null(type); + + if (can_be_null) { + indent(out) << "if (other." << generate_isset_check(field) << ") {" << endl; + indent_up(); + } + + if (type->is_container()) { + generate_deep_copy_container(out, "other", field_name, "__this__" + field_name, type); + indent(out) << "this." << field_name << " = __this__" << field_name << ";" << endl; + } else { + indent(out) << "this." << field_name << " = "; + generate_deep_copy_non_container(out, "other." + field_name, field_name, type); + out << ";" << endl; + } + + if (can_be_null) { + indent_down(); + indent(out) << "}" << endl; + } + } + + indent_down(); + indent(out) << "}" << endl << endl; + + // clone method, so that you can deep copy an object when you don't know its class. + indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl; + indent(out) << " return new " << tstruct->get_name() << "(this);" << endl; + indent(out) << "}" << endl << endl; + + generate_java_struct_clear(out, tstruct); + + generate_java_bean_boilerplate(out, tstruct); + generate_generic_field_getters_setters(out, tstruct); + generate_generic_isset_method(out, tstruct); + + generate_java_struct_equality(out, tstruct); + generate_java_struct_compare_to(out, tstruct); + generate_java_struct_field_by_id(out, tstruct); + + generate_java_struct_reader(out, tstruct); + if (is_result) { + generate_java_struct_result_writer(out, tstruct); + } else { + generate_java_struct_writer(out, tstruct); + } + generate_java_struct_tostring(out, tstruct); + generate_java_validator(out, tstruct); + + generate_java_struct_write_object(out, tstruct); + generate_java_struct_read_object(out, tstruct); + + generate_java_struct_standard_scheme(out, tstruct, is_result); + generate_java_struct_tuple_scheme(out, tstruct); + generate_java_scheme_lookup(out); + + scope_down(out); + out << endl; +} + +/** + * generates parcelable interface implementation + */ +void t_java_generator::generate_java_struct_parcelable(ofstream& out, t_struct* tstruct) { + string tname = tstruct->get_name(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + out << indent() << "@Override" << endl << indent() + << "public void writeToParcel(android.os.Parcel out, int flags) {" << endl; + indent_up(); + string bitsetPrimitiveType = ""; + switch (needs_isset(tstruct, &bitsetPrimitiveType)) { + case ISSET_NONE: + break; + case ISSET_PRIMITIVE: + indent(out) << "//primitive bitfield of type: " << bitsetPrimitiveType << endl; + if (bitsetPrimitiveType == "byte") { + indent(out) << "out.writeByte(__isset_bitfield);" << endl; + } else if (bitsetPrimitiveType == "short") { + indent(out) << "out.writeInt(new Short(__isset_bitfield).intValue());" << endl; + } else if (bitsetPrimitiveType == "int") { + indent(out) << "out.writeInt(__isset_bitfield);" << endl; + } else if (bitsetPrimitiveType == "long") { + indent(out) << "out.writeLong(__isset_bitfield);" << endl; + } + out << endl; + break; + case ISSET_BITSET: + indent(out) << "//BitSet" << endl; + indent(out) << "out.writeSerializable(__isset_bit_vector);" << endl; + out << endl; + break; + } + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + string name = (*m_iter)->get_name(); + + if (t->is_struct()) { + indent(out) << "out.writeParcelable(" << name << ", flags);" << endl; + } else if (type_name(t) == "float") { + indent(out) << "out.writeFloat(" << name << ");" << endl; + } else if (t->is_enum()) { + indent(out) << "out.writeInt(" << name << " != null ? " << name << ".getValue() : -1);" << endl; + } else if (t->is_list()) { + if (((t_list*)t)->get_elem_type()->get_true_type()->is_struct()) { + indent(out) << "out.writeTypedList(" << name << ");" << endl; + } else { + indent(out) << "out.writeList(" << name << ");" << endl; + } + } else if (t->is_map()) { + indent(out) << "out.writeMap(" << name << ");" << endl; + } else if (t->is_base_type()) { + if (t->is_binary()) { + indent(out) << "out.writeInt(" << name << "!=null ? 1 : 0);" << endl; + indent(out) << "if(" << name << " != null) { " << endl; + indent_up(); + indent(out) << "out.writeByteArray(" << name << ".array(), " << name << ".position() + " + << name << ".arrayOffset(), " << name << ".limit() - " << name + << ".position() );" << endl; + scope_down(out); + } else { + switch (((t_base_type*)t)->get_base()) { + case t_base_type::TYPE_I16: + indent(out) << "out.writeInt(new Short(" << name << ").intValue());" << endl; + break; + case t_base_type::TYPE_I32: + indent(out) << "out.writeInt(" << name << ");" << endl; + break; + case t_base_type::TYPE_I64: + indent(out) << "out.writeLong(" << name << ");" << endl; + break; + case t_base_type::TYPE_BOOL: + indent(out) << "out.writeInt(" << name << " ? 1 : 0);" << endl; + break; + case t_base_type::TYPE_I8: + indent(out) << "out.writeByte(" << name << ");" << endl; + break; + case t_base_type::TYPE_DOUBLE: + indent(out) << "out.writeDouble(" << name << ");" << endl; + break; + case t_base_type::TYPE_STRING: + indent(out) << "out.writeString(" << name << ");" << endl; + break; + case t_base_type::TYPE_VOID: + break; + } + } + } + } + scope_down(out); + out << endl; + + out << indent() << "@Override" << endl << indent() << "public int describeContents() {" << endl; + indent_up(); + out << indent() << "return 0;" << endl; + scope_down(out); + out << endl; + + indent(out) << "public " << tname << "(android.os.Parcel in) {" << endl; + indent_up(); + // read in the required bitfield + switch (needs_isset(tstruct, &bitsetPrimitiveType)) { + case ISSET_NONE: + break; + case ISSET_PRIMITIVE: + indent(out) << "//primitive bitfield of type: " << bitsetPrimitiveType << endl; + if (bitsetPrimitiveType == "byte") { + indent(out) << "__isset_bitfield = in.readByte();" << endl; + } else if (bitsetPrimitiveType == "short") { + indent(out) << "__isset_bitfield = (short) in.readInt();" << endl; + } else if (bitsetPrimitiveType == "int") { + indent(out) << "__isset_bitfield = in.readInt();" << endl; + } else if (bitsetPrimitiveType == "long") { + indent(out) << "__isset_bitfield = in.readLong();" << endl; + } + out << endl; + break; + case ISSET_BITSET: + indent(out) << "//BitSet" << endl; + indent(out) << "__isset_bit_vector = (java.util.BitSet) in.readSerializable();" << endl; + out << endl; + break; + } + // read all the fields + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + string name = (*m_iter)->get_name(); + string prefix = "this." + name; + + if (t->is_struct()) { + indent(out) << prefix << "= in.readParcelable(" << tname << ".class.getClassLoader());" + << endl; + } else if (t->is_enum()) { + indent(out) << prefix << " = " << type_name(t) << ".findByValue(in.readInt());" << endl; + } else if (t->is_list()) { + t_list* list = (t_list*)t; + indent(out) << prefix << " = new " << type_name(t, false, true) << "();" << endl; + if (list->get_elem_type()->get_true_type()->is_struct()) { + indent(out) << "in.readTypedList(" << prefix << ", " << type_name(list->get_elem_type()) + << ".CREATOR);" << endl; + } else { + indent(out) << "in.readList(" << prefix << ", " << tname << ".class.getClassLoader());" + << endl; + } + } else if (t->is_map()) { + indent(out) << prefix << " = new " << type_name(t, false, true) << "();" << endl; + indent(out) << " in.readMap(" << prefix << ", " << tname << ".class.getClassLoader());" + << endl; + } else if (type_name(t) == "float") { + indent(out) << prefix << " = in.readFloat();" << endl; + } else if (t->is_base_type()) { + t_base_type* bt = (t_base_type*)t; + if (bt->is_binary()) { + indent(out) << "if(in.readInt()==1) {" << endl; + indent_up(); + indent(out) << prefix << " = java.nio.ByteBuffer.wrap(in.createByteArray());" << endl; + scope_down(out); + } else { + switch (bt->get_base()) { + case t_base_type::TYPE_I16: + indent(out) << prefix << " = (short) in.readInt();" << endl; + break; + case t_base_type::TYPE_I32: + indent(out) << prefix << " = in.readInt();" << endl; + break; + case t_base_type::TYPE_I64: + indent(out) << prefix << " = in.readLong();" << endl; + break; + case t_base_type::TYPE_BOOL: + indent(out) << prefix << " = (in.readInt()==1);" << endl; + break; + case t_base_type::TYPE_I8: + indent(out) << prefix << " = in.readByte();" << endl; + break; + case t_base_type::TYPE_DOUBLE: + indent(out) << prefix << " = in.readDouble();" << endl; + break; + case t_base_type::TYPE_STRING: + indent(out) << prefix << "= in.readString();" << endl; + break; + case t_base_type::TYPE_VOID: + break; + } + } + } + } + + scope_down(out); + out << endl; + + indent(out) << "public static final android.os.Parcelable.Creator<" << tname + << "> CREATOR = new android.os.Parcelable.Creator<" << tname << ">() {" << endl; + indent_up(); + + indent(out) << "@Override" << endl << indent() << "public " << tname << "[] newArray(int size) {" + << endl; + indent_up(); + indent(out) << "return new " << tname << "[size];" << endl; + scope_down(out); + out << endl; + + indent(out) << "@Override" << endl << indent() << "public " << tname + << " createFromParcel(android.os.Parcel in) {" << endl; + indent_up(); + indent(out) << "return new " << tname << "(in);" << endl; + scope_down(out); + + indent_down(); + indent(out) << "};" << endl; + out << endl; +} + +/** + * Generates equals methods and a hashCode method for a structure. + * + * @param tstruct The struct definition + */ +void t_java_generator::generate_java_struct_equality(ofstream& out, t_struct* tstruct) { + out << indent() << "@Override" << endl << indent() << "public boolean equals(java.lang.Object that) {" + << endl; + indent_up(); + out << indent() << "if (that == null)" << endl << indent() << " return false;" << endl + << indent() << "if (that instanceof " << tstruct->get_name() << ")" << endl << indent() + << " return this.equals((" << tstruct->get_name() << ")that);" << endl << indent() + << "return false;" << endl; + scope_down(out); + out << endl; + + out << indent() << "public boolean equals(" << tstruct->get_name() << " that) {" << endl; + indent_up(); + out << indent() << "if (that == null)" << endl << indent() << " return false;" << endl + << indent() << "if (this == that)" << endl << indent() << " return true;" << endl; + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + out << endl; + + t_type* t = get_true_type((*m_iter)->get_type()); + // Most existing Thrift code does not use isset or optional/required, + // so we treat "default" fields as required. + bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL; + bool can_be_null = type_can_be_null(t); + string name = (*m_iter)->get_name(); + + string this_present = "true"; + string that_present = "true"; + string unequal; + + if (is_optional || can_be_null) { + this_present += " && this." + generate_isset_check(*m_iter); + that_present += " && that." + generate_isset_check(*m_iter); + } + + out << indent() << "boolean this_present_" << name << " = " << this_present << ";" << endl + << indent() << "boolean that_present_" << name << " = " << that_present << ";" << endl + << indent() << "if (" + << "this_present_" << name << " || that_present_" << name << ") {" << endl; + indent_up(); + out << indent() << "if (!(" + << "this_present_" << name << " && that_present_" << name << "))" << endl << indent() + << " return false;" << endl; + + if (t->is_binary()) { + unequal = "!this." + name + ".equals(that." + name + ")"; + } else if (can_be_null) { + unequal = "!this." + name + ".equals(that." + name + ")"; + } else { + unequal = "this." + name + " != that." + name; + } + + out << indent() << "if (" << unequal << ")" << endl << indent() << " return false;" << endl; + + scope_down(out); + } + out << endl; + indent(out) << "return true;" << endl; + scope_down(out); + out << endl; + + const int MUL = 8191; // HashCode multiplier + const int B_YES = 131071; + const int B_NO = 524287; + out << indent() << "@Override" << endl << indent() << "public int hashCode() {" << endl; + indent_up(); + indent(out) << "int hashCode = 1;" << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + out << endl; + + t_type* t = get_true_type((*m_iter)->get_type()); + bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL; + bool can_be_null = type_can_be_null(t); + string name = (*m_iter)->get_name(); + + if (is_optional || can_be_null) { + indent(out) << "hashCode = hashCode * " << MUL << " + ((" << generate_isset_check(*m_iter) + << ") ? " << B_YES << " : " << B_NO << ");" << endl; + } + + if (is_optional || can_be_null) { + indent(out) << "if (" + generate_isset_check(*m_iter) + ")" << endl; + indent_up(); + } + + if (t->is_enum()) { + indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ".getValue();" << endl; + } else if (t->is_base_type()) { + switch(((t_base_type*)t)->get_base()) { + case t_base_type::TYPE_STRING: + indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ".hashCode();" << endl; + break; + case t_base_type::TYPE_BOOL: + indent(out) << "hashCode = hashCode * " << MUL << " + ((" << name << ") ? " + << B_YES << " : " << B_NO << ");" << endl; + break; + case t_base_type::TYPE_I8: + indent(out) << "hashCode = hashCode * " << MUL << " + (int) (" << name << ");" << endl; + break; + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ";" << endl; + break; + case t_base_type::TYPE_I64: + case t_base_type::TYPE_DOUBLE: + indent(out) << "hashCode = hashCode * " << MUL << " + org.apache.thrift.TBaseHelper.hashCode(" << name << ");" << endl; + break; + case t_base_type::TYPE_VOID: + throw std::logic_error("compiler error: a struct field cannot be void"); + default: + throw std::logic_error("compiler error: the following base type has no hashcode generator: " + + t_base_type::t_base_name(((t_base_type*)t)->get_base())); + } + } else { + indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ".hashCode();" << endl; + } + + if (is_optional || can_be_null) { + indent_down(); + } + } + + out << endl; + indent(out) << "return hashCode;" << endl; + indent_down(); + indent(out) << "}" << endl << endl; +} + +void t_java_generator::generate_java_struct_compare_to(ofstream& out, t_struct* tstruct) { + indent(out) << "@Override" << endl; + indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl; + indent_up(); + + indent(out) << "if (!getClass().equals(other.getClass())) {" << endl; + indent(out) << " return getClass().getName().compareTo(other.getClass().getName());" << endl; + indent(out) << "}" << endl; + out << endl; + + indent(out) << "int lastComparison = 0;" << endl; + out << endl; + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = *m_iter; + indent(out) << "lastComparison = java.lang.Boolean.valueOf(" << generate_isset_check(field) + << ").compareTo(other." << generate_isset_check(field) << ");" << endl; + indent(out) << "if (lastComparison != 0) {" << endl; + indent(out) << " return lastComparison;" << endl; + indent(out) << "}" << endl; + + indent(out) << "if (" << generate_isset_check(field) << ") {" << endl; + indent(out) << " lastComparison = org.apache.thrift.TBaseHelper.compareTo(this." + << field->get_name() << ", other." << field->get_name() << ");" << endl; + indent(out) << " if (lastComparison != 0) {" << endl; + indent(out) << " return lastComparison;" << endl; + indent(out) << " }" << endl; + indent(out) << "}" << endl; + } + + indent(out) << "return 0;" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a function to read all the fields of the struct. + * + * @param tstruct The struct definition + */ +void t_java_generator::generate_java_struct_reader(ofstream& out, t_struct* tstruct) { + (void)tstruct; + indent(out) << "public void read(org.apache.thrift.protocol.TProtocol iprot) throws " + "org.apache.thrift.TException {" << endl; + indent_up(); + indent(out) << "scheme(iprot).read(iprot, this);" << endl; + indent_down(); + indent(out) << "}" << endl << endl; +} + +// generates java method to perform various checks +// (e.g. check that all required fields are set) +void t_java_generator::generate_java_validator(ofstream& out, t_struct* tstruct) { + indent(out) << "public void validate() throws org.apache.thrift.TException {" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out << indent() << "// check for required fields" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + if (bean_style_) { + out << indent() << "if (!" << generate_isset_check(*f_iter) << ") {" << endl << indent() + << " throw new org.apache.thrift.protocol.TProtocolException(\"Required field '" + << (*f_iter)->get_name() << "' is unset! Struct:\" + toString());" << endl << indent() + << "}" << endl << endl; + } else { + if (type_can_be_null((*f_iter)->get_type())) { + indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl; + indent(out) + << " throw new org.apache.thrift.protocol.TProtocolException(\"Required field '" + << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" << endl; + indent(out) << "}" << endl; + } else { + indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name() + << "' because it's a primitive and you chose the non-beans generator." + << endl; + } + } + } + } + + out << indent() << "// check for sub-struct validity" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_type* type = (*f_iter)->get_type(); + if (type->is_struct() && !((t_struct*)type)->is_union()) { + out << indent() << "if (" << (*f_iter)->get_name() << " != null) {" << endl; + out << indent() << " " << (*f_iter)->get_name() << ".validate();" << endl; + out << indent() << "}" << endl; + } + } + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a function to write all the fields of the struct + * + * @param tstruct The struct definition + */ +void t_java_generator::generate_java_struct_writer(ofstream& out, t_struct* tstruct) { + (void)tstruct; + indent(out) << "public void write(org.apache.thrift.protocol.TProtocol oprot) throws " + "org.apache.thrift.TException {" << endl; + indent_up(); + indent(out) << "scheme(oprot).write(oprot, this);" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a function to write all the fields of the struct, + * which is a function result. These fields are only written + * if they are set in the Isset array, and only one of them + * can be set at a time. + * + * @param tstruct The struct definition + */ +void t_java_generator::generate_java_struct_result_writer(ofstream& out, t_struct* tstruct) { + (void)tstruct; + indent(out) << "public void write(org.apache.thrift.protocol.TProtocol oprot) throws " + "org.apache.thrift.TException {" << endl; + indent_up(); + indent(out) << "scheme(oprot).write(oprot, this);" << endl; + + indent_down(); + indent(out) << " }" << endl << endl; +} + +void t_java_generator::generate_java_struct_field_by_id(ofstream& out, t_struct* tstruct) { + (void)tstruct; + indent(out) << "public _Fields fieldForId(int fieldId) {" << endl; + indent(out) << " return _Fields.findByThriftId(fieldId);" << endl; + indent(out) << "}" << endl << endl; +} + +void t_java_generator::generate_reflection_getters(ostringstream& out, + t_type* type, + string field_name, + string cap_name) { + indent(out) << "case " << constant_name(field_name) << ":" << endl; + indent_up(); + indent(out) << "return " << (type->is_bool() ? "is" : "get") << cap_name << "();" << endl << endl; + indent_down(); +} + +void t_java_generator::generate_reflection_setters(ostringstream& out, + t_type* type, + string field_name, + string cap_name) { + const bool is_binary = type->is_binary(); + indent(out) << "case " << constant_name(field_name) << ":" << endl; + indent_up(); + indent(out) << "if (value == null) {" << endl; + indent(out) << " unset" << get_cap_name(field_name) << "();" << endl; + indent(out) << "} else {" << endl; + if (is_binary) { + indent_up(); + indent(out) << "if (value instanceof byte[]) {" << endl; + indent(out) << " set" << cap_name << "((byte[])value);" << endl; + indent(out) << "} else {" << endl; + } + indent(out) << " set" << cap_name << "((" << type_name(type, true, false) << ")value);" << endl; + if (is_binary) { + indent(out) << "}" << endl; + indent_down(); + } + indent(out) << "}" << endl; + indent(out) << "break;" << endl << endl; + + indent_down(); +} + +void t_java_generator::generate_generic_field_getters_setters(std::ofstream& out, + t_struct* tstruct) { + std::ostringstream getter_stream; + std::ostringstream setter_stream; + + // build up the bodies of both the getter and setter at once + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + t_type* type = get_true_type(field->get_type()); + std::string field_name = field->get_name(); + std::string cap_name = get_cap_name(field_name); + + indent_up(); + generate_reflection_setters(setter_stream, type, field_name, cap_name); + generate_reflection_getters(getter_stream, type, field_name, cap_name); + indent_down(); + } + + // create the setter + + indent(out) << "public void setFieldValue(_Fields field, java.lang.Object value) {" << endl; + indent(out) << " switch (field) {" << endl; + out << setter_stream.str(); + indent(out) << " }" << endl; + indent(out) << "}" << endl << endl; + + // create the getter + indent(out) << "public java.lang.Object getFieldValue(_Fields field) {" << endl; + indent_up(); + indent(out) << "switch (field) {" << endl; + out << getter_stream.str(); + indent(out) << "}" << endl; + indent(out) << "throw new java.lang.IllegalStateException();" << endl; + indent_down(); + indent(out) << "}" << endl << endl; +} + +// Creates a generic isSet method that takes the field number as argument +void t_java_generator::generate_generic_isset_method(std::ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // create the isSet method + indent(out) << "/** Returns true if field corresponding to fieldID is set (has been assigned a " + "value) and false otherwise */" << endl; + indent(out) << "public boolean isSet(_Fields field) {" << endl; + indent_up(); + indent(out) << "if (field == null) {" << endl; + indent(out) << " throw new java.lang.IllegalArgumentException();" << endl; + indent(out) << "}" << endl << endl; + + indent(out) << "switch (field) {" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; + indent_up(); + indent(out) << "return " << generate_isset_check(field) << ";" << endl; + indent_down(); + } + + indent(out) << "}" << endl; + indent(out) << "throw new java.lang.IllegalStateException();" << endl; + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a set of Java Bean boilerplate functions (setters, getters, etc.) + * for the given struct. + * + * @param tstruct The struct definition + */ +void t_java_generator::generate_java_bean_boilerplate(ofstream& out, t_struct* tstruct) { + isset_type issetType = needs_isset(tstruct); + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + t_type* type = get_true_type(field->get_type()); + std::string field_name = field->get_name(); + std::string cap_name = get_cap_name(field_name); + bool optional = use_option_type_ && field->get_req() == t_field::T_OPTIONAL; + bool is_deprecated = this->is_deprecated(field->annotations_); + + if (type->is_container()) { + // Method to return the size of the collection + if (optional) { + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public org.apache.thrift.Option get" << cap_name; + out << get_cap_name("size() {") << endl; + + indent_up(); + indent(out) << "if (this." << field_name << " == null) {" << endl; + indent_up(); + indent(out) << "return org.apache.thrift.Option.none();" << endl; + indent_down(); + indent(out) << "} else {" << endl; + indent_up(); + indent(out) << "return org.apache.thrift.Option.some(this." << field_name << ".size());" << endl; + indent_down(); + indent(out) << "}" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } else { + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public int get" << cap_name; + out << get_cap_name("size() {") << endl; + + indent_up(); + indent(out) << "return (this." << field_name << " == null) ? 0 : " + << "this." << field_name << ".size();" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } + } + + if (type->is_set() || type->is_list()) { + t_type* element_type; + if (type->is_set()) { + element_type = ((t_set*)type)->get_elem_type(); + } else { + element_type = ((t_list*)type)->get_elem_type(); + } + + // Iterator getter for sets and lists + if (optional) { + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public org.apache.thrift.Option> get" << cap_name; + out << get_cap_name("iterator() {") << endl; + + indent_up(); + indent(out) << "if (this." << field_name << " == null) {" << endl; + indent_up(); + indent(out) << "return org.apache.thrift.Option.none();" << endl; + indent_down(); + indent(out) << "} else {" << endl; + indent_up(); + indent(out) << "return org.apache.thrift.Option.some(this." << field_name << ".iterator());" << endl; + indent_down(); + indent(out) << "}" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } else { + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public java.util.Iterator<" << type_name(element_type, true, false) + << "> get" << cap_name; + out << get_cap_name("iterator() {") << endl; + + indent_up(); + indent(out) << "return (this." << field_name << " == null) ? null : " + << "this." << field_name << ".iterator();" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } + + // Add to set or list, create if the set/list is null + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public void add" << get_cap_name("to"); + out << cap_name << "(" << type_name(element_type) << " elem) {" << endl; + + indent_up(); + indent(out) << "if (this." << field_name << " == null) {" << endl; + indent_up(); + indent(out) << "this." << field_name; + if (is_enum_set(type)) { + out << " = " << type_name(type, false, true, true) << ".noneOf(" << inner_enum_type_name(type) << ");" << endl; + } else { + out << " = new " << type_name(type, false, true) << "();" << endl; + } + indent_down(); + indent(out) << "}" << endl; + indent(out) << "this." << field_name << ".add(elem);" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } else if (type->is_map()) { + // Put to map + t_type* key_type = ((t_map*)type)->get_key_type(); + t_type* val_type = ((t_map*)type)->get_val_type(); + + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public void put" << get_cap_name("to"); + out << cap_name << "(" << type_name(key_type) << " key, " << type_name(val_type) << " val) {" + << endl; + + indent_up(); + indent(out) << "if (this." << field_name << " == null) {" << endl; + indent_up(); + std::string constructor_args; + if (is_enum_map(type)) { + constructor_args = inner_enum_type_name(type); + } + indent(out) << "this." << field_name << " = new " << type_name(type, false, true) << "(" << constructor_args << ");" + << endl; + indent_down(); + indent(out) << "}" << endl; + indent(out) << "this." << field_name << ".put(key, val);" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } + + // Simple getter + generate_java_doc(out, field); + if (type->is_binary()) { + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public byte[] get" << cap_name << "() {" << endl; + indent(out) << " set" << cap_name << "(org.apache.thrift.TBaseHelper.rightSize(" + << field_name << "));" << endl; + indent(out) << " return " << field_name << " == null ? null : " << field_name << ".array();" + << endl; + indent(out) << "}" << endl << endl; + + indent(out) << "public java.nio.ByteBuffer buffer" << get_cap_name("for") << cap_name << "() {" + << endl; + indent(out) << " return org.apache.thrift.TBaseHelper.copyBinary(" << field_name << ");" + << endl; + indent(out) << "}" << endl << endl; + } else { + if (optional) { + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public org.apache.thrift.Option<" << type_name(type, true) << ">"; + if (type->is_base_type() && ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) { + out << " is"; + } else { + out << " get"; + } + out << cap_name << "() {" << endl; + indent_up(); + + indent(out) << "if (this.isSet" << cap_name << "()) {" << endl; + indent_up(); + indent(out) << "return org.apache.thrift.Option.some(this." << field_name << ");" << endl; + indent_down(); + indent(out) << "} else {" << endl; + indent_up(); + indent(out) << "return org.apache.thrift.Option.none();" << endl; + indent_down(); + indent(out) << "}" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } else { + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public " << type_name(type); + if (type->is_base_type() && ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) { + out << " is"; + } else { + out << " get"; + } + out << cap_name << "() {" << endl; + indent_up(); + indent(out) << "return this." << field_name << ";" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } + } + + // Simple setter + generate_java_doc(out, field); + if (type->is_binary()) { + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public "; + if (bean_style_) { + out << "void"; + } else { + out << type_name(tstruct); + } + out << " set" << cap_name << "(byte[] " << field_name << ") {" << endl; + indent(out) << " this." << field_name << " = " << field_name << " == null ? (java.nio.ByteBuffer)null" + << " : java.nio.ByteBuffer.wrap(" << field_name << ".clone());" << endl; + if (!bean_style_) { + indent(out) << " return this;" << endl; + } + indent(out) << "}" << endl << endl; + } + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public "; + if (bean_style_) { + out << "void"; + } else { + out << type_name(tstruct); + } + out << " set" << cap_name << "(" << type_name(type) << " " << field_name << ") {" << endl; + indent_up(); + indent(out) << "this." << field_name << " = "; + if (type->is_binary()) { + out << "org.apache.thrift.TBaseHelper.copyBinary(" << field_name << ")"; + } else { + out << field_name; + } + out << ";" << endl; + generate_isset_set(out, field, ""); + if (!bean_style_) { + indent(out) << "return this;" << endl; + } + + indent_down(); + indent(out) << "}" << endl << endl; + + // Unsetter + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public void unset" << cap_name << "() {" << endl; + indent_up(); + if (type_can_be_null(type)) { + indent(out) << "this." << field_name << " = null;" << endl; + } else if (issetType == ISSET_PRIMITIVE) { + indent(out) << "__isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, " + << isset_field_id(field) << ");" << endl; + } else { + indent(out) << "__isset_bit_vector.clear(" << isset_field_id(field) << ");" << endl; + } + indent_down(); + indent(out) << "}" << endl << endl; + + // isSet method + indent(out) << "/** Returns true if field " << field_name + << " is set (has been assigned a value) and false otherwise */" << endl; + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public boolean is" << get_cap_name("set") << cap_name << "() {" << endl; + indent_up(); + if (type_can_be_null(type)) { + indent(out) << "return this." << field_name << " != null;" << endl; + } else if (issetType == ISSET_PRIMITIVE) { + indent(out) << "return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, " << isset_field_id(field) + << ");" << endl; + } else { + indent(out) << "return __isset_bit_vector.get(" << isset_field_id(field) << ");" << endl; + } + indent_down(); + indent(out) << "}" << endl << endl; + + if (is_deprecated) { + indent(out) << "@Deprecated" << endl; + } + indent(out) << "public void set" << cap_name << get_cap_name("isSet") << "(boolean value) {" + << endl; + indent_up(); + if (type_can_be_null(type)) { + indent(out) << "if (!value) {" << endl; + indent(out) << " this." << field_name << " = null;" << endl; + indent(out) << "}" << endl; + } else if (issetType == ISSET_PRIMITIVE) { + indent(out) << "__isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, " + << isset_field_id(field) << ", value);" << endl; + } else { + indent(out) << "__isset_bit_vector.set(" << isset_field_id(field) << ", value);" << endl; + } + indent_down(); + indent(out) << "}" << endl << endl; + } +} + +/** + * Generates a toString() method for the given struct + * + * @param tstruct The struct definition + */ +void t_java_generator::generate_java_struct_tostring(ofstream& out, t_struct* tstruct) { + out << indent() << "@Override" << endl << indent() << "public java.lang.String toString() {" << endl; + indent_up(); + + out << indent() << "java.lang.StringBuilder sb = new java.lang.StringBuilder(\"" << tstruct->get_name() << "(\");" + << endl; + out << indent() << "boolean first = true;" << endl << endl; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; + if (could_be_unset) { + indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl; + indent_up(); + } + + t_field* field = (*f_iter); + + if (!first) { + indent(out) << "if (!first) sb.append(\", \");" << endl; + } + indent(out) << "sb.append(\"" << (*f_iter)->get_name() << ":\");" << endl; + bool can_be_null = type_can_be_null(field->get_type()); + if (can_be_null) { + indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl; + indent(out) << " sb.append(\"null\");" << endl; + indent(out) << "} else {" << endl; + indent_up(); + } + + if (get_true_type(field->get_type())->is_binary()) { + indent(out) << "org.apache.thrift.TBaseHelper.toString(this." << field->get_name() << ", sb);" + << endl; + } else if ((field->get_type()->is_set()) + && (get_true_type(((t_set*)field->get_type())->get_elem_type())->is_binary())) { + indent(out) << "org.apache.thrift.TBaseHelper.toString(this." << field->get_name() << ", sb);" + << endl; + } else if ((field->get_type()->is_list()) + && (get_true_type(((t_list*)field->get_type())->get_elem_type())->is_binary())) { + indent(out) << "org.apache.thrift.TBaseHelper.toString(this." << field->get_name() << ", sb);" + << endl; + } else { + indent(out) << "sb.append(this." << (*f_iter)->get_name() << ");" << endl; + } + + if (can_be_null) { + indent_down(); + indent(out) << "}" << endl; + } + indent(out) << "first = false;" << endl; + + if (could_be_unset) { + indent_down(); + indent(out) << "}" << endl; + } + first = false; + } + out << indent() << "sb.append(\")\");" << endl << indent() << "return sb.toString();" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a static map with meta data to store information such as fieldID to + * fieldName mapping + * + * @param tstruct The struct definition + */ +void t_java_generator::generate_java_meta_data_map(ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Static Map with fieldID -> org.apache.thrift.meta_data.FieldMetaData mappings + indent(out) + << "public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;" + << endl; + indent(out) << "static {" << endl; + indent_up(); + + indent(out) << "java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new " + "java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);" + << endl; + + // Populate map + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + std::string field_name = field->get_name(); + indent(out) << "tmpMap.put(_Fields." << constant_name(field_name) + << ", new org.apache.thrift.meta_data.FieldMetaData(\"" << field_name << "\", "; + + // Set field requirement type (required, optional, etc.) + if (field->get_req() == t_field::T_REQUIRED) { + out << "org.apache.thrift.TFieldRequirementType.REQUIRED, "; + } else if (field->get_req() == t_field::T_OPTIONAL) { + out << "org.apache.thrift.TFieldRequirementType.OPTIONAL, "; + } else { + out << "org.apache.thrift.TFieldRequirementType.DEFAULT, "; + } + + // Create value meta data + generate_field_value_meta_data(out, field->get_type()); + out << "));" << endl; + } + + indent(out) << "metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);" << endl; + + indent(out) << "org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(" + << type_name(tstruct) << ".class, metaDataMap);" << endl; + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Returns a string with the java representation of the given thrift type + * (e.g. for the type struct it returns "org.apache.thrift.protocol.TType.STRUCT") + */ +std::string t_java_generator::get_java_type_string(t_type* type) { + if (type->is_list()) { + return "org.apache.thrift.protocol.TType.LIST"; + } else if (type->is_map()) { + return "org.apache.thrift.protocol.TType.MAP"; + } else if (type->is_set()) { + return "org.apache.thrift.protocol.TType.SET"; + } else if (type->is_struct() || type->is_xception()) { + return "org.apache.thrift.protocol.TType.STRUCT"; + } else if (type->is_enum()) { + return "org.apache.thrift.protocol.TType.ENUM"; + } else if (type->is_typedef()) { + return get_java_type_string(((t_typedef*)type)->get_type()); + } else if (type->is_base_type()) { + switch (((t_base_type*)type)->get_base()) { + case t_base_type::TYPE_VOID: + return "org.apache.thrift.protocol.TType.VOID"; + break; + case t_base_type::TYPE_STRING: + return "org.apache.thrift.protocol.TType.STRING"; + break; + case t_base_type::TYPE_BOOL: + return "org.apache.thrift.protocol.TType.BOOL"; + break; + case t_base_type::TYPE_I8: + return "org.apache.thrift.protocol.TType.BYTE"; + break; + case t_base_type::TYPE_I16: + return "org.apache.thrift.protocol.TType.I16"; + break; + case t_base_type::TYPE_I32: + return "org.apache.thrift.protocol.TType.I32"; + break; + case t_base_type::TYPE_I64: + return "org.apache.thrift.protocol.TType.I64"; + break; + case t_base_type::TYPE_DOUBLE: + return "org.apache.thrift.protocol.TType.DOUBLE"; + break; + default: + throw std::runtime_error("Unknown thrift type \"" + type->get_name() + + "\" passed to t_java_generator::get_java_type_string!"); + return "Unknown thrift type \"" + type->get_name() + + "\" passed to t_java_generator::get_java_type_string!"; + break; // This should never happen! + } + } else { + throw std::runtime_error("Unknown thrift type \"" + type->get_name() + + "\" passed to t_java_generator::get_java_type_string!"); + // This should never happen! + } +} + +void t_java_generator::generate_field_value_meta_data(std::ofstream& out, t_type* type) { + out << endl; + indent_up(); + indent_up(); + if (type->is_struct() || type->is_xception()) { + indent(out) << "new " + "org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType." + "STRUCT, " << type_name(type) << ".class"; + } else if (type->is_container()) { + if (type->is_list()) { + indent(out) + << "new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, "; + t_type* elem_type = ((t_list*)type)->get_elem_type(); + generate_field_value_meta_data(out, elem_type); + } else if (type->is_set()) { + indent(out) + << "new org.apache.thrift.meta_data.SetMetaData(org.apache.thrift.protocol.TType.SET, "; + t_type* elem_type = ((t_set*)type)->get_elem_type(); + generate_field_value_meta_data(out, elem_type); + } else { // map + indent(out) + << "new org.apache.thrift.meta_data.MapMetaData(org.apache.thrift.protocol.TType.MAP, "; + t_type* key_type = ((t_map*)type)->get_key_type(); + t_type* val_type = ((t_map*)type)->get_val_type(); + generate_field_value_meta_data(out, key_type); + out << ", "; + generate_field_value_meta_data(out, val_type); + } + } else if (type->is_enum()) { + indent(out) + << "new org.apache.thrift.meta_data.EnumMetaData(org.apache.thrift.protocol.TType.ENUM, " + << type_name(type) << ".class"; + } else { + indent(out) << "new org.apache.thrift.meta_data.FieldValueMetaData(" + << get_java_type_string(type); + if (type->is_typedef()) { + indent(out) << ", \"" << ((t_typedef*)type)->get_symbolic() << "\""; + } else if (type->is_binary()) { + indent(out) << ", true"; + } + } + out << ")"; + indent_down(); + indent_down(); +} + +/** + * Generates a thrift service. In C++, this comprises an entirely separate + * header and source file. The header file defines the methods and includes + * the data types defined in the main header file, and the implementation + * file contains implementations of the basic printer and default interfaces. + * + * @param tservice The service definition + */ +void t_java_generator::generate_service(t_service* tservice) { + // Make output file + string f_service_name = package_dir_ + "/" + make_valid_java_filename(service_name_) + ".java"; + f_service_.open(f_service_name.c_str()); + + f_service_ << autogen_comment() << java_package() << java_suppressions(); + + if (!suppress_generated_annotations_) { + generate_javax_generated_annotation(f_service_); + } + f_service_ << "public class " << service_name_ << " {" << endl << endl; + indent_up(); + + // Generate the three main parts of the service + generate_service_interface(tservice); + generate_service_async_interface(tservice); + generate_service_client(tservice); + generate_service_async_client(tservice); + generate_service_server(tservice); + generate_service_async_server(tservice); + generate_service_helpers(tservice); + + indent_down(); + f_service_ << "}" << endl; + f_service_.close(); +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_java_generator::generate_service_interface(t_service* tservice) { + string extends = ""; + string extends_iface = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_iface = " extends " + extends + ".Iface"; + } + + generate_java_doc(f_service_, tservice); + f_service_ << indent() << "public interface Iface" << extends_iface << " {" << endl << endl; + indent_up(); + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_java_doc(f_service_, *f_iter); + indent(f_service_) << "public " << function_signature(*f_iter) << ";" << endl << endl; + } + indent_down(); + f_service_ << indent() << "}" << endl << endl; +} + +void t_java_generator::generate_service_async_interface(t_service* tservice) { + string extends = ""; + string extends_iface = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_iface = " extends " + extends + " .AsyncIface"; + } + + f_service_ << indent() << "public interface AsyncIface" << extends_iface << " {" << endl << endl; + indent_up(); + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + indent(f_service_) << "public " << function_signature_async(*f_iter, true) + << " throws org.apache.thrift.TException;" << endl << endl; + } + indent_down(); + f_service_ << indent() << "}" << endl << endl; +} + +/** + * Generates structs for all the service args and return types + * + * @param tservice The service + */ +void t_java_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_java_struct_definition(f_service_, ts, false, true); + generate_function_helpers(*f_iter); + } +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_java_generator::generate_service_client(t_service* tservice) { + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() == NULL) { + extends_client = "org.apache.thrift.TServiceClient"; + } else { + extends = type_name(tservice->get_extends()); + extends_client = extends + ".Client"; + } + + indent(f_service_) << "public static class Client extends " << extends_client + << " implements Iface {" << endl; + indent_up(); + + indent(f_service_) + << "public static class Factory implements org.apache.thrift.TServiceClientFactory {" + << endl; + indent_up(); + indent(f_service_) << "public Factory() {}" << endl; + indent(f_service_) << "public Client getClient(org.apache.thrift.protocol.TProtocol prot) {" + << endl; + indent_up(); + indent(f_service_) << "return new Client(prot);" << endl; + indent_down(); + indent(f_service_) << "}" << endl; + indent(f_service_) << "public Client getClient(org.apache.thrift.protocol.TProtocol iprot, " + "org.apache.thrift.protocol.TProtocol oprot) {" << endl; + indent_up(); + indent(f_service_) << "return new Client(iprot, oprot);" << endl; + indent_down(); + indent(f_service_) << "}" << endl; + indent_down(); + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "public Client(org.apache.thrift.protocol.TProtocol prot)" << endl; + scope_up(f_service_); + indent(f_service_) << "super(prot, prot);" << endl; + scope_down(f_service_); + f_service_ << endl; + + indent(f_service_) << "public Client(org.apache.thrift.protocol.TProtocol iprot, " + "org.apache.thrift.protocol.TProtocol oprot) {" << endl; + indent(f_service_) << " super(iprot, oprot);" << endl; + indent(f_service_) << "}" << endl << endl; + + // Generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string funname = (*f_iter)->get_name(); + string sep = "_"; + string javaname = funname; + if (fullcamel_style_) { + sep = ""; + javaname = as_camel_case(funname); + } + + // Open function + indent(f_service_) << "public " << function_signature(*f_iter) << endl; + scope_up(f_service_); + indent(f_service_) << "send" << sep << javaname << "("; + + // Get the struct of function call params + t_struct* arg_struct = (*f_iter)->get_arglist(); + + // Declare the function arguments + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + bool first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << (*fld_iter)->get_name(); + } + f_service_ << ");" << endl; + + if (!(*f_iter)->is_oneway()) { + f_service_ << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << "return "; + } + f_service_ << "recv" << sep << javaname << "();" << endl; + } + scope_down(f_service_); + f_service_ << endl; + + t_function send_function(g_type_void, + string("send") + sep + javaname, + (*f_iter)->get_arglist()); + + string argsname = (*f_iter)->get_name() + "_args"; + + // Open function + indent(f_service_) << "public " << function_signature(&send_function) << endl; + scope_up(f_service_); + + // Serialize the request + indent(f_service_) << argsname << " args = new " << argsname << "();" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + indent(f_service_) << "args.set" << get_cap_name((*fld_iter)->get_name()) << "(" + << (*fld_iter)->get_name() << ");" << endl; + } + + const string sendBaseName = (*f_iter)->is_oneway() ? "sendBaseOneway" : "sendBase"; + indent(f_service_) << sendBaseName << "(\"" << funname << "\", args);" << endl; + + scope_down(f_service_); + f_service_ << endl; + + if (!(*f_iter)->is_oneway()) { + string resultname = (*f_iter)->get_name() + "_result"; + + t_struct noargs(program_); + t_function recv_function((*f_iter)->get_returntype(), + string("recv") + sep + javaname, + &noargs, + (*f_iter)->get_xceptions()); + // Open function + indent(f_service_) << "public " << function_signature(&recv_function) << endl; + scope_up(f_service_); + + f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl + << indent() << "receiveBase(result, \"" << funname << "\");" << endl; + + // Careful, only return _result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << indent() << "if (result." << generate_isset_check("success") << ") {" << endl + << indent() << " return result.success;" << endl << indent() << "}" << endl; + } + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << indent() << "if (result." << (*x_iter)->get_name() << " != null) {" << endl + << indent() << " throw result." << (*x_iter)->get_name() << ";" << endl + << indent() << "}" << endl; + } + + // If you get here it's an exception, unless a void function + if ((*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << "return;" << endl; + } else { + f_service_ << indent() << "throw new " + "org.apache.thrift.TApplicationException(org.apache.thrift." + "TApplicationException.MISSING_RESULT, \"" + << (*f_iter)->get_name() << " failed: unknown result\");" << endl; + } + + // Close function + scope_down(f_service_); + f_service_ << endl; + } + } + + indent_down(); + indent(f_service_) << "}" << endl; +} + +void t_java_generator::generate_service_async_client(t_service* tservice) { + string extends = "org.apache.thrift.async.TAsyncClient"; + string extends_client = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()) + ".AsyncClient"; + } + + indent(f_service_) << "public static class AsyncClient extends " << extends + << " implements AsyncIface {" << endl; + indent_up(); + + // Factory method + indent(f_service_) << "public static class Factory implements " + "org.apache.thrift.async.TAsyncClientFactory {" << endl; + indent(f_service_) << " private org.apache.thrift.async.TAsyncClientManager clientManager;" + << endl; + indent(f_service_) << " private org.apache.thrift.protocol.TProtocolFactory protocolFactory;" + << endl; + indent(f_service_) << " public Factory(org.apache.thrift.async.TAsyncClientManager " + "clientManager, org.apache.thrift.protocol.TProtocolFactory " + "protocolFactory) {" << endl; + indent(f_service_) << " this.clientManager = clientManager;" << endl; + indent(f_service_) << " this.protocolFactory = protocolFactory;" << endl; + indent(f_service_) << " }" << endl; + indent(f_service_) << " public AsyncClient " + "getAsyncClient(org.apache.thrift.transport.TNonblockingTransport " + "transport) {" << endl; + indent(f_service_) << " return new AsyncClient(protocolFactory, clientManager, transport);" + << endl; + indent(f_service_) << " }" << endl; + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "public AsyncClient(org.apache.thrift.protocol.TProtocolFactory " + "protocolFactory, org.apache.thrift.async.TAsyncClientManager " + "clientManager, org.apache.thrift.transport.TNonblockingTransport " + "transport) {" << endl; + indent(f_service_) << " super(protocolFactory, clientManager, transport);" << endl; + indent(f_service_) << "}" << endl << endl; + + // Generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string funname = (*f_iter)->get_name(); + string sep = "_"; + string javaname = funname; + if (fullcamel_style_) { + sep = ""; + javaname = as_camel_case(javaname); + } + t_type* ret_type = (*f_iter)->get_returntype(); + t_struct* arg_struct = (*f_iter)->get_arglist(); + string funclassname = funname + "_call"; + const vector& fields = arg_struct->get_members(); + const std::vector& xceptions = (*f_iter)->get_xceptions()->get_members(); + vector::const_iterator fld_iter; + string args_name = (*f_iter)->get_name() + "_args"; + string result_name = (*f_iter)->get_name() + "_result"; + + // Main method body + indent(f_service_) << "public " << function_signature_async(*f_iter, false) + << " throws org.apache.thrift.TException {" << endl; + indent(f_service_) << " checkReady();" << endl; + indent(f_service_) << " " << funclassname << " method_call = new " + funclassname + "(" + << async_argument_list(*f_iter, arg_struct, ret_type) + << ", this, ___protocolFactory, ___transport);" << endl; + indent(f_service_) << " this.___currentMethod = method_call;" << endl; + indent(f_service_) << " ___manager.call(method_call);" << endl; + indent(f_service_) << "}" << endl; + + f_service_ << endl; + + // TAsyncMethod object for this function call + indent(f_service_) << "public static class " + funclassname + + " extends org.apache.thrift.async.TAsyncMethodCall<" + + type_name((*f_iter)->get_returntype(), true) + "> {" << endl; + indent_up(); + + // Member variables + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + indent(f_service_) << "private " + type_name((*fld_iter)->get_type()) + " " + + (*fld_iter)->get_name() + ";" << endl; + } + + // NOTE since we use a new Client instance to deserialize, let's keep seqid to 0 for now + // indent(f_service_) << "private int seqid;" << endl << endl; + + // Constructor + indent(f_service_) << "public " + funclassname + "(" + + async_argument_list(*f_iter, arg_struct, ret_type, true) + << ", org.apache.thrift.async.TAsyncClient client, " + "org.apache.thrift.protocol.TProtocolFactory protocolFactory, " + "org.apache.thrift.transport.TNonblockingTransport transport) throws " + "org.apache.thrift.TException {" << endl; + indent(f_service_) << " super(client, protocolFactory, transport, resultHandler, " + << ((*f_iter)->is_oneway() ? "true" : "false") << ");" << endl; + + // Assign member variables + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + indent(f_service_) << " this." + (*fld_iter)->get_name() + " = " + (*fld_iter)->get_name() + + ";" << endl; + } + + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "public void write_args(org.apache.thrift.protocol.TProtocol prot) " + "throws org.apache.thrift.TException {" << endl; + indent_up(); + + // Serialize request + // NOTE we are leaving seqid as 0, for now (see above) + f_service_ << indent() << "prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage(\"" + << funname << "\", org.apache.thrift.protocol." + << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL") << ", 0));" + << endl << indent() << args_name << " args = new " << args_name << "();" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << indent() << "args.set" << get_cap_name((*fld_iter)->get_name()) << "(" + << (*fld_iter)->get_name() << ");" << endl; + } + + f_service_ << indent() << "args.write(prot);" << endl << indent() << "prot.writeMessageEnd();" + << endl; + + indent_down(); + indent(f_service_) << "}" << endl << endl; + + // Return method + indent(f_service_) << "public " + type_name(ret_type, true) + " getResult() throws "; + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << type_name((*x_iter)->get_type(), false, false) + ", "; + } + f_service_ << "org.apache.thrift.TException {" << endl; + + indent_up(); + f_service_ + << indent() + << "if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {" + << endl << indent() << " throw new java.lang.IllegalStateException(\"Method call not finished!\");" + << endl << indent() << "}" << endl << indent() + << "org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new " + "org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());" << endl + << indent() << "org.apache.thrift.protocol.TProtocol prot = " + "client.getProtocolFactory().getProtocol(memoryTransport);" << endl; + indent(f_service_); + if (ret_type->is_void()) { // NB: Includes oneways which always return void. + f_service_ << "return null;" << endl; + } else { + f_service_ << "return (new Client(prot)).recv" + sep + javaname + "();" << endl; + } + + // Close function + indent_down(); + indent(f_service_) << "}" << endl; + + // Close class + indent_down(); + indent(f_service_) << "}" << endl << endl; + } + + // Close AsyncClient + scope_down(f_service_); + f_service_ << endl; +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_java_generator::generate_service_server(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + // Extends stuff + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() == NULL) { + extends_processor = "org.apache.thrift.TBaseProcessor"; + } else { + extends = type_name(tservice->get_extends()); + extends_processor = extends + ".Processor"; + } + + // Generate the header portion + indent(f_service_) << "public static class Processor extends " + << extends_processor << " implements org.apache.thrift.TProcessor {" << endl; + indent_up(); + + indent(f_service_) + << "private static final org.slf4j.Logger _LOGGER = org.slf4j.LoggerFactory.getLogger(Processor.class.getName());" + << endl; + + indent(f_service_) << "public Processor(I iface) {" << endl; + indent(f_service_) << " super(iface, getProcessMap(new java.util.HashMap>()));" << endl; + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "protected Processor(I iface, java.util.Map> " + "processMap) {" << endl; + indent(f_service_) << " super(iface, getProcessMap(processMap));" << endl; + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "private static java.util.Map> " + "getProcessMap(java.util.Map> processMap) {" << endl; + indent_up(); + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + indent(f_service_) << "processMap.put(\"" << (*f_iter)->get_name() << "\", new " + << (*f_iter)->get_name() << "());" << endl; + } + indent(f_service_) << "return processMap;" << endl; + indent_down(); + indent(f_service_) << "}" << endl << endl; + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(tservice, *f_iter); + } + + indent_down(); + indent(f_service_) << "}" << endl << endl; +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_java_generator::generate_service_async_server(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + // Extends stuff + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() == NULL) { + extends_processor = "org.apache.thrift.TBaseAsyncProcessor"; + } else { + extends = type_name(tservice->get_extends()); + extends_processor = extends + ".AsyncProcessor"; + } + + // Generate the header portion + indent(f_service_) << "public static class AsyncProcessor extends " + << extends_processor << " {" << endl; + indent_up(); + + indent(f_service_) << "private static final org.slf4j.Logger _LOGGER = " + "org.slf4j.LoggerFactory.getLogger(AsyncProcessor.class.getName());" << endl; + + indent(f_service_) << "public AsyncProcessor(I iface) {" << endl; + indent(f_service_) << " super(iface, getProcessMap(new java.util.HashMap>()));" << endl; + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "protected AsyncProcessor(I iface, java.util.Map> processMap) {" << endl; + indent(f_service_) << " super(iface, getProcessMap(processMap));" << endl; + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "private static java.util.Map> getProcessMap(java.util.Map> processMap) {" << endl; + indent_up(); + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + indent(f_service_) << "processMap.put(\"" << (*f_iter)->get_name() << "\", new " + << (*f_iter)->get_name() << "());" << endl; + } + indent(f_service_) << "return processMap;" << endl; + indent_down(); + indent(f_service_) << "}" << endl << endl; + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_async_function(tservice, *f_iter); + } + + indent_down(); + indent(f_service_) << "}" << endl << endl; +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_java_generator::generate_function_helpers(t_function* tfunction) { + if (tfunction->is_oneway()) { + return; + } + + t_struct result(program_, tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + generate_java_struct_definition(f_service_, &result, false, true, true); +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_java_generator::generate_process_async_function(t_service* tservice, t_function* tfunction) { + string argsname = tfunction->get_name() + "_args"; + + string resultname = tfunction->get_name() + "_result"; + if (tfunction->is_oneway()) { + resultname = "org.apache.thrift.TBase"; + } + + string resulttype = type_name(tfunction->get_returntype(), true); + + (void)tservice; + // Open class + indent(f_service_) << "public static class " << tfunction->get_name() + << " extends org.apache.thrift.AsyncProcessFunction {" << endl; + indent_up(); + + indent(f_service_) << "public " << tfunction->get_name() << "() {" << endl; + indent(f_service_) << " super(\"" << tfunction->get_name() << "\");" << endl; + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "public " << argsname << " getEmptyArgsInstance() {" << endl; + indent(f_service_) << " return new " << argsname << "();" << endl; + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "public org.apache.thrift.async.AsyncMethodCallback<" << resulttype + << "> getResultHandler(final org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer fb, final int seqid) {" << endl; + indent_up(); + indent(f_service_) << "final org.apache.thrift.AsyncProcessFunction fcall = this;" << endl; + indent(f_service_) << "return new org.apache.thrift.async.AsyncMethodCallback<" << resulttype + << ">() { " << endl; + indent_up(); + indent(f_service_) << "public void onComplete(" << resulttype << " o) {" << endl; + + indent_up(); + if (!tfunction->is_oneway()) { + indent(f_service_) << resultname << " result = new " << resultname << "();" << endl; + + if (!tfunction->get_returntype()->is_void()) { + indent(f_service_) << "result.success = o;" << endl; + // Set isset on success field + if (!type_can_be_null(tfunction->get_returntype())) { + indent(f_service_) << "result.set" << get_cap_name("success") << get_cap_name("isSet") + << "(true);" << endl; + } + } + + indent(f_service_) << "try {" << endl; + indent(f_service_) + << " fcall.sendResponse(fb, result, org.apache.thrift.protocol.TMessageType.REPLY,seqid);" + << endl; + indent(f_service_) << "} catch (org.apache.thrift.transport.TTransportException e) {" << endl; + indent_up(); + f_service_ << indent() + << "_LOGGER.error(\"TTransportException writing to internal frame buffer\", e);" + << endl + << indent() << "fb.close();" << endl; + indent_down(); + indent(f_service_) << "} catch (java.lang.Exception e) {" << endl; + indent_up(); + f_service_ << indent() << "_LOGGER.error(\"Exception writing to internal frame buffer\", e);" + << endl + << indent() << "onError(e);" << endl; + indent_down(); + indent(f_service_) << "}" << endl; + } + indent_down(); + indent(f_service_) << "}" << endl; + + indent(f_service_) << "public void onError(java.lang.Exception e) {" << endl; + indent_up(); + + if (tfunction->is_oneway()) { + indent(f_service_) << "if (e instanceof org.apache.thrift.transport.TTransportException) {" + << endl; + indent_up(); + + f_service_ << indent() << "_LOGGER.error(\"TTransportException inside handler\", e);" << endl + << indent() << "fb.close();" << endl; + + indent_down(); + indent(f_service_) << "} else {" << endl; + indent_up(); + + f_service_ << indent() << "_LOGGER.error(\"Exception inside oneway handler\", e);" << endl; + + indent_down(); + indent(f_service_) << "}" << endl; + } else { + indent(f_service_) << "byte msgType = org.apache.thrift.protocol.TMessageType.REPLY;" << endl; + indent(f_service_) << "org.apache.thrift.TSerializable msg;" << endl; + indent(f_service_) << resultname << " result = new " << resultname << "();" << endl; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + + vector::const_iterator x_iter; + if (xceptions.size() > 0) { + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + if (x_iter == xceptions.begin()) + f_service_ << indent(); + string type = type_name((*x_iter)->get_type(), false, false); + string name = (*x_iter)->get_name(); + f_service_ << "if (e instanceof " << type << ") {" << endl; + indent_up(); + f_service_ << indent() << "result." << name << " = (" << type << ") e;" << endl + << indent() << "result.set" << get_cap_name(name) << get_cap_name("isSet") + << "(true);" << endl + << indent() << "msg = result;" << endl; + indent_down(); + indent(f_service_) << "} else "; + } + } else { + indent(f_service_); + } + f_service_ << "if (e instanceof org.apache.thrift.transport.TTransportException) {" << endl; + indent_up(); + f_service_ << indent() << "_LOGGER.error(\"TTransportException inside handler\", e);" << endl + << indent() << "fb.close();" << endl + << indent() << "return;" << endl; + indent_down(); + indent(f_service_) << "} else if (e instanceof org.apache.thrift.TApplicationException) {" + << endl; + indent_up(); + f_service_ << indent() << "_LOGGER.error(\"TApplicationException inside handler\", e);" << endl + << indent() << "msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;" << endl + << indent() << "msg = (org.apache.thrift.TApplicationException)e;" << endl; + indent_down(); + indent(f_service_) << "} else {" << endl; + indent_up(); + f_service_ << indent() << "_LOGGER.error(\"Exception inside handler\", e);" << endl + << indent() << "msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;" << endl + << indent() << "msg = new " + "org.apache.thrift.TApplicationException(org.apache.thrift." + "TApplicationException.INTERNAL_ERROR, e.getMessage());" + << endl; + indent_down(); + f_service_ << indent() << "}" << endl + << indent() << "try {" << endl + << indent() << " fcall.sendResponse(fb,msg,msgType,seqid);" << endl + << indent() << "} catch (java.lang.Exception ex) {" << endl + << indent() << " _LOGGER.error(\"Exception writing to internal frame buffer\", ex);" + << endl + << indent() << " fb.close();" << endl + << indent() << "}" << endl; + } + indent_down(); + indent(f_service_) << "}" << endl; + indent_down(); + indent(f_service_) << "};" << endl; + indent_down(); + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "protected boolean isOneway() {" << endl; + indent(f_service_) << " return " << ((tfunction->is_oneway()) ? "true" : "false") << ";" << endl; + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "public void start(I iface, " << argsname + << " args, org.apache.thrift.async.AsyncMethodCallback<" << resulttype + << "> resultHandler) throws org.apache.thrift.TException {" << endl; + indent_up(); + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + f_service_ << indent(); + + f_service_ << "iface." << get_rpc_method_name(tfunction->get_name()) << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "args." << (*f_iter)->get_name(); + } + if (!first) + f_service_ << ","; + f_service_ << "resultHandler"; + f_service_ << ");" << endl; + + indent_down(); + indent(f_service_) << "}"; + + // Close function + f_service_ << endl; + + // Close class + indent_down(); + f_service_ << indent() << "}" << endl << endl; +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_java_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + string argsname = tfunction->get_name() + "_args"; + string resultname = tfunction->get_name() + "_result"; + if (tfunction->is_oneway()) { + resultname = "org.apache.thrift.TBase"; + } + + (void)tservice; + // Open class + indent(f_service_) << "public static class " << tfunction->get_name() + << " extends org.apache.thrift.ProcessFunction {" << endl; + indent_up(); + + indent(f_service_) << "public " << tfunction->get_name() << "() {" << endl; + indent(f_service_) << " super(\"" << tfunction->get_name() << "\");" << endl; + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "public " << argsname << " getEmptyArgsInstance() {" << endl; + indent(f_service_) << " return new " << argsname << "();" << endl; + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "protected boolean isOneway() {" << endl; + indent(f_service_) << " return " << ((tfunction->is_oneway()) ? "true" : "false") << ";" << endl; + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "@Override" << endl; + indent(f_service_) << "protected boolean handleRuntimeExceptions() {" << endl; + indent(f_service_) << " return " << ((handle_runtime_exceptions_) ? "true" : "false") << ";" << endl; + indent(f_service_) << "}" << endl << endl; + + indent(f_service_) << "public " << resultname << " getResult(I iface, " << argsname + << " args) throws org.apache.thrift.TException {" << endl; + indent_up(); + if (!tfunction->is_oneway()) { + indent(f_service_) << resultname << " result = new " << resultname << "();" << endl; + } + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + // Try block for a function with exceptions + if (xceptions.size() > 0) { + f_service_ << indent() << "try {" << endl; + indent_up(); + } + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + f_service_ << indent(); + + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + f_service_ << "result.success = "; + } + f_service_ << "iface." << get_rpc_method_name(tfunction->get_name()) << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "args." << (*f_iter)->get_name(); + } + f_service_ << ");" << endl; + + // Set isset on success field + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void() + && !type_can_be_null(tfunction->get_returntype())) { + indent(f_service_) << "result.set" << get_cap_name("success") << get_cap_name("isSet") + << "(true);" << endl; + } + + if (!tfunction->is_oneway() && xceptions.size() > 0) { + indent_down(); + f_service_ << indent() << "}"; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " " + << (*x_iter)->get_name() << ") {" << endl; + if (!tfunction->is_oneway()) { + indent_up(); + f_service_ << indent() << "result." << (*x_iter)->get_name() << " = " + << (*x_iter)->get_name() << ";" << endl; + indent_down(); + f_service_ << indent() << "}"; + } else { + f_service_ << "}"; + } + } + f_service_ << endl; + } + + if (tfunction->is_oneway()) { + indent(f_service_) << "return null;" << endl; + } else { + indent(f_service_) << "return result;" << endl; + } + indent_down(); + indent(f_service_) << "}"; + + // Close function + f_service_ << endl; + + // Close class + indent_down(); + f_service_ << indent() << "}" << endl << endl; +} + +/** + * Deserializes a field of any type. + * + * @param tfield The field + * @param prefix The variable name or container for this field + */ +void t_java_generator::generate_deserialize_field(ofstream& out, + t_field* tfield, + string prefix, + bool has_metadata) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = prefix + tfield->get_name(); + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name); + } else if (type->is_container()) { + generate_deserialize_container(out, type, name, has_metadata); + } else if (type->is_base_type()) { + indent(out) << name << " = iprot."; + + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "readBinary();"; + } else { + out << "readString();"; + } + break; + case t_base_type::TYPE_BOOL: + out << "readBool();"; + break; + case t_base_type::TYPE_I8: + out << "readByte();"; + break; + case t_base_type::TYPE_I16: + out << "readI16();"; + break; + case t_base_type::TYPE_I32: + out << "readI32();"; + break; + case t_base_type::TYPE_I64: + out << "readI64();"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble();"; + break; + default: + throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase); + } + out << endl; + } else if (type->is_enum()) { + indent(out) << name << " = " + << type_name(tfield->get_type(), true, false, false, true) + + ".findByValue(iprot.readI32());" << endl; + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +/** + * Generates an unserializer for a struct, invokes read() + */ +void t_java_generator::generate_deserialize_struct(ofstream& out, + t_struct* tstruct, + string prefix) { + + if (reuse_objects_) { + indent(out) << "if (" << prefix << " == null) {" << endl; + indent_up(); + } + indent(out) << prefix << " = new " << type_name(tstruct) << "();" << endl; + if (reuse_objects_) { + indent_down(); + indent(out) << "}" << endl; + } + indent(out) << prefix << ".read(iprot);" << endl; +} + +/** + * Deserializes a container by reading its size and then iterating + */ +void t_java_generator::generate_deserialize_container(ofstream& out, + t_type* ttype, + string prefix, + bool has_metadata) { + + scope_up(out); + + string obj; + + if (ttype->is_map()) { + obj = tmp("_map"); + } else if (ttype->is_set()) { + obj = tmp("_set"); + } else if (ttype->is_list()) { + obj = tmp("_list"); + } + + if (has_metadata) { + // Declare variables, read header + if (ttype->is_map()) { + indent(out) << "org.apache.thrift.protocol.TMap " << obj << " = iprot.readMapBegin();" + << endl; + } else if (ttype->is_set()) { + indent(out) << "org.apache.thrift.protocol.TSet " << obj << " = iprot.readSetBegin();" + << endl; + } else if (ttype->is_list()) { + indent(out) << "org.apache.thrift.protocol.TList " << obj << " = iprot.readListBegin();" + << endl; + } + } else { + // Declare variables, read header + if (ttype->is_map()) { + indent(out) << "org.apache.thrift.protocol.TMap " << obj + << " = new org.apache.thrift.protocol.TMap(" + << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " + << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " + << "iprot.readI32());" << endl; + } else if (ttype->is_set()) { + indent(out) << "org.apache.thrift.protocol.TSet " << obj + << " = new org.apache.thrift.protocol.TSet(" + << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", iprot.readI32());" + << endl; + } else if (ttype->is_list()) { + indent(out) << "org.apache.thrift.protocol.TList " << obj + << " = new org.apache.thrift.protocol.TList(" + << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", iprot.readI32());" + << endl; + } + } + + if (reuse_objects_) { + indent(out) << "if (" << prefix << " == null) {" << endl; + indent_up(); + } + + if (is_enum_set(ttype)) { + out << indent() << prefix << " = " << type_name(ttype, false, true, true) << ".noneOf"; + } else { + out << indent() << prefix << " = new " << type_name(ttype, false, true); + } + + // construct the collection correctly i.e. with appropriate size/type + if (is_enum_set(ttype) || is_enum_map(ttype)) { + out << "(" << inner_enum_type_name(ttype) << ");" << endl; + } else if (sorted_containers_ && (ttype->is_map() || ttype->is_set())) { + // TreeSet and TreeMap don't have any constructor which takes a capacity as an argument + out << "();" << endl; + } else { + out << "(" << (ttype->is_list() ? "" : "2*") << obj << ".size" + << ");" << endl; + } + + if (reuse_objects_) { + indent_down(); + indent(out) << "}" << endl; + } + + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, prefix, obj, has_metadata); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, prefix, obj, has_metadata); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, prefix, obj, has_metadata); + } + + scope_down(out); + + if (has_metadata) { + // Read container end + if (ttype->is_map()) { + indent(out) << "iprot.readMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "iprot.readSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "iprot.readListEnd();" << endl; + } + } + scope_down(out); +} + +/** + * Generates code to deserialize a map + */ +void t_java_generator::generate_deserialize_map_element(ofstream& out, + t_map* tmap, + string prefix, + string obj, + bool has_metadata) { + string key = tmp("_key"); + string val = tmp("_val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + indent(out) << declare_field(&fkey, reuse_objects_, false) << endl; + indent(out) << declare_field(&fval, reuse_objects_, false) << endl; + + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size" + << "; " + << "++" << i << ")" << endl; + + scope_up(out); + + generate_deserialize_field(out, &fkey, "", has_metadata); + generate_deserialize_field(out, &fval, "", has_metadata); + + if (get_true_type(fkey.get_type())->is_enum()) { + indent(out) << "if (" << key << " != null)" << endl; + scope_up(out); + } + + indent(out) << prefix << ".put(" << key << ", " << val << ");" << endl; + + if (get_true_type(fkey.get_type())->is_enum()) { + scope_down(out); + } + + if (reuse_objects_ && !get_true_type(fkey.get_type())->is_base_type()) { + indent(out) << key << " = null;" << endl; + } + + if (reuse_objects_ && !get_true_type(fval.get_type())->is_base_type()) { + indent(out) << val << " = null;" << endl; + } +} + +/** + * Deserializes a set element + */ +void t_java_generator::generate_deserialize_set_element(ofstream& out, + t_set* tset, + string prefix, + string obj, + bool has_metadata) { + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); + + indent(out) << declare_field(&felem, reuse_objects_, false) << endl; + + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size" + << "; " + << "++" << i << ")" << endl; + scope_up(out); + + generate_deserialize_field(out, &felem, "", has_metadata); + + if (get_true_type(felem.get_type())->is_enum()) { + indent(out) << "if (" << elem << " != null)" << endl; + scope_up(out); + } + + indent(out) << prefix << ".add(" << elem << ");" << endl; + + if (get_true_type(felem.get_type())->is_enum()) { + scope_down(out); + } + + if (reuse_objects_ && !get_true_type(felem.get_type())->is_base_type()) { + indent(out) << elem << " = null;" << endl; + } +} + +/** + * Deserializes a list element + */ +void t_java_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix, + string obj, + bool has_metadata) { + string elem = tmp("_elem"); + t_field felem(tlist->get_elem_type(), elem); + + indent(out) << declare_field(&felem, reuse_objects_, false) << endl; + + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size" + << "; " + << "++" << i << ")" << endl; + scope_up(out); + + generate_deserialize_field(out, &felem, "", has_metadata); + + if (get_true_type(felem.get_type())->is_enum()) { + indent(out) << "if (" << elem << " != null)" << endl; + scope_up(out); + } + + indent(out) << prefix << ".add(" << elem << ");" << endl; + + if (get_true_type(felem.get_type())->is_enum()) { + scope_down(out); + } + + if (reuse_objects_ && !get_true_type(felem.get_type())->is_base_type()) { + indent(out) << elem << " = null;" << endl; + } +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_java_generator::generate_serialize_field(ofstream& out, + t_field* tfield, + string prefix, + bool has_metadata) { + t_type* type = get_true_type(tfield->get_type()); + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); + } else if (type->is_container()) { + generate_serialize_container(out, type, prefix + tfield->get_name(), has_metadata); + } else if (type->is_enum()) { + indent(out) << "oprot.writeI32(" << prefix + tfield->get_name() << ".getValue());" << endl; + } else if (type->is_base_type()) { + string name = prefix + tfield->get_name(); + indent(out) << "oprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "writeBinary(" << name << ");"; + } else { + out << "writeString(" << name << ");"; + } + break; + case t_base_type::TYPE_BOOL: + out << "writeBool(" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "writeByte(" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "writeI16(" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "writeI32(" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "writeI64(" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble(" << name << ");"; + break; + default: + throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "writeI32(struct." << name << ");"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", + prefix.c_str(), + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_java_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + (void)tstruct; + out << indent() << prefix << ".write(oprot);" << endl; +} + +/** + * Serializes a container by writing its size then the elements. + * + * @param ttype The type of container + * @param prefix String prefix for fields + */ +void t_java_generator::generate_serialize_container(ofstream& out, + t_type* ttype, + string prefix, + bool has_metadata) { + scope_up(out); + + if (has_metadata) { + if (ttype->is_map()) { + indent(out) << "oprot.writeMapBegin(new org.apache.thrift.protocol.TMap(" + << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " + << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix << ".size()));" + << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.writeSetBegin(new org.apache.thrift.protocol.TSet(" + << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix + << ".size()));" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.writeListBegin(new org.apache.thrift.protocol.TList(" + << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix + << ".size()));" << endl; + } + } else { + indent(out) << "oprot.writeI32(" << prefix << ".size());" << endl; + } + + string iter = tmp("_iter"); + if (ttype->is_map()) { + indent(out) << "for (java.util.Map.Entry<" << type_name(((t_map*)ttype)->get_key_type(), true, false) + << ", " << type_name(((t_map*)ttype)->get_val_type(), true, false) << "> " << iter + << " : " << prefix << ".entrySet())"; + } else if (ttype->is_set()) { + indent(out) << "for (" << type_name(((t_set*)ttype)->get_elem_type()) << " " << iter << " : " + << prefix << ")"; + } else if (ttype->is_list()) { + indent(out) << "for (" << type_name(((t_list*)ttype)->get_elem_type()) << " " << iter << " : " + << prefix << ")"; + } + + out << endl; + scope_up(out); + if (ttype->is_map()) { + generate_serialize_map_element(out, (t_map*)ttype, iter, prefix, has_metadata); + } else if (ttype->is_set()) { + generate_serialize_set_element(out, (t_set*)ttype, iter, has_metadata); + } else if (ttype->is_list()) { + generate_serialize_list_element(out, (t_list*)ttype, iter, has_metadata); + } + scope_down(out); + + if (has_metadata) { + if (ttype->is_map()) { + indent(out) << "oprot.writeMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.writeSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.writeListEnd();" << endl; + } + } + + scope_down(out); +} + +/** + * Serializes the members of a map. + */ +void t_java_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string iter, + string map, + bool has_metadata) { + (void)map; + t_field kfield(tmap->get_key_type(), iter + ".getKey()"); + generate_serialize_field(out, &kfield, "", has_metadata); + t_field vfield(tmap->get_val_type(), iter + ".getValue()"); + generate_serialize_field(out, &vfield, "", has_metadata); +} + +/** + * Serializes the members of a set. + */ +void t_java_generator::generate_serialize_set_element(ofstream& out, + t_set* tset, + string iter, + bool has_metadata) { + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, &efield, "", has_metadata); +} + +/** + * Serializes the members of a list. + */ +void t_java_generator::generate_serialize_list_element(ofstream& out, + t_list* tlist, + string iter, + bool has_metadata) { + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, &efield, "", has_metadata); +} + +/** + * Returns a Java type name + * + * @param ttype The type + * @param container Is the type going inside a container? + * @return Java type name, i.e. java.util.HashMap + */ +string t_java_generator::type_name(t_type* ttype, + bool in_container, + bool in_init, + bool skip_generic, + bool force_namespace) { + // In Java typedefs are just resolved to their real type + ttype = get_true_type(ttype); + string prefix; + + if (ttype->is_base_type()) { + return base_type_name((t_base_type*)ttype, in_container); + } else if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + if (in_init) { + if (is_enum_map(tmap)) { + prefix = "java.util.EnumMap"; + } else if (sorted_containers_) { + prefix = "java.util.TreeMap"; + } else { + prefix = "java.util.HashMap"; + } + } else { + prefix = "java.util.Map"; + } + return prefix + (skip_generic ? "" : "<" + type_name(tmap->get_key_type(), true) + "," + + type_name(tmap->get_val_type(), true) + ">"); + } else if (ttype->is_set()) { + t_set* tset = (t_set*)ttype; + if (in_init) { + if (is_enum_set(tset)) { + prefix = "java.util.EnumSet"; + } else if (sorted_containers_) { + prefix = "java.util.TreeSet"; + } else { + prefix = "java.util.HashSet"; + } + } else { + prefix = "java.util.Set"; + } + return prefix + (skip_generic ? "" : "<" + type_name(tset->get_elem_type(), true) + ">"); + } else if (ttype->is_list()) { + t_list* tlist = (t_list*)ttype; + if (in_init) { + prefix = "java.util.ArrayList"; + } else { + prefix = "java.util.List"; + } + return prefix + (skip_generic ? "" : "<" + type_name(tlist->get_elem_type(), true) + ">"); + } + + // Check for namespacing + t_program* program = ttype->get_program(); + if ((program != NULL) && ((program != program_) || force_namespace)) { + string package = program->get_namespace("java"); + if (!package.empty()) { + return package + "." + ttype->get_name(); + } + } + + return ttype->get_name(); +} + +/** + * Returns the Java type that corresponds to the thrift type. + * + * @param tbase The base type + * @param container Is it going in a Java container? + */ +string t_java_generator::base_type_name(t_base_type* type, bool in_container) { + t_base_type::t_base tbase = type->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + return (in_container ? "Void" : "void"); + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + return "java.nio.ByteBuffer"; + } else { + return "java.lang.String"; + } + case t_base_type::TYPE_BOOL: + return (in_container ? "java.lang.Boolean" : "boolean"); + case t_base_type::TYPE_I8: + return (in_container ? "java.lang.Byte" : "byte"); + case t_base_type::TYPE_I16: + return (in_container ? "java.lang.Short" : "short"); + case t_base_type::TYPE_I32: + return (in_container ? "java.lang.Integer" : "int"); + case t_base_type::TYPE_I64: + return (in_container ? "java.lang.Long" : "long"); + case t_base_type::TYPE_DOUBLE: + return (in_container ? "java.lang.Double" : "double"); + default: + throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase); + } +} + +/** + * Declares a field, which may include initialization as necessary. + * + * @param tfield The field + * @param init Whether to initialize the field + */ +string t_java_generator::declare_field(t_field* tfield, bool init, bool comment) { + // TODO(mcslee): do we ever need to initialize the field? + string result = type_name(tfield->get_type()) + " " + tfield->get_name(); + if (init) { + t_type* ttype = get_true_type(tfield->get_type()); + if (ttype->is_base_type() && tfield->get_value() != NULL) { + ofstream dummy; + result += " = " + render_const_value(dummy, ttype, tfield->get_value()); + } else if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + result += " = null"; + break; + case t_base_type::TYPE_BOOL: + result += " = false"; + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + result += " = 0"; + break; + case t_base_type::TYPE_DOUBLE: + result += " = (double)0"; + break; + } + } else if (ttype->is_enum()) { + result += " = null"; + } else if (ttype->is_container()) { + result += " = new " + type_name(ttype, false, true) + "()"; + } else { + result += " = new " + type_name(ttype, false, true) + "()"; + ; + } + } + result += ";"; + if (comment) { + result += " // "; + if (tfield->get_req() == t_field::T_OPTIONAL) { + result += "optional"; + } else { + result += "required"; + } + } + return result; +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_java_generator::function_signature(t_function* tfunction, string prefix) { + t_type* ttype = tfunction->get_returntype(); + std::string fn_name = get_rpc_method_name(tfunction->get_name()); + std::string result = type_name(ttype) + " " + prefix + fn_name + "(" + + argument_list(tfunction->get_arglist()) + ") throws "; + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + result += type_name((*x_iter)->get_type(), false, false) + ", "; + } + result += "org.apache.thrift.TException"; + return result; +} + +/** + * Renders a function signature of the form 'void name(args, resultHandler)' + * + * @params tfunction Function definition + * @return String of rendered function definition + */ +string t_java_generator::function_signature_async(t_function* tfunction, + bool use_base_method, + string prefix) { + std::string arglist = async_function_call_arglist(tfunction, use_base_method, true); + + std::string ret_type = ""; + if (use_base_method) { + ret_type += "AsyncClient."; + } + ret_type += tfunction->get_name() + "_call"; + + std::string fn_name = get_rpc_method_name(tfunction->get_name()); + + std::string result = prefix + "void " + fn_name + "(" + arglist + ")"; + return result; +} + +string t_java_generator::async_function_call_arglist(t_function* tfunc, + bool use_base_method, + bool include_types) { + (void)use_base_method; + std::string arglist = ""; + if (tfunc->get_arglist()->get_members().size() > 0) { + arglist = argument_list(tfunc->get_arglist(), include_types) + ", "; + } + + if (include_types) { + arglist += "org.apache.thrift.async.AsyncMethodCallback<"; + arglist += type_name(tfunc->get_returntype(), true) + "> "; + } + arglist += "resultHandler"; + + return arglist; +} + +/** + * Renders a comma separated field list, with type names + */ +string t_java_generator::argument_list(t_struct* tstruct, bool include_types) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + if (include_types) { + result += type_name((*f_iter)->get_type()) + " "; + } + result += (*f_iter)->get_name(); + } + return result; +} + +string t_java_generator::async_argument_list(t_function* tfunct, + t_struct* tstruct, + t_type* ttype, + bool include_types) { + (void)tfunct; + (void)ttype; + string result = ""; + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + if (include_types) { + result += type_name((*f_iter)->get_type()) + " "; + } + result += (*f_iter)->get_name(); + } + if (!first) { + result += ", "; + } + if (include_types) { + result += "org.apache.thrift.async.AsyncMethodCallback<"; + result += type_name(tfunct->get_returntype(), true) + "> "; + } + result += "resultHandler"; + return result; +} + +/** + * Converts the parse type to a Java enum string for the given type. + */ +string t_java_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "org.apache.thrift.protocol.TType.STRING"; + case t_base_type::TYPE_BOOL: + return "org.apache.thrift.protocol.TType.BOOL"; + case t_base_type::TYPE_I8: + return "org.apache.thrift.protocol.TType.BYTE"; + case t_base_type::TYPE_I16: + return "org.apache.thrift.protocol.TType.I16"; + case t_base_type::TYPE_I32: + return "org.apache.thrift.protocol.TType.I32"; + case t_base_type::TYPE_I64: + return "org.apache.thrift.protocol.TType.I64"; + case t_base_type::TYPE_DOUBLE: + return "org.apache.thrift.protocol.TType.DOUBLE"; + } + } else if (type->is_enum()) { + return "org.apache.thrift.protocol.TType.I32"; + } else if (type->is_struct() || type->is_xception()) { + return "org.apache.thrift.protocol.TType.STRUCT"; + } else if (type->is_map()) { + return "org.apache.thrift.protocol.TType.MAP"; + } else if (type->is_set()) { + return "org.apache.thrift.protocol.TType.SET"; + } else if (type->is_list()) { + return "org.apache.thrift.protocol.TType.LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** + * Takes a name and produes a valid Java source file name from it + * + * @param fromName The name which shall become a valid Java source file name + * @return The produced identifier + */ +std::string t_java_generator::make_valid_java_filename(std::string const& fromName) { + // if any further rules apply to source file names in Java, modify as necessary + return make_valid_java_identifier(fromName); +} + +/** + * Takes a name and produes a valid Java identifier from it + * + * @param fromName The name which shall become a valid Java identifier + * @return The produced identifier + */ +std::string t_java_generator::make_valid_java_identifier(std::string const& fromName) { + std::string str = fromName; + if (str.empty()) { + return str; + } + + // tests rely on this + assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9')); + + // if the first letter is a number, we add an additional underscore in front of it + char c = str.at(0); + if (('0' <= c) && (c <= '9')) { + str = "_" + str; + } + + // following chars: letter, number or underscore + for (size_t i = 0; i < str.size(); ++i) { + c = str.at(i); + if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9')) + && ('_' != c)) { + str.replace(i, 1, "_"); + } + } + + return str; +} + +std::string t_java_generator::as_camel_case(std::string name, bool ucfirst) { + std::string new_name; + size_t i = 0; + for (i = 0; i < name.size(); i++) { + if (name[i] != '_') + break; + } + if (ucfirst) { + new_name += toupper(name[i++]); + } else { + new_name += tolower(name[i++]); + } + for (; i < name.size(); i++) { + if (name[i] == '_') { + if (i < name.size() - 1) { + i++; + new_name += toupper(name[i]); + } + } else { + new_name += name[i]; + } + } + return new_name; +} + +std::string t_java_generator::get_rpc_method_name(std::string name) { + if (fullcamel_style_) { + return as_camel_case(name, false); + } else { + return name; + } +} + +/** + * Applies the correct style to a string based on the value of nocamel_style_ + * and/or fullcamel_style_ + */ +std::string t_java_generator::get_cap_name(std::string name) { + if (nocamel_style_) { + return "_" + name; + } else if (fullcamel_style_) { + return as_camel_case(name); + } else { + name[0] = toupper(name[0]); + return name; + } +} + +string t_java_generator::constant_name(string name) { + string constant_name; + + bool is_first = true; + bool was_previous_char_upper = false; + for (string::iterator iter = name.begin(); iter != name.end(); ++iter) { + string::value_type character = (*iter); + + bool is_upper = isupper(character); + + if (is_upper && !is_first && !was_previous_char_upper) { + constant_name += '_'; + } + constant_name += toupper(character); + + is_first = false; + was_previous_char_upper = is_upper; + } + + return constant_name; +} + +void t_java_generator::generate_deep_copy_container(ofstream& out, + std::string source_name_p1, + std::string source_name_p2, + std::string result_name, + t_type* type) { + + t_container* container = (t_container*)type; + std::string source_name; + if (source_name_p2 == "") + source_name = source_name_p1; + else + source_name = source_name_p1 + "." + source_name_p2; + + bool copy_construct_container; + if (container->is_map()) { + t_map* tmap = (t_map*)container; + copy_construct_container = tmap->get_key_type()->is_base_type() + && tmap->get_val_type()->is_base_type(); + } else { + t_type* elem_type = container->is_list() ? ((t_list*)container)->get_elem_type() + : ((t_set*)container)->get_elem_type(); + copy_construct_container = elem_type->is_base_type(); + } + + if (copy_construct_container) { + // deep copy of base types can be done much more efficiently than iterating over all the + // elements manually + indent(out) << type_name(type, true, false) << " " << result_name << " = new " + << type_name(container, false, true) << "(" << source_name << ");" << endl; + return; + } + + std::string constructor_args; + if (is_enum_set(container) || is_enum_map(container)) { + constructor_args = inner_enum_type_name(container); + } else if (!(sorted_containers_ && (container->is_map() || container->is_set()))) { + // unsorted containers accept a capacity value + constructor_args = source_name + ".size()"; + } + + if (is_enum_set(container)) { + indent(out) << type_name(type, true, false) << " " << result_name << " = " + << type_name(container, false, true, true) << ".noneOf(" << constructor_args << ");" << endl; + } else { + indent(out) << type_name(type, true, false) << " " << result_name << " = new " + << type_name(container, false, true) << "(" << constructor_args << ");" << endl; + } + + std::string iterator_element_name = source_name_p1 + "_element"; + std::string result_element_name = result_name + "_copy"; + + if (container->is_map()) { + t_type* key_type = ((t_map*)container)->get_key_type(); + t_type* val_type = ((t_map*)container)->get_val_type(); + + indent(out) << "for (java.util.Map.Entry<" << type_name(key_type, true, false) << ", " + << type_name(val_type, true, false) << "> " << iterator_element_name << " : " + << source_name << ".entrySet()) {" << endl; + indent_up(); + + out << endl; + + indent(out) << type_name(key_type, true, false) << " " << iterator_element_name + << "_key = " << iterator_element_name << ".getKey();" << endl; + indent(out) << type_name(val_type, true, false) << " " << iterator_element_name + << "_value = " << iterator_element_name << ".getValue();" << endl; + + out << endl; + + if (key_type->is_container()) { + generate_deep_copy_container(out, + iterator_element_name + "_key", + "", + result_element_name + "_key", + key_type); + } else { + indent(out) << type_name(key_type, true, false) << " " << result_element_name << "_key = "; + generate_deep_copy_non_container(out, + iterator_element_name + "_key", + result_element_name + "_key", + key_type); + out << ";" << endl; + } + + out << endl; + + if (val_type->is_container()) { + generate_deep_copy_container(out, + iterator_element_name + "_value", + "", + result_element_name + "_value", + val_type); + } else { + indent(out) << type_name(val_type, true, false) << " " << result_element_name << "_value = "; + generate_deep_copy_non_container(out, + iterator_element_name + "_value", + result_element_name + "_value", + val_type); + out << ";" << endl; + } + + out << endl; + + indent(out) << result_name << ".put(" << result_element_name << "_key, " << result_element_name + << "_value);" << endl; + + indent_down(); + indent(out) << "}" << endl; + + } else { + t_type* elem_type; + + if (container->is_set()) { + elem_type = ((t_set*)container)->get_elem_type(); + } else { + elem_type = ((t_list*)container)->get_elem_type(); + } + + indent(out) << "for (" << type_name(elem_type, true, false) << " " << iterator_element_name + << " : " << source_name << ") {" << endl; + + indent_up(); + + if (elem_type->is_container()) { + // recursive deep copy + generate_deep_copy_container(out, iterator_element_name, "", result_element_name, elem_type); + indent(out) << result_name << ".add(" << result_element_name << ");" << endl; + } else { + // iterative copy + if (elem_type->is_binary()) { + indent(out) << "java.nio.ByteBuffer temp_binary_element = "; + generate_deep_copy_non_container(out, + iterator_element_name, + "temp_binary_element", + elem_type); + out << ";" << endl; + indent(out) << result_name << ".add(temp_binary_element);" << endl; + } else { + indent(out) << result_name << ".add("; + generate_deep_copy_non_container(out, iterator_element_name, result_name, elem_type); + out << ");" << endl; + } + } + + indent_down(); + + indent(out) << "}" << endl; + } +} + +void t_java_generator::generate_deep_copy_non_container(ofstream& out, + std::string source_name, + std::string dest_name, + t_type* type) { + (void)dest_name; + type = get_true_type(type); + if (type->is_base_type() || type->is_enum() || type->is_typedef()) { + if (type->is_binary()) { + out << "org.apache.thrift.TBaseHelper.copyBinary(" << source_name << ")"; + } else { + // everything else can be copied directly + out << source_name; + } + } else { + out << "new " << type_name(type, true, true) << "(" << source_name << ")"; + } +} + +std::string t_java_generator::generate_isset_check(t_field* field) { + return generate_isset_check(field->get_name()); +} + +std::string t_java_generator::isset_field_id(t_field* field) { + return "__" + upcase_string(field->get_name() + "_isset_id"); +} + +std::string t_java_generator::generate_isset_check(std::string field_name) { + return "is" + get_cap_name("set") + get_cap_name(field_name) + "()"; +} + +void t_java_generator::generate_isset_set(ofstream& out, t_field* field, string prefix) { + if (!type_can_be_null(field->get_type())) { + indent(out) << prefix << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet") + << "(true);" << endl; + } +} + +void t_java_generator::generate_struct_desc(ofstream& out, t_struct* tstruct) { + indent(out) << "private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new " + "org.apache.thrift.protocol.TStruct(\"" << tstruct->get_name() << "\");" << endl; +} + +void t_java_generator::generate_field_descs(ofstream& out, t_struct* tstruct) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << "private static final org.apache.thrift.protocol.TField " + << constant_name((*m_iter)->get_name()) + << "_FIELD_DESC = new org.apache.thrift.protocol.TField(\"" << (*m_iter)->get_name() + << "\", " << type_to_enum((*m_iter)->get_type()) << ", " + << "(short)" << (*m_iter)->get_key() << ");" << endl; + } +} + +void t_java_generator::generate_scheme_map(ofstream& out, t_struct* tstruct) { + indent(out) << "private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new " + << tstruct->get_name() << "StandardSchemeFactory();" << endl; + indent(out) << "private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new " + << tstruct->get_name() << "TupleSchemeFactory();" << endl; +} + +void t_java_generator::generate_field_name_constants(ofstream& out, t_struct* tstruct) { + indent(out) << "/** The set of fields this struct contains, along with convenience methods for " + "finding and manipulating them. */" << endl; + indent(out) << "public enum _Fields implements org.apache.thrift.TFieldIdEnum {" << endl; + + indent_up(); + bool first = true; + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (!first) { + out << "," << endl; + } + first = false; + generate_java_doc(out, *m_iter); + indent(out) << constant_name((*m_iter)->get_name()) << "((short)" << (*m_iter)->get_key() + << ", \"" << (*m_iter)->get_name() << "\")"; + } + + out << ";" << endl << endl; + + indent(out) + << "private static final java.util.Map byName = new java.util.HashMap();" + << endl; + out << endl; + + indent(out) << "static {" << endl; + indent(out) << " for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {" << endl; + indent(out) << " byName.put(field.getFieldName(), field);" << endl; + indent(out) << " }" << endl; + indent(out) << "}" << endl << endl; + + indent(out) << "/**" << endl; + indent(out) << " * Find the _Fields constant that matches fieldId, or null if its not found." + << endl; + indent(out) << " */" << endl; + indent(out) << "public static _Fields findByThriftId(int fieldId) {" << endl; + indent_up(); + indent(out) << "switch(fieldId) {" << endl; + indent_up(); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << "case " << (*m_iter)->get_key() << ": // " + << constant_name((*m_iter)->get_name()) << endl; + indent(out) << " return " << constant_name((*m_iter)->get_name()) << ";" << endl; + } + + indent(out) << "default:" << endl; + indent(out) << " return null;" << endl; + + indent_down(); + indent(out) << "}" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; + + indent(out) << "/**" << endl; + indent(out) << " * Find the _Fields constant that matches fieldId, throwing an exception" << endl; + indent(out) << " * if it is not found." << endl; + indent(out) << " */" << endl; + indent(out) << "public static _Fields findByThriftIdOrThrow(int fieldId) {" << endl; + indent(out) << " _Fields fields = findByThriftId(fieldId);" << endl; + indent(out) << " if (fields == null) throw new java.lang.IllegalArgumentException(\"Field \" + fieldId + " + "\" doesn't exist!\");" << endl; + indent(out) << " return fields;" << endl; + indent(out) << "}" << endl << endl; + + indent(out) << "/**" << endl; + indent(out) << " * Find the _Fields constant that matches name, or null if its not found." + << endl; + indent(out) << " */" << endl; + indent(out) << "public static _Fields findByName(java.lang.String name) {" << endl; + indent(out) << " return byName.get(name);" << endl; + indent(out) << "}" << endl << endl; + + indent(out) << "private final short _thriftId;" << endl; + indent(out) << "private final java.lang.String _fieldName;" << endl << endl; + + indent(out) << "_Fields(short thriftId, java.lang.String fieldName) {" << endl; + indent(out) << " _thriftId = thriftId;" << endl; + indent(out) << " _fieldName = fieldName;" << endl; + indent(out) << "}" << endl << endl; + + indent(out) << "public short getThriftFieldId() {" << endl; + indent(out) << " return _thriftId;" << endl; + indent(out) << "}" << endl << endl; + + indent(out) << "public java.lang.String getFieldName() {" << endl; + indent(out) << " return _fieldName;" << endl; + indent(out) << "}" << endl; + + indent_down(); + + indent(out) << "}" << endl; +} + +t_java_generator::isset_type t_java_generator::needs_isset(t_struct* tstruct, + std::string* outPrimitiveType) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + int count = 0; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (!type_can_be_null(get_true_type((*m_iter)->get_type()))) { + count++; + } + } + if (count == 0) { + return ISSET_NONE; + } else if (count <= 64) { + if (outPrimitiveType != NULL) { + if (count <= 8) + *outPrimitiveType = "byte"; + else if (count <= 16) + *outPrimitiveType = "short"; + else if (count <= 32) + *outPrimitiveType = "int"; + else if (count <= 64) + *outPrimitiveType = "long"; + } + return ISSET_PRIMITIVE; + } else { + return ISSET_BITSET; + } +} + +void t_java_generator::generate_java_struct_clear(std::ofstream& out, t_struct* tstruct) { + if (!java5_) { + indent(out) << "@Override" << endl; + } + indent(out) << "public void clear() {" << endl; + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + indent_up(); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = *m_iter; + t_type* t = get_true_type(field->get_type()); + + if (field->get_value() != NULL) { + print_const_value(out, "this." + field->get_name(), t, field->get_value(), true, true); + continue; + } + + if (type_can_be_null(t)) { + + if (reuse_objects_ && (t->is_container() || t->is_struct())) { + indent(out) << "if (this." << field->get_name() << " != null) {" << endl; + indent_up(); + indent(out) << "this." << field->get_name() << ".clear();" << endl; + indent_down(); + indent(out) << "}" << endl; + + } else { + + indent(out) << "this." << field->get_name() << " = null;" << endl; + } + continue; + } + + // must be a base type + // means it also needs to be explicitly unset + indent(out) << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet") << "(false);" + << endl; + t_base_type* base_type = (t_base_type*)t; + + switch (base_type->get_base()) { + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + indent(out) << "this." << field->get_name() << " = 0;" << endl; + break; + case t_base_type::TYPE_DOUBLE: + indent(out) << "this." << field->get_name() << " = 0.0;" << endl; + break; + case t_base_type::TYPE_BOOL: + indent(out) << "this." << field->get_name() << " = false;" << endl; + break; + default: + throw "unsupported type: " + base_type->get_name() + " for field " + field->get_name(); + } + } + indent_down(); + + indent(out) << "}" << endl << endl; +} + +// generates java method to serialize (in the Java sense) the object +void t_java_generator::generate_java_struct_write_object(ofstream& out, t_struct* tstruct) { + (void)tstruct; + indent(out) + << "private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {" + << endl; + indent(out) << " try {" << endl; + indent(out) << " write(new org.apache.thrift.protocol.TCompactProtocol(new " + "org.apache.thrift.transport.TIOStreamTransport(out)));" << endl; + indent(out) << " } catch (org.apache.thrift.TException te) {" << endl; + indent(out) << " throw new java.io.IOException(te" << (android_legacy_ ? ".getMessage()" : "") + << ");" << endl; + indent(out) << " }" << endl; + indent(out) << "}" << endl << endl; +} + +// generates java method to serialize (in the Java sense) the object +void t_java_generator::generate_java_struct_read_object(ofstream& out, t_struct* tstruct) { + indent(out) << "private void readObject(java.io.ObjectInputStream in) throws " + "java.io.IOException, java.lang.ClassNotFoundException {" << endl; + indent(out) << " try {" << endl; + if (!tstruct->is_union()) { + switch (needs_isset(tstruct)) { + case ISSET_NONE: + break; + case ISSET_PRIMITIVE: + indent(out) << " // it doesn't seem like you should have to do this, but java " + "serialization is wacky, and doesn't call the default constructor." << endl; + indent(out) << " __isset_bitfield = 0;" << endl; + break; + case ISSET_BITSET: + indent(out) << " // it doesn't seem like you should have to do this, but java " + "serialization is wacky, and doesn't call the default constructor." << endl; + indent(out) << " __isset_bit_vector = new java.util.BitSet(1);" << endl; + break; + } + } + indent(out) << " read(new org.apache.thrift.protocol.TCompactProtocol(new " + "org.apache.thrift.transport.TIOStreamTransport(in)));" << endl; + indent(out) << " } catch (org.apache.thrift.TException te) {" << endl; + indent(out) << " throw new java.io.IOException(te" << (android_legacy_ ? ".getMessage()" : "") + << ");" << endl; + indent(out) << " }" << endl; + indent(out) << "}" << endl << endl; +} + +void t_java_generator::generate_standard_reader(ofstream& out, t_struct* tstruct) { + out << indent() << "public void read(org.apache.thrift.protocol.TProtocol iprot, " + << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Declare stack tmp variables and read struct header + out << indent() << "org.apache.thrift.protocol.TField schemeField;" << endl << indent() + << "iprot.readStructBegin();" << endl; + + // Loop over reading in fields + indent(out) << "while (true)" << endl; + scope_up(out); + + // Read beginning field marker + indent(out) << "schemeField = iprot.readFieldBegin();" << endl; + + // Check for field STOP marker and break + indent(out) << "if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { " << endl; + indent_up(); + indent(out) << "break;" << endl; + indent_down(); + indent(out) << "}" << endl; + + // Switch statement on the field we are reading + indent(out) << "switch (schemeField.id) {" << endl; + + indent_up(); + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << "case " << (*f_iter)->get_key() << ": // " + << constant_name((*f_iter)->get_name()) << endl; + indent_up(); + indent(out) << "if (schemeField.type == " << type_to_enum((*f_iter)->get_type()) << ") {" + << endl; + indent_up(); + + generate_deserialize_field(out, *f_iter, "struct.", true); + indent(out) << "struct." + << "set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet") + << "(true);" << endl; + indent_down(); + out << indent() << "} else { " << endl << indent() + << " org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);" << endl + << indent() << "}" << endl << indent() << "break;" << endl; + indent_down(); + } + + indent(out) << "default:" << endl; + indent(out) << " org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);" + << endl; + + indent_down(); + indent(out) << "}" << endl; + + // Read field end marker + indent(out) << "iprot.readFieldEnd();" << endl; + + indent_down(); + indent(out) << "}" << endl; + + out << indent() << "iprot.readStructEnd();" << endl; + + // in non-beans style, check for required fields of primitive type + // (which can be checked here but not in the general validate method) + if (!bean_style_) { + out << endl << indent() << "// check for required fields of primitive type, which can't be " + "checked in the validate method" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) { + out << indent() << "if (!struct." << generate_isset_check(*f_iter) << ") {" << endl + << indent() + << " throw new org.apache.thrift.protocol.TProtocolException(\"Required field '" + << (*f_iter)->get_name() + << "' was not found in serialized data! Struct: \" + toString());" << endl << indent() + << "}" << endl; + } + } + } + + // performs various checks (e.g. check that all required fields are set) + indent(out) << "struct.validate();" << endl; + + indent_down(); + out << indent() << "}" << endl; +} + +void t_java_generator::generate_standard_writer(ofstream& out, t_struct* tstruct, bool is_result) { + indent_up(); + out << indent() << "public void write(org.apache.thrift.protocol.TProtocol oprot, " + << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl; + indent_up(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + // performs various checks (e.g. check that all required fields are set) + indent(out) << "struct.validate();" << endl << endl; + + indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool null_allowed = type_can_be_null((*f_iter)->get_type()); + if (null_allowed) { + out << indent() << "if (struct." << (*f_iter)->get_name() << " != null) {" << endl; + indent_up(); + } + bool optional = ((*f_iter)->get_req() == t_field::T_OPTIONAL) || (is_result && !null_allowed); + if (optional) { + indent(out) << "if (" + << "struct." << generate_isset_check((*f_iter)) << ") {" << endl; + indent_up(); + } + + indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) + << "_FIELD_DESC);" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "struct.", true); + + // Write field closer + indent(out) << "oprot.writeFieldEnd();" << endl; + + if (optional) { + indent_down(); + indent(out) << "}" << endl; + } + if (null_allowed) { + indent_down(); + indent(out) << "}" << endl; + } + } + // Write the struct map + out << indent() << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();" + << endl; + + indent_down(); + out << indent() << "}" << endl << endl; + indent_down(); +} + +void t_java_generator::generate_java_struct_standard_scheme(ofstream& out, + t_struct* tstruct, + bool is_result) { + indent(out) << "private static class " << tstruct->get_name() + << "StandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {" << endl; + indent_up(); + indent(out) << "public " << tstruct->get_name() << "StandardScheme getScheme() {" << endl; + indent_up(); + indent(out) << "return new " << tstruct->get_name() << "StandardScheme();" << endl; + indent_down(); + indent(out) << "}" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + + out << indent() << "private static class " << tstruct->get_name() + << "StandardScheme extends org.apache.thrift.scheme.StandardScheme<" << tstruct->get_name() << "> {" << endl << endl; + indent_up(); + generate_standard_reader(out, tstruct); + indent_down(); + out << endl; + generate_standard_writer(out, tstruct, is_result); + + out << indent() << "}" << endl << endl; +} + +void t_java_generator::generate_java_struct_tuple_reader(ofstream& out, t_struct* tstruct) { + indent(out) << "@Override" << endl; + indent(out) << "public void read(org.apache.thrift.protocol.TProtocol prot, " + << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl; + indent_up(); + indent(out) << "org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;" << endl; + int optional_count = 0; + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_OPTIONAL + || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) { + optional_count++; + } + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + generate_deserialize_field(out, (*f_iter), "struct.", false); + indent(out) << "struct.set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet") + << "(true);" << endl; + } + } + if (optional_count > 0) { + indent(out) << "java.util.BitSet incoming = iprot.readBitSet(" << optional_count << ");" << endl; + int i = 0; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_OPTIONAL + || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) { + indent(out) << "if (incoming.get(" << i << ")) {" << endl; + indent_up(); + generate_deserialize_field(out, (*f_iter), "struct.", false); + indent(out) << "struct.set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet") + << "(true);" << endl; + indent_down(); + indent(out) << "}" << endl; + i++; + } + } + } + indent_down(); + indent(out) << "}" << endl; +} + +void t_java_generator::generate_java_struct_tuple_writer(ofstream& out, t_struct* tstruct) { + indent(out) << "@Override" << endl; + indent(out) << "public void write(org.apache.thrift.protocol.TProtocol prot, " + << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl; + indent_up(); + indent(out) << "org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;" << endl; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool has_optional = false; + int optional_count = 0; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_OPTIONAL + || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) { + optional_count++; + has_optional = true; + } + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + generate_serialize_field(out, (*f_iter), "struct.", false); + } + } + if (has_optional) { + indent(out) << "java.util.BitSet optionals = new java.util.BitSet();" << endl; + int i = 0; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_OPTIONAL + || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) { + indent(out) << "if (struct." << generate_isset_check((*f_iter)) << ") {" << endl; + indent_up(); + indent(out) << "optionals.set(" << i << ");" << endl; + indent_down(); + indent(out) << "}" << endl; + i++; + } + } + + indent(out) << "oprot.writeBitSet(optionals, " << optional_count << ");" << endl; + int j = 0; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_OPTIONAL + || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) { + indent(out) << "if (struct." << generate_isset_check(*f_iter) << ") {" << endl; + indent_up(); + generate_serialize_field(out, (*f_iter), "struct.", false); + indent_down(); + indent(out) << "}" << endl; + j++; + } + } + } + indent_down(); + indent(out) << "}" << endl; +} + +void t_java_generator::generate_java_struct_tuple_scheme(ofstream& out, t_struct* tstruct) { + indent(out) << "private static class " << tstruct->get_name() + << "TupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {" << endl; + indent_up(); + indent(out) << "public " << tstruct->get_name() << "TupleScheme getScheme() {" << endl; + indent_up(); + indent(out) << "return new " << tstruct->get_name() << "TupleScheme();" << endl; + indent_down(); + indent(out) << "}" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + out << indent() << "private static class " << tstruct->get_name() + << "TupleScheme extends org.apache.thrift.scheme.TupleScheme<" << tstruct->get_name() << "> {" << endl << endl; + indent_up(); + generate_java_struct_tuple_writer(out, tstruct); + out << endl; + generate_java_struct_tuple_reader(out, tstruct); + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_java_generator::generate_java_scheme_lookup(ofstream& out) { + indent(out) << "private static S scheme(" + << "org.apache.thrift.protocol.TProtocol proto) {" << endl; + indent_up(); + indent(out) << "return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) " + << "? STANDARD_SCHEME_FACTORY " + << ": TUPLE_SCHEME_FACTORY" + << ").getScheme();" << endl; + indent_down(); + indent(out) << "}" << endl; +} + +void t_java_generator::generate_javax_generated_annotation(ofstream& out) { + time_t seconds = time(NULL); + struct tm* now = localtime(&seconds); + indent(out) << "@javax.annotation.Generated(value = \"" << autogen_summary() << "\""; + if (undated_generated_annotations_) { + out << ")" << endl; + } else { + indent(out) << ", date = \"" << (now->tm_year + 1900) << "-" << setfill('0') << setw(2) + << (now->tm_mon + 1) << "-" << setfill('0') << setw(2) << now->tm_mday + << "\")" << endl; + } +} + +THRIFT_REGISTER_GENERATOR( + java, + "Java", + " beans: Members will be private, and setter methods will return void.\n" + " private-members: Members will be private, but setter methods will return 'this' like " + "usual.\n" + " nocamel: Do not use CamelCase field accessors with beans.\n" + " fullcamel: Convert underscored_accessor_or_service_names to camelCase.\n" + " android: Generated structures are Parcelable.\n" + " android_legacy: Do not use java.io.IOException(throwable) (available for Android 2.3 and " + "above).\n" + " option_type: Wrap optional fields in an Option type.\n" + " handle_runtime_exceptions:\n" + " Send TApplicationException to the client when RuntimeException occurs on " + "the server. (Default behavior is to close the connection instead.)\n" + " java5: Generate Java 1.5 compliant code (includes android_legacy flag).\n" + " reuse-objects: Data objects will not be allocated, but existing instances will be used " + "(read and write).\n" + " sorted_containers:\n" + " Use TreeSet/TreeMap instead of HashSet/HashMap as a implementation of " + "set/map.\n" + " generated_annotations=[undated|suppress]:\n" + " undated: suppress the date at @Generated annotations\n" + " suppress: suppress @Generated annotations entirely\n") diff --git a/compiler/cpp/src/thrift/generate/t_javame_generator.cc b/compiler/cpp/src/thrift/generate/t_javame_generator.cc new file mode 100644 index 0000000..24b7560 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_javame_generator.cc @@ -0,0 +1,3296 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * Java code generator. + * + */ +class t_javame_generator : public t_oop_generator { +public: + t_javame_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)parsed_options; + (void)option_string; + std::map::const_iterator iter; + + /* no options yet */ + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + throw "unknown option javame:" + iter->first; + } + + out_dir_base_ = "gen-javame"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + void generate_consts(std::vector consts); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_struct(t_struct* tstruct); + void generate_union(t_struct* tunion); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + void print_const_value(std::ofstream& out, + std::string name, + t_type* type, + t_const_value* value, + bool in_static, + bool defval = false); + std::string render_const_value(std::ofstream& out, + std::string name, + t_type* type, + t_const_value* value); + + /** + * Service-level generation functions + */ + + void generate_java_struct(t_struct* tstruct, bool is_exception); + + void generate_java_struct_definition(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false, + bool in_class = false, + bool is_result = false); + void generate_java_struct_equality(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_compare_to(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_reader(std::ofstream& out, t_struct* tstruct); + void generate_java_validator(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_result_writer(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_writer(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_tostring(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_clear(std::ofstream& out, t_struct* tstruct); + void generate_field_value_meta_data(std::ofstream& out, t_type* type); + std::string get_java_type_string(t_type* type); + void generate_reflection_setters(std::ostringstream& out, + t_type* type, + std::string field_name, + std::string cap_name); + void generate_reflection_getters(std::ostringstream& out, + t_type* type, + std::string field_name, + std::string cap_name); + void generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct); + void generate_java_bean_boilerplate(std::ofstream& out, t_struct* tstruct); + + void generate_function_helpers(t_function* tfunction); + std::string get_cap_name(std::string name); + std::string generate_isset_check(t_field* field); + std::string generate_isset_check(std::string field); + void generate_isset_set(ofstream& out, t_field* field); + std::string isset_field_id(t_field* field); + + void generate_primitive_service_interface(t_service* tservice); + void generate_service_interface(t_service* tservice); + void generate_service_helpers(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* tfunction); + + void generate_java_union(t_struct* tstruct); + void generate_union_constructor(ofstream& out, t_struct* tstruct); + void generate_union_getters_and_setters(ofstream& out, t_struct* tstruct); + void generate_union_abstract_methods(ofstream& out, t_struct* tstruct); + void generate_check_type(ofstream& out, t_struct* tstruct); + void generate_read_value(ofstream& out, t_struct* tstruct); + void generate_write_value(ofstream& out, t_struct* tstruct); + void generate_get_field_desc(ofstream& out, t_struct* tstruct); + void generate_get_struct_desc(ofstream& out, t_struct* tstruct); + void generate_get_field_name(ofstream& out, t_struct* tstruct); + + void generate_union_comparisons(ofstream& out, t_struct* tstruct); + void generate_union_hashcode(ofstream& out, t_struct* tstruct); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + + void generate_deserialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_deserialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_deserialize_set_element(std::ofstream& out, t_set* tset, std::string prefix = ""); + + void generate_deserialize_map_element(std::ofstream& out, t_map* tmap, std::string prefix = ""); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix = ""); + + void generate_serialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string iter, + std::string map); + + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + + void generate_java_doc(std::ofstream& out, t_field* field); + + void generate_java_doc(std::ofstream& out, t_doc* tdoc); + + void generate_java_doc(std::ofstream& out, t_function* tdoc); + + void generate_java_docstring_comment(std::ofstream& out, string contents); + + void generate_deep_copy_container(std::ofstream& out, + std::string source_name_p1, + std::string source_name_p2, + std::string result_name, + t_type* type); + void generate_deep_copy_non_container(std::ofstream& out, + std::string source_name, + std::string dest_name, + t_type* type); + + bool has_bit_vector(t_struct* tstruct); + + /** + * Helper rendering functions + */ + + std::string java_package(); + std::string java_type_imports(); + std::string java_thrift_imports(); + std::string type_name(t_type* ttype, + bool in_container = false, + bool in_init = false, + bool skip_generic = false); + std::string base_type_name(t_base_type* tbase, bool in_container = false); + std::string declare_field(t_field* tfield, bool init = false); + std::string function_signature(t_function* tfunction, std::string prefix = ""); + std::string argument_list(t_struct* tstruct, bool include_types = true); + std::string type_to_enum(t_type* ttype); + std::string get_enum_class_name(t_type* type); + void generate_struct_desc(ofstream& out, t_struct* tstruct); + void generate_field_descs(ofstream& out, t_struct* tstruct); + std::string box_type(t_type* type, string value); + + bool type_can_be_null(t_type* ttype) { + ttype = get_true_type(ttype); + + return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string() + || ttype->is_enum(); + } + + std::string constant_name(std::string name); + +private: + /** + * File streams + */ + + std::string package_name_; + std::ofstream f_service_; + std::string package_dir_; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_javame_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + package_name_ = program_->get_namespace("java"); + + string dir = package_name_; + string subdir = get_out_dir(); + string::size_type loc; + while ((loc = dir.find(".")) != string::npos) { + subdir = subdir + "/" + dir.substr(0, loc); + MKDIR(subdir.c_str()); + dir = dir.substr(loc + 1); + } + if (dir.size() > 0) { + subdir = subdir + "/" + dir; + MKDIR(subdir.c_str()); + } + + package_dir_ = subdir; +} + +/** + * Packages the generated file + * + * @return String of the package, i.e. "package org.apache.thriftdemo;" + */ +string t_javame_generator::java_package() { + if (!package_name_.empty()) { + return string("package ") + package_name_ + ";\n\n"; + } + return ""; +} + +/** + * Prints standard java imports + * + * @return List of imports for Java types that are used in here + */ +string t_javame_generator::java_type_imports() { + return string() + "import java.util.Hashtable;\n" + "import java.util.Vector;\n" + + "import java.util.Enumeration;\n\n"; +} + +/** + * Prints standard java imports + * + * @return List of imports necessary for thrift + */ +string t_javame_generator::java_thrift_imports() { + return string() + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n" + + "import org.apache.thrift.transport.*;\n" + "import org.apache.thrift.protocol.*;\n\n"; +} + +/** + * Nothing in Java + */ +void t_javame_generator::close_generator() { +} + +/** + * Generates a typedef. This is not done in Java, since it does + * not support arbitrary name replacements, and it'd be a wacky waste + * of overhead to make wrapper classes. + * + * @param ttypedef The type definition + */ +void t_javame_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + +/** + * Enums are a class with a set of static constants. + * + * @param tenum The enumeration + */ +void t_javame_generator::generate_enum(t_enum* tenum) { + // Make output file + string f_enum_name = package_dir_ + "/" + (tenum->get_name()) + ".java"; + ofstream f_enum; + f_enum.open(f_enum_name.c_str()); + + // Comment and package it + f_enum << autogen_comment() << java_package(); + + generate_java_doc(f_enum, tenum); + indent(f_enum) << "public class " << tenum->get_name() << " implements org.apache.thrift.TEnum "; + scope_up(f_enum); + f_enum << endl; + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + generate_java_doc(f_enum, *c_iter); + indent(f_enum) << "public static final " << tenum->get_name() << " " << (*c_iter)->get_name() + << " = new " << tenum->get_name() << "(" << value << ");" << endl; + } + f_enum << endl; + + // Field for thriftCode + indent(f_enum) << "private final int value;" << endl << endl; + + indent(f_enum) << "private " << tenum->get_name() << "(int value) {" << endl; + indent(f_enum) << " this.value = value;" << endl; + indent(f_enum) << "}" << endl << endl; + + indent(f_enum) << "/**" << endl; + indent(f_enum) << " * Get the integer value of this enum value, as defined in the Thrift IDL." + << endl; + indent(f_enum) << " */" << endl; + indent(f_enum) << "public int getValue() {" << endl; + indent(f_enum) << " return value;" << endl; + indent(f_enum) << "}" << endl << endl; + + indent(f_enum) << "/**" << endl; + indent(f_enum) << " * Find a the enum type by its integer value, as defined in the Thrift IDL." + << endl; + indent(f_enum) << " * @return null if the value is not found." << endl; + indent(f_enum) << " */" << endl; + indent(f_enum) << "public static " + tenum->get_name() + " findByValue(int value) { " << endl; + + indent_up(); + + indent(f_enum) << "switch (value) {" << endl; + indent_up(); + + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + indent(f_enum) << "case " << value << ":" << endl; + indent(f_enum) << " return " << (*c_iter)->get_name() << ";" << endl; + } + + indent(f_enum) << "default:" << endl; + indent(f_enum) << " return null;" << endl; + + indent_down(); + + indent(f_enum) << "}" << endl; + + indent_down(); + + indent(f_enum) << "}" << endl; + + scope_down(f_enum); + + f_enum.close(); +} + +/** + * Generates a class that holds all the constants. + */ +void t_javame_generator::generate_consts(std::vector consts) { + if (consts.empty()) { + return; + } + + string f_consts_name = package_dir_ + "/" + program_name_ + "Constants.java"; + ofstream f_consts; + f_consts.open(f_consts_name.c_str()); + + // Print header + f_consts << autogen_comment() << java_package() << java_type_imports(); + + f_consts << "public class " << program_name_ << "Constants {" << endl << endl; + indent_up(); + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + print_const_value(f_consts, + (*c_iter)->get_name(), + (*c_iter)->get_type(), + (*c_iter)->get_value(), + false); + } + indent_down(); + indent(f_consts) << "}" << endl; + f_consts.close(); +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +void t_javame_generator::print_const_value(std::ofstream& out, + string name, + t_type* type, + t_const_value* value, + bool in_static, + bool defval) { + type = get_true_type(type); + + indent(out); + if (!defval) { + out << (in_static ? "" : "public static final ") << type_name(type) << " "; + } + if (type->is_base_type()) { + string v2 = render_const_value(out, name, type, value); + out << name << " = " << v2 << ";" << endl << endl; + } else if (type->is_enum()) { + out << name << " = " << render_const_value(out, name, type, value) << ";" << endl << endl; + } else if (type->is_struct() || type->is_xception()) { + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + out << name << " = new " << type_name(type, false, true) << "();" << endl; + if (!in_static) { + indent(out) << "static {" << endl; + indent_up(); + } + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + string val = render_const_value(out, name, field_type, v_iter->second); + indent(out) << name << "."; + std::string cap_name = get_cap_name(v_iter->first->get_string()); + out << "set" << cap_name << "(" << val << ");" << endl; + } + if (!in_static) { + indent_down(); + indent(out) << "}" << endl; + } + out << endl; + } else if (type->is_map()) { + out << name << " = new " << type_name(type, false, true) << "();" << endl; + if (!in_static) { + indent(out) << "static {" << endl; + indent_up(); + } + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string key = render_const_value(out, name, ktype, v_iter->first); + string val = render_const_value(out, name, vtype, v_iter->second); + indent(out) << name << ".put(" << box_type(ktype, key) << ", " << box_type(vtype, val) << ");" + << endl; + } + if (!in_static) { + indent_down(); + indent(out) << "}" << endl; + } + out << endl; + } else if (type->is_list() || type->is_set()) { + out << name << " = new " << type_name(type, false, true) << "();" << endl; + if (!in_static) { + indent(out) << "static {" << endl; + indent_up(); + } + t_type* etype; + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(out, name, etype, *v_iter); + if (type->is_list()) { + indent(out) << name << ".addElement(" << box_type(etype, val) << ");" << endl; + } else { + indent(out) << name << ".put(" << box_type(etype, val) << ", " << box_type(etype, val) + << ");" << endl; + } + } + if (!in_static) { + indent_down(); + indent(out) << "}" << endl; + } + out << endl; + } else { + throw "compiler error: no const of type " + type->get_name(); + } +} + +string t_javame_generator::render_const_value(ofstream& out, + string name, + t_type* type, + t_const_value* value) { + (void)name; + type = get_true_type(type); + std::ostringstream render; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + render << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() > 0) ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + render << "(byte)" << value->get_integer(); + break; + case t_base_type::TYPE_I16: + render << "(short)" << value->get_integer(); + break; + case t_base_type::TYPE_I32: + render << value->get_integer(); + break; + case t_base_type::TYPE_I64: + render << value->get_integer() << "L"; + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + render << "(double)" << value->get_integer(); + } else { + render << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + render << type_name(type, false, false) << "." << value->get_identifier(); + } else { + string t = tmp("tmp"); + print_const_value(out, t, type, value, true); + render << t; + } + + return render.str(); +} + +string t_javame_generator::box_type(t_type* type, string value) { + if (type->is_base_type()) { + switch (((t_base_type*)type)->get_base()) { + case t_base_type::TYPE_BOOL: + return "new Boolean(" + value + ")"; + case t_base_type::TYPE_I8: + return "new Byte(" + value + ")"; + case t_base_type::TYPE_I16: + return "new Short(" + value + ")"; + case t_base_type::TYPE_I32: + return "new Integer(" + value + ")"; + case t_base_type::TYPE_I64: + return "new Long(" + value + ")"; + case t_base_type::TYPE_DOUBLE: + return "new Double(" + value + ")"; + default: + break; + } + } + return value; +} + +/** + * Generates a struct definition for a thrift data type. This will be a TBase + * implementor. + * + * @param tstruct The struct definition + */ +void t_javame_generator::generate_struct(t_struct* tstruct) { + if (tstruct->is_union()) { + generate_java_union(tstruct); + } else { + generate_java_struct(tstruct, false); + } +} + +/** + * Exceptions are structs, but they inherit from Exception + * + * @param tstruct The struct definition + */ +void t_javame_generator::generate_xception(t_struct* txception) { + generate_java_struct(txception, true); +} + +/** + * Java struct definition. + * + * @param tstruct The struct definition + */ +void t_javame_generator::generate_java_struct(t_struct* tstruct, bool is_exception) { + // Make output file + string f_struct_name = package_dir_ + "/" + (tstruct->get_name()) + ".java"; + ofstream f_struct; + f_struct.open(f_struct_name.c_str()); + + f_struct << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports(); + + generate_java_struct_definition(f_struct, tstruct, is_exception); + f_struct.close(); +} + +/** + * Java union definition. + * + * @param tstruct The struct definition + */ +void t_javame_generator::generate_java_union(t_struct* tstruct) { + // Make output file + string f_struct_name = package_dir_ + "/" + (tstruct->get_name()) + ".java"; + ofstream f_struct; + f_struct.open(f_struct_name.c_str()); + + f_struct << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports(); + + generate_java_doc(f_struct, tstruct); + + bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); + + indent(f_struct) << "public " << (is_final ? "final " : "") << "class " << tstruct->get_name() + << " extends TUnion "; + + scope_up(f_struct); + + generate_struct_desc(f_struct, tstruct); + generate_field_descs(f_struct, tstruct); + + f_struct << endl; + + generate_union_constructor(f_struct, tstruct); + + f_struct << endl; + + generate_union_abstract_methods(f_struct, tstruct); + + f_struct << endl; + + generate_union_getters_and_setters(f_struct, tstruct); + + f_struct << endl; + + generate_union_comparisons(f_struct, tstruct); + + f_struct << endl; + + generate_union_hashcode(f_struct, tstruct); + + f_struct << endl; + + scope_down(f_struct); + + f_struct.close(); +} + +void t_javame_generator::generate_union_constructor(ofstream& out, t_struct* tstruct) { + indent(out) << "public " << type_name(tstruct) << "() {" << endl; + indent(out) << " super();" << endl; + indent(out) << "}" << endl << endl; + + indent(out) << "public " << type_name(tstruct) << "(_Fields setField, Object value) {" << endl; + indent(out) << " super(setField, value);" << endl; + indent(out) << "}" << endl << endl; + + indent(out) << "public " << type_name(tstruct) << "(" << type_name(tstruct) << " other) {" + << endl; + indent(out) << " super(other);" << endl; + indent(out) << "}" << endl; + + indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl; + indent(out) << " return new " << tstruct->get_name() << "(this);" << endl; + indent(out) << "}" << endl << endl; + + // generate "constructors" for each field + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() << "(" + << type_name((*m_iter)->get_type()) << " value) {" << endl; + indent(out) << " " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" << endl; + indent(out) << " x.set" << get_cap_name((*m_iter)->get_name()) << "(value);" << endl; + indent(out) << " return x;" << endl; + indent(out) << "}" << endl << endl; + } +} + +void t_javame_generator::generate_union_getters_and_setters(ofstream& out, t_struct* tstruct) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + bool first = true; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (first) { + first = false; + } else { + out << endl; + } + + t_field* field = (*m_iter); + + generate_java_doc(out, field); + indent(out) << "public " << type_name(field->get_type()) << " get" + << get_cap_name(field->get_name()) << "() {" << endl; + indent(out) << " if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {" + << endl; + indent(out) << " return (" << type_name(field->get_type(), true) << ")getFieldValue();" + << endl; + indent(out) << " } else {" << endl; + indent(out) << " throw new RuntimeException(\"Cannot get field '" << field->get_name() + << "' because union is currently set to \" + getFieldDesc(getSetField()).name);" + << endl; + indent(out) << " }" << endl; + indent(out) << "}" << endl; + + out << endl; + + generate_java_doc(out, field); + indent(out) << "public void set" << get_cap_name(field->get_name()) << "(" + << type_name(field->get_type()) << " value) {" << endl; + if (type_can_be_null(field->get_type())) { + indent(out) << " if (value == null) throw new NullPointerException();" << endl; + } + indent(out) << " setField_ = _Fields." << constant_name(field->get_name()) << ";" << endl; + indent(out) << " value_ = value;" << endl; + indent(out) << "}" << endl; + } +} + +void t_javame_generator::generate_union_abstract_methods(ofstream& out, t_struct* tstruct) { + generate_check_type(out, tstruct); + out << endl; + generate_read_value(out, tstruct); + out << endl; + generate_write_value(out, tstruct); + out << endl; + generate_get_field_desc(out, tstruct); + out << endl; + generate_get_struct_desc(out, tstruct); + out << endl; +} + +void t_javame_generator::generate_check_type(ofstream& out, t_struct* tstruct) { + indent(out) + << "protected void checkType(_Fields setField, Object value) throws ClassCastException {" + << endl; + indent_up(); + + indent(out) << "switch (setField) {" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = (*m_iter); + + indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; + indent(out) << " if (value instanceof " << type_name(field->get_type(), true, false, true) + << ") {" << endl; + indent(out) << " break;" << endl; + indent(out) << " }" << endl; + indent(out) << " throw new ClassCastException(\"Was expecting value of type " + << type_name(field->get_type(), true, false) << " for field '" << field->get_name() + << "', but got \" + value.getClass().getSimpleName());" << endl; + // do the real check here + } + + indent(out) << "default:" << endl; + indent(out) << " throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl; + + indent_down(); + indent(out) << "}" << endl; + + indent_down(); + indent(out) << "}" << endl; +} + +void t_javame_generator::generate_read_value(ofstream& out, t_struct* tstruct) { + indent(out) << "protected Object readValue(TProtocol iprot, TField field) throws TException {" + << endl; + + indent_up(); + + indent(out) << "_Fields setField = _Fields.findByThriftId(field.id);" << endl; + indent(out) << "if (setField != null) {" << endl; + indent_up(); + indent(out) << "switch (setField) {" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = (*m_iter); + + indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; + indent_up(); + indent(out) << "if (field.type == " << constant_name(field->get_name()) << "_FIELD_DESC.type) {" + << endl; + indent_up(); + indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";" + << endl; + generate_deserialize_field(out, field, ""); + indent(out) << "return " << field->get_name() << ";" << endl; + indent_down(); + indent(out) << "} else {" << endl; + indent(out) << " TProtocolUtil.skip(iprot, field.type);" << endl; + indent(out) << " return null;" << endl; + indent(out) << "}" << endl; + indent_down(); + } + + indent(out) << "default:" << endl; + indent(out) << " throw new IllegalStateException(\"setField wasn't null, but didn't match any " + "of the case statements!\");" << endl; + + indent_down(); + indent(out) << "}" << endl; + + indent_down(); + indent(out) << "} else {" << endl; + indent_up(); + indent(out) << "TProtocolUtil.skip(iprot, field.type);" << endl; + indent(out) << "return null;" << endl; + indent_down(); + indent(out) << "}" << endl; + + indent_down(); + indent(out) << "}" << endl; +} + +void t_javame_generator::generate_write_value(ofstream& out, t_struct* tstruct) { + indent(out) << "protected void writeValue(TProtocol oprot) throws TException {" << endl; + + indent_up(); + + indent(out) << "switch (setField_) {" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = (*m_iter); + + indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; + indent_up(); + indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << " = (" + << type_name(field->get_type(), true, false) << ")value_;" << endl; + generate_serialize_field(out, field, ""); + indent(out) << "return;" << endl; + indent_down(); + } + + indent(out) << "default:" << endl; + indent(out) << " throw new IllegalStateException(\"Cannot write union with unknown field \" + " + "setField_);" << endl; + + indent_down(); + indent(out) << "}" << endl; + + indent_down(); + + indent(out) << "}" << endl; +} + +void t_javame_generator::generate_get_field_desc(ofstream& out, t_struct* tstruct) { + indent(out) << "protected TField getFieldDesc(_Fields setField) {" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + indent(out) << "switch (setField) {" << endl; + indent_up(); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = (*m_iter); + indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; + indent(out) << " return " << constant_name(field->get_name()) << "_FIELD_DESC;" << endl; + } + + indent(out) << "default:" << endl; + indent(out) << " throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl; + + indent_down(); + indent(out) << "}" << endl; + + indent_down(); + indent(out) << "}" << endl; +} + +void t_javame_generator::generate_get_struct_desc(ofstream& out, t_struct* tstruct) { + (void)tstruct; + indent(out) << "protected TStruct getStructDesc() {" << endl; + indent(out) << " return STRUCT_DESC;" << endl; + indent(out) << "}" << endl; +} + +void t_javame_generator::generate_union_comparisons(ofstream& out, t_struct* tstruct) { + // equality + indent(out) << "public boolean equals(Object other) {" << endl; + indent(out) << " if (other instanceof " << tstruct->get_name() << ") {" << endl; + indent(out) << " return equals((" << tstruct->get_name() << ")other);" << endl; + indent(out) << " } else {" << endl; + indent(out) << " return false;" << endl; + indent(out) << " }" << endl; + indent(out) << "}" << endl; + + out << endl; + + indent(out) << "public boolean equals(" << tstruct->get_name() << " other) {" << endl; + indent(out) << " return other != null && getSetField() == other.getSetField() && " + "getFieldValue().equals(other.getFieldValue());" << endl; + indent(out) << "}" << endl; + out << endl; + + indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl; + indent(out) << " int lastComparison = TBaseHelper.compareTo(getSetField(), other.getSetField());" + << endl; + indent(out) << " if (lastComparison == 0) {" << endl; + indent(out) << " return TBaseHelper.compareTo(getFieldValue(), other.getFieldValue());" + << endl; + indent(out) << " }" << endl; + indent(out) << " return lastComparison;" << endl; + indent(out) << "}" << endl; + out << endl; +} + +void t_javame_generator::generate_union_hashcode(ofstream& out, t_struct* tstruct) { + (void)tstruct; + indent(out) << "/**" << endl; + indent(out) + << " * If you'd like this to perform more respectably, use the hashcode generator option." + << endl; + indent(out) << " */" << endl; + indent(out) << "public int hashCode() {" << endl; + indent(out) << " return 0;" << endl; + indent(out) << "}" << endl; +} + +/** + * Java struct definition. This has various parameters, as it could be + * generated standalone or inside another class as a helper. If it + * is a helper than it is a static class. + * + * @param tstruct The struct definition + * @param is_exception Is this an exception? + * @param in_class If inside a class, needs to be static class + * @param is_result If this is a result it needs a different writer + */ +void t_javame_generator::generate_java_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool in_class, + bool is_result) { + generate_java_doc(out, tstruct); + + bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); + + indent(out) << "public " << (is_final ? "final " : "") << (in_class ? "static " : "") << "class " + << tstruct->get_name() << " "; + + if (is_exception) { + out << "extends Exception "; + } + out << "implements TBase "; + + scope_up(out); + + generate_struct_desc(out, tstruct); + + // Members are public for -java, private for -javabean + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + out << endl; + + generate_field_descs(out, tstruct); + + out << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << "private "; + out << declare_field(*m_iter, false) << endl; + } + + // isset data + if (members.size() > 0) { + out << endl; + + indent(out) << "// isset id assignments" << endl; + + int i = 0; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (!type_can_be_null((*m_iter)->get_type())) { + indent(out) << "private static final int " << isset_field_id(*m_iter) << " = " << i << ";" + << endl; + i++; + } + } + + if (i > 0) { + indent(out) << "private boolean[] __isset_vector = new boolean[" << i << "];" << endl; + } + + out << endl; + } + + bool all_optional_members = true; + + // Default constructor + indent(out) << "public " << tstruct->get_name() << "() {" << endl; + indent_up(); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if ((*m_iter)->get_value() != NULL) { + print_const_value(out, + "this." + (*m_iter)->get_name(), + t, + (*m_iter)->get_value(), + true, + true); + } + if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { + all_optional_members = false; + } + } + indent_down(); + indent(out) << "}" << endl << endl; + + if (!members.empty() && !all_optional_members) { + // Full constructor for all fields + indent(out) << "public " << tstruct->get_name() << "(" << endl; + indent_up(); + bool first = true; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { + if (!first) { + out << "," << endl; + } + first = false; + indent(out) << type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name(); + } + } + out << ")" << endl; + indent_down(); + indent(out) << "{" << endl; + indent_up(); + indent(out) << "this();" << endl; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { + indent(out) << "this." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << ";" + << endl; + generate_isset_set(out, (*m_iter)); + } + } + indent_down(); + indent(out) << "}" << endl << endl; + } + + // copy constructor + indent(out) << "/**" << endl; + indent(out) << " * Performs a deep copy on other." << endl; + indent(out) << " */" << endl; + indent(out) << "public " << tstruct->get_name() << "(" << tstruct->get_name() << " other) {" + << endl; + indent_up(); + + if (has_bit_vector(tstruct)) { + indent(out) << "System.arraycopy(other.__isset_vector, 0, __isset_vector, 0, " + "other.__isset_vector.length);" << endl; + } + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = (*m_iter); + std::string field_name = field->get_name(); + t_type* type = field->get_type(); + bool can_be_null = type_can_be_null(type); + + if (can_be_null) { + indent(out) << "if (other." << generate_isset_check(field) << ") {" << endl; + indent_up(); + } + + if (type->is_container()) { + generate_deep_copy_container(out, "other", field_name, "__this__" + field_name, type); + indent(out) << "this." << field_name << " = __this__" << field_name << ";" << endl; + } else { + indent(out) << "this." << field_name << " = "; + generate_deep_copy_non_container(out, "other." + field_name, field_name, type); + out << ";" << endl; + } + + if (can_be_null) { + indent_down(); + indent(out) << "}" << endl; + } + } + + indent_down(); + indent(out) << "}" << endl << endl; + + // clone method, so that you can deep copy an object when you don't know its class. + indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl; + indent(out) << " return new " << tstruct->get_name() << "(this);" << endl; + indent(out) << "}" << endl << endl; + + generate_java_struct_clear(out, tstruct); + + generate_java_bean_boilerplate(out, tstruct); + generate_generic_field_getters_setters(out, tstruct); + + generate_java_struct_equality(out, tstruct); + generate_java_struct_compare_to(out, tstruct); + + generate_java_struct_reader(out, tstruct); + if (is_result) { + generate_java_struct_result_writer(out, tstruct); + } else { + generate_java_struct_writer(out, tstruct); + } + generate_java_struct_tostring(out, tstruct); + generate_java_validator(out, tstruct); + scope_down(out); + out << endl; +} + +/** + * Generates equals methods and a hashCode method for a structure. + * + * @param tstruct The struct definition + */ +void t_javame_generator::generate_java_struct_equality(ofstream& out, t_struct* tstruct) { + out << indent() << "public boolean equals(Object that) {" << endl; + indent_up(); + out << indent() << "if (that == null)" << endl << indent() << " return false;" << endl + << indent() << "if (that instanceof " << tstruct->get_name() << ")" << endl << indent() + << " return this.equals((" << tstruct->get_name() << ")that);" << endl << indent() + << "return false;" << endl; + scope_down(out); + out << endl; + + out << indent() << "public boolean equals(" << tstruct->get_name() << " that) {" << endl; + indent_up(); + out << indent() << "if (that == null)" << endl << indent() << " return false;" << endl + << indent() << "if (this == that)" << endl << indent() << " return true;" << endl; + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + out << endl; + + t_type* t = get_true_type((*m_iter)->get_type()); + // Most existing Thrift code does not use isset or optional/required, + // so we treat "default" fields as required. + bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL; + bool can_be_null = type_can_be_null(t); + string name = (*m_iter)->get_name(); + + string this_present = "true"; + string that_present = "true"; + string unequal; + + if (is_optional || can_be_null) { + this_present += " && this." + generate_isset_check(*m_iter); + that_present += " && that." + generate_isset_check(*m_iter); + } + + out << indent() << "boolean this_present_" << name << " = " << this_present << ";" << endl + << indent() << "boolean that_present_" << name << " = " << that_present << ";" << endl + << indent() << "if (" + << "this_present_" << name << " || that_present_" << name << ") {" << endl; + indent_up(); + out << indent() << "if (!(" + << "this_present_" << name << " && that_present_" << name << "))" << endl << indent() + << " return false;" << endl; + + if (t->is_binary()) { + unequal = "TBaseHelper.compareTo(this." + name + ", that." + name + ") != 0"; + } else if (can_be_null) { + unequal = "!this." + name + ".equals(that." + name + ")"; + } else { + unequal = "this." + name + " != that." + name; + } + + out << indent() << "if (" << unequal << ")" << endl << indent() << " return false;" << endl; + + scope_down(out); + } + out << endl; + indent(out) << "return true;" << endl; + scope_down(out); + out << endl; + + out << indent() << "public int hashCode() {" << endl; + indent_up(); + indent(out) << "return 0;" << endl; + indent_down(); + indent(out) << "}" << endl << endl; +} + +void t_javame_generator::generate_java_struct_compare_to(ofstream& out, t_struct* tstruct) { + indent(out) << "public int compareTo(Object otherObject) {" << endl; + // indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl; + indent_up(); + + indent(out) << "if (!getClass().equals(otherObject.getClass())) {" << endl; + indent(out) << " return getClass().getName().compareTo(otherObject.getClass().getName());" + << endl; + indent(out) << "}" << endl; + out << endl; + indent(out) << type_name(tstruct) << " other = (" << type_name(tstruct) << ")otherObject;"; + + indent(out) << "int lastComparison = 0;" << endl; + out << endl; + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* field = *m_iter; + indent(out) << "lastComparison = TBaseHelper.compareTo(" << generate_isset_check(field) + << ", other." << generate_isset_check(field) << ");" << endl; + indent(out) << "if (lastComparison != 0) {" << endl; + indent(out) << " return lastComparison;" << endl; + indent(out) << "}" << endl; + + indent(out) << "if (" << generate_isset_check(field) << ") {" << endl; + if (field->get_type()->is_struct() || field->get_type()->is_xception()) { + indent(out) << " lastComparison = this." << field->get_name() << ".compareTo(other." + << field->get_name() << ");" << endl; + } else { + indent(out) << " lastComparison = TBaseHelper.compareTo(this." << field->get_name() + << ", other." << field->get_name() << ");" << endl; + } + + indent(out) << " if (lastComparison != 0) {" << endl; + indent(out) << " return lastComparison;" << endl; + indent(out) << " }" << endl; + indent(out) << "}" << endl; + } + + indent(out) << "return 0;" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a function to read all the fields of the struct. + * + * @param tstruct The struct definition + */ +void t_javame_generator::generate_java_struct_reader(ofstream& out, t_struct* tstruct) { + out << indent() << "public void read(TProtocol iprot) throws TException {" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Declare stack tmp variables and read struct header + out << indent() << "TField field;" << endl << indent() << "iprot.readStructBegin();" << endl; + + // Loop over reading in fields + indent(out) << "while (true)" << endl; + scope_up(out); + + // Read beginning field marker + indent(out) << "field = iprot.readFieldBegin();" << endl; + + // Check for field STOP marker and break + indent(out) << "if (field.type == TType.STOP) { " << endl; + indent_up(); + indent(out) << "break;" << endl; + indent_down(); + indent(out) << "}" << endl; + + // Switch statement on the field we are reading + indent(out) << "switch (field.id) {" << endl; + + indent_up(); + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << "case " << (*f_iter)->get_key() << ": // " + << constant_name((*f_iter)->get_name()) << endl; + indent_up(); + indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; + indent_up(); + + generate_deserialize_field(out, *f_iter, "this."); + generate_isset_set(out, *f_iter); + indent_down(); + out << indent() << "} else { " << endl << indent() << " TProtocolUtil.skip(iprot, field.type);" + << endl << indent() << "}" << endl << indent() << "break;" << endl; + indent_down(); + } + + indent(out) << "default:" << endl; + indent(out) << " TProtocolUtil.skip(iprot, field.type);" << endl; + + indent_down(); + indent(out) << "}" << endl; + + // Read field end marker + indent(out) << "iprot.readFieldEnd();" << endl; + + indent_down(); + indent(out) << "}" << endl; + + out << indent() << "iprot.readStructEnd();" << endl; + + // performs various checks (e.g. check that all required fields are set) + indent(out) << "validate();" << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +// generates java method to perform various checks +// (e.g. check that all required fields are set) +void t_javame_generator::generate_java_validator(ofstream& out, t_struct* tstruct) { + indent(out) << "public void validate() throws TException {" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out << indent() << "// check for required fields" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) { + out << indent() << "if (!" << generate_isset_check(*f_iter) << ") {" << endl << indent() + << " throw new TProtocolException(\"Required field '" << (*f_iter)->get_name() + << "' is unset! Struct:\" + toString());" << endl << indent() << "}" << endl << endl; + } + } + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates a function to write all the fields of the struct + * + * @param tstruct The struct definition + */ +void t_javame_generator::generate_java_struct_writer(ofstream& out, t_struct* tstruct) { + out << indent() << "public void write(TProtocol oprot) throws TException {" << endl; + indent_up(); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + // performs various checks (e.g. check that all required fields are set) + indent(out) << "validate();" << endl << endl; + + indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool null_allowed = type_can_be_null((*f_iter)->get_type()); + if (null_allowed) { + out << indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl; + indent_up(); + } + bool optional = (*f_iter)->get_req() == t_field::T_OPTIONAL; + if (optional) { + indent(out) << "if (" << generate_isset_check((*f_iter)) << ") {" << endl; + indent_up(); + } + + indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) + << "_FIELD_DESC);" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "this."); + + // Write field closer + indent(out) << "oprot.writeFieldEnd();" << endl; + + if (optional) { + indent_down(); + indent(out) << "}" << endl; + } + if (null_allowed) { + indent_down(); + indent(out) << "}" << endl; + } + } + // Write the struct map + out << indent() << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();" + << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +/** + * Generates a function to write all the fields of the struct, + * which is a function result. These fields are only written + * if they are set in the Isset array, and only one of them + * can be set at a time. + * + * @param tstruct The struct definition + */ +void t_javame_generator::generate_java_struct_result_writer(ofstream& out, t_struct* tstruct) { + out << indent() << "public void write(TProtocol oprot) throws TException {" << endl; + indent_up(); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; + + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + out << endl << indent() << "if "; + } else { + out << " else if "; + } + + out << "(this." << generate_isset_check(*f_iter) << ") {" << endl; + + indent_up(); + + indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) + << "_FIELD_DESC);" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "this."); + + // Write field closer + indent(out) << "oprot.writeFieldEnd();" << endl; + + indent_down(); + indent(out) << "}"; + } + // Write the struct map + out << endl << indent() << "oprot.writeFieldStop();" << endl << indent() + << "oprot.writeStructEnd();" << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_javame_generator::generate_reflection_getters(ostringstream& out, + t_type* type, + string field_name, + string cap_name) { + indent(out) << "case " << constant_name(field_name) << ":" << endl; + indent_up(); + + if (type->is_base_type() && !type->is_string()) { + t_base_type* base_type = (t_base_type*)type; + + indent(out) << "return new " << type_name(type, true, false) << "(" + << (base_type->is_bool() ? "is" : "get") << cap_name << "());" << endl << endl; + } else { + indent(out) << "return get" << cap_name << "();" << endl << endl; + } + + indent_down(); +} + +void t_javame_generator::generate_reflection_setters(ostringstream& out, + t_type* type, + string field_name, + string cap_name) { + indent(out) << "case " << constant_name(field_name) << ":" << endl; + indent_up(); + indent(out) << "if (value == null) {" << endl; + indent(out) << " unset" << get_cap_name(field_name) << "();" << endl; + indent(out) << "} else {" << endl; + indent(out) << " set" << cap_name << "((" << type_name(type, true, false) << ")value);" << endl; + indent(out) << "}" << endl; + indent(out) << "break;" << endl << endl; + + indent_down(); +} + +void t_javame_generator::generate_generic_field_getters_setters(std::ofstream& out, + t_struct* tstruct) { + (void)out; + std::ostringstream getter_stream; + std::ostringstream setter_stream; + + // build up the bodies of both the getter and setter at once + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + t_type* type = get_true_type(field->get_type()); + std::string field_name = field->get_name(); + std::string cap_name = get_cap_name(field_name); + + indent_up(); + generate_reflection_setters(setter_stream, type, field_name, cap_name); + generate_reflection_getters(getter_stream, type, field_name, cap_name); + indent_down(); + } +} + +/** + * Generates a set of Java Bean boilerplate functions (setters, getters, etc.) + * for the given struct. + * + * @param tstruct The struct definition + */ +void t_javame_generator::generate_java_bean_boilerplate(ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = *f_iter; + t_type* type = get_true_type(field->get_type()); + std::string field_name = field->get_name(); + std::string cap_name = get_cap_name(field_name); + + if (type->is_container()) { + // Method to return the size of the collection + indent(out) << "public int get" << cap_name; + out << get_cap_name("size() {") << endl; + + indent_up(); + indent(out) << "return (this." << field_name << " == null) ? 0 : " + << "this." << field_name << ".size();" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } + + if (type->is_set() || type->is_list()) { + + t_type* element_type; + if (type->is_set()) { + element_type = ((t_set*)type)->get_elem_type(); + } else { + element_type = ((t_list*)type)->get_elem_type(); + } + + // Iterator getter for sets and lists + indent(out) << "public Enumeration get" << cap_name; + out << get_cap_name("Enumeration() {") << endl; + + indent_up(); + indent(out) << "return (this." << field_name << " == null) ? null : " + << "this." << field_name << ".elements();" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + + // Add to set or list, create if the set/list is null + indent(out); + out << "public void add" << get_cap_name("to"); + out << cap_name << "(" << type_name(element_type) << " elem) {" << endl; + + indent_up(); + indent(out) << "if (this." << field_name << " == null) {" << endl; + indent_up(); + indent(out) << "this." << field_name << " = new " << type_name(type, false, true) << "();" + << endl; + indent_down(); + indent(out) << "}" << endl; + if (type->is_set()) { + indent(out) << "this." << field_name << ".put(" << box_type(element_type, "elem") << ", " + << box_type(element_type, "elem") << ");" << endl; + } else { + indent(out) << "this." << field_name << ".addElement(" << box_type(element_type, "elem") + << ");" << endl; + } + indent_down(); + indent(out) << "}" << endl << endl; + + } else if (type->is_map()) { + // Put to map + t_type* key_type = ((t_map*)type)->get_key_type(); + t_type* val_type = ((t_map*)type)->get_val_type(); + + indent(out); + out << "public void putTo" << cap_name << "(" << type_name(key_type, true) << " key, " + << type_name(val_type, true) << " val) {" << endl; + + indent_up(); + indent(out) << "if (this." << field_name << " == null) {" << endl; + indent_up(); + indent(out) << "this." << field_name << " = new " << type_name(type, false, true) << "();" + << endl; + indent_down(); + indent(out) << "}" << endl; + indent(out) << "this." << field_name << ".put(key, val);" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + } + + // Simple getter + generate_java_doc(out, field); + indent(out) << "public " << type_name(type); + if (type->is_base_type() && ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) { + out << " is"; + } else { + out << " get"; + } + out << cap_name << "() {" << endl; + indent_up(); + indent(out) << "return this." << field_name << ";" << endl; + indent_down(); + indent(out) << "}" << endl << endl; + + // Simple setter + generate_java_doc(out, field); + indent(out) << "public "; + out << "void"; + out << " set" << cap_name << "(" << type_name(type) << " " << field_name << ") {" << endl; + indent_up(); + indent(out) << "this." << field_name << " = " << field_name << ";" << endl; + generate_isset_set(out, field); + + indent_down(); + indent(out) << "}" << endl << endl; + + // Unsetter + indent(out) << "public void unset" << cap_name << "() {" << endl; + indent_up(); + if (type_can_be_null(type)) { + indent(out) << "this." << field_name << " = null;" << endl; + } else { + indent(out) << "__isset_vector[" << isset_field_id(field) << "] = false;" << endl; + } + indent_down(); + indent(out) << "}" << endl << endl; + + // isSet method + indent(out) << "/** Returns true if field " << field_name + << " is set (has been assigned a value) and false otherwise */" << endl; + indent(out) << "public boolean is" << get_cap_name("set") << cap_name << "() {" << endl; + indent_up(); + if (type_can_be_null(type)) { + indent(out) << "return this." << field_name << " != null;" << endl; + } else { + indent(out) << "return __isset_vector[" << isset_field_id(field) << "];" << endl; + } + indent_down(); + indent(out) << "}" << endl << endl; + + indent(out) << "public void set" << cap_name << get_cap_name("isSet") << "(boolean value) {" + << endl; + indent_up(); + if (type_can_be_null(type)) { + indent(out) << "if (!value) {" << endl; + indent(out) << " this." << field_name << " = null;" << endl; + indent(out) << "}" << endl; + } else { + indent(out) << "__isset_vector[" << isset_field_id(field) << "] = value;" << endl; + } + indent_down(); + indent(out) << "}" << endl << endl; + } +} + +/** + * Generates a toString() method for the given struct + * + * @param tstruct The struct definition + */ +void t_javame_generator::generate_java_struct_tostring(ofstream& out, t_struct* tstruct) { + out << indent() << "public String toString() {" << endl; + indent_up(); + + out << indent() << "StringBuffer sb = new StringBuffer(\"" << tstruct->get_name() << "(\");" + << endl; + out << indent() << "boolean first = true;" << endl << endl; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; + if (could_be_unset) { + indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl; + indent_up(); + } + + t_field* field = (*f_iter); + + if (!first) { + indent(out) << "if (!first) sb.append(\", \");" << endl; + } + indent(out) << "sb.append(\"" << (*f_iter)->get_name() << ":\");" << endl; + bool can_be_null = type_can_be_null(field->get_type()); + if (can_be_null) { + indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl; + indent(out) << " sb.append(\"null\");" << endl; + indent(out) << "} else {" << endl; + indent_up(); + } + + if (field->get_type()->is_binary()) { + indent(out) << "TBaseHelper.toString(this." << field->get_name() << ", sb);" << endl; + } else { + indent(out) << "sb.append(this." << (*f_iter)->get_name() << ");" << endl; + } + + if (can_be_null) { + indent_down(); + indent(out) << "}" << endl; + } + indent(out) << "first = false;" << endl; + + if (could_be_unset) { + indent_down(); + indent(out) << "}" << endl; + } + first = false; + } + out << indent() << "sb.append(\")\");" << endl << indent() << "return sb.toString();" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Returns a string with the java representation of the given thrift type + * (e.g. for the type struct it returns "TType.STRUCT") + */ +std::string t_javame_generator::get_java_type_string(t_type* type) { + if (type->is_list()) { + return "TType.LIST"; + } else if (type->is_map()) { + return "TType.MAP"; + } else if (type->is_set()) { + return "TType.SET"; + } else if (type->is_struct() || type->is_xception()) { + return "TType.STRUCT"; + } else if (type->is_enum()) { + return "TType.ENUM"; + } else if (type->is_typedef()) { + return get_java_type_string(((t_typedef*)type)->get_type()); + } else if (type->is_base_type()) { + switch (((t_base_type*)type)->get_base()) { + case t_base_type::TYPE_VOID: + return "TType.VOID"; + break; + case t_base_type::TYPE_STRING: + return "TType.STRING"; + break; + case t_base_type::TYPE_BOOL: + return "TType.BOOL"; + break; + case t_base_type::TYPE_I8: + return "TType.BYTE"; + break; + case t_base_type::TYPE_I16: + return "TType.I16"; + break; + case t_base_type::TYPE_I32: + return "TType.I32"; + break; + case t_base_type::TYPE_I64: + return "TType.I64"; + break; + case t_base_type::TYPE_DOUBLE: + return "TType.DOUBLE"; + break; + default: + throw std::runtime_error("Unknown thrift type \"" + type->get_name() + + "\" passed to t_javame_generator::get_java_type_string!"); + break; // This should never happen! + } + } else { + throw std::runtime_error( + "Unknown thrift type \"" + type->get_name() + + "\" passed to t_javame_generator::get_java_type_string!"); // This should never happen! + } +} + +void t_javame_generator::generate_field_value_meta_data(std::ofstream& out, t_type* type) { + out << endl; + indent_up(); + indent_up(); + if (type->is_struct() || type->is_xception()) { + indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type) << ".class"; + } else if (type->is_container()) { + if (type->is_list()) { + indent(out) << "new ListMetaData(TType.LIST, "; + t_type* elem_type = ((t_list*)type)->get_elem_type(); + generate_field_value_meta_data(out, elem_type); + } else if (type->is_set()) { + indent(out) << "new SetMetaData(TType.SET, "; + t_type* elem_type = ((t_list*)type)->get_elem_type(); + generate_field_value_meta_data(out, elem_type); + } else { // map + indent(out) << "new MapMetaData(TType.MAP, "; + t_type* key_type = ((t_map*)type)->get_key_type(); + t_type* val_type = ((t_map*)type)->get_val_type(); + generate_field_value_meta_data(out, key_type); + out << ", "; + generate_field_value_meta_data(out, val_type); + } + } else if (type->is_enum()) { + indent(out) << "new EnumMetaData(TType.ENUM, " << type_name(type) << ".class"; + } else { + indent(out) << "new FieldValueMetaData(" << get_java_type_string(type); + if (type->is_typedef()) { + indent(out) << ", \"" << ((t_typedef*)type)->get_symbolic() << "\""; + } + } + out << ")"; + indent_down(); + indent_down(); +} + +/** + * Generates a thrift service. In C++, this comprises an entirely separate + * header and source file. The header file defines the methods and includes + * the data types defined in the main header file, and the implementation + * file contains implementations of the basic printer and default interfaces. + * + * @param tservice The service definition + */ +void t_javame_generator::generate_service(t_service* tservice) { + // Make output file + string f_service_name = package_dir_ + "/" + service_name_ + ".java"; + f_service_.open(f_service_name.c_str()); + + f_service_ << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports(); + + f_service_ << "public class " << service_name_ << " {" << endl << endl; + indent_up(); + + // Generate the three main parts of the service + generate_service_interface(tservice); + generate_service_client(tservice); + generate_service_server(tservice); + generate_service_helpers(tservice); + + indent_down(); + f_service_ << "}" << endl; + f_service_.close(); +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_javame_generator::generate_primitive_service_interface(t_service* tservice) { + f_service_ << indent() << "public interface Iface extends " << service_name_ << "Iface { }" + << endl << endl; + + string f_interface_name = package_dir_ + "/" + service_name_ + "Iface.java"; + std::ofstream f_iface; + f_iface.open(f_interface_name.c_str()); + + string extends_iface = ""; + if (tservice->get_extends() != NULL) { + extends_iface = " extends " + type_name(tservice->get_extends()) + "Iface"; + } + + f_iface << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports(); + generate_java_doc(f_iface, tservice); + f_iface << "public interface " << service_name_ << "Iface" << extends_iface << " {" << endl + << endl; + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_java_doc(f_iface, *f_iter); + f_iface << " public " << function_signature(*f_iter) << ";" << endl << endl; + } + f_iface << "}" << endl << endl; +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_javame_generator::generate_service_interface(t_service* tservice) { + string extends = ""; + string extends_iface = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_iface = " extends " + extends + ".Iface"; + } + + generate_java_doc(f_service_, tservice); + f_service_ << indent() << "public interface Iface" << extends_iface << " {" << endl << endl; + indent_up(); + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_java_doc(f_service_, *f_iter); + indent(f_service_) << "public " << function_signature(*f_iter) << ";" << endl << endl; + } + indent_down(); + f_service_ << indent() << "}" << endl << endl; +} + +/** + * Generates structs for all the service args and return types + * + * @param tservice The service + */ +void t_javame_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_java_struct_definition(f_service_, ts, false, true); + generate_function_helpers(*f_iter); + } +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_javame_generator::generate_service_client(t_service* tservice) { + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_client = " extends " + extends + ".Client"; + } + + indent(f_service_) << "public static class Client" << extends_client + << " implements TServiceClient, Iface {" << endl; + indent_up(); + + indent(f_service_) << "public Client(TProtocol prot)" << endl; + scope_up(f_service_); + indent(f_service_) << "this(prot, prot);" << endl; + scope_down(f_service_); + f_service_ << endl; + + indent(f_service_) << "public Client(TProtocol iprot, TProtocol oprot)" << endl; + scope_up(f_service_); + if (extends.empty()) { + f_service_ << indent() << "iprot_ = iprot;" << endl << indent() << "oprot_ = oprot;" << endl; + } else { + f_service_ << indent() << "super(iprot, oprot);" << endl; + } + scope_down(f_service_); + f_service_ << endl; + + if (extends.empty()) { + f_service_ << indent() << "protected TProtocol iprot_;" << endl << indent() + << "protected TProtocol oprot_;" << endl << endl << indent() + << "protected int seqid_;" << endl << endl; + + indent(f_service_) << "public TProtocol getInputProtocol()" << endl; + scope_up(f_service_); + indent(f_service_) << "return this.iprot_;" << endl; + scope_down(f_service_); + f_service_ << endl; + + indent(f_service_) << "public TProtocol getOutputProtocol()" << endl; + scope_up(f_service_); + indent(f_service_) << "return this.oprot_;" << endl; + scope_down(f_service_); + f_service_ << endl; + } + + // Generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string funname = (*f_iter)->get_name(); + + // Open function + indent(f_service_) << "public " << function_signature(*f_iter) << endl; + scope_up(f_service_); + indent(f_service_) << "send_" << funname << "("; + + // Get the struct of function call params + t_struct* arg_struct = (*f_iter)->get_arglist(); + + // Declare the function arguments + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + bool first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << (*fld_iter)->get_name(); + } + f_service_ << ");" << endl; + + if (!(*f_iter)->is_oneway()) { + f_service_ << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << "return "; + } + f_service_ << "recv_" << funname << "();" << endl; + } + scope_down(f_service_); + f_service_ << endl; + + t_function send_function(g_type_void, + string("send_") + (*f_iter)->get_name(), + (*f_iter)->get_arglist()); + + string argsname = (*f_iter)->get_name() + "_args"; + + // Open function + indent(f_service_) << "public " << function_signature(&send_function) << endl; + scope_up(f_service_); + + // Serialize the request + f_service_ << indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", " + << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL") + << ", ++seqid_));" << endl << indent() << argsname << " args = new " << argsname + << "();" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << indent() << "args.set" << get_cap_name((*fld_iter)->get_name()) << "(" + << (*fld_iter)->get_name() << ");" << endl; + } + + f_service_ << indent() << "args.write(oprot_);" << endl << indent() + << "oprot_.writeMessageEnd();" << endl << indent() + << "oprot_.getTransport().flush();" << endl; + + scope_down(f_service_); + f_service_ << endl; + + if (!(*f_iter)->is_oneway()) { + string resultname = (*f_iter)->get_name() + "_result"; + + t_struct noargs(program_); + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + &noargs, + (*f_iter)->get_xceptions()); + // Open function + indent(f_service_) << "public " << function_signature(&recv_function) << endl; + scope_up(f_service_); + + f_service_ << indent() << "TMessage msg = iprot_.readMessageBegin();" << endl << indent() + << "if (msg.type == TMessageType.EXCEPTION) {" << endl << indent() + << " TApplicationException x = TApplicationException.read(iprot_);" << endl + << indent() << " iprot_.readMessageEnd();" << endl << indent() << " throw x;" + << endl << indent() << "}" << endl << indent() << "if (msg.seqid != seqid_) {" + << endl << indent() + << " throw new TApplicationException(TApplicationException.BAD_SEQUENCE_ID, \"" + << (*f_iter)->get_name() << " failed: out of sequence response\");" << endl + << indent() << "}" << endl << indent() << resultname << " result = new " + << resultname << "();" << endl << indent() << "result.read(iprot_);" << endl + << indent() << "iprot_.readMessageEnd();" << endl; + + // Careful, only return _result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << indent() << "if (result." << generate_isset_check("success") << ") {" << endl + << indent() << " return result.success;" << endl << indent() << "}" << endl; + } + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << indent() << "if (result." << (*x_iter)->get_name() << " != null) {" << endl + << indent() << " throw result." << (*x_iter)->get_name() << ";" << endl + << indent() << "}" << endl; + } + + // If you get here it's an exception, unless a void function + if ((*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << "return;" << endl; + } else { + f_service_ << indent() + << "throw new TApplicationException(TApplicationException.MISSING_RESULT, \"" + << (*f_iter)->get_name() << " failed: unknown result\");" << endl; + } + + // Close function + scope_down(f_service_); + f_service_ << endl; + } + } + + indent_down(); + indent(f_service_) << "}" << endl; +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_javame_generator::generate_service_server(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + // Extends stuff + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_processor = " extends " + extends + ".Processor"; + } + + // Generate the header portion + indent(f_service_) << "public static class Processor" << extends_processor + << " implements TProcessor {" << endl; + indent_up(); + + indent(f_service_) << "public Processor(Iface iface)" << endl; + scope_up(f_service_); + if (!extends.empty()) { + f_service_ << indent() << "super(iface);" << endl; + } + f_service_ << indent() << "iface_ = iface;" << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << indent() << "processMap_.put(\"" << (*f_iter)->get_name() << "\", new " + << (*f_iter)->get_name() << "());" << endl; + } + + scope_down(f_service_); + f_service_ << endl; + + if (extends.empty()) { + f_service_ + << indent() << "protected static interface ProcessFunction {" << endl << indent() + << " public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException;" + << endl << indent() << "}" << endl << endl; + } + + f_service_ << indent() << "private Iface iface_;" << endl; + + if (extends.empty()) { + f_service_ << indent() << "protected final Hashtable processMap_ = new Hashtable();" << endl; + } + + f_service_ << endl; + + // Generate the server implementation + indent(f_service_) << "public boolean process(TProtocol iprot, TProtocol oprot) throws TException" + << endl; + scope_up(f_service_); + + f_service_ << indent() << "TMessage msg = iprot.readMessageBegin();" << endl; + + // TODO(mcslee): validate message, was the seqid etc. legit? + + f_service_ + << indent() << "ProcessFunction fn = (ProcessFunction)processMap_.get(msg.name);" << endl + << indent() << "if (fn == null) {" << endl << indent() + << " TProtocolUtil.skip(iprot, TType.STRUCT);" << endl << indent() + << " iprot.readMessageEnd();" << endl << indent() + << " TApplicationException x = new " + "TApplicationException(TApplicationException.UNKNOWN_METHOD, \"Invalid method name: " + "'\"+msg.name+\"'\");" << endl << indent() + << " oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" + << endl << indent() << " x.write(oprot);" << endl << indent() << " oprot.writeMessageEnd();" + << endl << indent() << " oprot.getTransport().flush();" << endl << indent() + << " return true;" << endl << indent() << "}" << endl << indent() + << "fn.process(msg.seqid, iprot, oprot);" << endl; + + f_service_ << indent() << "return true;" << endl; + + scope_down(f_service_); + f_service_ << endl; + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(tservice, *f_iter); + } + + indent_down(); + indent(f_service_) << "}" << endl << endl; +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_javame_generator::generate_function_helpers(t_function* tfunction) { + if (tfunction->is_oneway()) { + return; + } + + t_struct result(program_, tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + generate_java_struct_definition(f_service_, &result, false, true, true); +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_javame_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + (void)tservice; + // Open class + indent(f_service_) << "private class " << tfunction->get_name() << " implements ProcessFunction {" + << endl; + indent_up(); + + // Open function + indent(f_service_) + << "public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException" + << endl; + scope_up(f_service_); + + string argsname = tfunction->get_name() + "_args"; + string resultname = tfunction->get_name() + "_result"; + + f_service_ << indent() << argsname << " args = new " << argsname << "();" << endl << indent() + << "try {" << endl; + indent_up(); + f_service_ << indent() << "args.read(iprot);" << endl; + indent_down(); + f_service_ << indent() << "} catch (TProtocolException e) {" << endl; + indent_up(); + f_service_ << indent() << "iprot.readMessageEnd();" << endl << indent() + << "TApplicationException x = new " + "TApplicationException(TApplicationException.PROTOCOL_ERROR, e.getMessage());" + << endl << indent() << "oprot.writeMessageBegin(new TMessage(\"" + << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl << indent() + << "x.write(oprot);" << endl << indent() << "oprot.writeMessageEnd();" << endl + << indent() << "oprot.getTransport().flush();" << endl << indent() << "return;" + << endl; + indent_down(); + f_service_ << indent() << "}" << endl; + f_service_ << indent() << "iprot.readMessageEnd();" << endl; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + // Declare result for non oneway function + if (!tfunction->is_oneway()) { + f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl; + } + + // Try block for a function with exceptions + if (xceptions.size() > 0) { + f_service_ << indent() << "try {" << endl; + indent_up(); + } + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + f_service_ << indent(); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + f_service_ << "result.success = "; + } + f_service_ << "iface_." << tfunction->get_name() << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "args." << (*f_iter)->get_name(); + } + f_service_ << ");" << endl; + + // Set isset on success field + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void() + && !type_can_be_null(tfunction->get_returntype())) { + f_service_ << indent() << "result.set" << get_cap_name("success") << get_cap_name("isSet") + << "(true);" << endl; + } + + if (!tfunction->is_oneway() && xceptions.size() > 0) { + indent_down(); + f_service_ << indent() << "}"; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " " + << (*x_iter)->get_name() << ") {" << endl; + if (!tfunction->is_oneway()) { + indent_up(); + f_service_ << indent() << "result." << (*x_iter)->get_name() << " = " + << (*x_iter)->get_name() << ";" << endl; + indent_down(); + f_service_ << indent() << "}"; + } else { + f_service_ << "}"; + } + } + f_service_ << " catch (Throwable th) {" << endl; + indent_up(); + f_service_ << indent() << "TApplicationException x = new " + "TApplicationException(TApplicationException.INTERNAL_ERROR, " + "\"Internal error processing " << tfunction->get_name() << "\");" + << endl << indent() << "oprot.writeMessageBegin(new TMessage(\"" + << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl + << indent() << "x.write(oprot);" << endl << indent() << "oprot.writeMessageEnd();" + << endl << indent() << "oprot.getTransport().flush();" << endl << indent() + << "return;" << endl; + indent_down(); + f_service_ << indent() << "}" << endl; + } + + // Shortcut out here for oneway functions + if (tfunction->is_oneway()) { + f_service_ << indent() << "return;" << endl; + scope_down(f_service_); + + // Close class + indent_down(); + f_service_ << indent() << "}" << endl << endl; + return; + } + + f_service_ << indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() + << "\", TMessageType.REPLY, seqid));" << endl << indent() << "result.write(oprot);" + << endl << indent() << "oprot.writeMessageEnd();" << endl << indent() + << "oprot.getTransport().flush();" << endl; + + // Close function + scope_down(f_service_); + f_service_ << endl; + + // Close class + indent_down(); + f_service_ << indent() << "}" << endl << endl; +} + +/** + * Deserializes a field of any type. + * + * @param tfield The field + * @param prefix The variable name or container for this field + */ +void t_javame_generator::generate_deserialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = prefix + tfield->get_name(); + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name); + } else if (type->is_container()) { + generate_deserialize_container(out, type, name); + } else if (type->is_base_type()) { + indent(out) << name << " = iprot."; + + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (!type->is_binary()) { + out << "readString();"; + } else { + out << "readBinary();"; + } + break; + case t_base_type::TYPE_BOOL: + out << "readBool();"; + break; + case t_base_type::TYPE_I8: + out << "readByte();"; + break; + case t_base_type::TYPE_I16: + out << "readI16();"; + break; + case t_base_type::TYPE_I32: + out << "readI32();"; + break; + case t_base_type::TYPE_I64: + out << "readI64();"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble();"; + break; + default: + throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase); + } + out << endl; + } else if (type->is_enum()) { + indent(out) << name << " = " + << type_name(tfield->get_type(), true, false) + ".findByValue(iprot.readI32());" + << endl; + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +/** + * Generates an unserializer for a struct, invokes read() + */ +void t_javame_generator::generate_deserialize_struct(ofstream& out, + t_struct* tstruct, + string prefix) { + out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl << indent() + << prefix << ".read(iprot);" << endl; +} + +/** + * Deserializes a container by reading its size and then iterating + */ +void t_javame_generator::generate_deserialize_container(ofstream& out, + t_type* ttype, + string prefix) { + scope_up(out); + + string obj; + + if (ttype->is_map()) { + obj = tmp("_map"); + } else if (ttype->is_set()) { + obj = tmp("_set"); + } else if (ttype->is_list()) { + obj = tmp("_list"); + } + + // Declare variables, read header + if (ttype->is_map()) { + indent(out) << "TMap " << obj << " = iprot.readMapBegin();" << endl; + } else if (ttype->is_set()) { + indent(out) << "TSet " << obj << " = iprot.readSetBegin();" << endl; + } else if (ttype->is_list()) { + indent(out) << "TList " << obj << " = iprot.readListBegin();" << endl; + } + + indent(out) << prefix << " = new " << type_name(ttype, false, true) + // size the collection correctly + << "(" << (ttype->is_list() ? "" : "2*") << obj << ".size" + << ");" << endl; + + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size" + << "; " + << "++" << i << ")" << endl; + + scope_up(out); + + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, prefix); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, prefix); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, prefix); + } + + scope_down(out); + + // Read container end + if (ttype->is_map()) { + indent(out) << "iprot.readMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "iprot.readSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "iprot.readListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Generates code to deserialize a map + */ +void t_javame_generator::generate_deserialize_map_element(ofstream& out, + t_map* tmap, + string prefix) { + string key = tmp("_key"); + string val = tmp("_val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + indent(out) << declare_field(&fkey) << endl; + indent(out) << declare_field(&fval) << endl; + + generate_deserialize_field(out, &fkey); + generate_deserialize_field(out, &fval); + + indent(out) << prefix << ".put(" << box_type(tmap->get_key_type(), key) << ", " + << box_type(tmap->get_val_type(), val) << ");" << endl; +} + +/** + * Deserializes a set element + */ +void t_javame_generator::generate_deserialize_set_element(ofstream& out, + t_set* tset, + string prefix) { + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); + + indent(out) << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".put(" << box_type(tset->get_elem_type(), elem) << ", " + << box_type(tset->get_elem_type(), elem) << ");" << endl; +} + +/** + * Deserializes a list element + */ +void t_javame_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix) { + string elem = tmp("_elem"); + t_field felem(tlist->get_elem_type(), elem); + + indent(out) << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".addElement(" << box_type(tlist->get_elem_type(), elem) << ");" << endl; +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_javame_generator::generate_serialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = get_true_type(tfield->get_type()); + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); + } else if (type->is_container()) { + generate_serialize_container(out, type, prefix + tfield->get_name()); + } else if (type->is_enum()) { + indent(out) << "oprot.writeI32(" << prefix + tfield->get_name() << ".getValue());" << endl; + } else if (type->is_base_type()) { + string name = prefix + tfield->get_name(); + indent(out) << "oprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "writeBinary(" << name << ");"; + } else { + out << "writeString(" << name << ");"; + } + break; + case t_base_type::TYPE_BOOL: + out << "writeBool(" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "writeByte(" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "writeI16(" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "writeI32(" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "writeI64(" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble(" << name << ");"; + break; + default: + throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "writeI32(" << name << ");"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", + prefix.c_str(), + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_javame_generator::generate_serialize_struct(ofstream& out, + t_struct* tstruct, + string prefix) { + (void)tstruct; + out << indent() << prefix << ".write(oprot);" << endl; +} + +/** + * Serializes a container by writing its size then the elements. + * + * @param ttype The type of container + * @param prefix String prefix for fields + */ +void t_javame_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + scope_up(out); + + if (ttype->is_map()) { + indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type()) + << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix + << ".size()));" << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type()) + << ", " << prefix << ".size()));" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.writeListBegin(new TList(" + << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".size()));" + << endl; + } + + string iter = tmp("_iter"); + if (ttype->is_map()) { + string enumer = iter + "_enum"; + string key_type = type_name(((t_map*)ttype)->get_key_type(), true, false); + indent(out) << "for (Enumeration " << enumer << " = " << prefix << ".keys(); " << enumer + << ".hasMoreElements(); ) "; + scope_up(out); + indent(out) << key_type << " " << iter << " = (" << key_type << ")" << enumer + << ".nextElement();" << endl; + } else if (ttype->is_set()) { + string enumer = iter + "_enum"; + string ele_type = type_name(((t_list*)ttype)->get_elem_type(), true); + indent(out) << "for (Enumeration " << enumer << " = " << prefix << ".keys(); " << enumer + << ".hasMoreElements(); ) "; + scope_up(out); + indent(out) << ele_type << " " << iter << " = (" << ele_type << ")" << enumer + << ".nextElement();" << endl; + } else if (ttype->is_list()) { + string enumer = iter + "_enum"; + indent(out) << "for (Enumeration " << enumer << " = " << prefix << ".elements(); " << enumer + << ".hasMoreElements(); ) "; + scope_up(out); + string ele_type = type_name(((t_list*)ttype)->get_elem_type(), true); + indent(out) << ele_type << " " << iter << " = (" << ele_type << ")" << enumer + << ".nextElement();" << endl; + } + + if (ttype->is_map()) { + generate_serialize_map_element(out, (t_map*)ttype, iter, prefix); + } else if (ttype->is_set()) { + generate_serialize_set_element(out, (t_set*)ttype, iter); + } else if (ttype->is_list()) { + generate_serialize_list_element(out, (t_list*)ttype, iter); + } + scope_down(out); + + if (ttype->is_map()) { + indent(out) << "oprot.writeMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.writeSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.writeListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Serializes the members of a map. + */ +void t_javame_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string iter, + string map) { + t_field kfield(tmap->get_key_type(), iter); + generate_serialize_field(out, &kfield, ""); + string val_type = type_name(tmap->get_val_type(), true, false); + t_field vfield(tmap->get_val_type(), "((" + val_type + ")" + map + ".get(" + iter + "))"); + generate_serialize_field(out, &vfield, ""); +} + +/** + * Serializes the members of a set. + */ +void t_javame_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) { + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +/** + * Serializes the members of a list. + */ +void t_javame_generator::generate_serialize_list_element(ofstream& out, + t_list* tlist, + string iter) { + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +/** + * Returns a Java type name + * + * @param ttype The type + * @param container Is the type going inside a container? + * @return Java type name, i.e. Vector + */ +string t_javame_generator::type_name(t_type* ttype, + bool in_container, + bool in_init, + bool skip_generic) { + (void)in_init; + (void)skip_generic; + // In Java typedefs are just resolved to their real type + ttype = get_true_type(ttype); + string prefix; + + if (ttype->is_base_type()) { + return base_type_name((t_base_type*)ttype, in_container); + } else if (ttype->is_map()) { + return "Hashtable"; + } else if (ttype->is_set()) { + return "Hashtable"; + } else if (ttype->is_list()) { + return "Vector"; + } + + // Check for namespacing + t_program* program = ttype->get_program(); + if (program != NULL && program != program_) { + string package = program->get_namespace("java"); + if (!package.empty()) { + return package + "." + ttype->get_name(); + } + } + + return ttype->get_name(); +} + +/** + * Returns the C++ type that corresponds to the thrift type. + * + * @param tbase The base type + * @param container Is it going in a Java container? + */ +string t_javame_generator::base_type_name(t_base_type* type, bool in_container) { + t_base_type::t_base tbase = type->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + return "void"; + case t_base_type::TYPE_STRING: + if (!type->is_binary()) { + return "String"; + } else { + return "byte[]"; + } + case t_base_type::TYPE_BOOL: + return (in_container ? "Boolean" : "boolean"); + case t_base_type::TYPE_I8: + return (in_container ? "Byte" : "byte"); + case t_base_type::TYPE_I16: + return (in_container ? "Short" : "short"); + case t_base_type::TYPE_I32: + return (in_container ? "Integer" : "int"); + case t_base_type::TYPE_I64: + return (in_container ? "Long" : "long"); + case t_base_type::TYPE_DOUBLE: + return (in_container ? "Double" : "double"); + default: + throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase); + } +} + +/** + * Declares a field, which may include initialization as necessary. + * + * @param ttype The type + */ +string t_javame_generator::declare_field(t_field* tfield, bool init) { + // TODO(mcslee): do we ever need to initialize the field? + string result = type_name(tfield->get_type()) + " " + tfield->get_name(); + if (init) { + t_type* ttype = get_true_type(tfield->get_type()); + if (ttype->is_base_type() && tfield->get_value() != NULL) { + ofstream dummy; + result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value()); + } else if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + result += " = null"; + break; + case t_base_type::TYPE_BOOL: + result += " = false"; + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + result += " = 0"; + break; + case t_base_type::TYPE_DOUBLE: + result += " = (double)0"; + break; + } + + } else if (ttype->is_enum()) { + result += " = 0"; + } else if (ttype->is_container()) { + result += " = new " + type_name(ttype, false, true) + "()"; + } else { + result += " = new " + type_name(ttype, false, true) + "()"; + ; + } + } + return result + ";"; +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_javame_generator::function_signature(t_function* tfunction, string prefix) { + t_type* ttype = tfunction->get_returntype(); + std::string result = type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + + argument_list(tfunction->get_arglist()) + ") throws "; + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + result += type_name((*x_iter)->get_type(), false, false) + ", "; + } + result += "TException"; + return result; +} + +/** + * Renders a comma separated field list, with type names + */ +string t_javame_generator::argument_list(t_struct* tstruct, bool include_types) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + if (include_types) { + result += type_name((*f_iter)->get_type()) + " "; + } + result += (*f_iter)->get_name(); + } + return result; +} + +/** + * Converts the parse type to a C++ enum string for the given type. + */ +string t_javame_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "TType.STRING"; + case t_base_type::TYPE_BOOL: + return "TType.BOOL"; + case t_base_type::TYPE_I8: + return "TType.BYTE"; + case t_base_type::TYPE_I16: + return "TType.I16"; + case t_base_type::TYPE_I32: + return "TType.I32"; + case t_base_type::TYPE_I64: + return "TType.I64"; + case t_base_type::TYPE_DOUBLE: + return "TType.DOUBLE"; + } + } else if (type->is_enum()) { + return "TType.I32"; + } else if (type->is_struct() || type->is_xception()) { + return "TType.STRUCT"; + } else if (type->is_map()) { + return "TType.MAP"; + } else if (type->is_set()) { + return "TType.SET"; + } else if (type->is_list()) { + return "TType.LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** + * Applies the correct style to a string based on the value of nocamel_style_ + */ +std::string t_javame_generator::get_cap_name(std::string name) { + name[0] = toupper(name[0]); + return name; +} + +string t_javame_generator::constant_name(string name) { + string constant_name; + + bool is_first = true; + bool was_previous_char_upper = false; + for (string::iterator iter = name.begin(); iter != name.end(); ++iter) { + string::value_type character = (*iter); + + bool is_upper = isupper(character); + + if (is_upper && !is_first && !was_previous_char_upper) { + constant_name += '_'; + } + constant_name += toupper(character); + + is_first = false; + was_previous_char_upper = is_upper; + } + + return constant_name; +} + +void t_javame_generator::generate_java_docstring_comment(ofstream& out, string contents) { + generate_docstring_comment(out, "/**\n", " * ", contents, " */\n"); +} + +void t_javame_generator::generate_java_doc(ofstream& out, t_field* field) { + if (field->get_type()->is_enum()) { + string combined_message = field->get_doc() + "\n@see " + get_enum_class_name(field->get_type()); + generate_java_docstring_comment(out, combined_message); + } else { + generate_java_doc(out, (t_doc*)field); + } +} + +/** + * Emits a JavaDoc comment if the provided object has a doc in Thrift + */ +void t_javame_generator::generate_java_doc(ofstream& out, t_doc* tdoc) { + if (tdoc->has_doc()) { + generate_java_docstring_comment(out, tdoc->get_doc()); + } +} + +/** + * Emits a JavaDoc comment if the provided function object has a doc in Thrift + */ +void t_javame_generator::generate_java_doc(ofstream& out, t_function* tfunction) { + if (tfunction->has_doc()) { + stringstream ss; + ss << tfunction->get_doc(); + const vector& fields = tfunction->get_arglist()->get_members(); + vector::const_iterator p_iter; + for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { + t_field* p = *p_iter; + ss << "\n@param " << p->get_name(); + if (p->has_doc()) { + ss << " " << p->get_doc(); + } + } + generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n"); + } +} + +void t_javame_generator::generate_deep_copy_container(ofstream& out, + std::string source_name_p1, + std::string source_name_p2, + std::string result_name, + t_type* type) { + + t_container* container = (t_container*)type; + std::string source_name; + if (source_name_p2 == "") + source_name = source_name_p1; + else + source_name = source_name_p1 + "." + source_name_p2; + + indent(out) << type_name(type, true, false) << " " << result_name << " = new " + << type_name(container, false, true) << "();" << endl; + + std::string iterator_element_name = source_name_p1 + "_element"; + std::string enumeration_name = source_name_p1 + "_enum"; + std::string result_element_name = result_name + "_copy"; + + if (container->is_map()) { + t_type* key_type = ((t_map*)container)->get_key_type(); + t_type* val_type = ((t_map*)container)->get_val_type(); + + indent(out) << "for (Enumeration " << enumeration_name << " = " << source_name << ".keys(); " + << enumeration_name << ".hasMoreElements(); ) {" << endl; + indent_up(); + + out << endl; + + indent(out) << type_name(key_type, true, false) << " " << iterator_element_name << "_key = (" + << type_name(key_type, true, false) << ")" << enumeration_name << ".nextElement();" + << endl; + indent(out) << type_name(val_type, true, false) << " " << iterator_element_name << "_value = (" + << type_name(val_type, true, false) << ")" << source_name << ".get(" + << iterator_element_name << "_key);" << endl; + + out << endl; + + if (key_type->is_container()) { + generate_deep_copy_container(out, + iterator_element_name + "_key", + "", + result_element_name + "_key", + key_type); + } else { + indent(out) << type_name(key_type, true, false) << " " << result_element_name << "_key = "; + generate_deep_copy_non_container(out, + iterator_element_name + "_key", + result_element_name + "_key", + key_type); + out << ";" << endl; + } + + out << endl; + + if (val_type->is_container()) { + generate_deep_copy_container(out, + iterator_element_name + "_value", + "", + result_element_name + "_value", + val_type); + } else { + indent(out) << type_name(val_type, true, false) << " " << result_element_name << "_value = "; + generate_deep_copy_non_container(out, + iterator_element_name + "_value", + result_element_name + "_value", + val_type); + out << ";" << endl; + } + + out << endl; + + indent(out) << result_name << ".put(" << result_element_name << "_key, " << result_element_name + << "_value);" << endl; + + indent_down(); + indent(out) << "}" << endl; + + } else { + t_type* elem_type; + + if (container->is_set()) { + elem_type = ((t_set*)container)->get_elem_type(); + } else { + elem_type = ((t_list*)container)->get_elem_type(); + } + + indent(out) << "for (Enumeration " << enumeration_name << " = " << source_name + << ".elements(); " << enumeration_name << ".hasMoreElements(); ) {" << endl; + indent_up(); + indent(out) << type_name(elem_type, true, false) << " " << iterator_element_name << " = (" + << type_name(elem_type, true, false) << ")" << enumeration_name << ".nextElement();" + << endl; + if (elem_type->is_container()) { + // recursive deep copy + generate_deep_copy_container(out, iterator_element_name, "", result_element_name, elem_type); + if (elem_type->is_list()) { + indent(out) << result_name << ".addElement(" << result_element_name << ");" << endl; + } else { + indent(out) << result_name << ".put(" << result_element_name << ", " << result_element_name + << ");" << endl; + } + } else { + // iterative copy + if (elem_type->is_binary()) { + indent(out) << type_name(elem_type, true, false) << " temp_binary_element = "; + generate_deep_copy_non_container(out, + iterator_element_name, + "temp_binary_element", + elem_type); + out << ";" << endl; + if (elem_type->is_list()) { + indent(out) << result_name << ".addElement(temp_binary_element);" << endl; + } else { + indent(out) << result_name << ".put(temp_binary_element, temp_binary_element);" << endl; + } + } else { + indent(out) << result_name << ".addElement("; + generate_deep_copy_non_container(out, iterator_element_name, result_name, elem_type); + out << ");" << endl; + } + } + + indent_down(); + + indent(out) << "}" << endl; + } +} + +void t_javame_generator::generate_deep_copy_non_container(ofstream& out, + std::string source_name, + std::string dest_name, + t_type* type) { + if (type->is_base_type() || type->is_enum() || type->is_typedef()) { + // binary fields need to be copied with System.arraycopy + if (type->is_binary()) { + out << "new byte[" << source_name << ".length];" << endl; + indent(out) << "System.arraycopy(" << source_name << ", 0, " << dest_name << ", 0, " + << source_name << ".length)"; + } + // everything else can be copied directly + else + out << source_name; + } else { + out << "new " << type_name(type, true, true) << "(" << source_name << ")"; + } +} + +std::string t_javame_generator::generate_isset_check(t_field* field) { + return generate_isset_check(field->get_name()); +} + +std::string t_javame_generator::isset_field_id(t_field* field) { + return "__" + upcase_string(field->get_name() + "_isset_id"); +} + +std::string t_javame_generator::generate_isset_check(std::string field_name) { + return "is" + get_cap_name("set") + get_cap_name(field_name) + "()"; +} + +void t_javame_generator::generate_isset_set(ofstream& out, t_field* field) { + if (!type_can_be_null(field->get_type())) { + indent(out) << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet") << "(true);" + << endl; + } +} + +std::string t_javame_generator::get_enum_class_name(t_type* type) { + string package = ""; + t_program* program = type->get_program(); + if (program != NULL && program != program_) { + package = program->get_namespace("java") + "."; + } + return package + type->get_name(); +} + +void t_javame_generator::generate_struct_desc(ofstream& out, t_struct* tstruct) { + indent(out) << "private static final TStruct STRUCT_DESC = new TStruct(\"" << tstruct->get_name() + << "\");" << endl; +} + +void t_javame_generator::generate_field_descs(ofstream& out, t_struct* tstruct) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << "private static final TField " << constant_name((*m_iter)->get_name()) + << "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", " + << type_to_enum((*m_iter)->get_type()) << ", " + << "(short)" << (*m_iter)->get_key() << ");" << endl; + } +} + +bool t_javame_generator::has_bit_vector(t_struct* tstruct) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (!type_can_be_null(get_true_type((*m_iter)->get_type()))) { + return true; + } + } + return false; +} + +void t_javame_generator::generate_java_struct_clear(std::ofstream& out, t_struct* tstruct) { + indent(out) << "public void clear() {" << endl; + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + indent_up(); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if ((*m_iter)->get_value() != NULL) { + print_const_value(out, + "this." + (*m_iter)->get_name(), + t, + (*m_iter)->get_value(), + true, + true); + } else { + if (type_can_be_null(t)) { + indent(out) << "this." << (*m_iter)->get_name() << " = null;" << endl; + } else { + // must be a base type + // means it also needs to be explicitly unset + indent(out) << "set" << get_cap_name((*m_iter)->get_name()) << get_cap_name("isSet") + << "(false);" << endl; + switch (((t_base_type*)t)->get_base()) { + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + indent(out) << "this." << (*m_iter)->get_name() << " = 0;" << endl; + break; + case t_base_type::TYPE_DOUBLE: + indent(out) << "this." << (*m_iter)->get_name() << " = 0.0;" << endl; + break; + case t_base_type::TYPE_BOOL: + indent(out) << "this." << (*m_iter)->get_name() << " = false;" << endl; + break; + default: // prevent gcc compiler warning + break; + } + } + } + } + indent_down(); + + indent(out) << "}" << endl << endl; +} + +THRIFT_REGISTER_GENERATOR(javame, "Java ME", "") diff --git a/compiler/cpp/src/thrift/generate/t_js_generator.cc b/compiler/cpp/src/thrift/generate/t_js_generator.cc new file mode 100644 index 0000000..f45ef57 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_js_generator.cc @@ -0,0 +1,2285 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "thrift/platform.h" +#include "thrift/version.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +#include "thrift/generate/t_oop_generator.h" + + +/** + * JS code generator. + */ +class t_js_generator : public t_oop_generator { +public: + t_js_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + gen_node_ = false; + gen_jquery_ = false; + gen_ts_ = false; + + bool with_ns_ = false; + + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("node") == 0) { + gen_node_ = true; + } else if( iter->first.compare("jquery") == 0) { + gen_jquery_ = true; + } else if( iter->first.compare("ts") == 0) { + gen_ts_ = true; + } else if( iter->first.compare("with_ns") == 0) { + with_ns_ = true; + } else { + throw "unknown option js:" + iter->first; + } + } + + if (gen_node_ && gen_ts_) { + throw "Invalid switch: [-gen js:node,ts] options not compatible"; + } + + if (gen_node_ && gen_jquery_) { + throw "Invalid switch: [-gen js:node,jquery] options not compatible, try: [-gen js:node -gen " + "js:jquery]"; + } + + if (!gen_node_ && with_ns_) { + throw "Invalid switch: [-gen js:with_ns] is only valid when using node.js"; + } + + if (gen_node_) { + out_dir_base_ = "gen-nodejs"; + no_ns_ = !with_ns_; + } else { + out_dir_base_ = "gen-js"; + no_ns_ = false; + } + + escape_['\''] = "\\'"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + std::string render_recv_throw(std::string var); + std::string render_recv_return(std::string var); + + std::string render_const_value(t_type* type, t_const_value* value); + + /** + * Structs! + */ + void generate_js_struct(t_struct* tstruct, bool is_exception); + void generate_js_struct_definition(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false, + bool is_exported = true); + void generate_js_struct_reader(std::ofstream& out, t_struct* tstruct); + void generate_js_struct_writer(std::ofstream& out, t_struct* tstruct); + void generate_js_function_helpers(t_function* tfunction); + + /** + * Service-level generation functions + */ + void generate_service_helpers(t_service* tservice); + void generate_service_interface(t_service* tservice); + void generate_service_rest(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_processor(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* tfunction); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, + t_field* tfield, + std::string prefix = "", + bool inclass = false); + + void generate_deserialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_deserialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_deserialize_set_element(std::ofstream& out, t_set* tset, std::string prefix = ""); + + void generate_deserialize_map_element(std::ofstream& out, t_map* tmap, std::string prefix = ""); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix = ""); + + void generate_serialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string kiter, + std::string viter); + + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + + /** + * Helper rendering functions + */ + + std::string js_includes(); + std::string render_includes(); + std::string declare_field(t_field* tfield, bool init = false, bool obj = false); + std::string function_signature(t_function* tfunction, + std::string prefix = "", + bool include_callback = false); + std::string argument_list(t_struct* tstruct, bool include_callback = false); + std::string type_to_enum(t_type* ttype); + std::string make_valid_nodeJs_identifier(std::string const& name); + + std::string autogen_comment() { + return std::string("//\n") + "// Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + + "//\n" + "// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + + "//\n"; + } + + t_type* get_contained_type(t_type* t); + + std::vector js_namespace_pieces(t_program* p) { + std::string ns = p->get_namespace("js"); + + std::string::size_type loc; + std::vector pieces; + + if (no_ns_) { + return pieces; + } + + if (ns.size() > 0) { + while ((loc = ns.find(".")) != std::string::npos) { + pieces.push_back(ns.substr(0, loc)); + ns = ns.substr(loc + 1); + } + } + + if (ns.size() > 0) { + pieces.push_back(ns); + } + + return pieces; + } + + std::string js_type_namespace(t_program* p) { + if (gen_node_) { + if (p != NULL && p != program_) { + return make_valid_nodeJs_identifier(p->get_name()) + "_ttypes."; + } + return "ttypes."; + } + return js_namespace(p); + } + + std::string js_export_namespace(t_program* p) { + if (gen_node_) { + return "exports."; + } + return js_namespace(p); + } + + bool has_js_namespace(t_program* p) { + if (no_ns_) { + return false; + } + std::string ns = p->get_namespace("js"); + return (ns.size() > 0); + } + + std::string js_namespace(t_program* p) { + if (no_ns_) { + return ""; + } + std::string ns = p->get_namespace("js"); + if (ns.size() > 0) { + ns += "."; + } + + return ns; + } + + /** + * TypeScript Definition File helper functions + */ + + string ts_function_signature(t_function* tfunction, bool include_callback); + string ts_get_type(t_type* type); + + /** + * Special indentation for TypeScript Definitions because of the module. + * Returns the normal indentation + " " if a module was defined. + * @return string + */ + string ts_indent() { return indent() + (!ts_module_.empty() ? " " : ""); } + + /** + * Returns "declare " if no module was defined. + * @return string + */ + string ts_declare() { return (ts_module_.empty() ? "declare " : ""); } + + /** + * Returns "?" if the given field is optional. + * @param t_field The field to check + * @return string + */ + string ts_get_req(t_field* field) { return (field->get_req() == t_field::T_OPTIONAL ? "?" : ""); } + + /** + * Returns the documentation, if the provided documentable object has one. + * @param t_doc The object to get the documentation from + * @return string The documentation + */ + string ts_print_doc(t_doc* tdoc) { + string result = endl; + + if (tdoc->has_doc()) { + std::stringstream doc(tdoc->get_doc()); + string item; + + result += ts_indent() + "/**" + endl; + while (std::getline(doc, item)) { + result += ts_indent() + " * " + item + endl; + } + result += ts_indent() + " */" + endl; + } + return result; + } + +private: + /** + * True if we should generate NodeJS-friendly RPC services. + */ + bool gen_node_; + + /** + * True if we should generate services that use jQuery ajax (async/sync). + */ + bool gen_jquery_; + + /** + * True if we should generate a TypeScript Definition File for each service. + */ + bool gen_ts_; + + /** + * The name of the defined module(s), for TypeScript Definition Files. + */ + string ts_module_; + + /** + * True if we should not generate namespace objects for node. + */ + bool no_ns_; + + /** + * File streams + */ + std::ofstream f_types_; + std::ofstream f_service_; + std::ofstream f_types_ts_; + std::ofstream f_service_ts_; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_js_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + + string outdir = get_out_dir(); + + // Make output file(s) + string f_types_name = outdir + program_->get_name() + "_types.js"; + f_types_.open(f_types_name.c_str()); + + if (gen_ts_) { + string f_types_ts_name = outdir + program_->get_name() + "_types.d.ts"; + f_types_ts_.open(f_types_ts_name.c_str()); + } + + // Print header + f_types_ << autogen_comment(); + + if (gen_node_ && no_ns_) { + f_types_ << "\"use strict\";" << endl << endl; + } + + f_types_ << js_includes() << endl << render_includes() << endl; + + if (gen_ts_) { + f_types_ts_ << autogen_comment() << endl; + } + + if (gen_node_) { + f_types_ << "var ttypes = module.exports = {};" << endl; + } + + string pns; + + // setup the namespace + // TODO should the namespace just be in the directory structure for node? + vector ns_pieces = js_namespace_pieces(program_); + if (ns_pieces.size() > 0) { + for (size_t i = 0; i < ns_pieces.size(); ++i) { + pns += ((i == 0) ? "" : ".") + ns_pieces[i]; + f_types_ << "if (typeof " << pns << " === 'undefined') {" << endl; + f_types_ << " " << pns << " = {};" << endl; + f_types_ << "}" << endl; + } + if (gen_ts_) { + ts_module_ = pns; + f_types_ts_ << "declare module " << ts_module_ << " {"; + } + } +} + +/** + * Prints standard js imports + */ +string t_js_generator::js_includes() { + if (gen_node_) { + return string( + "var thrift = require('thrift');\n" + "var Thrift = thrift.Thrift;\n" + "var Q = thrift.Q;\n"); + } + + return ""; +} + +/** + * Renders all the imports necessary for including another Thrift program + */ +string t_js_generator::render_includes() { + string result = ""; + + if (gen_node_) { + const vector& includes = program_->get_includes(); + for (size_t i = 0; i < includes.size(); ++i) { + result += "var " + make_valid_nodeJs_identifier(includes[i]->get_name()) + "_ttypes = require('./" + includes[i]->get_name() + + "_types');\n"; + } + if (includes.size() > 0) { + result += "\n"; + } + } + + return result; +} + +/** + * Close up (or down) some filez. + */ +void t_js_generator::close_generator() { + // Close types file(s) + + f_types_.close(); + + if (gen_ts_) { + if (!ts_module_.empty()) { + f_types_ts_ << "}"; + } + f_types_ts_.close(); + } +} + +/** + * Generates a typedef. This is not done in JS, types are all implicit. + * + * @param ttypedef The type definition + */ +void t_js_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + +/** + * Generates code for an enumerated type. Since define is expensive to lookup + * in JS, we use a global array for this. + * + * @param tenum The enumeration + */ +void t_js_generator::generate_enum(t_enum* tenum) { + f_types_ << js_type_namespace(tenum->get_program()) << tenum->get_name() << " = {" << endl; + + if (gen_ts_) { + f_types_ts_ << ts_print_doc(tenum) << ts_indent() << ts_declare() << "enum " + << tenum->get_name() << " {" << endl; + } + + indent_up(); + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + if (gen_ts_) { + f_types_ts_ << ts_indent() << (*c_iter)->get_name() << " = " << value << "," << endl; + // add 'value: key' in addition to 'key: value' for TypeScript enums + f_types_ << indent() << "'" << value << "' : '" << (*c_iter)->get_name() << "'," << endl; + } + f_types_ << indent() << "'" << (*c_iter)->get_name() << "' : " << value; + if (c_iter != constants.end() - 1) { + f_types_ << ","; + } + f_types_ << endl; + } + + indent_down(); + + f_types_ << "};" << endl; + + if (gen_ts_) { + f_types_ts_ << ts_indent() << "}" << endl; + } +} + +/** + * Generate a constant value + */ +void t_js_generator::generate_const(t_const* tconst) { + t_type* type = tconst->get_type(); + string name = tconst->get_name(); + t_const_value* value = tconst->get_value(); + + f_types_ << js_type_namespace(program_) << name << " = "; + f_types_ << render_const_value(type, value) << ";" << endl; + + if (gen_ts_) { + f_types_ts_ << ts_print_doc(tconst) << ts_indent() << ts_declare() << "var " << name << ": " + << ts_get_type(type) << ";" << endl; + } +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +string t_js_generator::render_const_value(t_type* type, t_const_value* value) { + std::ostringstream out; + + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + out << "'" << get_escaped_string(value) << "'"; + break; + case t_base_type::TYPE_BOOL: + out << (value->get_integer() > 0 ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + out << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + out << value->get_integer(); + } else { + out << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << value->get_integer(); + } else if (type->is_struct() || type->is_xception()) { + out << "new " << js_type_namespace(type->get_program()) << type->get_name() << "({"; + indent_up(); + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + if (v_iter != val.begin()) + out << ","; + out << endl << indent() << render_const_value(g_type_string, v_iter->first); + out << " : "; + out << render_const_value(field_type, v_iter->second); + } + indent_down(); + out << endl << indent() << "})"; + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + + t_type* vtype = ((t_map*)type)->get_val_type(); + out << "{" << endl; + indent_up(); + + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + if (v_iter != val.begin()) + out << "," << endl; + + out << indent() << render_const_value(ktype, v_iter->first); + + out << " : "; + out << render_const_value(vtype, v_iter->second); + } + indent_down(); + out << endl << indent() << "}"; + } else if (type->is_list() || type->is_set()) { + t_type* etype; + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + out << "["; + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + if (v_iter != val.begin()) + out << ","; + out << render_const_value(etype, *v_iter); + } + out << "]"; + } + return out.str(); +} + +/** + * Make a struct + */ +void t_js_generator::generate_struct(t_struct* tstruct) { + generate_js_struct(tstruct, false); +} + +/** + * Generates a struct definition for a thrift exception. Basically the same + * as a struct but extends the Exception class. + * + * @param txception The struct definition + */ +void t_js_generator::generate_xception(t_struct* txception) { + generate_js_struct(txception, true); +} + +/** + * Structs can be normal or exceptions. + */ +void t_js_generator::generate_js_struct(t_struct* tstruct, bool is_exception) { + generate_js_struct_definition(f_types_, tstruct, is_exception); +} + +/** + * Return type of contained elements for a container type. For maps + * this is type of value (keys are always strings in js) + */ +t_type* t_js_generator::get_contained_type(t_type* t) { + t_type* etype; + if (t->is_list()) { + etype = ((t_list*)t)->get_elem_type(); + } else if (t->is_set()) { + etype = ((t_set*)t)->get_elem_type(); + } else { + etype = ((t_map*)t)->get_val_type(); + } + return etype; +} + +/** + * Generates a struct definition for a thrift data type. This is nothing in JS + * where the objects are all just associative arrays (unless of course we + * decide to start using objects for them...) + * + * @param tstruct The struct definition + */ +void t_js_generator::generate_js_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool is_exported) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + if (gen_node_) { + string prefix = has_js_namespace(tstruct->get_program()) ? js_namespace(tstruct->get_program()) : "var "; + if (is_exported) { + out << prefix << tstruct->get_name() << " = " + << "module.exports." << tstruct->get_name() << " = function(args) {" << endl; + } else { + out << prefix << tstruct->get_name() << " = function(args) {" + << endl; + } + } else { + out << js_namespace(tstruct->get_program()) << tstruct->get_name() << " = function(args) {" + << endl; + if (gen_ts_) { + f_types_ts_ << ts_print_doc(tstruct) << ts_indent() << ts_declare() << "class " + << tstruct->get_name() << (is_exception ? " extends Thrift.TException" : "") + << " {" << endl; + } + } + + indent_up(); + + if (gen_node_ && is_exception) { + out << indent() << "Thrift.TException.call(this, \"" << js_namespace(tstruct->get_program()) + << tstruct->get_name() << "\");" << endl; + out << indent() << "this.name = \"" << js_namespace(tstruct->get_program()) + << tstruct->get_name() << "\";" << endl; + } + + // members with arguments + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + string dval = declare_field(*m_iter, false, true); + t_type* t = get_true_type((*m_iter)->get_type()); + if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) { + dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value()); + out << indent() << "this." << (*m_iter)->get_name() << " = " << dval << ";" << endl; + } else { + out << indent() << dval << ";" << endl; + } + if (gen_ts_) { + f_types_ts_ << ts_indent() << (*m_iter)->get_name() << ": " + << ts_get_type((*m_iter)->get_type()) << ";" << endl; + } + } + + // Generate constructor from array + if (members.size() > 0) { + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) { + indent(out) << "this." << (*m_iter)->get_name() << " = " + << render_const_value(t, (*m_iter)->get_value()) << ";" << endl; + } + } + + // Early returns for exceptions + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if (t->is_xception()) { + out << indent() << "if (args instanceof " << js_type_namespace(t->get_program()) + << t->get_name() << ") {" << endl << indent() << indent() << "this." + << (*m_iter)->get_name() << " = args;" << endl << indent() << indent() << "return;" + << endl << indent() << "}" << endl; + } + } + + out << indent() << "if (args) {" << endl; + if (gen_ts_) { + f_types_ts_ << endl << ts_indent() << "constructor(args?: { "; + } + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + out << indent() << indent() << "if (args." << (*m_iter)->get_name() << " !== undefined && args." << (*m_iter)->get_name() << " !== null) {" + << endl << indent() << indent() << indent() << "this." << (*m_iter)->get_name(); + + if (t->is_struct()) { + out << (" = new " + js_type_namespace(t->get_program()) + t->get_name() + + "(args."+(*m_iter)->get_name() +");"); + out << endl; + } else if (t->is_container()) { + t_type* etype = get_contained_type(t); + string copyFunc = t->is_map() ? "Thrift.copyMap" : "Thrift.copyList"; + string type_list = ""; + + while (etype->is_container()) { + if (type_list.length() > 0) { + type_list += ", "; + } + type_list += etype->is_map() ? "Thrift.copyMap" : "Thrift.copyList"; + etype = get_contained_type(etype); + } + + if (etype->is_struct()) { + if (type_list.length() > 0) { + type_list += ", "; + } + type_list += js_type_namespace(etype->get_program()) + etype->get_name(); + } + else { + if (type_list.length() > 0) { + type_list += ", "; + } + type_list += "null"; + } + + out << (" = " + copyFunc + "(args." + (*m_iter)->get_name() + + ", [" + type_list + "]);"); + out << endl; + } else { + out << " = args." << (*m_iter)->get_name() << ";" << endl; + } + + if (!(*m_iter)->get_req()) { + out << indent() << indent() << "} else {" << endl << indent() << indent() << indent() + << "throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.UNKNOWN, " + "'Required field " << (*m_iter)->get_name() << " is unset!');" << endl; + } + out << indent() << indent() << "}" << endl; + if (gen_ts_) { + f_types_ts_ << (*m_iter)->get_name() << ts_get_req(*m_iter) << ": " + << ts_get_type((*m_iter)->get_type()) << "; "; + } + } + + out << indent() << "}" << endl; + if (gen_ts_) { + f_types_ts_ << "});" << endl; + } + } + + indent_down(); + out << "};" << endl; + if (gen_ts_) { + f_types_ts_ << ts_indent() << "}" << endl; + } + + if (is_exception) { + out << "Thrift.inherits(" << js_namespace(tstruct->get_program()) << tstruct->get_name() + << ", Thrift.TException);" << endl; + out << js_namespace(tstruct->get_program()) << tstruct->get_name() << ".prototype.name = '" + << tstruct->get_name() << "';" << endl; + } else { + // init prototype + out << js_namespace(tstruct->get_program()) << tstruct->get_name() << ".prototype = {};" + << endl; + } + + generate_js_struct_reader(out, tstruct); + generate_js_struct_writer(out, tstruct); +} + +/** + * Generates the read() method for a struct + */ +void t_js_generator::generate_js_struct_reader(ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out << js_namespace(tstruct->get_program()) << tstruct->get_name() + << ".prototype.read = function(input) {" << endl; + + indent_up(); + + indent(out) << "input.readStructBegin();" << endl; + + // Loop over reading in fields + indent(out) << "while (true)" << endl; + + scope_up(out); + + indent(out) << "var ret = input.readFieldBegin();" << endl; + indent(out) << "var fname = ret.fname;" << endl; + indent(out) << "var ftype = ret.ftype;" << endl; + indent(out) << "var fid = ret.fid;" << endl; + + // Check for field STOP marker and break + indent(out) << "if (ftype == Thrift.Type.STOP) {" << endl; + indent_up(); + indent(out) << "break;" << endl; + indent_down(); + indent(out) << "}" << endl; + if (!fields.empty()) { + // Switch statement on the field we are reading + indent(out) << "switch (fid)" << endl; + + scope_up(out); + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + + indent(out) << "case " << (*f_iter)->get_key() << ":" << endl; + indent(out) << "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; + + indent_up(); + generate_deserialize_field(out, *f_iter, "this."); + indent_down(); + + indent(out) << "} else {" << endl; + + indent(out) << " input.skip(ftype);" << endl; + + out << indent() << "}" << endl << indent() << "break;" << endl; + } + if (fields.size() == 1) { + // pseudo case to make jslint happy + indent(out) << "case 0:" << endl; + indent(out) << " input.skip(ftype);" << endl; + indent(out) << " break;" << endl; + } + // In the default case we skip the field + indent(out) << "default:" << endl; + indent(out) << " input.skip(ftype);" << endl; + + scope_down(out); + } else { + indent(out) << "input.skip(ftype);" << endl; + } + + indent(out) << "input.readFieldEnd();" << endl; + + scope_down(out); + + indent(out) << "input.readStructEnd();" << endl; + + indent(out) << "return;" << endl; + + indent_down(); + out << indent() << "};" << endl << endl; +} + +/** + * Generates the write() method for a struct + */ +void t_js_generator::generate_js_struct_writer(ofstream& out, t_struct* tstruct) { + string name = tstruct->get_name(); + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out << js_namespace(tstruct->get_program()) << tstruct->get_name() + << ".prototype.write = function(output) {" << endl; + + indent_up(); + + indent(out) << "output.writeStructBegin('" << name << "');" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + out << indent() << "if (this." << (*f_iter)->get_name() << " !== null && this." + << (*f_iter)->get_name() << " !== undefined) {" << endl; + indent_up(); + + indent(out) << "output.writeFieldBegin(" + << "'" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type()) + << ", " << (*f_iter)->get_key() << ");" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "this."); + + indent(out) << "output.writeFieldEnd();" << endl; + + indent_down(); + indent(out) << "}" << endl; + } + + out << indent() << "output.writeFieldStop();" << endl << indent() << "output.writeStructEnd();" + << endl; + + out << indent() << "return;" << endl; + + indent_down(); + out << indent() << "};" << endl << endl; +} + +/** + * Generates a thrift service. + * + * @param tservice The service definition + */ +void t_js_generator::generate_service(t_service* tservice) { + string f_service_name = get_out_dir() + service_name_ + ".js"; + f_service_.open(f_service_name.c_str()); + + if (gen_ts_) { + string f_service_ts_name = get_out_dir() + service_name_ + ".d.ts"; + f_service_ts_.open(f_service_ts_name.c_str()); + } + + f_service_ << autogen_comment(); + + if (gen_node_ && no_ns_) { + f_service_ << "\"use strict\";" << endl << endl; + } + + f_service_ << js_includes() << endl << render_includes() << endl; + + if (gen_ts_) { + if (tservice->get_extends() != NULL) { + f_service_ts_ << "/// get_extends()->get_name() + << ".d.ts\" />" << endl; + } + f_service_ts_ << autogen_comment() << endl; + if (!ts_module_.empty()) { + f_service_ts_ << "declare module " << ts_module_ << " {"; + } + } + + if (gen_node_) { + if (tservice->get_extends() != NULL) { + f_service_ << "var " << tservice->get_extends()->get_name() << " = require('./" + << tservice->get_extends()->get_name() << "');" << endl << "var " + << tservice->get_extends()->get_name() + << "Client = " << tservice->get_extends()->get_name() << ".Client;" << endl + << "var " << tservice->get_extends()->get_name() + << "Processor = " << tservice->get_extends()->get_name() << ".Processor;" << endl; + } + + f_service_ << "var ttypes = require('./" + program_->get_name() + "_types');" << endl; + } + + generate_service_helpers(tservice); + generate_service_interface(tservice); + generate_service_client(tservice); + + if (gen_node_) { + generate_service_processor(tservice); + } + + f_service_.close(); + if (gen_ts_) { + if (!ts_module_.empty()) { + f_service_ts_ << "}"; + } + f_service_ts_.close(); + } +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_js_generator::generate_service_processor(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + if (gen_node_) { + string prefix = has_js_namespace(tservice->get_program()) ? js_namespace(tservice->get_program()) : "var "; + f_service_ << prefix << service_name_ << "Processor = " << "exports.Processor = function(handler) "; + } else { + f_service_ << js_namespace(tservice->get_program()) << service_name_ << "Processor = " + << "exports.Processor = function(handler) "; + } + + scope_up(f_service_); + + f_service_ << indent() << "this._handler = handler;" << endl; + + scope_down(f_service_); + f_service_ << ";" << endl; + + if (tservice->get_extends() != NULL) { + indent(f_service_) << "Thrift.inherits(" << js_namespace(tservice->get_program()) + << service_name_ << "Processor, " << tservice->get_extends()->get_name() + << "Processor);" << endl; + } + + // Generate the server implementation + indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ + << "Processor.prototype.process = function(input, output) "; + + scope_up(f_service_); + + f_service_ << indent() << "var r = input.readMessageBegin();" << endl << indent() + << "if (this['process_' + r.fname]) {" << endl << indent() + << " return this['process_' + r.fname].call(this, r.rseqid, input, output);" << endl + << indent() << "} else {" << endl << indent() << " input.skip(Thrift.Type.STRUCT);" + << endl << indent() << " input.readMessageEnd();" << endl << indent() + << " var x = new " + "Thrift.TApplicationException(Thrift.TApplicationExceptionType.UNKNOWN_METHOD, " + "'Unknown function ' + r.fname);" << endl << indent() + << " output.writeMessageBegin(r.fname, Thrift.MessageType.EXCEPTION, r.rseqid);" + << endl << indent() << " x.write(output);" << endl << indent() + << " output.writeMessageEnd();" << endl << indent() << " output.flush();" << endl + << indent() << "}" << endl; + + scope_down(f_service_); + f_service_ << ";" << endl; + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(tservice, *f_iter); + } +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_js_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ + << "Processor.prototype.process_" + tfunction->get_name() + + " = function(seqid, input, output) "; + + scope_up(f_service_); + + string argsname = js_namespace(program_) + service_name_ + "_" + tfunction->get_name() + "_args"; + string resultname = js_namespace(program_) + service_name_ + "_" + tfunction->get_name() + + "_result"; + + f_service_ << indent() << "var args = new " << argsname << "();" << endl << indent() + << "args.read(input);" << endl << indent() << "input.readMessageEnd();" << endl; + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + // Shortcut out here for oneway functions + if (tfunction->is_oneway()) { + indent(f_service_) << "this._handler." << tfunction->get_name() << "("; + + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "args." << (*f_iter)->get_name(); + } + + f_service_ << ");" << endl; + scope_down(f_service_); + f_service_ << ";" << endl; + return; + } + + f_service_ << indent() << "if (this._handler." << tfunction->get_name() + << ".length === " << fields.size() << ") {" << endl; + indent_up(); + indent(f_service_) << "Q.fcall(this._handler." << tfunction->get_name() << ".bind(this._handler)"; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + f_service_ << ", args." << (*f_iter)->get_name(); + } + + f_service_ << ")" << endl; + indent_up(); + indent(f_service_) << ".then(function(result) {" << endl; + indent_up(); + f_service_ << indent() << "var result_obj = new " << resultname << "({success: result});" << endl + << indent() << "output.writeMessageBegin(\"" << tfunction->get_name() + << "\", Thrift.MessageType.REPLY, seqid);" << endl << indent() + << "result_obj.write(output);" << endl << indent() << "output.writeMessageEnd();" << endl + << indent() << "output.flush();" << endl; + indent_down(); + indent(f_service_) << "}, function (err) {" << endl; + indent_up(); + indent(f_service_) << "var result;" << endl; + + bool has_exception = false; + t_struct* exceptions = tfunction->get_xceptions(); + if (exceptions) { + const vector& members = exceptions->get_members(); + for (vector::const_iterator it = members.begin(); it != members.end(); ++it) { + t_type* t = get_true_type((*it)->get_type()); + if (t->is_xception()) { + if (!has_exception) { + has_exception = true; + indent(f_service_) << "if (err instanceof " << js_type_namespace(t->get_program()) + << t->get_name(); + } else { + f_service_ << " || err instanceof " << js_type_namespace(t->get_program()) + << t->get_name(); + } + } + } + } + + if (has_exception) { + f_service_ << ") {" << endl; + indent_up(); + f_service_ << indent() << "result = new " << resultname << "(err);" << endl << indent() + << "output.writeMessageBegin(\"" << tfunction->get_name() + << "\", Thrift.MessageType.REPLY, seqid);" << endl; + + indent_down(); + indent(f_service_) << "} else {" << endl; + indent_up(); + } + + f_service_ << indent() << "result = new " + "Thrift.TApplicationException(Thrift.TApplicationExceptionType.UNKNOWN," + " err.message);" << endl << indent() << "output.writeMessageBegin(\"" + << tfunction->get_name() << "\", Thrift.MessageType.EXCEPTION, seqid);" << endl; + + if (has_exception) { + indent_down(); + indent(f_service_) << "}" << endl; + } + + f_service_ << indent() << "result.write(output);" << endl << indent() + << "output.writeMessageEnd();" << endl << indent() << "output.flush();" << endl; + indent_down(); + indent(f_service_) << "});" << endl; + indent_down(); + indent_down(); + indent(f_service_) << "} else {" << endl; + indent_up(); + indent(f_service_) << "this._handler." << tfunction->get_name() << "("; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + f_service_ << "args." << (*f_iter)->get_name() << ", "; + } + + f_service_ << "function (err, result) {" << endl; + indent_up(); + indent(f_service_) << "var result_obj;" << endl; + + indent(f_service_) << "if ((err === null || typeof err === 'undefined')"; + if (has_exception) { + const vector& members = exceptions->get_members(); + for (vector::const_iterator it = members.begin(); it != members.end(); ++it) { + t_type* t = get_true_type((*it)->get_type()); + if (t->is_xception()) { + f_service_ << " || err instanceof " << js_type_namespace(t->get_program()) << t->get_name(); + } + } + } + f_service_ << ") {" << endl; + indent_up(); + f_service_ << indent() << "result_obj = new " << resultname + << "((err !== null || typeof err === 'undefined') ? err : {success: result});" << endl << indent() + << "output.writeMessageBegin(\"" << tfunction->get_name() + << "\", Thrift.MessageType.REPLY, seqid);" << endl; + indent_down(); + indent(f_service_) << "} else {" << endl; + indent_up(); + f_service_ << indent() << "result_obj = new " + "Thrift.TApplicationException(Thrift.TApplicationExceptionType.UNKNOWN," + " err.message);" << endl << indent() << "output.writeMessageBegin(\"" + << tfunction->get_name() << "\", Thrift.MessageType.EXCEPTION, seqid);" << endl; + indent_down(); + f_service_ << indent() << "}" << endl << indent() << "result_obj.write(output);" << endl << indent() + << "output.writeMessageEnd();" << endl << indent() << "output.flush();" << endl; + + indent_down(); + indent(f_service_) << "});" << endl; + indent_down(); + indent(f_service_) << "}" << endl; + indent_down(); + indent(f_service_) << "};" << endl; +} + +/** + * Generates helper functions for a service. + * + * @param tservice The service to generate a header definition for + */ +void t_js_generator::generate_service_helpers(t_service* tservice) { + // Do not generate TS definitions for helper functions + bool gen_ts_tmp = gen_ts_; + gen_ts_ = false; + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + f_service_ << "//HELPER FUNCTIONS AND STRUCTURES" << endl << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + string name = ts->get_name(); + ts->set_name(service_name_ + "_" + name); + generate_js_struct_definition(f_service_, ts, false, false); + generate_js_function_helpers(*f_iter); + ts->set_name(name); + } + + gen_ts_ = gen_ts_tmp; +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_js_generator::generate_js_function_helpers(t_function* tfunction) { + t_struct result(program_, service_name_ + "_" + tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + generate_js_struct_definition(f_service_, &result, false, false); +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_js_generator::generate_service_interface(t_service* tservice) { + (void)tservice; +} + +/** + * Generates a REST interface + */ +void t_js_generator::generate_service_rest(t_service* tservice) { + (void)tservice; +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_js_generator::generate_service_client(t_service* tservice) { + if (gen_node_) { + string prefix = has_js_namespace(tservice->get_program()) ? js_namespace(tservice->get_program()) : "var "; + f_service_ << prefix << service_name_ << "Client = " + << "exports.Client = function(output, pClass) {" << endl; + } else { + f_service_ << js_namespace(tservice->get_program()) << service_name_ + << "Client = function(input, output) {" << endl; + if (gen_ts_) { + f_service_ts_ << ts_print_doc(tservice) << ts_indent() << ts_declare() << "class " + << service_name_ << "Client "; + if (tservice->get_extends() != NULL) { + f_service_ts_ << "extends " << tservice->get_extends()->get_name() << "Client "; + } + f_service_ts_ << "{" << endl; + } + } + + indent_up(); + + if (gen_node_) { + f_service_ << indent() << " this.output = output;" << endl << indent() + << " this.pClass = pClass;" << endl << indent() << " this._seqid = 0;" << endl + << indent() << " this._reqs = {};" << endl; + } else { + f_service_ << indent() << " this.input = input;" << endl << indent() + << " this.output = (!output) ? input : output;" << endl << indent() + << " this.seqid = 0;" << endl; + if (gen_ts_) { + f_service_ts_ << ts_indent() << "input: Thrift.TJSONProtocol;" << endl << ts_indent() + << "output: Thrift.TJSONProtocol;" << endl << ts_indent() << "seqid: number;" + << endl << endl << ts_indent() + << "constructor(input: Thrift.TJSONProtocol, output?: Thrift.TJSONProtocol);" + << endl; + } + } + + indent_down(); + + f_service_ << indent() << "};" << endl; + + if (tservice->get_extends() != NULL) { + indent(f_service_) << "Thrift.inherits(" << js_namespace(tservice->get_program()) + << service_name_ << "Client, " + << js_namespace(tservice->get_extends()->get_program()) + << tservice->get_extends()->get_name() << "Client);" << endl; + } else { + // init prototype + indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ + << "Client.prototype = {};" << endl; + } + + // utils for multiplexed services + if (gen_node_) { + indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ + << "Client.prototype.seqid = function() { return this._seqid; };" << endl + << js_namespace(tservice->get_program()) << service_name_ + << "Client.prototype.new_seqid = function() { return this._seqid += 1; };" + << endl; + } + // Generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* arg_struct = (*f_iter)->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + string funname = (*f_iter)->get_name(); + string arglist = argument_list(arg_struct); + + // Open function + f_service_ << js_namespace(tservice->get_program()) << service_name_ << "Client.prototype." + << function_signature(*f_iter, "", true) << " {" << endl; + + indent_up(); + + if (gen_ts_) { + f_service_ts_ << ts_print_doc(*f_iter) << + // function definition without callback + ts_indent() << ts_function_signature(*f_iter, false) << endl << ts_print_doc(*f_iter) << + // overload with callback + ts_indent() << ts_function_signature(*f_iter, true) << endl; + } + + if (gen_node_) { // Node.js output ./gen-nodejs + f_service_ << indent() << "this._seqid = this.new_seqid();" << endl << indent() + << "if (callback === undefined) {" << endl; + indent_up(); + f_service_ << indent() << "var _defer = Q.defer();" << endl << indent() + << "this._reqs[this.seqid()] = function(error, result) {" << endl; + indent_up(); + indent(f_service_) << "if (error) {" << endl; + indent_up(); + indent(f_service_) << "_defer.reject(error);" << endl; + indent_down(); + indent(f_service_) << "} else {" << endl; + indent_up(); + indent(f_service_) << "_defer.resolve(result);" << endl; + indent_down(); + indent(f_service_) << "}" << endl; + indent_down(); + indent(f_service_) << "};" << endl; + f_service_ << indent() << "this.send_" << funname << "(" << arglist << ");" << endl + << indent() << "return _defer.promise;" << endl; + indent_down(); + indent(f_service_) << "} else {" << endl; + indent_up(); + f_service_ << indent() << "this._reqs[this.seqid()] = callback;" << endl << indent() + << "this.send_" << funname << "(" << arglist << ");" << endl; + indent_down(); + indent(f_service_) << "}" << endl; + } else if (gen_jquery_) { // jQuery output ./gen-js + f_service_ << indent() << "if (callback === undefined) {" << endl; + indent_up(); + f_service_ << indent() << "this.send_" << funname << "(" << arglist << ");" << endl; + if (!(*f_iter)->is_oneway()) { + f_service_ << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << "return "; + } + f_service_ << "this.recv_" << funname << "();" << endl; + } + indent_down(); + f_service_ << indent() << "} else {" << endl; + indent_up(); + f_service_ << indent() << "var postData = this.send_" << funname << "(" << arglist + << (arglist.empty() ? "" : ", ") << "true);" << endl; + f_service_ << indent() << "return this.output.getTransport()" << endl; + indent_up(); + f_service_ << indent() << ".jqRequest(this, postData, arguments, this.recv_" << funname + << ");" << endl; + indent_down(); + indent_down(); + f_service_ << indent() << "}" << endl; + } else { // Standard JavaScript ./gen-js + f_service_ << indent() << "this.send_" << funname << "(" << arglist + << (arglist.empty() ? "" : ", ") << "callback); " << endl; + if (!(*f_iter)->is_oneway()) { + f_service_ << indent() << "if (!callback) {" << endl; + f_service_ << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << " return "; + } + f_service_ << "this.recv_" << funname << "();" << endl; + f_service_ << indent() << "}" << endl; + } + } + + indent_down(); + + f_service_ << "};" << endl << endl; + + // Send function + f_service_ << js_namespace(tservice->get_program()) << service_name_ << "Client.prototype.send_" + << function_signature(*f_iter, "", !gen_node_) << " {" << endl; + + indent_up(); + + std::string outputVar; + if (gen_node_) { + f_service_ << indent() << "var output = new this.pClass(this.output);" << endl; + outputVar = "output"; + } else { + outputVar = "this.output"; + } + + std::string argsname = js_namespace(program_) + service_name_ + "_" + (*f_iter)->get_name() + + "_args"; + + std::string messageType = (*f_iter)->is_oneway() ? "Thrift.MessageType.ONEWAY" + : "Thrift.MessageType.CALL"; + + // Serialize the request header + if (gen_node_) { + f_service_ << indent() << outputVar << ".writeMessageBegin('" << (*f_iter)->get_name() + << "', " << messageType << ", this.seqid());" << endl; + } else { + f_service_ << indent() << outputVar << ".writeMessageBegin('" << (*f_iter)->get_name() + << "', " << messageType << ", this.seqid);" << endl; + } + + if (fields.size() > 0){ + f_service_ << indent() << "var params = {" << endl; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << indent() << indent() << (*fld_iter)->get_name() << ": " << (*fld_iter)->get_name(); + if (fld_iter != fields.end()-1) { + f_service_ << "," << endl; + } else { + f_service_ << endl; + } + } + f_service_ << indent() << "};" << endl; + f_service_ << indent() << "var args = new " << argsname << "(params);" << endl; + } else { + f_service_ << indent() << "var args = new " << argsname << "();" << endl; + } + + // Write to the stream + f_service_ << indent() << "args.write(" << outputVar << ");" << endl << indent() << outputVar + << ".writeMessageEnd();" << endl; + + if (gen_node_) { + f_service_ << indent() << "return this.output.flush();" << endl; + } else { + if (gen_jquery_) { + f_service_ << indent() << "return this.output.getTransport().flush(callback);" << endl; + } else { + f_service_ << indent() << "if (callback) {" << endl; + if((*f_iter)->is_oneway()) { + f_service_ << indent() << " this.output.getTransport().flush(true, null);" << endl; + } else { + f_service_ << indent() << " var self = this;" << endl; + f_service_ << indent() << " this.output.getTransport().flush(true, function() {" << endl; + f_service_ << indent() << " var result = null;" << endl; + f_service_ << indent() << " try {" << endl; + f_service_ << indent() << " result = self.recv_" << funname << "();" << endl; + f_service_ << indent() << " } catch (e) {" << endl; + f_service_ << indent() << " result = e;" << endl; + f_service_ << indent() << " }" << endl; + f_service_ << indent() << " callback(result);" << endl; + f_service_ << indent() << " });" << endl; + } + f_service_ << indent() << "} else {" << endl; + f_service_ << indent() << " return this.output.getTransport().flush();" << endl; + f_service_ << indent() << "}" << endl; + } + } + + indent_down(); + + f_service_ << "};" << endl; + + if (!(*f_iter)->is_oneway()) { + std::string resultname = js_namespace(tservice->get_program()) + service_name_ + "_" + + (*f_iter)->get_name() + "_result"; + + if (gen_node_) { + // Open function + f_service_ << endl << js_namespace(tservice->get_program()) << service_name_ + << "Client.prototype.recv_" << (*f_iter)->get_name() + << " = function(input,mtype,rseqid) {" << endl; + } else { + t_struct noargs(program_); + + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + &noargs); + // Open function + f_service_ << endl << js_namespace(tservice->get_program()) << service_name_ + << "Client.prototype." << function_signature(&recv_function) << " {" << endl; + } + + indent_up(); + + std::string inputVar; + if (gen_node_) { + inputVar = "input"; + } else { + inputVar = "this.input"; + } + + if (gen_node_) { + f_service_ << indent() << "var callback = this._reqs[rseqid] || function() {};" << endl + << indent() << "delete this._reqs[rseqid];" << endl; + } else { + f_service_ << indent() << "var ret = this.input.readMessageBegin();" << endl << indent() + << "var fname = ret.fname;" << endl << indent() << "var mtype = ret.mtype;" + << endl << indent() << "var rseqid = ret.rseqid;" << endl; + } + + f_service_ << indent() << "if (mtype == Thrift.MessageType.EXCEPTION) {" << endl << indent() + << " var x = new Thrift.TApplicationException();" << endl << indent() + << " x.read(" << inputVar << ");" << endl << indent() << " " << inputVar + << ".readMessageEnd();" << endl << indent() << " " << render_recv_throw("x") + << endl << indent() << "}" << endl; + + f_service_ << indent() << "var result = new " << resultname << "();" << endl << indent() + << "result.read(" << inputVar << ");" << endl; + + f_service_ << indent() << inputVar << ".readMessageEnd();" << endl << endl; + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << indent() << "if (null !== result." << (*x_iter)->get_name() << ") {" << endl + << indent() << " " << render_recv_throw("result." + (*x_iter)->get_name()) + << endl << indent() << "}" << endl; + } + + // Careful, only return result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << indent() << "if (null !== result.success) {" << endl << indent() << " " + << render_recv_return("result.success") << endl << indent() << "}" << endl; + f_service_ << indent() + << render_recv_throw("'" + (*f_iter)->get_name() + " failed: unknown result'") + << endl; + } else { + if (gen_node_) { + indent(f_service_) << "callback(null);" << endl; + } else { + indent(f_service_) << "return;" << endl; + } + } + + // Close function + indent_down(); + f_service_ << "};" << endl; + } + } + + if (gen_ts_) { + f_service_ts_ << ts_indent() << "}" << endl; + } +} + +std::string t_js_generator::render_recv_throw(std::string var) { + if (gen_node_) { + return "return callback(" + var + ");"; + } else { + return "throw " + var + ";"; + } +} + +std::string t_js_generator::render_recv_return(std::string var) { + if (gen_node_) { + return "return callback(null, " + var + ");"; + } else { + return "return " + var + ";"; + } +} + +/** + * Deserializes a field of any type. + */ +void t_js_generator::generate_deserialize_field(ofstream& out, + t_field* tfield, + string prefix, + bool inclass) { + (void)inclass; + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = prefix + tfield->get_name(); + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name); + } else if (type->is_container()) { + generate_deserialize_container(out, type, name); + } else if (type->is_base_type() || type->is_enum()) { + indent(out) << name << " = input."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + out << (type->is_binary() ? "readBinary()" : "readString()"); + break; + case t_base_type::TYPE_BOOL: + out << "readBool()"; + break; + case t_base_type::TYPE_I8: + out << "readByte()"; + break; + case t_base_type::TYPE_I16: + out << "readI16()"; + break; + case t_base_type::TYPE_I32: + out << "readI32()"; + break; + case t_base_type::TYPE_I64: + out << "readI64()"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble()"; + break; + default: + throw "compiler error: no JS name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "readI32()"; + } + + if (!gen_node_) { + out << ".value"; + } + + out << ";" << endl; + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type->get_name().c_str()); + } +} + +/** + * Generates an unserializer for a variable. This makes two key assumptions, + * first that there is a const char* variable named data that points to the + * buffer for deserialization, and that there is a variable protocol which + * is a reference to a TProtocol serialization object. + */ +void t_js_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + out << indent() << prefix << " = new " << js_type_namespace(tstruct->get_program()) + << tstruct->get_name() << "();" << endl << indent() << prefix << ".read(input);" << endl; +} + +void t_js_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) { + string size = tmp("_size"); + string ktype = tmp("_ktype"); + string vtype = tmp("_vtype"); + string etype = tmp("_etype"); + string rtmp3 = tmp("_rtmp3"); + + t_field fsize(g_type_i32, size); + t_field fktype(g_type_i8, ktype); + t_field fvtype(g_type_i8, vtype); + t_field fetype(g_type_i8, etype); + + out << indent() << "var " << size << " = 0;" << endl; + out << indent() << "var " << rtmp3 << ";" << endl; + + // Declare variables, read header + if (ttype->is_map()) { + out << indent() << prefix << " = {};" << endl << indent() << "var " << ktype << " = 0;" << endl + << indent() << "var " << vtype << " = 0;" << endl; + + out << indent() << rtmp3 << " = input.readMapBegin();" << endl; + out << indent() << ktype << " = " << rtmp3 << ".ktype;" << endl; + out << indent() << vtype << " = " << rtmp3 << ".vtype;" << endl; + out << indent() << size << " = " << rtmp3 << ".size;" << endl; + + } else if (ttype->is_set()) { + + out << indent() << prefix << " = [];" << endl << indent() << "var " << etype << " = 0;" << endl + << indent() << rtmp3 << " = input.readSetBegin();" << endl << indent() << etype << " = " + << rtmp3 << ".etype;" << endl << indent() << size << " = " << rtmp3 << ".size;" << endl; + + } else if (ttype->is_list()) { + + out << indent() << prefix << " = [];" << endl << indent() << "var " << etype << " = 0;" << endl + << indent() << rtmp3 << " = input.readListBegin();" << endl << indent() << etype << " = " + << rtmp3 << ".etype;" << endl << indent() << size << " = " << rtmp3 << ".size;" << endl; + } + + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << "for (var " << i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl; + + scope_up(out); + + if (ttype->is_map()) { + if (!gen_node_) { + out << indent() << "if (" << i << " > 0 ) {" << endl << indent() + << " if (input.rstack.length > input.rpos[input.rpos.length -1] + 1) {" << endl + << indent() << " input.rstack.pop();" << endl << indent() << " }" << endl << indent() + << "}" << endl; + } + + generate_deserialize_map_element(out, (t_map*)ttype, prefix); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, prefix); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, prefix); + } + + scope_down(out); + + // Read container end + if (ttype->is_map()) { + indent(out) << "input.readMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "input.readSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "input.readListEnd();" << endl; + } +} + +/** + * Generates code to deserialize a map + */ +void t_js_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) { + string key = tmp("key"); + string val = tmp("val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + indent(out) << declare_field(&fkey, false, false) << ";" << endl; + indent(out) << declare_field(&fval, false, false) << ";" << endl; + + generate_deserialize_field(out, &fkey); + generate_deserialize_field(out, &fval); + + indent(out) << prefix << "[" << key << "] = " << val << ";" << endl; +} + +void t_js_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) { + string elem = tmp("elem"); + t_field felem(tset->get_elem_type(), elem); + + indent(out) << "var " << elem << " = null;" << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".push(" << elem << ");" << endl; +} + +void t_js_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix) { + string elem = tmp("elem"); + t_field felem(tlist->get_elem_type(), elem); + + indent(out) << "var " << elem << " = null;" << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".push(" << elem << ");" << endl; +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_js_generator::generate_serialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = get_true_type(tfield->get_type()); + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); + } else if (type->is_container()) { + generate_serialize_container(out, type, prefix + tfield->get_name()); + } else if (type->is_base_type() || type->is_enum()) { + + string name = tfield->get_name(); + + // Hack for when prefix is defined (always a hash ref) + if (!prefix.empty()) + name = prefix + tfield->get_name(); + + indent(out) << "output."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + out << (type->is_binary() ? "writeBinary(" : "writeString(") << name << ")"; + break; + case t_base_type::TYPE_BOOL: + out << "writeBool(" << name << ")"; + break; + case t_base_type::TYPE_I8: + out << "writeByte(" << name << ")"; + break; + case t_base_type::TYPE_I16: + out << "writeI16(" << name << ")"; + break; + case t_base_type::TYPE_I32: + out << "writeI32(" << name << ")"; + break; + case t_base_type::TYPE_I64: + out << "writeI64(" << name << ")"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble(" << name << ")"; + break; + default: + throw "compiler error: no JS name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "writeI32(" << name << ")"; + } + out << ";" << endl; + + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", + prefix.c_str(), + tfield->get_name().c_str(), + type->get_name().c_str()); + } +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_js_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + (void)tstruct; + indent(out) << prefix << ".write(output);" << endl; +} + +/** + * Writes out a container + */ +void t_js_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + if (ttype->is_map()) { + indent(out) << "output.writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " + << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " + << "Thrift.objectLength(" << prefix << "));" << endl; + } else if (ttype->is_set()) { + indent(out) << "output.writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " + << prefix << ".length);" << endl; + + } else if (ttype->is_list()) { + + indent(out) << "output.writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) + << ", " << prefix << ".length);" << endl; + } + + if (ttype->is_map()) { + string kiter = tmp("kiter"); + string viter = tmp("viter"); + indent(out) << "for (var " << kiter << " in " << prefix << ")" << endl; + scope_up(out); + indent(out) << "if (" << prefix << ".hasOwnProperty(" << kiter << "))" << endl; + scope_up(out); + indent(out) << "var " << viter << " = " << prefix << "[" << kiter << "];" << endl; + generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); + scope_down(out); + scope_down(out); + + } else if (ttype->is_set()) { + string iter = tmp("iter"); + indent(out) << "for (var " << iter << " in " << prefix << ")" << endl; + scope_up(out); + indent(out) << "if (" << prefix << ".hasOwnProperty(" << iter << "))" << endl; + scope_up(out); + indent(out) << iter << " = " << prefix << "[" << iter << "];" << endl; + generate_serialize_set_element(out, (t_set*)ttype, iter); + scope_down(out); + scope_down(out); + + } else if (ttype->is_list()) { + string iter = tmp("iter"); + indent(out) << "for (var " << iter << " in " << prefix << ")" << endl; + scope_up(out); + indent(out) << "if (" << prefix << ".hasOwnProperty(" << iter << "))" << endl; + scope_up(out); + indent(out) << iter << " = " << prefix << "[" << iter << "];" << endl; + generate_serialize_list_element(out, (t_list*)ttype, iter); + scope_down(out); + scope_down(out); + } + + if (ttype->is_map()) { + indent(out) << "output.writeMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "output.writeSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "output.writeListEnd();" << endl; + } +} + +/** + * Serializes the members of a map. + * + */ +void t_js_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string kiter, + string viter) { + t_field kfield(tmap->get_key_type(), kiter); + generate_serialize_field(out, &kfield); + + t_field vfield(tmap->get_val_type(), viter); + generate_serialize_field(out, &vfield); +} + +/** + * Serializes the members of a set. + */ +void t_js_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) { + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, &efield); +} + +/** + * Serializes the members of a list. + */ +void t_js_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) { + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, &efield); +} + +/** + * Declares a field, which may include initialization as necessary. + * + * @param ttype The type + */ +string t_js_generator::declare_field(t_field* tfield, bool init, bool obj) { + string result = "this." + tfield->get_name(); + + if (!obj) { + result = "var " + tfield->get_name(); + } + + if (init) { + t_type* type = get_true_type(tfield->get_type()); + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + break; + case t_base_type::TYPE_STRING: + case t_base_type::TYPE_BOOL: + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + case t_base_type::TYPE_DOUBLE: + result += " = null"; + break; + default: + throw "compiler error: no JS initializer for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + result += " = null"; + } else if (type->is_map()) { + result += " = null"; + } else if (type->is_container()) { + result += " = null"; + } else if (type->is_struct() || type->is_xception()) { + if (obj) { + result += " = new " + js_type_namespace(type->get_program()) + type->get_name() + "()"; + } else { + result += " = null"; + } + } + } else { + result += " = null"; + } + return result; +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_js_generator::function_signature(t_function* tfunction, + string prefix, + bool include_callback) { + + string str; + + str = prefix + tfunction->get_name() + " = function("; + + str += argument_list(tfunction->get_arglist(), include_callback); + + str += ")"; + return str; +} + +/** + * Renders a field list + */ +string t_js_generator::argument_list(t_struct* tstruct, bool include_callback) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + result += (*f_iter)->get_name(); + } + + if (include_callback) { + if (!fields.empty()) { + result += ", "; + } + result += "callback"; + } + + return result; +} + +/** + * Converts the parse type to a C++ enum string for the given type. + */ +string t_js_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "Thrift.Type.STRING"; + case t_base_type::TYPE_BOOL: + return "Thrift.Type.BOOL"; + case t_base_type::TYPE_I8: + return "Thrift.Type.BYTE"; + case t_base_type::TYPE_I16: + return "Thrift.Type.I16"; + case t_base_type::TYPE_I32: + return "Thrift.Type.I32"; + case t_base_type::TYPE_I64: + return "Thrift.Type.I64"; + case t_base_type::TYPE_DOUBLE: + return "Thrift.Type.DOUBLE"; + } + } else if (type->is_enum()) { + return "Thrift.Type.I32"; + } else if (type->is_struct() || type->is_xception()) { + return "Thrift.Type.STRUCT"; + } else if (type->is_map()) { + return "Thrift.Type.MAP"; + } else if (type->is_set()) { + return "Thrift.Type.SET"; + } else if (type->is_list()) { + return "Thrift.Type.LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** + * Converts a t_type to a TypeScript type (string). + * @param t_type Type to convert to TypeScript + * @return String TypeScript type + */ +string t_js_generator::ts_get_type(t_type* type) { + std::string ts_type; + + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + ts_type = "string"; + break; + case t_base_type::TYPE_BOOL: + ts_type = "boolean"; + break; + case t_base_type::TYPE_I8: + ts_type = "any"; + break; + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + case t_base_type::TYPE_DOUBLE: + ts_type = "number"; + break; + case t_base_type::TYPE_VOID: + ts_type = "void"; + } + } else if (type->is_enum() || type->is_struct() || type->is_xception()) { + std::string type_name; + if (type->get_program()) { + type_name = js_namespace(type->get_program()); + } + type_name.append(type->get_name()); + ts_type = type_name; + } else if (type->is_list() || type->is_set()) { + t_type* etype; + + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + + ts_type = ts_get_type(etype) + "[]"; + } else if (type->is_map()) { + string ktype = ts_get_type(((t_map*)type)->get_key_type()); + string vtype = ts_get_type(((t_map*)type)->get_val_type()); + + + if (ktype == "number" || ktype == "string" ) { + ts_type = "{ [k: " + ktype + "]: " + vtype + "; }"; + } else if ((((t_map*)type)->get_key_type())->is_enum()) { + // Not yet supported (enum map): https://github.com/Microsoft/TypeScript/pull/2652 + //ts_type = "{ [k: " + ktype + "]: " + vtype + "; }"; + ts_type = "{ [k: number /*" + ktype + "*/]: " + vtype + "; }"; + } else { + ts_type = "any"; + } + } + + return ts_type; +} + +/** + * Renders a TypeScript function signature of the form 'name(args: types): type;' + * + * @param t_function Function definition + * @param bool in-/exclude the callback argument + * @return String of rendered function definition + */ +std::string t_js_generator::ts_function_signature(t_function* tfunction, bool include_callback) { + string str; + const vector& fields = tfunction->get_arglist()->get_members(); + vector::const_iterator f_iter; + + str = tfunction->get_name() + "("; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + str += (*f_iter)->get_name() + ts_get_req(*f_iter) + ": " + ts_get_type((*f_iter)->get_type()); + + if (f_iter + 1 != fields.end() || (include_callback && fields.size() > 0)) { + str += ", "; + } + } + + if (include_callback) { + str += "callback: (data: " + ts_get_type(tfunction->get_returntype()) + ")=>void): "; + + if (gen_jquery_) { + str += "JQueryPromise<" + ts_get_type(tfunction->get_returntype()) +">;"; + } else { + str += "void;"; + } + } else { + str += "): " + ts_get_type(tfunction->get_returntype()) + ";"; + } + + return str; +} + +/** + * Takes a name and produces a valid NodeJS identifier from it + * + * @param name The name which shall become a valid NodeJS identifier + * @return The modified name with the updated identifier + */ +std::string t_js_generator::make_valid_nodeJs_identifier(std::string const& name) { + std::string str = name; + if (str.empty()) { + return str; + } + + // tests rely on this + assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9')); + + // if the first letter is a number, we add an additional underscore in front of it + char c = str.at(0); + if (('0' <= c) && (c <= '9')) { + str = "_" + str; + } + + // following chars: letter, number or underscore + for (size_t i = 0; i < str.size(); ++i) { + c = str.at(i); + if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9')) + && ('_' != c) && ('$' != c)) { + str.replace(i, 1, "_"); + } + } + + return str; +} + +THRIFT_REGISTER_GENERATOR(js, + "Javascript", + " jquery: Generate jQuery compatible code.\n" + " node: Generate node.js compatible code.\n" + " ts: Generate TypeScript definition files.\n" + " with_ns: Create global namespace objects when using node.js\n") diff --git a/compiler/cpp/src/thrift/generate/t_json_generator.cc b/compiler/cpp/src/thrift/generate/t_json_generator.cc new file mode 100644 index 0000000..153ec35 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_json_generator.cc @@ -0,0 +1,793 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_generator.h" + +using std::map; +using std::ofstream; +using std::ostream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; +using std::stack; + +static const string endl = "\n"; +static const string quot = "\""; +static const bool NO_INDENT = false; +static const bool FORCE_STRING = true; + +class t_json_generator : public t_generator { +public: + t_json_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + should_merge_includes_ = false; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("merge") == 0) { + should_merge_includes_ = true; + } else { + throw "unknown option json:" + iter->first; + } + } + + out_dir_base_ = "gen-json"; + } + + virtual ~t_json_generator() {} + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_program(); + void generate_function(t_function* tfunc); + void generate_field(t_field* field); + + void generate_service(t_service* tservice); + void generate_struct(t_struct* tstruct); + +private: + bool should_merge_includes_; + + std::ofstream f_json_; + std::stack comma_needed_; + + template + string number_to_string(T t) { + std::ostringstream out; + out.imbue(std::locale::classic()); + out.precision(std::numeric_limits::digits10); + out << t; + return out.str(); + } + + template + void write_number(T n) { + f_json_ << number_to_string(n); + } + + string get_type_name(t_type* ttype); + string get_qualified_name(t_type* ttype); + + void start_object(bool should_indent = true); + void start_array(); + void end_object(); + void end_array(); + void write_comma_if_needed(); + void indicate_comma_needed(); + string escape_json_string(const string& input); + string json_str(const string& str); + void merge_includes(t_program*); + + void generate_constant(t_const* con); + + void write_type_spec_entry(const char* name, t_type* ttype); + void write_type_spec_object(const char* name, t_type* ttype); + void write_type_spec(t_type* ttype); + void write_string(const string& value); + void write_value(t_type* tvalue); + void write_const_value(t_const_value* value, bool force_string = false); + void write_key_and(string key); + void write_key_and_string(string key, string val); + void write_key_and_integer(string key, int val); + void write_key_and_bool(string key, bool val); +}; + +void t_json_generator::init_generator() { + MKDIR(get_out_dir().c_str()); + + string f_json_name = get_out_dir() + program_->get_name() + ".json"; + f_json_.open(f_json_name.c_str()); + + // Merge all included programs into this one so we can output one big file. + if (should_merge_includes_) { + merge_includes(program_); + } +} + +string t_json_generator::escape_json_string(const string& input) { + std::ostringstream ss; + for (std::string::const_iterator iter = input.begin(); iter != input.end(); iter++) { + switch (*iter) { + case '\\': + ss << "\\\\"; + break; + case '"': + ss << "\\\""; + break; + case '/': + ss << "\\/"; + break; + case '\b': + ss << "\\b"; + break; + case '\f': + ss << "\\f"; + break; + case '\n': + ss << "\\n"; + break; + case '\r': + ss << "\\r"; + break; + case '\t': + ss << "\\t"; + break; + default: + ss << *iter; + break; + } + } + return ss.str(); +} + +void t_json_generator::start_object(bool should_indent) { + f_json_ << (should_indent ? indent() : "") << "{" << endl; + indent_up(); + comma_needed_.push(false); +} + +void t_json_generator::start_array() { + f_json_ << "[" << endl; + indent_up(); + comma_needed_.push(false); +} + +void t_json_generator::write_comma_if_needed() { + if (comma_needed_.top()) { + f_json_ << "," << endl; + } +} + +void t_json_generator::indicate_comma_needed() { + comma_needed_.pop(); + comma_needed_.push(true); +} + +void t_json_generator::write_key_and(string key) { + write_comma_if_needed(); + indent(f_json_) << json_str(key) << ": "; + indicate_comma_needed(); +} + +void t_json_generator::write_key_and_integer(string key, int val) { + write_comma_if_needed(); + indent(f_json_) << json_str(key) << ": " << number_to_string(val); + indicate_comma_needed(); +} + +void t_json_generator::write_key_and_string(string key, string val) { + write_comma_if_needed(); + indent(f_json_) << json_str(key) << ": " << json_str(val); + indicate_comma_needed(); +} + +void t_json_generator::write_key_and_bool(string key, bool val) { + write_comma_if_needed(); + indent(f_json_) << json_str(key) << ": " << (val ? "true" : "false"); + indicate_comma_needed(); +} + +void t_json_generator::end_object() { + indent_down(); + f_json_ << endl << indent() << "}"; + comma_needed_.pop(); +} + +void t_json_generator::end_array() { + indent_down(); + if (comma_needed_.top()) { + f_json_ << endl; + } + indent(f_json_) << "]"; + comma_needed_.pop(); +} + +void t_json_generator::write_type_spec_object(const char* name, t_type* ttype) { + ttype = ttype->get_true_type(); + if (ttype->is_struct() || ttype->is_xception() || ttype->is_container()) { + write_key_and(name); + start_object(NO_INDENT); + write_key_and("typeId"); + write_type_spec(ttype); + end_object(); + } +} + +void t_json_generator::write_type_spec_entry(const char* name, t_type* ttype) { + write_key_and(name); + write_type_spec(ttype); +} + +void t_json_generator::write_type_spec(t_type* ttype) { + ttype = ttype->get_true_type(); + + write_string(get_type_name(ttype)); + + if (ttype->annotations_.size() > 0) { + write_key_and("annotations"); + start_object(); + for (map::iterator it = ttype->annotations_.begin(); it != ttype->annotations_.end(); ++it) { + write_key_and_string(it->first, it->second); + } + end_object(); + } + + if (ttype->is_struct() || ttype->is_xception()) { + write_key_and_string("class", get_qualified_name(ttype)); + } else if (ttype->is_map()) { + t_type* ktype = ((t_map*)ttype)->get_key_type(); + t_type* vtype = ((t_map*)ttype)->get_val_type(); + write_key_and_string("keyTypeId", get_type_name(ktype)); + write_key_and_string("valueTypeId", get_type_name(vtype)); + write_type_spec_object("keyType", ktype); + write_type_spec_object("valueType", vtype); + } else if (ttype->is_list()) { + t_type* etype = ((t_list*)ttype)->get_elem_type(); + write_key_and_string("elemTypeId", get_type_name(etype)); + write_type_spec_object("elemType", etype); + } else if (ttype->is_set()) { + t_type* etype = ((t_set*)ttype)->get_elem_type(); + write_key_and_string("elemTypeId", get_type_name(etype)); + write_type_spec_object("elemType", etype); + } +} + +void t_json_generator::close_generator() { + f_json_ << endl; + f_json_.close(); +} + +void t_json_generator::merge_includes(t_program* program) { + vector includes = program->get_includes(); + vector::iterator inc_iter; + for (inc_iter = includes.begin(); inc_iter != includes.end(); ++inc_iter) { + t_program* include = *inc_iter; + // recurse in case we get crazy + merge_includes(include); + // merge enums + vector enums = include->get_enums(); + vector::iterator en_iter; + for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { + program->add_enum(*en_iter); + } + // merge typedefs + vector typedefs = include->get_typedefs(); + vector::iterator td_iter; + for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { + program->add_typedef(*td_iter); + } + // merge structs + vector objects = include->get_objects(); + vector::iterator o_iter; + for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { + program->add_struct(*o_iter); + } + // merge constants + vector consts = include->get_consts(); + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + program->add_const(*c_iter); + } + + // merge services + vector services = include->get_services(); + vector::iterator sv_iter; + for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { + program->add_service(*sv_iter); + } + } +} + +void t_json_generator::generate_program() { + + init_generator(); + + start_object(); + write_key_and_string("name", program_->get_name()); + if (program_->has_doc()) { + write_key_and_string("doc", program_->get_doc()); + } + + // When merging includes, the "namespaces" and "includes" sections + // become ambiguous, so just skip them. + if (!should_merge_includes_) { + // Generate namespaces + write_key_and("namespaces"); + start_object(NO_INDENT); + const map& namespaces = program_->get_namespaces(); + map::const_iterator ns_it; + for (ns_it = namespaces.begin(); ns_it != namespaces.end(); ++ns_it) { + write_key_and_string(ns_it->first, ns_it->second); + indicate_comma_needed(); + } + end_object(); + + // Generate includes + write_key_and("includes"); + start_array(); + const vector includes = program_->get_includes(); + vector::const_iterator inc_it; + for (inc_it = includes.begin(); inc_it != includes.end(); ++inc_it) { + write_comma_if_needed(); + write_string((*inc_it)->get_name()); + indicate_comma_needed(); + } + end_array(); + } + + // Generate enums + write_key_and("enums"); + start_array(); + vector enums = program_->get_enums(); + vector::iterator en_iter; + for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { + write_comma_if_needed(); + generate_enum(*en_iter); + indicate_comma_needed(); + } + end_array(); + + // Generate typedefs + write_key_and("typedefs"); + start_array(); + vector typedefs = program_->get_typedefs(); + vector::iterator td_iter; + for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { + write_comma_if_needed(); + generate_typedef(*td_iter); + indicate_comma_needed(); + } + end_array(); + + // Generate structs, exceptions, and unions in declared order + write_key_and("structs"); + start_array(); + vector objects = program_->get_objects(); + vector::iterator o_iter; + for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { + write_comma_if_needed(); + if ((*o_iter)->is_xception()) { + generate_xception(*o_iter); + } else { + generate_struct(*o_iter); + } + indicate_comma_needed(); + } + end_array(); + + // Generate constants + write_key_and("constants"); + start_array(); + vector consts = program_->get_consts(); + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + write_comma_if_needed(); + generate_constant(*c_iter); + indicate_comma_needed(); + } + end_array(); + + // Generate services + write_key_and("services"); + start_array(); + vector services = program_->get_services(); + vector::iterator sv_iter; + for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { + write_comma_if_needed(); + generate_service(*sv_iter); + indicate_comma_needed(); + } + end_array(); + + end_object(); + + // Close the generator + close_generator(); +} + +void t_json_generator::generate_typedef(t_typedef* ttypedef) { + start_object(); + write_key_and_string("name", get_qualified_name(ttypedef)); + write_key_and_string("typeId", get_type_name(ttypedef->get_true_type())); + write_type_spec_object("type", ttypedef->get_true_type()); + if (ttypedef->has_doc()) { + write_key_and_string("doc", ttypedef->get_doc()); + } + if (ttypedef->annotations_.size() > 0) { + write_key_and("annotations"); + start_object(); + for (map::iterator it = ttypedef->annotations_.begin(); it != ttypedef->annotations_.end(); ++it) { + write_key_and_string(it->first, it->second); + } + end_object(); + } + end_object(); +} + +void t_json_generator::write_string(const string& value) { + f_json_ << quot << escape_json_string(value) << quot; +} + +void t_json_generator::write_const_value(t_const_value* value, bool should_force_string) { + + switch (value->get_type()) { + + case t_const_value::CV_IDENTIFIER: + case t_const_value::CV_INTEGER: + if (should_force_string) { + write_string(number_to_string(value->get_integer())); + } else { + write_number(value->get_integer()); + } + break; + + case t_const_value::CV_DOUBLE: + if (should_force_string) { + write_string(number_to_string(value->get_double())); + } else { + write_number(value->get_double()); + } + break; + + case t_const_value::CV_STRING: + write_string(value->get_string()); + break; + + case t_const_value::CV_LIST: { + start_array(); + std::vector list = value->get_list(); + std::vector::iterator lit; + for (lit = list.begin(); lit != list.end(); ++lit) { + write_comma_if_needed(); + f_json_ << indent(); + write_const_value(*lit); + indicate_comma_needed(); + } + end_array(); + break; + } + + case t_const_value::CV_MAP: { + start_object(NO_INDENT); + std::map map = value->get_map(); + std::map::iterator mit; + for (mit = map.begin(); mit != map.end(); ++mit) { + write_comma_if_needed(); + f_json_ << indent(); + // JSON objects only allow string keys + write_const_value(mit->first, FORCE_STRING); + f_json_ << ": "; + write_const_value(mit->second); + indicate_comma_needed(); + } + end_object(); + break; + } + + default: + f_json_ << "null"; + break; + } +} + +string t_json_generator::json_str(const string& str) { + return quot + escape_json_string(str) + quot; +} + +void t_json_generator::generate_constant(t_const* con) { + start_object(); + + write_key_and_string("name", con->get_name()); + write_key_and_string("typeId", get_type_name(con->get_type())); + write_type_spec_object("type", con->get_type()); + + if (con->has_doc()) { + write_key_and_string("doc", con->get_doc()); + } + + write_key_and("value"); + write_const_value(con->get_value()); + + end_object(); +} + +void t_json_generator::generate_enum(t_enum* tenum) { + start_object(); + + write_key_and_string("name", tenum->get_name()); + + if (tenum->has_doc()) { + write_key_and_string("doc", tenum->get_doc()); + } + + if (tenum->annotations_.size() > 0) { + write_key_and("annotations"); + start_object(); + for (map::iterator it = tenum->annotations_.begin(); it != tenum->annotations_.end(); ++it) { + write_key_and_string(it->first, it->second); + } + end_object(); + } + + write_key_and("members"); + start_array(); + vector values = tenum->get_constants(); + vector::iterator val_iter; + for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) { + write_comma_if_needed(); + t_enum_value* val = (*val_iter); + start_object(); + write_key_and_string("name", val->get_name()); + write_key_and_integer("value", val->get_value()); + if (val->has_doc()) { + write_key_and_string("doc", val->get_doc()); + } + end_object(); + indicate_comma_needed(); + } + end_array(); + + end_object(); +} + +void t_json_generator::generate_struct(t_struct* tstruct) { + start_object(); + + write_key_and_string("name", tstruct->get_name()); + + if (tstruct->has_doc()) { + write_key_and_string("doc", tstruct->get_doc()); + } + + if (tstruct->annotations_.size() > 0) { + write_key_and("annotations"); + start_object(); + for (map::iterator it = tstruct->annotations_.begin(); it != tstruct->annotations_.end(); ++it) { + write_key_and_string(it->first, it->second); + } + end_object(); + } + + write_key_and_bool("isException", tstruct->is_xception()); + + write_key_and_bool("isUnion", tstruct->is_union()); + + write_key_and("fields"); + start_array(); + vector members = tstruct->get_members(); + vector::iterator mem_iter; + for (mem_iter = members.begin(); mem_iter != members.end(); mem_iter++) { + write_comma_if_needed(); + generate_field(*mem_iter); + indicate_comma_needed(); + } + end_array(); + + end_object(); +} + +void t_json_generator::generate_service(t_service* tservice) { + start_object(); + + write_key_and_string("name", get_qualified_name(tservice)); + + if (tservice->get_extends()) { + write_key_and_string("extends", get_qualified_name(tservice->get_extends())); + } + + if (tservice->has_doc()) { + write_key_and_string("doc", tservice->get_doc()); + } + + if (tservice->annotations_.size() > 0) { + write_key_and("annotations"); + start_object(); + for (map::iterator it = tservice->annotations_.begin(); it != tservice->annotations_.end(); ++it) { + write_key_and_string(it->first, it->second); + } + end_object(); + } + + write_key_and("functions"); + start_array(); + vector functions = tservice->get_functions(); + vector::iterator fn_iter = functions.begin(); + for (; fn_iter != functions.end(); fn_iter++) { + write_comma_if_needed(); + generate_function(*fn_iter); + indicate_comma_needed(); + } + end_array(); + + end_object(); +} + +void t_json_generator::generate_function(t_function* tfunc) { + start_object(); + + write_key_and_string("name", tfunc->get_name()); + + write_key_and_string("returnTypeId", get_type_name(tfunc->get_returntype())); + write_type_spec_object("returnType", tfunc->get_returntype()); + + write_key_and_bool("oneway", tfunc->is_oneway()); + + if (tfunc->has_doc()) { + write_key_and_string("doc", tfunc->get_doc()); + } + + if (tfunc->annotations_.size() > 0) { + write_key_and("annotations"); + start_object(); + for (map::iterator it = tfunc->annotations_.begin(); it != tfunc->annotations_.end(); ++it) { + write_key_and_string(it->first, it->second); + } + end_object(); + } + + write_key_and("arguments"); + start_array(); + vector members = tfunc->get_arglist()->get_members(); + vector::iterator mem_iter = members.begin(); + for (; mem_iter != members.end(); mem_iter++) { + write_comma_if_needed(); + generate_field(*mem_iter); + indicate_comma_needed(); + } + end_array(); + + write_key_and("exceptions"); + start_array(); + vector excepts = tfunc->get_xceptions()->get_members(); + vector::iterator ex_iter = excepts.begin(); + for (; ex_iter != excepts.end(); ex_iter++) { + write_comma_if_needed(); + generate_field(*ex_iter); + indicate_comma_needed(); + } + end_array(); + + end_object(); +} + +void t_json_generator::generate_field(t_field* field) { + start_object(); + + write_key_and_integer("key", field->get_key()); + write_key_and_string("name", field->get_name()); + write_key_and_string("typeId", get_type_name(field->get_type())); + write_type_spec_object("type", field->get_type()); + + if (field->has_doc()) { + write_key_and_string("doc", field->get_doc()); + } + + if (field->annotations_.size() > 0) { + write_key_and("annotations"); + start_object(); + for (map::iterator it = field->annotations_.begin(); it != field->annotations_.end(); ++it) { + write_key_and_string(it->first, it->second); + } + end_object(); + } + + write_key_and("required"); + switch (field->get_req()) { + case t_field::T_REQUIRED: + write_string("required"); + break; + case t_field::T_OPT_IN_REQ_OUT: + write_string("req_out"); + break; + default: + write_string("optional"); + break; + } + + if (field->get_value()) { + write_key_and("default"); + write_const_value(field->get_value()); + } + + end_object(); +} + +string t_json_generator::get_type_name(t_type* ttype) { + ttype = ttype->get_true_type(); + if (ttype->is_list()) { + return "list"; + } + if (ttype->is_set()) { + return "set"; + } + if (ttype->is_map()) { + return "map"; + } + if (ttype->is_enum()) { + return "i32"; + } + if (ttype->is_struct()) { + return ((t_struct*)ttype)->is_union() ? "union" : "struct"; + } + if (ttype->is_xception()) { + return "exception"; + } + if (ttype->is_base_type()) { + t_base_type* tbasetype = (t_base_type*)ttype; + return tbasetype->is_binary() ? "binary" : t_base_type::t_base_name(tbasetype->get_base()); + } + + return "(unknown)"; +} + +string t_json_generator::get_qualified_name(t_type* ttype) { + if (should_merge_includes_ || ttype->get_program() == program_) { + return ttype->get_name(); + } + return ttype->get_program()->get_name() + "." + ttype->get_name(); +} + +THRIFT_REGISTER_GENERATOR(json, + "JSON", + " merge: Generate output with included files merged\n") diff --git a/compiler/cpp/src/thrift/generate/t_lua_generator.cc b/compiler/cpp/src/thrift/generate/t_lua_generator.cc new file mode 100644 index 0000000..92e6749 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_lua_generator.cc @@ -0,0 +1,1138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::ofstream; +using std::string; +using std::vector; +using std::map; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * LUA code generator. + * + */ +class t_lua_generator : public t_oop_generator { +public: + t_lua_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + gen_requires_ = true; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("omit_requires") == 0) { + gen_requires_ = false; + } else { + throw "unknown option lua:" + iter->first; + } + } + + out_dir_base_ = "gen-lua"; + } + + /** + * Init and close methods + */ + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + std::string render_const_value(t_type* type, t_const_value* value); + +private: + /** + * True iff we should generate lua require statements. + */ + bool gen_requires_; + + /** + * Struct-level generation functions + */ + void generate_lua_struct_definition(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false); + void generate_lua_struct_reader(std::ofstream& out, t_struct* tstruct); + void generate_lua_struct_writer(std::ofstream& out, t_struct* tstruct); + + /** + * Service-level generation functions + */ + void generate_service_client(std::ofstream& out, t_service* tservice); + void generate_service_interface(std::ofstream& out, t_service* tservice); + void generate_service_processor(std::ofstream& out, t_service* tservice); + void generate_process_function(std::ofstream& out, t_service* tservice, t_function* tfunction); + void generate_service_helpers(ofstream& out, t_service* tservice); + void generate_function_helpers(ofstream& out, t_function* tfunction); + + /** + * Deserialization (Read) + */ + void generate_deserialize_field(std::ofstream& out, + t_field* tfield, + bool local, + std::string prefix = ""); + + void generate_deserialize_struct(std::ofstream& out, + t_struct* tstruct, + bool local, + std::string prefix = ""); + + void generate_deserialize_container(std::ofstream& out, + t_type* ttype, + bool local, + std::string prefix = ""); + + void generate_deserialize_set_element(std::ofstream& out, t_set* tset, std::string prefix = ""); + + void generate_deserialize_map_element(std::ofstream& out, t_map* tmap, std::string prefix = ""); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix = ""); + + /** + * Serialization (Write) + */ + void generate_serialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string kiter, + std::string viter); + + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + + /** + * Helper rendering functions + */ + std::string lua_includes(); + std::string function_signature(t_function* tfunction, std::string prefix = ""); + std::string argument_list(t_struct* tstruct, std::string prefix = ""); + std::string type_to_enum(t_type* ttype); + static std::string get_namespace(const t_program* program); + + std::string autogen_comment() { + return std::string("--\n") + "-- Autogenerated by Thrift\n" + "--\n" + + "-- DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "-- @" + "generated\n" + + "--\n"; + } + + /** + * File streams + */ + std::ofstream f_types_; + std::ofstream f_consts_; + std::ofstream f_service_; +}; + +/** + * Init and close methods + */ +void t_lua_generator::init_generator() { + // Make output directory + string outdir = get_out_dir(); + MKDIR(outdir.c_str()); + + // Make output files + string cur_namespace = get_namespace(program_); + string f_consts_name = outdir + cur_namespace + "constants.lua"; + f_consts_.open(f_consts_name.c_str()); + string f_types_name = outdir + cur_namespace + "ttypes.lua"; + f_types_.open(f_types_name.c_str()); + + // Add headers + f_consts_ << autogen_comment() << lua_includes(); + f_types_ << autogen_comment() << lua_includes(); + if (gen_requires_) { + f_types_ << endl << "require '" << cur_namespace << "constants'"; + } +} + +void t_lua_generator::close_generator() { + // Close types file + f_types_.close(); + f_consts_.close(); +} + +/** + * Generate a typedef (essentially a constant) + */ +void t_lua_generator::generate_typedef(t_typedef* ttypedef) { + f_types_ << endl << endl << indent() << ttypedef->get_symbolic() << " = " + << ttypedef->get_type()->get_name(); +} + +/** + * Generates code for an enumerated type (table) + */ +void t_lua_generator::generate_enum(t_enum* tenum) { + f_types_ << endl << endl << tenum->get_name() << " = {" << endl; + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end();) { + int32_t value = (*c_iter)->get_value(); + + f_types_ << " " << (*c_iter)->get_name() << " = " << value; + ++c_iter; + if (c_iter != constants.end()) { + f_types_ << ","; + } + f_types_ << endl; + } + f_types_ << "}"; +} + +/** + * Generate a constant (non-local) value + */ +void t_lua_generator::generate_const(t_const* tconst) { + t_type* type = tconst->get_type(); + string name = tconst->get_name(); + t_const_value* value = tconst->get_value(); + + f_consts_ << endl << endl << name << " = "; + f_consts_ << render_const_value(type, value); +} + +/** + * Prints the value of a constant with the given type. + */ +string t_lua_generator::render_const_value(t_type* type, t_const_value* value) { + std::ostringstream out; + + type = get_true_type(type); + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + out << "'" << value->get_string() << "'"; + break; + case t_base_type::TYPE_BOOL: + out << (value->get_integer() > 0 ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + out << value->get_integer(); + break; + case t_base_type::TYPE_I64: + out << "lualongnumber.new('" << value->get_string() << "')"; + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + out << value->get_integer(); + } else { + out << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << value->get_integer(); + } else if (type->is_struct() || type->is_xception()) { + out << type->get_name() << " = {" << endl; + indent_up(); + + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end();) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + + indent(out); + out << render_const_value(g_type_string, v_iter->first); + out << " = "; + out << render_const_value(field_type, v_iter->second); + ++v_iter; + if (v_iter != val.end()) { + out << ","; + } + } + + out << "}"; + indent_down(); + } else if (type->is_map()) { + out << type->get_name() << "{" << endl; + indent_up(); + + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end();) { + indent(out) << "[" << render_const_value(ktype, v_iter->first) + << "] = " << render_const_value(vtype, v_iter->second); + ++v_iter; + if (v_iter != val.end()) { + out << ","; + } + out << endl; + } + indent_down(); + indent(out) << "}"; + } else if (type->is_list() || type->is_set()) { + t_type* etype; + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + out << type->get_name() << " = {" << endl; + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end();) { + indent(out); + out << "[" << render_const_value(etype, *v_iter) << "]"; + if (type->is_set()) { + out << " = true"; + } else { + out << " = false"; + } + ++v_iter; + if (v_iter != val.end()) { + out << "," << endl; + } + } + out << "}"; + } + return out.str(); +} + +/** + * Generate a thrift struct + */ +void t_lua_generator::generate_struct(t_struct* tstruct) { + generate_lua_struct_definition(f_types_, tstruct, false); +} + +/** + * Generate a thrift exception + */ +void t_lua_generator::generate_xception(t_struct* txception) { + generate_lua_struct_definition(f_types_, txception, true); +} + +/** + * Generate a thrift struct or exception (lua table) + */ +void t_lua_generator::generate_lua_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception) { + vector::const_iterator m_iter; + const vector& members = tstruct->get_members(); + + indent(out) << endl << endl << tstruct->get_name(); + if (is_exception) { + out << " = TException:new{" << endl << indent() << " __type = '" << tstruct->get_name() << "'"; + if (members.size() > 0) { + out << ","; + } + out << endl; + } else { + out << " = __TObject:new{" << endl; + } + indent_up(); + for (m_iter = members.begin(); m_iter != members.end();) { + indent(out); + out << (*m_iter)->get_name(); + ++m_iter; + if (m_iter != members.end()) { + out << "," << endl; + } + } + indent_down(); + indent(out); + out << endl << "}"; + + generate_lua_struct_reader(out, tstruct); + generate_lua_struct_writer(out, tstruct); +} + +/** + * Generate a struct/exception reader + */ +void t_lua_generator::generate_lua_struct_reader(ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // function + indent(out) << endl << endl << "function " << tstruct->get_name() << ":read(iprot)" << endl; + indent_up(); + + indent(out) << "iprot:readStructBegin()" << endl; + + // while: Read in fields + indent(out) << "while true do" << endl; + indent_up(); + + // if: Check what to read + indent(out) << "local fname, ftype, fid = iprot:readFieldBegin()" << endl; + indent(out) << "if ftype == TType.STOP then" << endl; + indent_up(); + indent(out) << "break" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent_down(); + indent(out) << "elseif fid == " << (*f_iter)->get_key() << " then" << endl; + indent_up(); + indent(out) << "if ftype == " << type_to_enum((*f_iter)->get_type()) << " then" << endl; + indent_up(); + + // Read field contents + generate_deserialize_field(out, *f_iter, false, "self."); + + indent_down(); + indent(out) << "else" << endl; + indent(out) << " iprot:skip(ftype)" << endl; + indent(out) << "end" << endl; + } + + // end if + indent_down(); + indent(out) << "else" << endl; + indent(out) << " iprot:skip(ftype)" << endl; + indent(out) << "end" << endl; + indent(out) << "iprot:readFieldEnd()" << endl; + + // end while + indent_down(); + indent(out) << "end" << endl; + indent(out) << "iprot:readStructEnd()" << endl; + + // end function + indent_down(); + indent(out); + out << "end"; +} + +/** + * Generate a struct/exception writer + */ +void t_lua_generator::generate_lua_struct_writer(ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // function + indent(out) << endl << endl << "function " << tstruct->get_name() << ":write(oprot)" << endl; + indent_up(); + + indent(out) << "oprot:writeStructBegin('" << tstruct->get_name() << "')" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + // To check element of self whether nil or not. + // avoid the value(false) of BOOL is lost. + indent(out) << "if self." << (*f_iter)->get_name() << " ~= nil then" << endl; + indent_up(); + indent(out) << "oprot:writeFieldBegin('" << (*f_iter)->get_name() << "', " + << type_to_enum((*f_iter)->get_type()) << ", " << (*f_iter)->get_key() << ")" + << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "self."); + + indent(out) << "oprot:writeFieldEnd()" << endl; + indent_down(); + indent(out) << "end" << endl; + } + indent(out) << "oprot:writeFieldStop()" << endl; + indent(out) << "oprot:writeStructEnd()" << endl; + + // end function + indent_down(); + indent(out); + out << "end"; +} + +/** + * Generate a thrift service + */ +void t_lua_generator::generate_service(t_service* tservice) { + // Get output directory + string outdir = get_out_dir(); + + // Open the file for writing + string cur_ns = get_namespace(program_); + string f_service_name = outdir + cur_ns + tservice->get_name() + ".lua"; + f_service_.open(f_service_name.c_str()); + + // Headers + f_service_ << autogen_comment() << lua_includes(); + if (gen_requires_) { + f_service_ << endl << "require '" << cur_ns << "ttypes'" << endl; + + if (tservice->get_extends() != NULL) { + f_service_ << "require '" << get_namespace(tservice->get_extends()->get_program()) + << tservice->get_extends()->get_name() << "'" << endl; + } + } + + f_service_ << endl; + + generate_service_client(f_service_, tservice); + generate_service_interface(f_service_, tservice); + generate_service_processor(f_service_, tservice); + generate_service_helpers(f_service_, tservice); + + // Close the file + f_service_.close(); +} + +void t_lua_generator::generate_service_interface(ofstream& out, t_service* tservice) { + string classname = tservice->get_name() + "Iface"; + t_service* extends_s = tservice->get_extends(); + + // Interface object definition + out << classname << " = "; + if (extends_s) { + out << extends_s->get_name() << "Iface:new{" << endl; + } else { + out << "__TObject:new{" << endl; + } + out << " __type = '" << classname << "'" << endl << "}" << endl << endl; +} + +void t_lua_generator::generate_service_client(ofstream& out, t_service* tservice) { + string classname = tservice->get_name() + "Client"; + t_service* extends_s = tservice->get_extends(); + + // Client object definition + out << classname << " = __TObject.new("; + if (extends_s != NULL) { + out << extends_s->get_name() << "Client"; + } else { + out << "__TClient"; + } + out << ", {" << endl << " __type = '" << classname << "'" << endl << "})" << endl; + + // Send/Recv functions + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string sig = function_signature(*f_iter); + string funcname = (*f_iter)->get_name(); + + // Wrapper function + indent(out) << endl << "function " << classname << ":" << sig << endl; + indent_up(); + + indent(out) << "self:send_" << sig << endl << indent(); + if (!(*f_iter)->is_oneway()) { + if (!(*f_iter)->get_returntype()->is_void()) { + out << "return "; + } + out << "self:recv_" << sig << endl; + } + + indent_down(); + indent(out) << "end" << endl; + + // Send function + indent(out) << endl << "function " << classname << ":send_" << sig << endl; + indent_up(); + + indent(out) << "self.oprot:writeMessageBegin('" << funcname << "', " + << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL") + << ", self._seqid)" << endl; + indent(out) << "local args = " << funcname << "_args:new{}" << endl; + + // Set the args + const vector& args = (*f_iter)->get_arglist()->get_members(); + vector::const_iterator fld_iter; + for (fld_iter = args.begin(); fld_iter != args.end(); ++fld_iter) { + std::string argname = (*fld_iter)->get_name(); + indent(out) << "args." << argname << " = " << argname << endl; + } + + indent(out) << "args:write(self.oprot)" << endl; + indent(out) << "self.oprot:writeMessageEnd()" << endl; + indent(out) << "self.oprot.trans:flush()" << endl; + + indent_down(); + indent(out) << "end" << endl; + + // Recv function + if (!(*f_iter)->is_oneway()) { + indent(out) << endl << "function " << classname << ":recv_" << sig << endl; + indent_up(); + + out << indent() << "local fname, mtype, rseqid = self.iprot:" + << "readMessageBegin()" << endl << indent() << "if mtype == TMessageType.EXCEPTION then" + << endl << indent() << " local x = TApplicationException:new{}" << endl << indent() + << " x:read(self.iprot)" << endl << indent() << " self.iprot:readMessageEnd()" << endl + << indent() << " error(x)" << endl << indent() << "end" << endl << indent() + << "local result = " << funcname << "_result:new{}" << endl << indent() + << "result:read(self.iprot)" << endl << indent() << "self.iprot:readMessageEnd()" << endl; + + // Return the result if it's not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + out << indent() << "if result.success ~= nil then" << endl << indent() << " return result.success" + << endl; + + // Throw custom exceptions + const std::vector& xf = (*f_iter)->get_xceptions()->get_members(); + vector::const_iterator x_iter; + for (x_iter = xf.begin(); x_iter != xf.end(); ++x_iter) { + out << indent() << "elseif result." << (*x_iter)->get_name() << " then" << endl + << indent() << " error(result." << (*x_iter)->get_name() << ")" << endl; + } + + out << indent() << "end" << endl << indent() + << "error(TApplicationException:new{errorCode = " + << "TApplicationException.MISSING_RESULT})" << endl; + } + + indent_down(); + indent(out) << "end" << endl; + } + } +} + +void t_lua_generator::generate_service_processor(ofstream& out, t_service* tservice) { + string classname = tservice->get_name() + "Processor"; + t_service* extends_s = tservice->get_extends(); + + // Define processor table + out << endl << classname << " = __TObject.new("; + if (extends_s != NULL) { + out << extends_s->get_name() << "Processor" << endl; + } else { + out << "__TProcessor" << endl; + } + out << ", {" << endl << " __type = '" << classname << "'" << endl << "})" << endl; + + // Process function + indent(out) << endl << "function " << classname << ":process(iprot, oprot, server_ctx)" << endl; + indent_up(); + + indent(out) << "local name, mtype, seqid = iprot:readMessageBegin()" << endl; + indent(out) << "local func_name = 'process_' .. name" << endl; + indent(out) << "if not self[func_name] or ttype(self[func_name]) ~= 'function' then"; + indent_up(); + out << endl << indent() << "iprot:skip(TType.STRUCT)" << endl << indent() + << "iprot:readMessageEnd()" << endl << indent() << "x = TApplicationException:new{" << endl + << indent() << " errorCode = TApplicationException.UNKNOWN_METHOD" << endl << indent() << "}" + << endl << indent() << "oprot:writeMessageBegin(name, TMessageType.EXCEPTION, " + << "seqid)" << endl << indent() << "x:write(oprot)" << endl << indent() + << "oprot:writeMessageEnd()" << endl << indent() << "oprot.trans:flush()" << endl; + indent_down(); + indent(out) << "else" << endl << indent() + << " self[func_name](self, seqid, iprot, oprot, server_ctx)" << endl << indent() + << "end" << endl; + + indent_down(); + indent(out) << "end" << endl; + + // Generate the process subfunctions + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(out, tservice, *f_iter); + } +} + +void t_lua_generator::generate_process_function(ofstream& out, + t_service* tservice, + t_function* tfunction) { + string classname = tservice->get_name() + "Processor"; + string argsname = tfunction->get_name() + "_args"; + string resultname = tfunction->get_name() + "_result"; + string fn_name = tfunction->get_name(); + + indent(out) << endl << "function " << classname << ":process_" << fn_name + << "(seqid, iprot, oprot, server_ctx)" << endl; + indent_up(); + + // Read the request + out << indent() << "local args = " << argsname << ":new{}" << endl << indent() + << "local reply_type = TMessageType.REPLY" << endl << indent() << "args:read(iprot)" << endl + << indent() << "iprot:readMessageEnd()" << endl << indent() << "local result = " << resultname + << ":new{}" << endl << indent() << "local status, res = pcall(self.handler." << fn_name + << ", self.handler"; + + // Print arguments + t_struct* args = tfunction->get_arglist(); + if (args->get_members().size() > 0) { + out << ", " << argument_list(args, "args."); + } + + // Check for errors + out << ")" << endl << indent() << "if not status then" << endl << indent() + << " reply_type = TMessageType.EXCEPTION" << endl << indent() + << " result = TApplicationException:new{message = res}" << endl; + + // Handle custom exceptions + const std::vector& xf = tfunction->get_xceptions()->get_members(); + if (xf.size() > 0) { + vector::const_iterator x_iter; + for (x_iter = xf.begin(); x_iter != xf.end(); ++x_iter) { + out << indent() << "elseif ttype(res) == '" << (*x_iter)->get_type()->get_name() << "' then" + << endl << indent() << " result." << (*x_iter)->get_name() << " = res" << endl; + } + } + + // Set the result and write the reply + out << indent() << "else" << endl << indent() << " result.success = res" << endl << indent() + << "end" << endl << indent() << "oprot:writeMessageBegin('" << fn_name << "', reply_type, " + << "seqid)" << endl << indent() << "result:write(oprot)" << endl << indent() + << "oprot:writeMessageEnd()" << endl << indent() << "oprot.trans:flush()" << endl; + + indent_down(); + indent(out) << "end" << endl; +} + +// Service helpers +void t_lua_generator::generate_service_helpers(ofstream& out, t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + out << endl << "-- HELPER FUNCTIONS AND STRUCTURES"; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_lua_struct_definition(out, ts, false); + generate_function_helpers(out, *f_iter); + } +} + +void t_lua_generator::generate_function_helpers(ofstream& out, t_function* tfunction) { + if (!tfunction->is_oneway()) { + t_struct result(program_, tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + generate_lua_struct_definition(out, &result, false); + } +} + +/** + * Deserialize (Read) + */ +void t_lua_generator::generate_deserialize_field(ofstream& out, + t_field* tfield, + bool local, + string prefix) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = prefix + tfield->get_name(); + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, local, name); + } else if (type->is_container()) { + generate_deserialize_container(out, type, local, name); + } else if (type->is_base_type() || type->is_enum()) { + indent(out) << (local ? "local " : "") << name << " = iprot:"; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + out << "readString()"; + break; + case t_base_type::TYPE_BOOL: + out << "readBool()"; + break; + case t_base_type::TYPE_I8: + out << "readByte()"; + break; + case t_base_type::TYPE_I16: + out << "readI16()"; + break; + case t_base_type::TYPE_I32: + out << "readI32()"; + break; + case t_base_type::TYPE_I64: + out << "readI64()"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble()"; + break; + default: + throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "readI32()"; + } + out << endl; + + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type->get_name().c_str()); + } +} + +void t_lua_generator::generate_deserialize_struct(ofstream& out, + t_struct* tstruct, + bool local, + string prefix) { + indent(out) << (local ? "local " : "") << prefix << " = " << tstruct->get_name() << ":new{}" + << endl << indent() << prefix << ":read(iprot)" << endl; +} + +void t_lua_generator::generate_deserialize_container(ofstream& out, + t_type* ttype, + bool local, + string prefix) { + string size = tmp("_size"); + string ktype = tmp("_ktype"); + string vtype = tmp("_vtype"); + string etype = tmp("_etype"); + + t_field fsize(g_type_i32, size); + t_field fktype(g_type_i8, ktype); + t_field fvtype(g_type_i8, vtype); + t_field fetype(g_type_i8, etype); + + // Declare variables, read header + indent(out) << (local ? "local " : "") << prefix << " = {}" << endl; + if (ttype->is_map()) { + indent(out) << "local " << ktype << ", " << vtype << ", " << size << " = iprot:readMapBegin() " + << endl; + } else if (ttype->is_set()) { + indent(out) << "local " << etype << ", " << size << " = iprot:readSetBegin()" << endl; + } else if (ttype->is_list()) { + indent(out) << "local " << etype << ", " << size << " = iprot:readListBegin()" << endl; + } + + // Deserialize + indent(out) << "for _i=1," << size << " do" << endl; + indent_up(); + + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, prefix); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, prefix); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, prefix); + } + + indent_down(); + indent(out) << "end" << endl; + + // Read container end + if (ttype->is_map()) { + indent(out) << "iprot:readMapEnd()" << endl; + } else if (ttype->is_set()) { + indent(out) << "iprot:readSetEnd()" << endl; + } else if (ttype->is_list()) { + indent(out) << "iprot:readListEnd()" << endl; + } +} + +void t_lua_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) { + // A map is represented by a table indexable by any lua type + string key = tmp("_key"); + string val = tmp("_val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + generate_deserialize_field(out, &fkey, true); + generate_deserialize_field(out, &fval, true); + + indent(out) << prefix << "[" << key << "] = " << val << endl; +} + +void t_lua_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) { + // A set is represented by a table indexed by the value + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); + + generate_deserialize_field(out, &felem, true); + + indent(out) << prefix << "[" << elem << "] = " << elem << endl; +} + +void t_lua_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix) { + // A list is represented by a table indexed by integer values + // LUA natively provides all of the functions required to maintain a list + string elem = tmp("_elem"); + t_field felem(tlist->get_elem_type(), elem); + + generate_deserialize_field(out, &felem, true); + + indent(out) << "table.insert(" << prefix << ", " << elem << ")" << endl; +} + +/** + * Serialize (Write) + */ +void t_lua_generator::generate_serialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = get_true_type(tfield->get_type()); + string name = prefix + tfield->get_name(); + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name; + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, name); + } else if (type->is_container()) { + generate_serialize_container(out, type, name); + } else if (type->is_base_type() || type->is_enum()) { + indent(out) << "oprot:"; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + out << "writeString(" << name << ")"; + break; + case t_base_type::TYPE_BOOL: + out << "writeBool(" << name << ")"; + break; + case t_base_type::TYPE_I8: + out << "writeByte(" << name << ")"; + break; + case t_base_type::TYPE_I16: + out << "writeI16(" << name << ")"; + break; + case t_base_type::TYPE_I32: + out << "writeI32(" << name << ")"; + break; + case t_base_type::TYPE_I64: + out << "writeI64(" << name << ")"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble(" << name << ")"; + break; + default: + throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "writeI32(" << name << ")"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n", + name.c_str(), + type->get_name().c_str()); + } +} + +void t_lua_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + (void)tstruct; + indent(out) << prefix << ":write(oprot)" << endl; +} + +void t_lua_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + // Begin writing + if (ttype->is_map()) { + indent(out) << "oprot:writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " + << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " + << "ttable_size(" << prefix << "))" << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot:writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " + << "ttable_size(" << prefix << "))" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot:writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) + << ", " + << "#" << prefix << ")" << endl; + } + + // Serialize + if (ttype->is_map()) { + string kiter = tmp("kiter"); + string viter = tmp("viter"); + indent(out) << "for " << kiter << "," << viter << " in pairs(" << prefix << ") do" << endl; + indent_up(); + generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); + indent_down(); + indent(out) << "end" << endl; + } else if (ttype->is_set()) { + string iter = tmp("iter"); + indent(out) << "for " << iter << ",_ in pairs(" << prefix << ") do" << endl; + indent_up(); + generate_serialize_set_element(out, (t_set*)ttype, iter); + indent_down(); + indent(out) << "end" << endl; + } else if (ttype->is_list()) { + string iter = tmp("iter"); + indent(out) << "for _," << iter << " in ipairs(" << prefix << ") do" << endl; + indent_up(); + generate_serialize_list_element(out, (t_list*)ttype, iter); + indent_down(); + indent(out) << "end" << endl; + } + + // Finish writing + if (ttype->is_map()) { + indent(out) << "oprot:writeMapEnd()" << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot:writeSetEnd()" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot:writeListEnd()" << endl; + } +} + +void t_lua_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string kiter, + string viter) { + t_field kfield(tmap->get_key_type(), kiter); + generate_serialize_field(out, &kfield, ""); + + t_field vfield(tmap->get_val_type(), viter); + generate_serialize_field(out, &vfield, ""); +} + +void t_lua_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) { + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +void t_lua_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) { + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +/** + * Helper rendering functions + */ +string t_lua_generator::lua_includes() { + if (gen_requires_) { + return "\n\nrequire 'Thrift'"; + } else { + return ""; + } +} + +string t_lua_generator::get_namespace(const t_program* program) { + std::string real_module = program->get_namespace("lua"); + if (real_module.empty()) { + return program->get_name() + "_"; + } + return real_module + "_"; +} + +string t_lua_generator::function_signature(t_function* tfunction, string prefix) { + (void)prefix; + std::string ret = tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")"; + return ret; +} + +string t_lua_generator::argument_list(t_struct* tstruct, string prefix) { + const vector& fields = tstruct->get_members(); + vector::const_iterator fld_iter; + std::string ret = ""; + for (fld_iter = fields.begin(); fld_iter != fields.end();) { + ret += prefix + (*fld_iter)->get_name(); + ++fld_iter; + if (fld_iter != fields.end()) { + ret += ", "; + } + } + return ret; +} + +string t_lua_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "TType.STRING"; + case t_base_type::TYPE_BOOL: + return "TType.BOOL"; + case t_base_type::TYPE_I8: + return "TType.BYTE"; + case t_base_type::TYPE_I16: + return "TType.I16"; + case t_base_type::TYPE_I32: + return "TType.I32"; + case t_base_type::TYPE_I64: + return "TType.I64"; + case t_base_type::TYPE_DOUBLE: + return "TType.DOUBLE"; + } + } else if (type->is_enum()) { + return "TType.I32"; + } else if (type->is_struct() || type->is_xception()) { + return "TType.STRUCT"; + } else if (type->is_map()) { + return "TType.MAP"; + } else if (type->is_set()) { + return "TType.SET"; + } else if (type->is_list()) { + return "TType.LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +THRIFT_REGISTER_GENERATOR( + lua, + "Lua", + " omit_requires: Suppress generation of require 'somefile'.\n") diff --git a/compiler/cpp/src/thrift/generate/t_netcore_generator.cc b/compiler/cpp/src/thrift/generate/t_netcore_generator.cc new file mode 100644 index 0000000..8d157a9 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_netcore_generator.cc @@ -0,0 +1,3187 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +//TODO: check for indentation +//TODO: Do we need seqId_ in generation? + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +struct member_mapping_scope +{ + void* scope_member; + map mapping_table; +}; + +class t_netcore_generator : public t_oop_generator +{ +public: + t_netcore_generator(t_program* program, const map& parsed_options, const string& option_string) + : t_oop_generator(program) + { + (void)option_string; + + nullable_ = false; + hashcode_ = false; + union_ = false; + serialize_ = false; + wcf_ = false; + wcf_namespace_.clear(); + + map::const_iterator iter; + + for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) + { + if (iter->first.compare("nullable") == 0) + { + nullable_ = true; + } + else if (iter->first.compare("hashcode") == 0) + { + hashcode_ = true; + } + else if (iter->first.compare("union") == 0) + { + union_ = true; + } + else if (iter->first.compare("serial") == 0) + { + serialize_ = true; + wcf_namespace_ = iter->second; // since there can be only one namespace + } + else if (iter->first.compare("wcf") == 0) + { + wcf_ = true; + wcf_namespace_ = iter->second; + } + else + { + throw "unknown option netcore:" + iter->first; + } + } + + out_dir_base_ = "gen-netcore"; + } + + // overrides + void init_generator(); + void close_generator(); + void generate_consts(vector consts); + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + void generate_property(ofstream& out, t_field* tfield, bool isPublic, bool generateIsset); + void generate_netcore_property(ofstream& out, t_field* tfield, bool isPublic, bool includeIsset = true, string fieldPrefix = ""); + bool print_const_value(ofstream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval = false, bool needtype = false); + string render_const_value(ofstream& out, string name, t_type* type, t_const_value* value); + void print_const_constructor(ofstream& out, vector consts); + void print_const_def_value(ofstream& out, string name, t_type* type, t_const_value* value); + void generate_netcore_struct(t_struct* tstruct, bool is_exception); + void generate_netcore_union(t_struct* tunion); + void generate_netcore_struct_definition(ofstream& out, t_struct* tstruct, bool is_xception = false, bool in_class = false, bool is_result = false); + void generate_netcore_union_definition(ofstream& out, t_struct* tunion); + void generate_netcore_union_class(ofstream& out, t_struct* tunion, t_field* tfield); + void generate_netcore_wcffault(ofstream& out, t_struct* tstruct); + void generate_netcore_struct_reader(ofstream& out, t_struct* tstruct); + void generate_netcore_struct_result_writer(ofstream& out, t_struct* tstruct); + void generate_netcore_struct_writer(ofstream& out, t_struct* tstruct); + void generate_netcore_struct_tostring(ofstream& out, t_struct* tstruct); + void generate_netcore_struct_equals(ofstream& out, t_struct* tstruct); + void generate_netcore_struct_hashcode(ofstream& out, t_struct* tstruct); + void generate_netcore_union_reader(ofstream& out, t_struct* tunion); + void generate_function_helpers(ofstream& out, t_function* tfunction); + void generate_service_interface(ofstream& out, t_service* tservice); + void generate_service_helpers(ofstream& out, t_service* tservice); + void generate_service_client(ofstream& out, t_service* tservice); + void generate_service_server(ofstream& out, t_service* tservice); + void generate_process_function_async(ofstream& out, t_service* tservice, t_function* function); + void generate_deserialize_field(ofstream& out, t_field* tfield, string prefix = "", bool is_propertyless = false); + void generate_deserialize_struct(ofstream& out, t_struct* tstruct, string prefix = ""); + void generate_deserialize_container(ofstream& out, t_type* ttype, string prefix = ""); + void generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix = ""); + void generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix = ""); + void generate_deserialize_list_element(ofstream& out, t_list* list, string prefix = ""); + void generate_serialize_field(ofstream& out, t_field* tfield, string prefix = "", bool is_element = false, bool is_propertyless = false); + void generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix = ""); + void generate_serialize_container(ofstream& out, t_type* ttype, string prefix = ""); + void generate_serialize_map_element(ofstream& out, t_map* tmap, string iter, string map); + void generate_serialize_set_element(ofstream& out, t_set* tmap, string iter); + void generate_serialize_list_element(ofstream& out, t_list* tlist, string iter); + void generate_netcore_doc(ofstream& out, t_field* field); + void generate_netcore_doc(ofstream& out, t_doc* tdoc); + void generate_netcore_doc(ofstream& out, t_function* tdoc); + void generate_netcore_docstring_comment(ofstream& out, string contents); + void docstring_comment(ofstream& out, const string& comment_start, const string& line_prefix, const string& contents, const string& comment_end); + void start_netcore_namespace(ofstream& out); + void end_netcore_namespace(ofstream& out); + + string netcore_type_usings() const; + string netcore_thrift_usings() const; + string type_name(t_type* ttype, bool in_countainer = false, bool in_init = false, bool in_param = false, bool is_required = false); + string base_type_name(t_base_type* tbase, bool in_container = false, bool in_param = false, bool is_required = false); + string declare_field(t_field* tfield, bool init = false, string prefix = ""); + string function_signature_async(t_function* tfunction, string prefix = ""); + string function_signature(t_function* tfunction, string prefix = ""); + string argument_list(t_struct* tstruct); + string type_to_enum(t_type* ttype); + string prop_name(t_field* tfield, bool suppress_mapping = false); + string get_enum_class_name(t_type* type); + + static string correct_function_name_for_async(string const& function_name) + { + string const async_end = "Async"; + size_t i = function_name.find(async_end); + if (i != string::npos) + { + return function_name + async_end; + } + + return function_name; + } + + /** + * \brief Search and replace "_args" substring in struct name if exist (for C# class naming) + * \param struct_name + * \return Modified struct name ("Struct_args" -> "StructArgs") or original name + */ + static string check_and_correct_struct_name(const string& struct_name) + { + string args_end = "_args"; + size_t i = struct_name.find(args_end); + if (i != string::npos) + { + string new_struct_name = struct_name; + new_struct_name.replace(i, args_end.length(), "Args"); + return new_struct_name; + } + + string result_end = "_result"; + size_t j = struct_name.find(result_end); + if (j != string::npos) + { + string new_struct_name = struct_name; + new_struct_name.replace(j, result_end.length(), "Result"); + return new_struct_name; + } + + return struct_name; + } + + static bool field_has_default(t_field* tfield) { return tfield->get_value() != NULL; } + + static bool field_is_required(t_field* tfield) { return tfield->get_req() == t_field::T_REQUIRED; } + + static bool type_can_be_null(t_type* ttype) + { + while (ttype->is_typedef()) + { + ttype = static_cast(ttype)->get_type(); + } + + return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string(); + } + + +private: + string namespace_name_; + string namespace_dir_; + + bool nullable_; + bool union_; + bool hashcode_; + bool serialize_; + bool wcf_; + + string wcf_namespace_; + map netcore_keywords; + vector member_mapping_scopes; + + void init_keywords(); + string normalize_name(string name); + string make_valid_csharp_identifier(string const& fromName); + void prepare_member_name_mapping(t_struct* tstruct); + void prepare_member_name_mapping(void* scope, const vector& members, const string& structname); + void cleanup_member_name_mapping(void* scope); + string get_mapped_member_name(string oldname); +}; + +void t_netcore_generator::init_generator() +{ + MKDIR(get_out_dir().c_str()); + + // for usage of csharp namespaces in thrift files (from files for csharp) + namespace_name_ = program_->get_namespace("netcore"); + if (namespace_name_.empty()) + { + namespace_name_ = program_->get_namespace("netcore"); + } + + string dir = namespace_name_; + string subdir = get_out_dir().c_str(); + string::size_type loc; + + while ((loc = dir.find(".")) != string::npos) + { + subdir = subdir + "/" + dir.substr(0, loc); + MKDIR(subdir.c_str()); + dir = dir.substr(loc + 1); + } + if (dir.size() > 0) + { + subdir = subdir + "/" + dir; + MKDIR(subdir.c_str()); + } + + namespace_dir_ = subdir; + init_keywords(); + + while (!member_mapping_scopes.empty()) + { + cleanup_member_name_mapping(member_mapping_scopes.back().scope_member); + } + + pverbose(".NET Core options:\n"); + pverbose("- nullable ... %s\n", (nullable_ ? "ON" : "off")); + pverbose("- union ...... %s\n", (union_ ? "ON" : "off")); + pverbose("- hashcode ... %s\n", (hashcode_ ? "ON" : "off")); + pverbose("- serialize .. %s\n", (serialize_ ? "ON" : "off")); + pverbose("- wcf ........ %s\n", (wcf_ ? "ON" : "off")); +} + +string t_netcore_generator::normalize_name(string name) +{ + string tmp(name); + transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast(tolower)); + + // un-conflict keywords by prefixing with "@" + if (netcore_keywords.find(tmp) != netcore_keywords.end()) + { + return "@" + name; + } + + // no changes necessary + return name; +} + +void t_netcore_generator::init_keywords() +{ + netcore_keywords.clear(); + + // C# keywords + netcore_keywords["abstract"] = 1; + netcore_keywords["as"] = 1; + netcore_keywords["base"] = 1; + netcore_keywords["bool"] = 1; + netcore_keywords["break"] = 1; + netcore_keywords["byte"] = 1; + netcore_keywords["case"] = 1; + netcore_keywords["catch"] = 1; + netcore_keywords["char"] = 1; + netcore_keywords["checked"] = 1; + netcore_keywords["class"] = 1; + netcore_keywords["const"] = 1; + netcore_keywords["continue"] = 1; + netcore_keywords["decimal"] = 1; + netcore_keywords["default"] = 1; + netcore_keywords["delegate"] = 1; + netcore_keywords["do"] = 1; + netcore_keywords["double"] = 1; + netcore_keywords["else"] = 1; + netcore_keywords["enum"] = 1; + netcore_keywords["event"] = 1; + netcore_keywords["explicit"] = 1; + netcore_keywords["extern"] = 1; + netcore_keywords["false"] = 1; + netcore_keywords["finally"] = 1; + netcore_keywords["fixed"] = 1; + netcore_keywords["float"] = 1; + netcore_keywords["for"] = 1; + netcore_keywords["foreach"] = 1; + netcore_keywords["goto"] = 1; + netcore_keywords["if"] = 1; + netcore_keywords["implicit"] = 1; + netcore_keywords["in"] = 1; + netcore_keywords["int"] = 1; + netcore_keywords["interface"] = 1; + netcore_keywords["internal"] = 1; + netcore_keywords["is"] = 1; + netcore_keywords["lock"] = 1; + netcore_keywords["long"] = 1; + netcore_keywords["namespace"] = 1; + netcore_keywords["new"] = 1; + netcore_keywords["null"] = 1; + netcore_keywords["object"] = 1; + netcore_keywords["operator"] = 1; + netcore_keywords["out"] = 1; + netcore_keywords["override"] = 1; + netcore_keywords["params"] = 1; + netcore_keywords["private"] = 1; + netcore_keywords["protected"] = 1; + netcore_keywords["public"] = 1; + netcore_keywords["readonly"] = 1; + netcore_keywords["ref"] = 1; + netcore_keywords["return"] = 1; + netcore_keywords["sbyte"] = 1; + netcore_keywords["sealed"] = 1; + netcore_keywords["short"] = 1; + netcore_keywords["sizeof"] = 1; + netcore_keywords["stackalloc"] = 1; + netcore_keywords["static"] = 1; + netcore_keywords["string"] = 1; + netcore_keywords["struct"] = 1; + netcore_keywords["switch"] = 1; + netcore_keywords["this"] = 1; + netcore_keywords["throw"] = 1; + netcore_keywords["true"] = 1; + netcore_keywords["try"] = 1; + netcore_keywords["typeof"] = 1; + netcore_keywords["uint"] = 1; + netcore_keywords["ulong"] = 1; + netcore_keywords["unchecked"] = 1; + netcore_keywords["unsafe"] = 1; + netcore_keywords["ushort"] = 1; + netcore_keywords["using"] = 1; + netcore_keywords["virtual"] = 1; + netcore_keywords["void"] = 1; + netcore_keywords["volatile"] = 1; + netcore_keywords["while"] = 1; + + // C# contextual keywords + netcore_keywords["add"] = 1; + netcore_keywords["alias"] = 1; + netcore_keywords["ascending"] = 1; + netcore_keywords["async"] = 1; + netcore_keywords["await"] = 1; + netcore_keywords["descending"] = 1; + netcore_keywords["dynamic"] = 1; + netcore_keywords["from"] = 1; + netcore_keywords["get"] = 1; + netcore_keywords["global"] = 1; + netcore_keywords["group"] = 1; + netcore_keywords["into"] = 1; + netcore_keywords["join"] = 1; + netcore_keywords["let"] = 1; + netcore_keywords["orderby"] = 1; + netcore_keywords["partial"] = 1; + netcore_keywords["remove"] = 1; + netcore_keywords["select"] = 1; + netcore_keywords["set"] = 1; + netcore_keywords["value"] = 1; + netcore_keywords["var"] = 1; + netcore_keywords["where"] = 1; + netcore_keywords["yield"] = 1; +} + +void t_netcore_generator::start_netcore_namespace(ofstream& out) +{ + if (!namespace_name_.empty()) + { + out << "namespace " << namespace_name_ << endl; + scope_up(out); + } +} + +void t_netcore_generator::end_netcore_namespace(ofstream& out) +{ + if (!namespace_name_.empty()) + { + scope_down(out); + } +} + +string t_netcore_generator::netcore_type_usings() const +{ + string namespaces = + "using System;\n" + "using System.Collections;\n" + "using System.Collections.Generic;\n" + "using System.Text;\n" + "using System.IO;\n" + "using System.Threading;\n" + "using System.Threading.Tasks;\n" + "using Thrift;\n" + "using Thrift.Collections;\n"; + + if (wcf_) + { + namespaces += "using System.ServiceModel;\n"; + namespaces += "using System.Runtime.Serialization;\n"; + } + + return namespaces + endl; +} + +string t_netcore_generator::netcore_thrift_usings() const +{ + string namespaces = + "using Thrift.Protocols;\n" + "using Thrift.Protocols.Entities;\n" + "using Thrift.Protocols.Utilities;\n" + "using Thrift.Transports;\n" + "using Thrift.Transports.Client;\n" + "using Thrift.Transports.Server;\n"; + + return namespaces + endl; +} + +void t_netcore_generator::close_generator() +{ +} + +void t_netcore_generator::generate_typedef(t_typedef* ttypedef) +{ + (void)ttypedef; +} + +void t_netcore_generator::generate_enum(t_enum* tenum) +{ + int ic = indent_count(); + + string f_enum_name = namespace_dir_ + "/" + tenum->get_name() + ".cs"; + + ofstream f_enum; + f_enum.open(f_enum_name.c_str()); + f_enum << autogen_comment() << endl; + + start_netcore_namespace(f_enum); + generate_netcore_doc(f_enum, tenum); + + f_enum << indent() << "public enum " << tenum->get_name() << endl; + scope_up(f_enum); + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) + { + generate_netcore_doc(f_enum, *c_iter); + int value = (*c_iter)->get_value(); + f_enum << indent() << (*c_iter)->get_name() << " = " << value << "," << endl; + } + + scope_down(f_enum); + end_netcore_namespace(f_enum); + f_enum.close(); + + indent_validate(ic, "generate_enum"); +} + +void t_netcore_generator::generate_consts(vector consts) +{ + if (consts.empty()) + { + return; + } + + string f_consts_name = namespace_dir_ + '/' + program_name_ + ".Constants.cs"; + ofstream f_consts; + f_consts.open(f_consts_name.c_str()); + + f_consts << autogen_comment() << netcore_type_usings() << endl; + + start_netcore_namespace(f_consts); + + f_consts << indent() << "public static class " << make_valid_csharp_identifier(program_name_) << "Constants" << endl; + + scope_up(f_consts); + + vector::iterator c_iter; + bool need_static_constructor = false; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) + { + generate_netcore_doc(f_consts, *c_iter); + if (print_const_value(f_consts, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value(), false)) + { + need_static_constructor = true; + } + } + + if (need_static_constructor) + { + print_const_constructor(f_consts, consts); + } + + scope_down(f_consts); + end_netcore_namespace(f_consts); + f_consts.close(); +} + +void t_netcore_generator::print_const_def_value(ofstream& out, string name, t_type* type, t_const_value* value) +{ + if (type->is_struct() || type->is_xception()) + { + const vector& fields = static_cast(type)->get_members(); + const map& val = value->get_map(); + vector::const_iterator f_iter; + map::const_iterator v_iter; + prepare_member_name_mapping(static_cast(type)); + + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) + { + t_field* field = NULL; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + if ((*f_iter)->get_name() == v_iter->first->get_string()) + { + field = *f_iter; + } + } + + if (field == NULL) + { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + + t_type* field_type = field->get_type(); + + string val = render_const_value(out, name, field_type, v_iter->second); + out << indent() << name << "." << prop_name(field) << " = " << val << ";" << endl; + } + + cleanup_member_name_mapping(static_cast(type)); + } + else if (type->is_map()) + { + t_type* ktype = static_cast(type)->get_key_type(); + t_type* vtype = static_cast(type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) + { + string key = render_const_value(out, name, ktype, v_iter->first); + string val = render_const_value(out, name, vtype, v_iter->second); + out << indent() << name << "[" << key << "]" << " = " << val << ";" << endl; + } + } + else if (type->is_list() || type->is_set()) + { + t_type* etype; + if (type->is_list()) + { + etype = static_cast(type)->get_elem_type(); + } + else + { + etype = static_cast(type)->get_elem_type(); + } + + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) + { + string val = render_const_value(out, name, etype, *v_iter); + out << indent() << name << ".Add(" << val << ");" << endl; + } + } +} + +void t_netcore_generator::print_const_constructor(ofstream& out, vector consts) +{ + out << indent() << "static " << make_valid_csharp_identifier(program_name_).c_str() << "Constants()" << endl; + scope_up(out); + + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) + { + string name = (*c_iter)->get_name(); + t_type* type = (*c_iter)->get_type(); + t_const_value* value = (*c_iter)->get_value(); + + print_const_def_value(out, name, type, value); + } + scope_down(out); +} + +bool t_netcore_generator::print_const_value(ofstream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval, bool needtype) +{ + out << indent(); + bool need_static_construction = !in_static; + while (type->is_typedef()) + { + type = static_cast(type)->get_type(); + } + + if (!defval || needtype) + { + out << (in_static ? "" : type->is_base_type() ? "public const " : "public static ") << type_name(type) << " "; + } + + if (type->is_base_type()) + { + string v2 = render_const_value(out, name, type, value); + out << name << " = " << v2 << ";" << endl; + need_static_construction = false; + } + else if (type->is_enum()) + { + out << name << " = " << type_name(type, false, true) << "." << value->get_identifier_name() << ";" << endl; + need_static_construction = false; + } + else if (type->is_struct() || type->is_xception()) + { + out << name << " = new " << type_name(type) << "();" << endl; + } + else if (type->is_map()) + { + out << name << " = new " << type_name(type, true, true) << "();" << endl; + } + else if (type->is_list() || type->is_set()) + { + out << name << " = new " << type_name(type) << "();" << endl; + } + + if (defval && !type->is_base_type() && !type->is_enum()) + { + print_const_def_value(out, name, type, value); + } + + return need_static_construction; +} + +string t_netcore_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) +{ + (void)name; + ostringstream render; + + if (type->is_base_type()) + { + t_base_type::t_base tbase = static_cast(type)->get_base(); + switch (tbase) + { + case t_base_type::TYPE_STRING: + render << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() > 0) ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + render << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) + { + render << value->get_integer(); + } + else + { + render << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } + else if (type->is_enum()) + { + render << type->get_name() << "." << value->get_identifier_name(); + } + else + { + string t = tmp("tmp"); + print_const_value(out, t, type, value, true, true, true); + render << t; + } + + return render.str(); +} + +void t_netcore_generator::generate_struct(t_struct* tstruct) +{ + if (union_ && tstruct->is_union()) + { + generate_netcore_union(tstruct); + } + else + { + generate_netcore_struct(tstruct, false); + } +} + +void t_netcore_generator::generate_xception(t_struct* txception) +{ + generate_netcore_struct(txception, true); +} + +void t_netcore_generator::generate_netcore_struct(t_struct* tstruct, bool is_exception) +{ + int ic = indent_count(); + + string f_struct_name = namespace_dir_ + "/" + (tstruct->get_name()) + ".cs"; + ofstream f_struct; + + f_struct.open(f_struct_name.c_str()); + + f_struct << autogen_comment() << netcore_type_usings() << netcore_thrift_usings() << endl; + + generate_netcore_struct_definition(f_struct, tstruct, is_exception); + + f_struct.close(); + + indent_validate(ic, "generate_netcore_struct"); +} + +void t_netcore_generator::generate_netcore_struct_definition(ofstream& out, t_struct* tstruct, bool is_exception, bool in_class, bool is_result) +{ + if (!in_class) + { + start_netcore_namespace(out); + } + + out << endl; + + generate_netcore_doc(out, tstruct); + prepare_member_name_mapping(tstruct); + + if ((serialize_ || wcf_) && !is_exception) + { + out << indent() << "[DataContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl; + } + + bool is_final = tstruct->annotations_.find("final") != tstruct->annotations_.end(); + + string sharp_struct_name = check_and_correct_struct_name(normalize_name(tstruct->get_name())); + + out << indent() << "public " << (is_final ? "sealed " : "") << "partial class " << sharp_struct_name << " : "; + + if (is_exception) + { + out << "TException, "; + } + + out << "TBase" << endl + << indent() << "{" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + // make private members with public Properties + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) + { + // if the field is requied, then we use auto-properties + if (!field_is_required((*m_iter)) && (!nullable_ || field_has_default((*m_iter)))) + { + out << indent() << "private " << declare_field(*m_iter, false, "_") << endl; + } + } + out << endl; + + bool has_non_required_fields = false; + bool has_non_required_default_value_fields = false; + bool has_required_fields = false; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) + { + generate_netcore_doc(out, *m_iter); + generate_property(out, *m_iter, true, true); + bool is_required = field_is_required((*m_iter)); + bool has_default = field_has_default((*m_iter)); + if (is_required) + { + has_required_fields = true; + } + else + { + if (has_default) + { + has_non_required_default_value_fields = true; + } + has_non_required_fields = true; + } + } + + bool generate_isset = (nullable_ && has_non_required_default_value_fields) || (!nullable_ && has_non_required_fields); + if (generate_isset) + { + out << endl; + if (serialize_ || wcf_) + { + out << indent() << "[DataMember(Order = 1)]" << endl; + } + out << indent() << "public Isset __isset;" << endl; + if (serialize_ || wcf_) + { + out << indent() << "[DataContract]" << endl; + } + + out << indent() << "public struct Isset" << endl + << indent() << "{" << endl; + indent_up(); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) + { + bool is_required = field_is_required((*m_iter)); + bool has_default = field_has_default((*m_iter)); + // if it is required, don't need Isset for that variable + // if it is not required, if it has a default value, we need to generate Isset + // if we are not nullable, then we generate Isset + if (!is_required && (!nullable_ || has_default)) + { + if (serialize_ || wcf_) + { + out << indent() << "[DataMember]" << endl; + } + out << indent() << "public bool " << normalize_name((*m_iter)->get_name()) << ";" << endl; + } + } + + indent_down(); + out << indent() << "}" << endl << endl; + + if (generate_isset && (serialize_ || wcf_)) + { + out << indent() << "#region XmlSerializer support" << endl << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) + { + bool is_required = field_is_required(*m_iter); + bool has_default = field_has_default(*m_iter); + // if it is required, don't need Isset for that variable + // if it is not required, if it has a default value, we need to generate Isset + // if we are not nullable, then we generate Isset + if (!is_required && (!nullable_ || has_default)) + { + out << indent() << "public bool ShouldSerialize" << prop_name(*m_iter) << "()" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "return __isset." << normalize_name((*m_iter)->get_name()) << ";" << endl; + indent_down(); + out << indent() << "}" << endl << endl; + } + } + + out << indent() << "#endregion XmlSerializer support" << endl << endl; + } + } + + // We always want a default, no argument constructor for Reading + out << indent() << "public " << sharp_struct_name << "()" << endl + << indent() << "{" << endl; + indent_up(); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) + { + t_type* t = (*m_iter)->get_type(); + while (t->is_typedef()) + { + t = static_cast(t)->get_type(); + } + if ((*m_iter)->get_value() != NULL) + { + if (field_is_required((*m_iter))) + { + print_const_value(out, "this." + prop_name(*m_iter), t, (*m_iter)->get_value(), true, true); + } + else + { + print_const_value(out, "this._" + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true); + // Optionals with defaults are marked set + out << indent() << "this.__isset." << normalize_name((*m_iter)->get_name()) << " = true;" << endl; + } + } + } + indent_down(); + out << indent() << "}" << endl << endl; + + if (has_required_fields) + { + out << indent() << "public " << sharp_struct_name << "("; + bool first = true; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) + { + if (field_is_required(*m_iter)) + { + if (first) + { + first = false; + } + else + { + out << ", "; + } + out << type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name(); + } + } + out << ") : this()" << endl + << indent() << "{" << endl; + indent_up(); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) + { + if (field_is_required(*m_iter)) + { + out << indent() << "this." << prop_name(*m_iter) << " = " << (*m_iter)->get_name() << ";" << endl; + } + } + + indent_down(); + out << indent() << "}" << endl << endl; + } + + generate_netcore_struct_reader(out, tstruct); + if (is_result) + { + generate_netcore_struct_result_writer(out, tstruct); + } + else + { + generate_netcore_struct_writer(out, tstruct); + } + if (hashcode_) + { + generate_netcore_struct_equals(out, tstruct); + generate_netcore_struct_hashcode(out, tstruct); + } + generate_netcore_struct_tostring(out, tstruct); + + indent_down(); + out << indent() << "}" << endl << endl; + + // generate a corresponding WCF fault to wrap the exception + if ((serialize_ || wcf_) && is_exception) + { + generate_netcore_wcffault(out, tstruct); + } + + cleanup_member_name_mapping(tstruct); + if (!in_class) + { + end_netcore_namespace(out); + } +} + +void t_netcore_generator::generate_netcore_wcffault(ofstream& out, t_struct* tstruct) +{ + out << endl; + out << indent() << "[DataContract]" << endl; + + bool is_final = tstruct->annotations_.find("final") != tstruct->annotations_.end(); + + out << indent() << "public " << (is_final ? "sealed " : "") << "partial class " << tstruct->get_name() << "Fault" << endl + << indent() << "{" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + // make private members with public Properties + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) + { + out << indent() << "private " << declare_field(*m_iter, false, "_") << endl; + } + out << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) + { + generate_property(out, *m_iter, true, false); + } + + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_netcore_generator::generate_netcore_struct_reader(ofstream& out, t_struct* tstruct) +{ + out << indent() << "public async Task ReadAsync(TProtocol iprot, CancellationToken cancellationToken)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "iprot.IncrementRecursionDepth();" << endl + << indent() << "try" << endl + << indent() << "{" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Required variables aren't in __isset, so we need tmp vars to check them + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + if (field_is_required(*f_iter)) + { + out << indent() << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl; + } + } + + out << indent() << "TField field;" << endl + << indent() << "await iprot.ReadStructBeginAsync(cancellationToken);" << endl + << indent() << "while (true)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "field = await iprot.ReadFieldBeginAsync(cancellationToken);" << endl + << indent() << "if (field.Type == TType.Stop)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "break;" << endl; + indent_down(); + out << indent() << "}" << endl << endl + << indent() << "switch (field.ID)" << endl + << indent() << "{" << endl; + indent_up(); + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + bool is_required = field_is_required(*f_iter); + out << indent() << "case " << (*f_iter)->get_key() << ":" << endl; + indent_up(); + out << indent() << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ")" << endl + << indent() << "{" << endl; + indent_up(); + + generate_deserialize_field(out, *f_iter); + if (is_required) + { + out << indent() << "isset_" << (*f_iter)->get_name() << " = true;" << endl; + } + + indent_down(); + out << indent() << "}" << endl + << indent() << "else" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);" << endl; + indent_down(); + out << indent() << "}" << endl + << indent() << "break;" << endl; + indent_down(); + } + + out << indent() << "default: " << endl; + indent_up(); + out << indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);" << endl + << indent() << "break;" << endl; + indent_down(); + indent_down(); + out << indent() << "}" << endl + << endl + << indent() << "await iprot.ReadFieldEndAsync(cancellationToken);" << endl; + indent_down(); + out << indent() << "}" << endl + << endl + << indent() << "await iprot.ReadStructEndAsync(cancellationToken);" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + if (field_is_required((*f_iter))) + { + out << indent() << "if (!isset_" << (*f_iter)->get_name() << ")" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl; + indent_down(); + out << indent() << "}" << endl; + } + } + + indent_down(); + out << indent() << "}" << endl; + out << indent() << "finally" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "iprot.DecrementRecursionDepth();" << endl; + indent_down(); + out << indent() << "}" << endl; + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_netcore_generator::generate_netcore_struct_writer(ofstream& out, t_struct* tstruct) +{ + out << indent() << "public async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)" << endl + << indent() << "{" << endl; + indent_up(); + + out << indent() << "oprot.IncrementRecursionDepth();" << endl + << indent() << "try" << endl + << indent() << "{" << endl; + indent_up(); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + out << indent() << "var struc = new TStruct(\"" << name << "\");" << endl + << indent() << "await oprot.WriteStructBeginAsync(struc, cancellationToken);" << endl; + + if (fields.size() > 0) + { + out << indent() << "var field = new TField();" << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + bool is_required = field_is_required(*f_iter); + bool has_default = field_has_default(*f_iter); + if (nullable_ && !has_default && !is_required) + { + out << indent() << "if (" << prop_name(*f_iter) << " != null)" << endl + << indent() << "{" << endl; + indent_up(); + } + else if (!is_required) + { + bool null_allowed = type_can_be_null((*f_iter)->get_type()); + if (null_allowed) + { + out << indent() << "if (" << prop_name(*f_iter) << " != null && __isset." << normalize_name((*f_iter)->get_name()) << ")" << endl + << indent() << "{" << endl; + indent_up(); + } + else + { + out << indent() << "if (__isset." << normalize_name((*f_iter)->get_name()) << ")" << endl + << indent() << "{" << endl; + indent_up(); + } + } + out << indent() << "field.Name = \"" << (*f_iter)->get_name() << "\";" << endl + << indent() << "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl + << indent() << "field.ID = " << (*f_iter)->get_key() << ";" << endl + << indent() << "await oprot.WriteFieldBeginAsync(field, cancellationToken);" << endl; + + generate_serialize_field(out, *f_iter); + + out << indent() << "await oprot.WriteFieldEndAsync(cancellationToken);" << endl; + if (!is_required) + { + indent_down(); + out << indent() << "}" << endl; + } + } + } + + out << indent() << "await oprot.WriteFieldStopAsync(cancellationToken);" << endl + << indent() << "await oprot.WriteStructEndAsync(cancellationToken);" << endl; + indent_down(); + out << indent() << "}" << endl + << indent() << "finally" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "oprot.DecrementRecursionDepth();" << endl; + indent_down(); + out << indent() << "}" << endl; + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_netcore_generator::generate_netcore_struct_result_writer(ofstream& out, t_struct* tstruct) +{ + out << indent() << "public async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)" << endl + << indent() << "{" << endl; + indent_up(); + + out << indent() << "oprot.IncrementRecursionDepth();" << endl + << indent() << "try" << endl + << indent() << "{" << endl; + indent_up(); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + out << indent() << "var struc = new TStruct(\"" << name << "\");" << endl + << indent() << "await oprot.WriteStructBeginAsync(struc, cancellationToken);" << endl; + + if (fields.size() > 0) + { + out << indent() << "var field = new TField();" << endl; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + if (first) + { + first = false; + out << endl << indent() << "if"; + } + else + { + out << indent() << "else if"; + } + + if (nullable_) + { + out << "(this." << prop_name((*f_iter)) << " != null)" << endl + << indent() << "{" << endl; + } + else + { + out << "(this.__isset." << normalize_name((*f_iter)->get_name()) << ")" << endl + << indent() << "{" << endl; + } + indent_up(); + + bool null_allowed = !nullable_ && type_can_be_null((*f_iter)->get_type()); + if (null_allowed) + { + out << indent() << "if (" << prop_name(*f_iter) << " != null)" << endl + << indent() << "{" << endl; + indent_up(); + } + + out << indent() << "field.Name = \"" << prop_name(*f_iter) << "\";" << endl + << indent() << "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl + << indent() << "field.ID = " << (*f_iter)->get_key() << ";" << endl + << indent() << "await oprot.WriteFieldBeginAsync(field, cancellationToken);" << endl; + + generate_serialize_field(out, *f_iter); + + out << indent() << "await oprot.WriteFieldEndAsync(cancellationToken);" << endl; + + if (null_allowed) + { + indent_down(); + out << indent() << "}" << endl; + } + + indent_down(); + out << indent() << "}" << endl; + } + } + + out << indent() << "await oprot.WriteFieldStopAsync(cancellationToken);" << endl + << indent() << "await oprot.WriteStructEndAsync(cancellationToken);" << endl; + indent_down(); + out << indent() << "}" << endl + << indent() << "finally" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "oprot.DecrementRecursionDepth();" << endl; + indent_down(); + out << indent() << "}" << endl; + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_netcore_generator::generate_netcore_struct_tostring(ofstream& out, t_struct* tstruct) +{ + out << indent() << "public override string ToString()" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "var sb = new StringBuilder(\"" << tstruct->get_name() << "(\");" << endl; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + bool useFirstFlag = false; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + if (!field_is_required((*f_iter))) + { + out << indent() << "bool __first = true;" << endl; + useFirstFlag = true; + } + break; + } + + bool had_required = false; // set to true after first required field has been processed + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + bool is_required = field_is_required((*f_iter)); + bool has_default = field_has_default((*f_iter)); + if (nullable_ && !has_default && !is_required) + { + out << indent() << "if (" << prop_name((*f_iter)) << " != null)" << endl + << indent() << "{" << endl; + indent_up(); + } + else if (!is_required) + { + bool null_allowed = type_can_be_null((*f_iter)->get_type()); + if (null_allowed) + { + out << indent() << "if (" << prop_name((*f_iter)) << " != null && __isset." << normalize_name((*f_iter)->get_name()) << ")" << endl + << indent() << "{" << endl; + indent_up(); + } + else + { + out << indent() << "if (__isset." << normalize_name((*f_iter)->get_name()) << ")" << endl + << indent() << "{" << endl; + indent_up(); + } + } + + if (useFirstFlag && (!had_required)) + { + out << indent() << "if(!__first) { sb.Append(\", \"); }" << endl; + if (!is_required) + { + out << indent() << "__first = false;" << endl; + } + out << indent() << "sb.Append(\"" << prop_name(*f_iter) << ": \");" << endl; + } + else + { + out << indent() << "sb.Append(\", " << prop_name(*f_iter) << ": \");" << endl; + } + + t_type* ttype = (*f_iter)->get_type(); + if (ttype->is_xception() || ttype->is_struct()) + { + out << indent() << "sb.Append(" << prop_name(*f_iter) << "== null ? \"\" : " << prop_name(*f_iter) << ".ToString());" << endl; + } + else + { + out << indent() << "sb.Append(" << prop_name(*f_iter) << ");" << endl; + } + + if (!is_required) + { + indent_down(); + out << indent() << "}" << endl; + } + else + { + had_required = true; // now __first must be false, so we don't need to check it anymore + } + } + + out << indent() << "sb.Append(\")\");" << endl + << indent() << "return sb.ToString();" << endl; + indent_down(); + out << indent() << "}" << endl; +} + +void t_netcore_generator::generate_netcore_union(t_struct* tunion) +{ + int ic = indent_count(); + + string f_union_name = namespace_dir_ + "/" + (tunion->get_name()) + ".cs"; + ofstream f_union; + + f_union.open(f_union_name.c_str()); + + f_union << autogen_comment() << netcore_type_usings() << netcore_thrift_usings() << endl; + + generate_netcore_union_definition(f_union, tunion); + + f_union.close(); + + indent_validate(ic, "generate_netcore_union."); +} + +void t_netcore_generator::generate_netcore_union_definition(ofstream& out, t_struct* tunion) +{ + // Let's define the class first + start_netcore_namespace(out); + + out << indent() << "public abstract partial class " << tunion->get_name() << " : TAbstractBase" << endl + << indent() << "{" << endl; + indent_up(); + + out << indent() << "public abstract void Write(TProtocol protocol);" << endl + << indent() << "public readonly bool Isset;" << endl + << indent() << "public abstract object Data { get; }" << endl + << indent() << "protected " << tunion->get_name() << "(bool isset)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "Isset = isset;" << endl; + indent_down(); + out << indent() << "}" << endl << endl; + + out << indent() << "public class ___undefined : " << tunion->get_name() << endl + << indent() << "{" << endl; + indent_up(); + + out << indent() << "public override object Data { get { return null; } }" << endl + << indent() << "public ___undefined() : base(false) {}" << endl << endl; + + out << indent() << "public override void Write(TProtocol protocol)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "throw new TProtocolException( TProtocolException.INVALID_DATA, \"Cannot persist an union type which is not set.\");" << endl; + indent_down(); + out << indent() << "}" << endl << endl; + indent_down(); + out << indent() << "}" << endl << endl; + + const vector& fields = tunion->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + generate_netcore_union_class(out, tunion, (*f_iter)); + } + + generate_netcore_union_reader(out, tunion); + + indent_down(); + out << indent() << "}" << endl << endl; + + end_netcore_namespace(out); +} + +void t_netcore_generator::generate_netcore_union_class(ofstream& out, t_struct* tunion, t_field* tfield) +{ + out << indent() << "public class " << tfield->get_name() << " : " << tunion->get_name() << endl + << indent() << "{" << endl; + indent_up(); + + out << indent() << "private " << type_name(tfield->get_type()) << " _data;" << endl + << indent() << "public override object Data { get { return _data; } }" << endl + << indent() << "public " << tfield->get_name() << "(" << type_name(tfield->get_type()) << " data) : base(true)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "this._data = data;" << endl; + indent_down(); + out << indent() << "}" << endl; + + out << indent() << "public override async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken) {" << endl; + indent_up(); + + out << indent() << "oprot.IncrementRecursionDepth();" << endl + << indent() << "try" << endl + << indent() << "{" << endl; + indent_up(); + + out << indent() << "var struc = new TStruct(\"" << tunion->get_name() << "\");" << endl + << indent() << "await oprot.WriteStructBeginAsync(struc, cancellationToken);" << endl; + + out << indent() << "var field = new TField();" << endl + << indent() << "field.Name = \"" << tfield->get_name() << "\";" << endl + << indent() << "field.Type = " << type_to_enum(tfield->get_type()) << ";" << endl + << indent() << "field.ID = " << tfield->get_key() << ";" << endl + << indent() << "await oprot.WriteFieldBeginAsync(field, cancellationToken);" << endl; + + generate_serialize_field(out, tfield, "_data", true, true); + + out << indent() << "await oprot.WriteFieldEndAsync(cancellationToken);" << endl + << indent() << "await oprot.WriteFieldStop(cancellationToken);" << endl + << indent() << "await oprot.WriteStructEnd(cancellationToken);" << endl; + indent_down(); + out << indent() << "}" << endl + << indent() << "finally" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "oprot.DecrementRecursionDepth();" << endl; + indent_down(); + out << indent() << "}" << endl; + out << indent() << "}" << endl; + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_netcore_generator::generate_netcore_struct_equals(ofstream& out, t_struct* tstruct) +{ + out << indent() << "public override bool Equals(object that)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "var other = that as " << type_name(tstruct) << ";" << endl + << indent() << "if (other == null) return false;" << endl + << indent() << "if (ReferenceEquals(this, other)) return true;" << endl; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + bool first = true; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + if (first) + { + first = false; + out << indent() << "return "; + indent_up(); + } + else + { + out << endl; + out << indent() << "&& "; + } + if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) + { + out << "((__isset." << normalize_name((*f_iter)->get_name()) << " == other.__isset." + << normalize_name((*f_iter)->get_name()) << ") && ((!__isset." + << normalize_name((*f_iter)->get_name()) << ") || ("; + } + t_type* ttype = (*f_iter)->get_type(); + if (ttype->is_container() || ttype->is_binary()) + { + out << "TCollections.Equals("; + } + else + { + out << "System.Object.Equals("; + } + out << prop_name((*f_iter)) << ", other." << prop_name((*f_iter)) << ")"; + if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) + { + out << ")))"; + } + } + if (first) + { + out << indent() << "return true;" << endl; + } + else + { + out << ";" << endl; + indent_down(); + } + + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_netcore_generator::generate_netcore_struct_hashcode(ofstream& out, t_struct* tstruct) +{ + out << indent() << "public override int GetHashCode() {" << endl; + indent_up(); + + out << indent() << "int hashcode = 0;" << endl; + out << indent() << "unchecked {" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + t_type* ttype = (*f_iter)->get_type(); + out << indent() << "hashcode = (hashcode * 397) ^ "; + if (field_is_required((*f_iter))) + { + out << "("; + } + else if (nullable_) + { + out << "(" << prop_name((*f_iter)) << " == null ? 0 : "; + } + else + { + out << "(!__isset." << normalize_name((*f_iter)->get_name()) << " ? 0 : "; + } + if (ttype->is_container()) + { + out << "(TCollections.GetHashCode(" << prop_name((*f_iter)) << "))"; + } + else + { + out << "(" << prop_name((*f_iter)) << ".GetHashCode())"; + } + out << ");" << endl; + } + + indent_down(); + out << indent() << "}" << endl; + out << indent() << "return hashcode;" << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_netcore_generator::generate_service(t_service* tservice) +{ + int ic = indent_count(); + + string f_service_name = namespace_dir_ + "/" + service_name_ + ".cs"; + ofstream f_service; + f_service.open(f_service_name.c_str()); + + f_service << autogen_comment() << netcore_type_usings() << netcore_thrift_usings() << endl; + + start_netcore_namespace(f_service); + + f_service << indent() << "public partial class " << normalize_name(service_name_) << endl + << indent() << "{" << endl; + indent_up(); + + generate_service_interface(f_service, tservice); + generate_service_client(f_service, tservice); + generate_service_server(f_service, tservice); + generate_service_helpers(f_service, tservice); + + indent_down(); + f_service << indent() << "}" << endl; + + end_netcore_namespace(f_service); + f_service.close(); + + indent_validate(ic, "generate_service."); +} + +void t_netcore_generator::generate_service_interface(ofstream& out, t_service* tservice) +{ + string extends = ""; + string extends_iface = ""; + if (tservice->get_extends() != NULL) + { + extends = type_name(tservice->get_extends()); + extends_iface = " : " + extends + ".IAsync"; + } + + //out << endl << endl; + + generate_netcore_doc(out, tservice); + + if (wcf_) + { + out << indent() << "[ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl; + } + + out << indent() << "public interface IAsync" << extends_iface << endl + << indent() << "{" << endl; + + indent_up(); + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) + { + generate_netcore_doc(out, *f_iter); + + // if we're using WCF, add the corresponding attributes + if (wcf_) + { + out << indent() << "[OperationContract]" << endl; + + const vector& xceptions = (*f_iter)->get_xceptions()->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) + { + out << indent() << "[FaultContract(typeof(" + type_name((*x_iter)->get_type(), false, false) + "Fault))]" << endl; + } + } + + out << indent() << function_signature_async(*f_iter) << ";" << endl << endl; + } + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_netcore_generator::generate_service_helpers(ofstream& out, t_service* tservice) +{ + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) + { + t_struct* ts = (*f_iter)->get_arglist(); + generate_netcore_struct_definition(out, ts, false, true); + generate_function_helpers(out, *f_iter); + } +} + +void t_netcore_generator::generate_service_client(ofstream& out, t_service* tservice) +{ + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() != NULL) + { + extends = type_name(tservice->get_extends()); + extends_client = extends + ".Client, "; + } + else + { + extends_client = "TBaseClient, IDisposable, "; + } + + out << endl; + + generate_netcore_doc(out, tservice); + + out << indent() << "public class Client : " << extends_client << "IAsync" << endl + << indent() << "{" << endl; + indent_up(); + + out << indent() << "public Client(TProtocol protocol) : this(protocol, protocol)" << endl + << indent() << "{" << endl + << indent() << "}" << endl + << endl + << indent() << "public Client(TProtocol inputProtocol, TProtocol outputProtocol) : base(inputProtocol, outputProtocol)" + << indent() << "{" << endl + << indent() << "}" << endl; + + vector functions = tservice->get_functions(); + vector::const_iterator functions_iterator; + + for (functions_iterator = functions.begin(); functions_iterator != functions.end(); ++functions_iterator) + { + string function_name = correct_function_name_for_async((*functions_iterator)->get_name()); + + // async + out << indent() << "public async " << function_signature_async(*functions_iterator, "") << endl + << indent() << "{" << endl; + indent_up(); + + string argsname = (*functions_iterator)->get_name() + "Args"; + + out << indent() << "await OutputProtocol.WriteMessageBeginAsync(new TMessage(\"" << function_name + << "\", " << ((*functions_iterator)->is_oneway() ? "TMessageType.Oneway" : "TMessageType.Call") << ", SeqId), cancellationToken);" << endl + << indent() << endl + << indent() << "var args = new " << argsname << "();" << endl; + + t_struct* arg_struct = (*functions_iterator)->get_arglist(); + prepare_member_name_mapping(arg_struct); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) + { + out << indent() << "args." << prop_name(*fld_iter) << " = " << normalize_name((*fld_iter)->get_name()) << ";" << endl; + } + + out << indent() << endl + << indent() << "await args.WriteAsync(OutputProtocol, cancellationToken);" << endl + << indent() << "await OutputProtocol.WriteMessageEndAsync(cancellationToken);" << endl + << indent() << "await OutputProtocol.Transport.FlushAsync(cancellationToken);" << endl; + + if (!(*functions_iterator)->is_oneway()) + { + string resultname = (*functions_iterator)->get_name() + "Result"; + t_struct noargs(program_); + t_struct* xs = (*functions_iterator)->get_xceptions(); + prepare_member_name_mapping(xs, xs->get_members(), resultname); + + out << indent() << endl + << indent() << "var msg = await InputProtocol.ReadMessageBeginAsync(cancellationToken);" << endl + << indent() << "if (msg.Type == TMessageType.Exception)" << endl + << indent() << "{" << endl; + indent_up(); + + out << indent() << "var x = await TApplicationException.ReadAsync(InputProtocol, cancellationToken);" << endl + << indent() << "await InputProtocol.ReadMessageEndAsync(cancellationToken);" << endl + << indent() << "throw x;" << endl; + indent_down(); + + out << indent() << "}" << endl + << endl + << indent() << "var result = new " << resultname << "();" << endl + << indent() << "await result.ReadAsync(InputProtocol, cancellationToken);" << endl + << indent() << "await InputProtocol.ReadMessageEndAsync(cancellationToken);" << endl; + + if (!(*functions_iterator)->get_returntype()->is_void()) + { + if (nullable_) + { + if (type_can_be_null((*functions_iterator)->get_returntype())) + { + out << indent() << "if (result.Success != null)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "return result.Success;" << endl; + indent_down(); + out << indent() << "}" << endl; + } + else + { + out << indent() << "if (result.Success.HasValue)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "return result.Success.Value;" << endl; + indent_down(); + out << indent() << "}" << endl; + } + } + else + { + out << indent() << "if (result.__isset.success)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "return result.Success;" << endl; + indent_down(); + out << indent() << "}" << endl; + } + } + + const vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) + { + if (nullable_) + { + out << indent() << "if (result." << prop_name(*x_iter) << " != null)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "throw result." << prop_name(*x_iter) << ";" << endl; + indent_down(); + out << indent() << "}" << endl; + } + else + { + out << indent() << "if (result.__isset." << normalize_name((*x_iter)->get_name()) << ")" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "throw result." << prop_name(*x_iter) << ";" << endl; + indent_down(); + out << indent() << "}" << endl; + } + } + + if ((*functions_iterator)->get_returntype()->is_void()) + { + out << indent() << "return;" << endl; + } + else + { + out << indent() << "throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, \"" + << function_name << " failed: unknown result\");" << endl; + } + + cleanup_member_name_mapping((*functions_iterator)->get_xceptions()); + indent_down(); + out << indent() << "}" << endl << endl; + } + else + { + indent_down(); + out << indent() << "}" << endl; + } + } + + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_netcore_generator::generate_service_server(ofstream& out, t_service* tservice) +{ + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() != NULL) + { + extends = type_name(tservice->get_extends()); + extends_processor = extends + ".AsyncProcessor, "; + } + + out << indent() << "public class AsyncProcessor : " << extends_processor << "ITAsyncProcessor" << endl + << indent() << "{" << endl; + + indent_up(); + + out << indent() << "private IAsync _iAsync;" << endl + << endl + << indent() << "public AsyncProcessor(IAsync iAsync)"; + + if (!extends.empty()) + { + out << " : base(iAsync)"; + } + + out << endl + << indent() << "{" << endl; + indent_up(); + + out << indent() << "if (iAsync == null) throw new ArgumentNullException(nameof(iAsync));" << endl + << endl + << indent() << "_iAsync = iAsync;" << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) + { + string function_name = (*f_iter)->get_name(); + out << indent() << "processMap_[\"" << correct_function_name_for_async(function_name) << "\"] = " << function_name << "_ProcessAsync;" << endl; + } + + indent_down(); + out << indent() << "}" << endl + << endl; + + if (extends.empty()) + { + out << indent() << "protected delegate Task ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken);" << endl; + } + + if (extends.empty()) + { + out << indent() << "protected Dictionary processMap_ = new Dictionary();" << endl; + } + + out << endl; + + if (extends.empty()) + { + out << indent() << "public async Task ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "return await ProcessAsync(iprot, oprot, CancellationToken.None);" << endl; + indent_down(); + out << indent() << "}" << endl << endl; + + out << indent() << "public async Task ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)" << endl; + } + else + { + out << indent() << "public new async Task ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "return await ProcessAsync(iprot, oprot, CancellationToken.None);" << endl; + indent_down(); + out << indent() << "}" << endl << endl; + + out << indent() << "public new async Task ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)" << endl; + } + + out << indent() << "{" << endl; + indent_up(); + out << indent() << "try" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "var msg = await iprot.ReadMessageBeginAsync(cancellationToken);" << endl + << endl + << indent() << "ProcessFunction fn;" << endl + << indent() << "processMap_.TryGetValue(msg.Name, out fn);" << endl + << endl + << indent() << "if (fn == null)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "await TProtocolUtil.SkipAsync(iprot, TType.Struct, cancellationToken);" << endl + << indent() << "await iprot.ReadMessageEndAsync(cancellationToken);" << endl + << indent() << "var x = new TApplicationException (TApplicationException.ExceptionType.UnknownMethod, \"Invalid method name: '\" + msg.Name + \"'\");" << endl + << indent() << "await oprot.WriteMessageBeginAsync(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID), cancellationToken);" << endl + << indent() << "await x.WriteAsync(oprot, cancellationToken);" << endl + << indent() << "await oprot.WriteMessageEndAsync(cancellationToken);" << endl + << indent() << "await oprot.Transport.FlushAsync(cancellationToken);" << endl + << indent() << "return true;" << endl; + indent_down(); + out << indent() << "}" << endl + << endl + << indent() << "await fn(msg.SeqID, iprot, oprot, cancellationToken);" << endl + << endl; + indent_down(); + out << indent() << "}" << endl; + out << indent() << "catch (IOException)" << endl + << indent() << "{" << endl; + indent_up(); + out << indent() << "return false;" << endl; + indent_down(); + out << indent() << "}" << endl + << endl + << indent() << "return true;" << endl; + indent_down(); + out << indent() << "}" << endl << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) + { + generate_process_function_async(out, tservice, *f_iter); + } + + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_netcore_generator::generate_function_helpers(ofstream& out, t_function* tfunction) +{ + if (tfunction->is_oneway()) + { + return; + } + + t_struct result(program_, tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) + { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + result.append(*f_iter); + } + + generate_netcore_struct_definition(out, &result, false, true, true); +} + +void t_netcore_generator::generate_process_function_async(ofstream& out, t_service* tservice, t_function* tfunction) +{ + (void)tservice; + out << indent() << "public async Task " << tfunction->get_name() + << "_ProcessAsync(int seqid, TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)" << endl + << indent() << "{" << endl; + indent_up(); + + string argsname = tfunction->get_name() + "Args"; + string resultname = tfunction->get_name() + "Result"; + + out << indent() << "var args = new " << argsname << "();" << endl + << indent() << "await args.ReadAsync(iprot, cancellationToken);" << endl + << indent() << "await iprot.ReadMessageEndAsync(cancellationToken);" << endl; + + if (!tfunction->is_oneway()) + { + out << indent() << "var result = new " << resultname << "();" << endl; + } + + out << indent() << "try" << endl + << indent() << "{" << endl; + indent_up(); + + t_struct* xs = tfunction->get_xceptions(); + const vector& xceptions = xs->get_members(); + + if (xceptions.size() > 0) + { + out << indent() << "try" << endl + << indent() << "{" << endl; + indent_up(); + } + + t_struct* arg_struct = tfunction->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + out << indent(); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) + { + out << "result.Success = "; + } + + out << "await _iAsync." << normalize_name(tfunction->get_name()) << "Async("; + + bool first = true; + prepare_member_name_mapping(arg_struct); + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + if (first) + { + first = false; + } + else + { + out << ", "; + } + + out << "args." << prop_name(*f_iter); + if (nullable_ && !type_can_be_null((*f_iter)->get_type())) + { + out << ".Value"; + } + } + + cleanup_member_name_mapping(arg_struct); + + if (!first) + { + out << ", "; + } + + out << "cancellationToken);" << endl; + + vector::const_iterator x_iter; + + prepare_member_name_mapping(xs, xs->get_members(), resultname); + if (xceptions.size() > 0) + { + indent_down(); + out << indent() << "}" << endl; + + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) + { + out << indent() << "catch (" << type_name((*x_iter)->get_type(), false, false) << " " << (*x_iter)->get_name() << ")" << endl + << indent() << "{" << endl; + + if (!tfunction->is_oneway()) + { + indent_up(); + out << indent() << "result." << prop_name(*x_iter) << " = " << (*x_iter)->get_name() << ";" << endl; + indent_down(); + } + out << indent() << "}" << endl; + } + } + + if (!tfunction->is_oneway()) + { + out << indent() << "await oprot.WriteMessageBeginAsync(new TMessage(\"" + << correct_function_name_for_async(tfunction->get_name()) << "\", TMessageType.Reply, seqid), cancellationToken); " << endl + << indent() << "await result.WriteAsync(oprot, cancellationToken);" << endl; + } + indent_down(); + + cleanup_member_name_mapping(xs); + + out << indent() << "}" << endl + << indent() << "catch (TTransportException)" << endl + << indent() << "{" << endl + << indent() << " throw;" << endl + << indent() << "}" << endl + << indent() << "catch (Exception ex)" << endl + << indent() << "{" << endl; + indent_up(); + + out << indent() << "Console.Error.WriteLine(\"Error occurred in processor:\");" << endl + << indent() << "Console.Error.WriteLine(ex.ToString());" << endl; + + if (tfunction->is_oneway()) + { + indent_down(); + out << indent() << "}" << endl; + } + else + { + out << indent() << "var x = new TApplicationException(TApplicationException.ExceptionType.InternalError,\" Internal error.\");" << endl + << indent() << "await oprot.WriteMessageBeginAsync(new TMessage(\"" << correct_function_name_for_async(tfunction->get_name()) + << "\", TMessageType.Exception, seqid), cancellationToken);" << endl + << indent() << "await x.WriteAsync(oprot, cancellationToken);" << endl; + indent_down(); + + out << indent() << "}" << endl + << indent() << "await oprot.WriteMessageEndAsync(cancellationToken);" << endl + << indent() << "await oprot.Transport.FlushAsync(cancellationToken);" << endl; + } + + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_netcore_generator::generate_netcore_union_reader(ofstream& out, t_struct* tunion) +{ + // Thanks to THRIFT-1768, we don't need to check for required fields in the union + const vector& fields = tunion->get_members(); + vector::const_iterator f_iter; + + out << indent() << "public static " << tunion->get_name() << " Read(TProtocol iprot)" << endl; + scope_up(out); + + out << indent() << "iprot.IncrementRecursionDepth();" << endl; + out << indent() << "try" << endl; + scope_up(out); + + out << indent() << tunion->get_name() << " retval;" << endl; + out << indent() << "iprot.ReadStructBegin();" << endl; + out << indent() << "TField field = iprot.ReadFieldBegin();" << endl; + // we cannot have the first field be a stop -- we must have a single field defined + out << indent() << "if (field.Type == TType.Stop)" << endl; + scope_up(out); + out << indent() << "iprot.ReadFieldEnd();" << endl; + out << indent() << "retval = new ___undefined();" << endl; + scope_down(out); + out << indent() << "else" << endl; + scope_up(out); + out << indent() << "switch (field.ID)" << endl; + scope_up(out); + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + out << indent() << "case " << (*f_iter)->get_key() << ":" << endl; + indent_up(); + out << indent() << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; + indent_up(); + + out << indent() << type_name((*f_iter)->get_type()) << " temp;" << endl; + generate_deserialize_field(out, (*f_iter), "temp", true); + out << indent() << "retval = new " << (*f_iter)->get_name() << "(temp);" << endl; + + indent_down(); + out << indent() << "} else { " << endl << indent() << " TProtocolUtil.Skip(iprot, field.Type);" + << endl << indent() << " retval = new ___undefined();" << endl << indent() << "}" << endl + << indent() << "break;" << endl; + indent_down(); + } + + out << indent() << "default: " << endl; + indent_up(); + out << indent() << "TProtocolUtil.Skip(iprot, field.Type);" << endl << indent() + << "retval = new ___undefined();" << endl; + out << indent() << "break;" << endl; + indent_down(); + + scope_down(out); + + out << indent() << "iprot.ReadFieldEnd();" << endl; + + out << indent() << "if (iprot.ReadFieldBegin().Type != TType.Stop)" << endl; + scope_up(out); + out << indent() << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl; + scope_down(out); + + // end of else for TStop + scope_down(out); + out << indent() << "iprot.ReadStructEnd();" << endl; + out << indent() << "return retval;" << endl; + indent_down(); + + scope_down(out); + out << indent() << "finally" << endl; + scope_up(out); + out << indent() << "iprot.DecrementRecursionDepth();" << endl; + scope_down(out); + + out << indent() << "}" << endl << endl; +} + +void t_netcore_generator::generate_deserialize_field(ofstream& out, t_field* tfield, string prefix, bool is_propertyless) +{ + t_type* type = tfield->get_type(); + while (type->is_typedef()) + { + type = static_cast(type)->get_type(); + } + + if (type->is_void()) + { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = prefix + (is_propertyless ? "" : prop_name(tfield)); + + if (type->is_struct() || type->is_xception()) + { + generate_deserialize_struct(out, static_cast(type), name); + } + else if (type->is_container()) + { + generate_deserialize_container(out, type, name); + } + else if (type->is_base_type() || type->is_enum()) + { + out << indent() << name << " = "; + + if (type->is_enum()) + { + out << "(" << type_name(type, false, true) << ")"; + } + + out << "await iprot."; + + if (type->is_base_type()) + { + t_base_type::t_base tbase = static_cast(type)->get_base(); + switch (tbase) + { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) + { + out << "ReadBinaryAsync(cancellationToken);"; + } + else + { + out << "ReadStringAsync(cancellationToken);"; + } + break; + case t_base_type::TYPE_BOOL: + out << "ReadBoolAsync(cancellationToken);"; + break; + case t_base_type::TYPE_I8: + out << "ReadByteAsync(cancellationToken);"; + break; + case t_base_type::TYPE_I16: + out << "ReadI16Async(cancellationToken);"; + break; + case t_base_type::TYPE_I32: + out << "ReadI32Async(cancellationToken);"; + break; + case t_base_type::TYPE_I64: + out << "ReadI64Async(cancellationToken);"; + break; + case t_base_type::TYPE_DOUBLE: + out << "ReadDoubleAsync(cancellationToken);"; + break; + default: + throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase); + } + } + else if (type->is_enum()) + { + out << "ReadI32Async(cancellationToken);"; + } + out << endl; + } + else + { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type_name(type).c_str()); + } +} + +void t_netcore_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, string prefix) +{ + if (union_ && tstruct->is_union()) + { + out << indent() << prefix << " = await " << type_name(tstruct) << ".ReadAsync(iprot, cancellationToken);" << endl; + } + else + { + out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl + << indent() << "await " << prefix << ".ReadAsync(iprot, cancellationToken);" << endl; + } +} + +void t_netcore_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) +{ + out << indent() << "{" << endl; + indent_up(); + + string obj; + + if (ttype->is_map()) + { + obj = tmp("_map"); + } + else if (ttype->is_set()) + { + obj = tmp("_set"); + } + else if (ttype->is_list()) + { + obj = tmp("_list"); + } + + out << indent() << prefix << " = new " << type_name(ttype, false, true) << "();" << endl; + if (ttype->is_map()) + { + out << indent() << "TMap " << obj << " = await iprot.ReadMapBeginAsync(cancellationToken);" << endl; + } + else if (ttype->is_set()) + { + out << indent() << "TSet " << obj << " = await iprot.ReadSetBeginAsync(cancellationToken);" << endl; + } + else if (ttype->is_list()) + { + out << indent() << "TList " << obj << " = await iprot.ReadListBeginAsync(cancellationToken);" << endl; + } + + string i = tmp("_i"); + out << indent() << "for(int " << i << " = 0; " << i << " < " << obj << ".Count; ++" << i << ")" << endl + << indent() << "{" << endl; + indent_up(); + + if (ttype->is_map()) + { + generate_deserialize_map_element(out, static_cast(ttype), prefix); + } + else if (ttype->is_set()) + { + generate_deserialize_set_element(out, static_cast(ttype), prefix); + } + else if (ttype->is_list()) + { + generate_deserialize_list_element(out, static_cast(ttype), prefix); + } + + indent_down(); + out << indent() << "}" << endl; + + if (ttype->is_map()) + { + out << indent() << "await iprot.ReadMapEndAsync(cancellationToken);" << endl; + } + else if (ttype->is_set()) + { + out << indent() << "await iprot.ReadSetEndAsync(cancellationToken);" << endl; + } + else if (ttype->is_list()) + { + out << indent() << "await iprot.ReadListEndAsync(cancellationToken);" << endl; + } + + indent_down(); + out << indent() << "}" << endl; +} + +void t_netcore_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) +{ + string key = tmp("_key"); + string val = tmp("_val"); + + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + out << indent() << declare_field(&fkey) << endl; + out << indent() << declare_field(&fval) << endl; + + generate_deserialize_field(out, &fkey); + generate_deserialize_field(out, &fval); + + out << indent() << prefix << "[" << key << "] = " << val << ";" << endl; +} + +void t_netcore_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) +{ + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); + + out << indent() << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + out << indent() << prefix << ".Add(" << elem << ");" << endl; +} + +void t_netcore_generator::generate_deserialize_list_element(ofstream& out, t_list* tlist, string prefix) +{ + string elem = tmp("_elem"); + t_field felem(tlist->get_elem_type(), elem); + + out << indent() << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + out << indent() << prefix << ".Add(" << elem << ");" << endl; +} + +void t_netcore_generator::generate_serialize_field(ofstream& out, t_field* tfield, string prefix, bool is_element, bool is_propertyless) +{ + t_type* type = tfield->get_type(); + while (type->is_typedef()) + { + type = static_cast(type)->get_type(); + } + + string name = prefix + (is_propertyless ? "" : prop_name(tfield)); + + if (type->is_void()) + { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name; + } + + if (type->is_struct() || type->is_xception()) + { + generate_serialize_struct(out, static_cast(type), name); + } + else if (type->is_container()) + { + generate_serialize_container(out, type, name); + } + else if (type->is_base_type() || type->is_enum()) + { + out << indent() << "await oprot."; + + string nullable_name = nullable_ && !is_element && !field_is_required(tfield) ? name + ".Value" : name; + + if (type->is_base_type()) + { + t_base_type::t_base tbase = static_cast(type)->get_base(); + switch (tbase) + { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + case t_base_type::TYPE_STRING: + if (type->is_binary()) + { + out << "WriteBinaryAsync("; + } + else + { + out << "WriteStringAsync("; + } + out << name << ", cancellationToken);"; + break; + case t_base_type::TYPE_BOOL: + out << "WriteBoolAsync(" << nullable_name << ", cancellationToken);"; + break; + case t_base_type::TYPE_I8: + out << "WriteByteAsync(" << nullable_name << ", cancellationToken);"; + break; + case t_base_type::TYPE_I16: + out << "WriteI16Async(" << nullable_name << ", cancellationToken);"; + break; + case t_base_type::TYPE_I32: + out << "WriteI32Async(" << nullable_name << ", cancellationToken);"; + break; + case t_base_type::TYPE_I64: + out << "WriteI64Async(" << nullable_name << ", cancellationToken);"; + break; + case t_base_type::TYPE_DOUBLE: + out << "WriteDoubleAsync(" << nullable_name << ", cancellationToken);"; + break; + default: + throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase); + } + } + else if (type->is_enum()) + { + out << "WriteI32Async((int)" << nullable_name << ", cancellationToken);"; + } + out << endl; + } + else + { + printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), type_name(type).c_str()); + } +} + +void t_netcore_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) +{ + (void)tstruct; + out << indent() << "await " << prefix << ".WriteAsync(oprot, cancellationToken);" << endl; +} + +void t_netcore_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) +{ + out << indent() << "{" << endl; + indent_up(); + + if (ttype->is_map()) + { + out << indent() << "await oprot.WriteMapBeginAsync(new TMap(" << type_to_enum(static_cast(ttype)->get_key_type()) + << ", " << type_to_enum(static_cast(ttype)->get_val_type()) << ", " << prefix + << ".Count), cancellationToken);" << endl; + } + else if (ttype->is_set()) + { + out << indent() << "await oprot.WriteSetBeginAsync(new TSet(" << type_to_enum(static_cast(ttype)->get_elem_type()) + << ", " << prefix << ".Count), cancellationToken);" << endl; + } + else if (ttype->is_list()) + { + out << indent() << "await oprot.WriteListBeginAsync(new TList(" + << type_to_enum(static_cast(ttype)->get_elem_type()) << ", " << prefix << ".Count), cancellationToken);" + << endl; + } + + string iter = tmp("_iter"); + if (ttype->is_map()) + { + out << indent() << "foreach (" << type_name(static_cast(ttype)->get_key_type()) << " " << iter + << " in " << prefix << ".Keys)"; + } + else if (ttype->is_set()) + { + out << indent() << "foreach (" << type_name(static_cast(ttype)->get_elem_type()) << " " << iter + << " in " << prefix << ")"; + } + else if (ttype->is_list()) + { + out << indent() << "foreach (" << type_name(static_cast(ttype)->get_elem_type()) << " " << iter + << " in " << prefix << ")"; + } + + out << endl; + out << indent() << "{" << endl; + indent_up(); + + if (ttype->is_map()) + { + generate_serialize_map_element(out, static_cast(ttype), iter, prefix); + } + else if (ttype->is_set()) + { + generate_serialize_set_element(out, static_cast(ttype), iter); + } + else if (ttype->is_list()) + { + generate_serialize_list_element(out, static_cast(ttype), iter); + } + + indent_down(); + out << indent() << "}" << endl; + + if (ttype->is_map()) + { + out << indent() << "await oprot.WriteMapEndAsync(cancellationToken);" << endl; + } + else if (ttype->is_set()) + { + out << indent() << "await oprot.WriteSetEndAsync(cancellationToken);" << endl; + } + else if (ttype->is_list()) + { + out << indent() << "await oprot.WriteListEndAsync(cancellationToken);" << endl; + } + + indent_down(); + out << indent() << "}" << endl; +} + +void t_netcore_generator::generate_serialize_map_element(ofstream& out, t_map* tmap, string iter, string map) +{ + t_field kfield(tmap->get_key_type(), iter); + generate_serialize_field(out, &kfield, "", true); + t_field vfield(tmap->get_val_type(), map + "[" + iter + "]"); + generate_serialize_field(out, &vfield, "", true); +} + +void t_netcore_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) +{ + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, &efield, "", true); +} + +void t_netcore_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) +{ + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, &efield, "", true); +} + +void t_netcore_generator::generate_property(ofstream& out, t_field* tfield, bool isPublic, bool generateIsset) +{ + generate_netcore_property(out, tfield, isPublic, generateIsset, "_"); +} + +void t_netcore_generator::generate_netcore_property(ofstream& out, t_field* tfield, bool isPublic, bool generateIsset, string fieldPrefix) +{ + if ((serialize_ || wcf_) && isPublic) + { + out << indent() << "[DataMember(Order = 0)]" << endl; + } + bool has_default = field_has_default(tfield); + bool is_required = field_is_required(tfield); + if ((nullable_ && !has_default) || is_required) + { + out << indent() << (isPublic ? "public " : "private ") << type_name(tfield->get_type(), false, false, true, is_required) << " " << prop_name(tfield) << " { get; set; }" << endl; + } + else + { + out << indent() << (isPublic ? "public " : "private ") << type_name(tfield->get_type(), false, false, true) << " " << prop_name(tfield) << endl + << indent() << "{" << endl; + indent_up(); + + out << indent() << "get" << endl + << indent() << "{" << endl; + indent_up(); + + bool use_nullable = false; + if (nullable_) + { + t_type* ttype = tfield->get_type(); + while (ttype->is_typedef()) + { + ttype = static_cast(ttype)->get_type(); + } + if (ttype->is_base_type()) + { + use_nullable = static_cast(ttype)->get_base() != t_base_type::TYPE_STRING; + } + } + + out << indent() << "return " << fieldPrefix + tfield->get_name() << ";" << endl; + indent_down(); + out << indent() << "}" << endl + << indent() << "set" << endl + << indent() << "{" << endl; + indent_up(); + + if (use_nullable) + { + if (generateIsset) + { + out << indent() << "__isset." << normalize_name(tfield->get_name()) << " = value.HasValue;" << endl; + } + out << indent() << "if (value.HasValue) this." << fieldPrefix + tfield->get_name() << " = value.Value;" << endl; + } + else + { + if (generateIsset) + { + out << indent() << "__isset." << normalize_name(tfield->get_name()) << " = true;" << endl; + } + out << indent() << "this." << fieldPrefix + tfield->get_name() << " = value;" << endl; + } + + indent_down(); + out << indent() << "}" << endl; + indent_down(); + out << indent() << "}" << endl; + } + out << endl; +} + +string t_netcore_generator::make_valid_csharp_identifier(string const& fromName) +{ + string str = fromName; + if (str.empty()) + { + return str; + } + + // tests rely on this + assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9')); + + // if the first letter is a number, we add an additional underscore in front of it + char c = str.at(0); + if (('0' <= c) && (c <= '9')) + { + str = "_" + str; + } + + // following chars: letter, number or underscore + for (size_t i = 0; i < str.size(); ++i) + { + c = str.at(i); + if (('A' > c || c > 'Z') && ('a' > c || c > 'z') && ('0' > c || c > '9') && '_' != c) + { + str.replace(i, 1, "_"); + } + } + + return str; +} + +void t_netcore_generator::cleanup_member_name_mapping(void* scope) +{ + if (member_mapping_scopes.empty()) + { + throw "internal error: cleanup_member_name_mapping() no scope active"; + } + + member_mapping_scope& active = member_mapping_scopes.back(); + if (active.scope_member != scope) + { + throw "internal error: cleanup_member_name_mapping() called for wrong struct"; + } + + member_mapping_scopes.pop_back(); +} + +string t_netcore_generator::get_mapped_member_name(string name) +{ + if (!member_mapping_scopes.empty()) + { + member_mapping_scope& active = member_mapping_scopes.back(); + map::iterator iter = active.mapping_table.find(name); + if (active.mapping_table.end() != iter) + { + return iter->second; + } + } + + pverbose("no mapping for member %s\n", name.c_str()); + return name; +} + +void t_netcore_generator::prepare_member_name_mapping(t_struct* tstruct) +{ + prepare_member_name_mapping(tstruct, tstruct->get_members(), tstruct->get_name()); +} + +void t_netcore_generator::prepare_member_name_mapping(void* scope, const vector& members, const string& structname) +{ + // begin new scope + member_mapping_scope dummy; + dummy.scope_member = 0; + member_mapping_scopes.push_back(dummy); + member_mapping_scope& active = member_mapping_scopes.back(); + active.scope_member = scope; + + // current C# generator policy: + // - prop names are always rendered with an Uppercase first letter + // - struct names are used as given + std::set used_member_names; + vector::const_iterator iter; + + // prevent name conflicts with struct (CS0542 error) + used_member_names.insert(structname); + + // prevent name conflicts with known methods (THRIFT-2942) + used_member_names.insert("Read"); + used_member_names.insert("Write"); + + for (iter = members.begin(); iter != members.end(); ++iter) + { + string oldname = (*iter)->get_name(); + string newname = prop_name(*iter, true); + while (true) + { + // new name conflicts with another member + if (used_member_names.find(newname) != used_member_names.end()) + { + pverbose("struct %s: member %s conflicts with another member\n", structname.c_str(), newname.c_str()); + newname += '_'; + continue; + } + + // add always, this helps us to detect edge cases like + // different spellings ("foo" and "Foo") within the same struct + pverbose("struct %s: member mapping %s => %s\n", structname.c_str(), oldname.c_str(), newname.c_str()); + active.mapping_table[oldname] = newname; + used_member_names.insert(newname); + break; + } + } +} + +string t_netcore_generator::prop_name(t_field* tfield, bool suppress_mapping) +{ + string name(tfield->get_name()); + if (suppress_mapping) + { + name[0] = toupper(name[0]); + } + else + { + name = get_mapped_member_name(name); + } + return name; +} + +string t_netcore_generator::type_name(t_type* ttype, bool in_container, bool in_init, bool in_param, bool is_required) +{ + (void)in_init; + + while (ttype->is_typedef()) + { + ttype = static_cast(ttype)->get_type(); + } + + if (ttype->is_base_type()) + { + return base_type_name(static_cast(ttype), in_container, in_param, is_required); + } + + if (ttype->is_map()) + { + t_map* tmap = static_cast(ttype); + return "Dictionary<" + type_name(tmap->get_key_type(), true) + ", " + type_name(tmap->get_val_type(), true) + ">"; + } + + if (ttype->is_set()) + { + t_set* tset = static_cast(ttype); + return "THashSet<" + type_name(tset->get_elem_type(), true) + ">"; + } + + if (ttype->is_list()) + { + t_list* tlist = static_cast(ttype); + return "List<" + type_name(tlist->get_elem_type(), true) + ">"; + } + + t_program* program = ttype->get_program(); + string postfix = (!is_required && nullable_ && in_param && ttype->is_enum()) ? "?" : ""; + if (program != NULL && program != program_) + { + string ns = program->get_namespace("netcore"); + if (!ns.empty()) + { + return ns + "." + normalize_name(ttype->get_name()) + postfix; + } + } + + return normalize_name(ttype->get_name()) + postfix; +} + +string t_netcore_generator::base_type_name(t_base_type* tbase, bool in_container, bool in_param, bool is_required) +{ + (void)in_container; + string postfix = (!is_required && nullable_ && in_param) ? "?" : ""; + switch (tbase->get_base()) + { + case t_base_type::TYPE_VOID: + return "void"; + case t_base_type::TYPE_STRING: + { + if (tbase->is_binary()) + { + return "byte[]"; + } + return "string"; + } + case t_base_type::TYPE_BOOL: + return "bool" + postfix; + case t_base_type::TYPE_I8: + return "sbyte" + postfix; + case t_base_type::TYPE_I16: + return "short" + postfix; + case t_base_type::TYPE_I32: + return "int" + postfix; + case t_base_type::TYPE_I64: + return "long" + postfix; + case t_base_type::TYPE_DOUBLE: + return "double" + postfix; + default: + throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase->get_base()); + } +} + +string t_netcore_generator::declare_field(t_field* tfield, bool init, string prefix) +{ + string result = type_name(tfield->get_type()) + " " + prefix + tfield->get_name(); + if (init) + { + t_type* ttype = tfield->get_type(); + while (ttype->is_typedef()) + { + ttype = static_cast(ttype)->get_type(); + } + if (ttype->is_base_type() && field_has_default(tfield)) + { + ofstream dummy; + result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value()); + } + else if (ttype->is_base_type()) + { + t_base_type::t_base tbase = static_cast(ttype)->get_base(); + switch (tbase) + { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + result += " = null"; + break; + case t_base_type::TYPE_BOOL: + result += " = false"; + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + result += " = 0"; + break; + case t_base_type::TYPE_DOUBLE: + result += " = (double)0"; + break; + } + } + else if (ttype->is_enum()) + { + result += " = (" + type_name(ttype, false, true) + ")0"; + } + else if (ttype->is_container()) + { + result += " = new " + type_name(ttype, false, true) + "()"; + } + else + { + result += " = new " + type_name(ttype, false, true) + "()"; + } + } + return result + ";"; +} + +string t_netcore_generator::function_signature(t_function* tfunction, string prefix) +{ + t_type* ttype = tfunction->get_returntype(); + return type_name(ttype) + " " + normalize_name(prefix + tfunction->get_name()) + "(" + argument_list(tfunction->get_arglist()) + ")"; +} + +string t_netcore_generator::function_signature_async(t_function* tfunction, string prefix) +{ + t_type* ttype = tfunction->get_returntype(); + string task = "Task"; + if (!ttype->is_void()) + { + task += "<" + type_name(ttype) + ">"; + } + + string result = task + " " + normalize_name(prefix + tfunction->get_name()) + "Async("; + string args = argument_list(tfunction->get_arglist()); + result += args; + if (!args.empty()) + { + result += ", "; + } + result += "CancellationToken cancellationToken)"; + + return result; +} + +string t_netcore_generator::argument_list(t_struct* tstruct) +{ + string result = ""; + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) + { + if (first) + { + first = false; + } + else + { + result += ", "; + } + result += type_name((*f_iter)->get_type()) + " " + normalize_name((*f_iter)->get_name()); + } + return result; +} + +string t_netcore_generator::type_to_enum(t_type* type) +{ + while (type->is_typedef()) + { + type = static_cast(type)->get_type(); + } + + if (type->is_base_type()) + { + t_base_type::t_base tbase = static_cast(type)->get_base(); + switch (tbase) + { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "TType.String"; + case t_base_type::TYPE_BOOL: + return "TType.Bool"; + case t_base_type::TYPE_I8: + return "TType.Byte"; + case t_base_type::TYPE_I16: + return "TType.I16"; + case t_base_type::TYPE_I32: + return "TType.I32"; + case t_base_type::TYPE_I64: + return "TType.I64"; + case t_base_type::TYPE_DOUBLE: + return "TType.Double"; + } + } + else if (type->is_enum()) + { + return "TType.I32"; + } + else if (type->is_struct() || type->is_xception()) + { + return "TType.Struct"; + } + else if (type->is_map()) + { + return "TType.Map"; + } + else if (type->is_set()) + { + return "TType.Set"; + } + else if (type->is_list()) + { + return "TType.List"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +void t_netcore_generator::generate_netcore_docstring_comment(ofstream& out, string contents) +{ + docstring_comment(out, "/// " + endl, "/// ", contents, "/// " + endl); +} + +void t_netcore_generator::generate_netcore_doc(ofstream& out, t_field* field) +{ + if (field->get_type()->is_enum()) + { + string combined_message = field->get_doc() + endl + "get_type()) + "\"/>"; + generate_netcore_docstring_comment(out, combined_message); + } + else + { + generate_netcore_doc(out, static_cast(field)); + } +} + +void t_netcore_generator::generate_netcore_doc(ofstream& out, t_doc* tdoc) +{ + if (tdoc->has_doc()) + { + generate_netcore_docstring_comment(out, tdoc->get_doc()); + } +} + +void t_netcore_generator::generate_netcore_doc(ofstream& out, t_function* tfunction) +{ + if (tfunction->has_doc()) + { + stringstream ps; + const vector& fields = tfunction->get_arglist()->get_members(); + vector::const_iterator p_iter; + for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) + { + t_field* p = *p_iter; + ps << endl << "get_name() << "\">"; + if (p->has_doc()) + { + string str = p->get_doc(); + str.erase(remove(str.begin(), str.end(), '\n'), str.end()); + ps << str; + } + ps << ""; + } + + docstring_comment(out, + "", + "/// ", + "" + endl + tfunction->get_doc() + "" + ps.str(), + ""); + } +} + +void t_netcore_generator::docstring_comment(ofstream& out, const string& comment_start, const string& line_prefix, const string& contents, const string& comment_end) +{ + if (comment_start != "") + { + out << indent() << comment_start; + } + + stringstream docs(contents, std::ios_base::in); + + while (!(docs.eof() || docs.fail())) + { + char line[1024]; + docs.getline(line, 1024); + + // Just prnt a newline when the line & prefix are empty. + if (strlen(line) == 0 && line_prefix == "" && !docs.eof()) + { + out << endl; + } + else if (strlen(line) > 0 || !docs.eof()) + { // skip the empty last line + out << indent() << line_prefix << line << endl; + } + } + if (comment_end != "") + { + out << indent() << comment_end; + } +} + +string t_netcore_generator::get_enum_class_name(t_type* type) +{ + string package = ""; + t_program* program = type->get_program(); + if (program != NULL && program != program_) + { + package = program->get_namespace("netcore") + "."; + } + return package + type->get_name(); +} + +THRIFT_REGISTER_GENERATOR( + netcore, + "C#", + " wcf: Adds bindings for WCF to generated classes.\n" + " serial: Add serialization support to generated classes.\n" + " nullable: Use nullable types for properties.\n" + " hashcode: Generate a hashcode and equals implementation for classes.\n" + " union: Use new union typing, which includes a static read function for union types.\n" +) diff --git a/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc b/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc new file mode 100644 index 0000000..594219a --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc @@ -0,0 +1,1762 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "thrift/platform.h" +#include "thrift/version.h" +#include "thrift/generate/t_oop_generator.h" + +using std::ios; +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * OCaml code generator. + * + */ +class t_ocaml_generator : public t_oop_generator { +public: + t_ocaml_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + /* no options yet */ + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + throw "unknown option ocaml:" + iter->first; + } + + out_dir_base_ = "gen-ocaml"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + void generate_program(); + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + std::string render_const_value(t_type* type, t_const_value* value); + bool struct_member_persistent(t_field* tmember); + bool struct_member_omitable(t_field* tmember); + bool struct_member_default_cheaply_comparable(t_field* tmember); + std::string struct_member_copy_of(t_type* type, string what); + + /** + * Struct generation code + */ + + void generate_ocaml_struct(t_struct* tstruct, bool is_exception); + void generate_ocaml_struct_definition(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false); + void generate_ocaml_struct_member(std::ofstream& out, string tname, t_field* tmember); + void generate_ocaml_struct_sig(std::ofstream& out, t_struct* tstruct, bool is_exception); + void generate_ocaml_struct_reader(std::ofstream& out, t_struct* tstruct); + void generate_ocaml_struct_writer(std::ofstream& out, t_struct* tstruct); + void generate_ocaml_function_helpers(t_function* tfunction); + void generate_ocaml_method_copy(std::ofstream& out, const vector& members); + void generate_ocaml_member_copy(std::ofstream& out, t_field* member); + + /** + * Service-level generation functions + */ + + void generate_service_helpers(t_service* tservice); + void generate_service_interface(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* tfunction); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, t_field* tfield, std::string prefix); + + void generate_deserialize_struct(std::ofstream& out, t_struct* tstruct); + + void generate_deserialize_container(std::ofstream& out, t_type* ttype); + + void generate_deserialize_set_element(std::ofstream& out, t_set* tset); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix = ""); + void generate_deserialize_type(std::ofstream& out, t_type* type); + + void generate_serialize_field(std::ofstream& out, t_field* tfield, std::string name = ""); + + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string kiter, + std::string viter); + + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + + /** + * Helper rendering functions + */ + + std::string ocaml_autogen_comment(); + std::string ocaml_imports(); + std::string type_name(t_type* ttype); + std::string function_signature(t_function* tfunction, std::string prefix = ""); + std::string function_type(t_function* tfunc, bool method = false, bool options = false); + std::string argument_list(t_struct* tstruct); + std::string type_to_enum(t_type* ttype); + std::string render_ocaml_type(t_type* type); + +private: + /** + * File streams + */ + + std::ofstream f_types_; + std::ofstream f_consts_; + std::ofstream f_service_; + + std::ofstream f_types_i_; + std::ofstream f_service_i_; +}; + +/* + * This is necessary because we want typedefs to appear later, + * after all the types have been declared. + */ +void t_ocaml_generator::generate_program() { + // Initialize the generator + init_generator(); + + // Generate enums + vector enums = program_->get_enums(); + vector::iterator en_iter; + for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { + generate_enum(*en_iter); + } + + // Generate structs + vector structs = program_->get_structs(); + vector::iterator st_iter; + for (st_iter = structs.begin(); st_iter != structs.end(); ++st_iter) { + generate_struct(*st_iter); + } + + // Generate xceptions + vector xceptions = program_->get_xceptions(); + vector::iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + generate_xception(*x_iter); + } + + // Generate typedefs + vector typedefs = program_->get_typedefs(); + vector::iterator td_iter; + for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { + generate_typedef(*td_iter); + } + + // Generate services + vector services = program_->get_services(); + vector::iterator sv_iter; + for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { + service_name_ = get_service_name(*sv_iter); + generate_service(*sv_iter); + } + + // Generate constants + vector consts = program_->get_consts(); + generate_consts(consts); + + // Close the generator + close_generator(); +} + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_ocaml_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + + // Make output file + string f_types_name = get_out_dir() + program_name_ + "_types.ml"; + f_types_.open(f_types_name.c_str()); + string f_types_i_name = get_out_dir() + program_name_ + "_types.mli"; + f_types_i_.open(f_types_i_name.c_str()); + + string f_consts_name = get_out_dir() + program_name_ + "_consts.ml"; + f_consts_.open(f_consts_name.c_str()); + + // Print header + f_types_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl; + f_types_i_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl; + f_consts_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl << "open " + << capitalize(program_name_) << "_types" << endl; +} + +/** + * Autogen'd comment + */ +string t_ocaml_generator::ocaml_autogen_comment() { + return std::string("(*\n") + " Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + "\n" + + " DO NOT EDIT UNLESS YOU ARE SURE YOU KNOW WHAT YOU ARE DOING\n" + "*)\n"; +} + +/** + * Prints standard thrift imports + */ +string t_ocaml_generator::ocaml_imports() { + return "open Thrift"; +} + +/** + * Closes the type files + */ +void t_ocaml_generator::close_generator() { + // Close types file + f_types_.close(); +} + +/** + * Generates a typedef. Ez. + * + * @param ttypedef The type definition + */ +void t_ocaml_generator::generate_typedef(t_typedef* ttypedef) { + f_types_ << indent() << "type " << decapitalize(ttypedef->get_symbolic()) << " = " + << render_ocaml_type(ttypedef->get_type()) << endl << endl; + f_types_i_ << indent() << "type " << decapitalize(ttypedef->get_symbolic()) << " = " + << render_ocaml_type(ttypedef->get_type()) << endl << endl; +} + +/** + * Generates code for an enumerated type. + * the values. + * + * @param tenum The enumeration + */ +void t_ocaml_generator::generate_enum(t_enum* tenum) { + indent(f_types_) << "module " << capitalize(tenum->get_name()) << " = " << endl << "struct" + << endl; + indent(f_types_i_) << "module " << capitalize(tenum->get_name()) << " : " << endl << "sig" + << endl; + indent_up(); + indent(f_types_) << "type t = " << endl; + indent(f_types_i_) << "type t = " << endl; + indent_up(); + vector constants = tenum->get_constants(); + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + string name = capitalize((*c_iter)->get_name()); + indent(f_types_) << "| " << name << endl; + indent(f_types_i_) << "| " << name << endl; + } + indent_down(); + + indent(f_types_) << "let to_i = function" << endl; + indent(f_types_i_) << "val to_i : t -> Int32.t" << endl; + indent_up(); + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + string name = capitalize((*c_iter)->get_name()); + indent(f_types_) << "| " << name << " -> " << value << "l" << endl; + } + indent_down(); + + indent(f_types_) << "let of_i = function" << endl; + indent(f_types_i_) << "val of_i : Int32.t -> t" << endl; + indent_up(); + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + string name = capitalize((*c_iter)->get_name()); + indent(f_types_) << "| " << value << "l -> " << name << endl; + } + indent(f_types_) << "| _ -> raise Thrift_error" << endl; + indent_down(); + indent_down(); + indent(f_types_) << "end" << endl; + indent(f_types_i_) << "end" << endl; +} + +/** + * Generate a constant value + */ +void t_ocaml_generator::generate_const(t_const* tconst) { + t_type* type = tconst->get_type(); + string name = decapitalize(tconst->get_name()); + t_const_value* value = tconst->get_value(); + + indent(f_consts_) << "let " << name << " = " << render_const_value(type, value) << endl << endl; +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +string t_ocaml_generator::render_const_value(t_type* type, t_const_value* value) { + type = get_true_type(type); + std::ostringstream out; + // OCaml requires all floating point numbers contain a decimal point + out.setf(ios::showpoint); + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + out << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + out << (value->get_integer() > 0 ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + out << value->get_integer(); + break; + case t_base_type::TYPE_I32: + out << value->get_integer() << "l"; + break; + case t_base_type::TYPE_I64: + out << value->get_integer() << "L"; + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + out << value->get_integer() << ".0"; + } else { + out << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + t_enum* tenum = (t_enum*)type; + vector constants = tenum->get_constants(); + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int val = (*c_iter)->get_value(); + if (val == value->get_integer()) { + indent(out) << capitalize(tenum->get_name()) << "." << capitalize((*c_iter)->get_name()); + break; + } + } + } else if (type->is_struct() || type->is_xception()) { + string cname = type_name(type); + string ct = tmp("_c"); + out << endl; + indent_up(); + indent(out) << "(let " << ct << " = new " << cname << " in" << endl; + indent_up(); + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + string fname = v_iter->first->get_string(); + out << indent(); + out << ct << "#set_" << fname << " "; + out << render_const_value(field_type, v_iter->second); + out << ";" << endl; + } + indent(out) << ct << ")"; + indent_down(); + indent_down(); + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + string hm = tmp("_hm"); + out << endl; + indent_up(); + indent(out) << "(let " << hm << " = Hashtbl.create " << val.size() << " in" << endl; + indent_up(); + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string key = render_const_value(ktype, v_iter->first); + string val = render_const_value(vtype, v_iter->second); + indent(out) << "Hashtbl.add " << hm << " " << key << " " << val << ";" << endl; + } + indent(out) << hm << ")"; + indent_down(); + indent_down(); + } else if (type->is_list()) { + t_type* etype; + etype = ((t_list*)type)->get_elem_type(); + out << "[" << endl; + indent_up(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + out << indent(); + out << render_const_value(etype, *v_iter); + out << ";" << endl; + } + indent_down(); + indent(out) << "]"; + } else if (type->is_set()) { + t_type* etype = ((t_set*)type)->get_elem_type(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + string hm = tmp("_hm"); + indent(out) << "(let " << hm << " = Hashtbl.create " << val.size() << " in" << endl; + indent_up(); + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(etype, *v_iter); + indent(out) << "Hashtbl.add " << hm << " " << val << " true;" << endl; + } + indent(out) << hm << ")" << endl; + indent_down(); + out << endl; + } else { + throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); + } + return out.str(); +} + +/** + * Generates a "struct" + */ +void t_ocaml_generator::generate_struct(t_struct* tstruct) { + generate_ocaml_struct(tstruct, false); +} + +/** + * Generates a struct definition for a thrift exception. Basically the same + * as a struct, but also has an exception declaration. + * + * @param txception The struct definition + */ +void t_ocaml_generator::generate_xception(t_struct* txception) { + generate_ocaml_struct(txception, true); +} + +/** + * Generates an OCaml struct + */ +void t_ocaml_generator::generate_ocaml_struct(t_struct* tstruct, bool is_exception) { + generate_ocaml_struct_definition(f_types_, tstruct, is_exception); + generate_ocaml_struct_sig(f_types_i_, tstruct, is_exception); +} + +void t_ocaml_generator::generate_ocaml_method_copy(ofstream& out, const vector& members) { + vector::const_iterator m_iter; + + /* Create a copy of the current object */ + indent(out) << "method copy =" << endl; + indent_up(); + indent_up(); + indent(out) << "let _new = Oo.copy self in" << endl; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) + generate_ocaml_member_copy(out, *m_iter); + + indent_down(); + indent(out) << "_new" << endl; + indent_down(); +} + +string t_ocaml_generator::struct_member_copy_of(t_type* type, string what) { + if (type->is_struct() || type->is_xception()) { + return what + string("#copy"); + } + if (type->is_map()) { + string copy_of_k = struct_member_copy_of(((t_map*)type)->get_key_type(), "k"); + string copy_of_v = struct_member_copy_of(((t_map*)type)->get_val_type(), "v"); + + if (copy_of_k == "k" && copy_of_v == "v") { + return string("(Hashtbl.copy ") + what + string(")"); + } else { + return string( + "((fun oh -> let nh = Hashtbl.create (Hashtbl.length oh) in Hashtbl.iter (fun k v " + "-> Hashtbl.add nh ") + copy_of_k + string(" ") + copy_of_v + string(") oh; nh) ") + + what + ")"; + } + } + if (type->is_set()) { + string copy_of = struct_member_copy_of(((t_set*)type)->get_elem_type(), "k"); + + if (copy_of == "k") { + return string("(Hashtbl.copy ") + what + string(")"); + } else { + return string( + "((fun oh -> let nh = Hashtbl.create (Hashtbl.length oh) in Hashtbl.iter (fun k v " + "-> Hashtbl.add nh ") + copy_of + string(" true") + string(") oh; nh) ") + what + + ")"; + } + } + if (type->is_list()) { + string copy_of = struct_member_copy_of(((t_list*)type)->get_elem_type(), "x"); + if (copy_of != "x") { + return string("(List.map (fun x -> ") + copy_of + string(") ") + what + string(")"); + } else { + return what; + } + } + return what; +} + +void t_ocaml_generator::generate_ocaml_member_copy(ofstream& out, t_field* tmember) { + string mname = decapitalize(tmember->get_name()); + t_type* type = get_true_type(tmember->get_type()); + + string grab_field = string("self#grab_") + mname; + string copy_of = struct_member_copy_of(type, grab_field); + if (copy_of != grab_field) { + indent(out); + if (!struct_member_persistent(tmember)) { + out << "if _" << mname << " <> None then" << endl; + indent(out) << " "; + } + out << "_new#set_" << mname << " " << copy_of << ";" << endl; + } +} + +/** + * Generates a struct definition for a thrift data type. + * + * @param tstruct The struct definition + */ +void t_ocaml_generator::generate_ocaml_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + string tname = type_name(tstruct); + indent(out) << "class " << tname << " =" << endl; + indent(out) << "object (self)" << endl; + + indent_up(); + + if (members.size() > 0) { + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + generate_ocaml_struct_member(out, tname, (*m_iter)); + out << endl; + } + } + generate_ocaml_method_copy(out, members); + generate_ocaml_struct_writer(out, tstruct); + indent_down(); + indent(out) << "end" << endl; + + if (is_exception) { + indent(out) << "exception " << capitalize(tname) << " of " << tname << endl; + } + + generate_ocaml_struct_reader(out, tstruct); +} + +/** + * Generates a structure member for a thrift data type. + * + * @param tname Name of the parent structure for the member + * @param tmember Member definition + */ +void t_ocaml_generator::generate_ocaml_struct_member(ofstream& out, + string tname, + t_field* tmember) { + string x = tmp("_x"); + string mname = decapitalize(tmember->get_name()); + + indent(out) << "val mutable _" << mname << " : " << render_ocaml_type(tmember->get_type()); + t_const_value* val = tmember->get_value(); + if (val) { + if (struct_member_persistent(tmember)) + out << " = " << render_const_value(tmember->get_type(), tmember->get_value()) << endl; + else + out << " option = Some " << render_const_value(tmember->get_type(), tmember->get_value()) + << endl; + } else { + // assert(!struct_member_persistent(tmember)) + out << " option = None" << endl; + } + + if (struct_member_persistent(tmember)) { + indent(out) << "method get_" << mname << " = Some _" << mname << endl; + indent(out) << "method grab_" << mname << " = _" << mname << endl; + indent(out) << "method set_" << mname << " " << x << " = _" << mname << " <- " << x << endl; + } else { + indent(out) << "method get_" << mname << " = _" << mname << endl; + indent(out) << "method grab_" << mname << " = match _" << mname + << " with None->raise (Field_empty \"" << tname << "." << mname << "\") | Some " + << x << " -> " << x << endl; + indent(out) << "method set_" << mname << " " << x << " = _" << mname << " <- Some " << x + << endl; + indent(out) << "method unset_" << mname << " = _" << mname << " <- None" << endl; + } + + indent(out) << "method reset_" << mname << " = _" << mname << " <- "; + if (val) { + if (struct_member_persistent(tmember)) + out << render_const_value(tmember->get_type(), tmember->get_value()) << endl; + else + out << "Some " << render_const_value(tmember->get_type(), tmember->get_value()) << endl; + } else { + out << "None" << endl; + } +} + +/** + * Check whether a member of the structure can not have undefined value + * + * @param tmember Member definition + */ +bool t_ocaml_generator::struct_member_persistent(t_field* tmember) { + t_const_value* val = tmember->get_value(); + return (val ? true : false); +} + +/** + * Check whether a member of the structure can be skipped during encoding + * + * @param tmember Member definition + */ +bool t_ocaml_generator::struct_member_omitable(t_field* tmember) { + return (tmember->get_req() != t_field::T_REQUIRED); +} + +/** + * Figure out whether a member of the structure has + * a cheaply comparable default value. + * + * @param tmember Member definition + */ +bool t_ocaml_generator::struct_member_default_cheaply_comparable(t_field* tmember) { + t_type* type = get_true_type(tmember->get_type()); + t_const_value* val = tmember->get_value(); + if (!val) { + return false; + } else if (type->is_base_type()) { + // Base types are generally cheaply compared for structural equivalence. + switch (((t_base_type*)type)->get_base()) { + case t_base_type::TYPE_DOUBLE: + if (val->get_double() == 0.0) + return true; + else + return false; + default: + return true; + } + } else if (type->is_list()) { + // Empty lists are cheaply compared for structural equivalence. + // Is empty list? + if (val->get_list().size() == 0) + return true; + else + return false; + } else { + return false; + } +} + +/** + * Generates a struct definition for a thrift data type. + * + * @param tstruct The struct definition + */ +void t_ocaml_generator::generate_ocaml_struct_sig(ofstream& out, + t_struct* tstruct, + bool is_exception) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + string tname = type_name(tstruct); + indent(out) << "class " << tname << " :" << endl; + indent(out) << "object ('a)" << endl; + + indent_up(); + + string x = tmp("_x"); + if (members.size() > 0) { + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + string mname = decapitalize((*m_iter)->get_name()); + string type = render_ocaml_type((*m_iter)->get_type()); + indent(out) << "method get_" << mname << " : " << type << " option" << endl; + indent(out) << "method grab_" << mname << " : " << type << endl; + indent(out) << "method set_" << mname << " : " << type << " -> unit" << endl; + if (!struct_member_persistent(*m_iter)) + indent(out) << "method unset_" << mname << " : unit" << endl; + indent(out) << "method reset_" << mname << " : unit" << endl; + } + } + indent(out) << "method copy : 'a" << endl; + indent(out) << "method write : Protocol.t -> unit" << endl; + indent_down(); + indent(out) << "end" << endl; + + if (is_exception) { + indent(out) << "exception " << capitalize(tname) << " of " << tname << endl; + } + + indent(out) << "val read_" << tname << " : Protocol.t -> " << tname << endl; +} + +/** + * Generates the read method for a struct + */ +void t_ocaml_generator::generate_ocaml_struct_reader(ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + string sname = type_name(tstruct); + string str = tmp("_str"); + string t = tmp("_t"); + string id = tmp("_id"); + indent(out) << "let rec read_" << sname << " (iprot : Protocol.t) =" << endl; + indent_up(); + indent(out) << "let " << str << " = new " << sname << " in" << endl; + indent_up(); + indent(out) << "ignore(iprot#readStructBegin);" << endl; + + // Loop over reading in fields + indent(out) << "(try while true do" << endl; + indent_up(); + indent_up(); + + // Read beginning field marker + indent(out) << "let (_," << t << "," << id << ") = iprot#readFieldBegin in" << endl; + + // Check for field STOP marker and break + indent(out) << "if " << t << " = Protocol.T_STOP then" << endl; + indent_up(); + indent(out) << "raise Break" << endl; + indent_down(); + indent(out) << "else ();" << endl; + + indent(out) << "(match " << id << " with " << endl; + indent_up(); + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << "| " << (*f_iter)->get_key() << " -> ("; + out << "if " << t << " = " << type_to_enum((*f_iter)->get_type()) << " then" << endl; + indent_up(); + indent_up(); + generate_deserialize_field(out, *f_iter, str); + indent_down(); + out << indent() << "else" << endl << indent() << " iprot#skip " << t << ")" << endl; + indent_down(); + } + + // In the default case we skip the field + out << indent() << "| _ -> " + << "iprot#skip " << t << ");" << endl; + indent_down(); + // Read field end marker + indent(out) << "iprot#readFieldEnd;" << endl; + indent_down(); + indent(out) << "done; ()" << endl; + indent_down(); + indent(out) << "with Break -> ());" << endl; + + indent(out) << "iprot#readStructEnd;" << endl; + + indent(out) << str << endl << endl; + indent_down(); + indent_down(); +} + +void t_ocaml_generator::generate_ocaml_struct_writer(ofstream& out, t_struct* tstruct) { + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + string str = tmp("_str"); + string f = tmp("_f"); + + indent(out) << "method write (oprot : Protocol.t) =" << endl; + indent_up(); + indent(out) << "oprot#writeStructBegin \"" << name << "\";" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* tmember = (*f_iter); + string mname = "_" + decapitalize(tmember->get_name()); + string _v; + + if (struct_member_persistent(tmember)) { + + if (struct_member_omitable(tmember) && struct_member_default_cheaply_comparable(tmember)) { + _v = "_v"; + // Avoid redundant encoding of members having default values. + indent(out) << "(match " << mname << " with " + << render_const_value(tmember->get_type(), tmember->get_value()) << " -> () | " + << _v << " -> " << endl; + } else { + _v = mname; + indent(out) << "(" << endl; + } + + } else { + + indent(out) << "(match " << mname << " with "; + + if (struct_member_omitable(tmember)) { + out << "None -> ()"; + + if (struct_member_default_cheaply_comparable(tmember)) { + // Avoid redundant encoding of members having default values. + out << " | Some " << render_const_value(tmember->get_type(), tmember->get_value()) + << " -> ()"; + } + out << " | Some _v -> " << endl; + } else { + out << endl; + indent(out) << "| None -> raise (Field_empty \"" << type_name(tstruct) << "." << mname + << "\")" << endl; + indent(out) << "| Some _v -> " << endl; + } + + _v = "_v"; + } + indent_up(); + // Write field header + indent(out) << "oprot#writeFieldBegin(\"" << tmember->get_name() << "\"," + << type_to_enum(tmember->get_type()) << "," << tmember->get_key() << ");" << endl; + + // Write field contents + generate_serialize_field(out, tmember, _v); + + // Write field closer + indent(out) << "oprot#writeFieldEnd" << endl; + + indent_down(); + indent(out) << ");" << endl; + } + + // Write the struct map + out << indent() << "oprot#writeFieldStop;" << endl << indent() << "oprot#writeStructEnd" << endl; + + indent_down(); +} + +/** + * Generates a thrift service. + * + * @param tservice The service definition + */ +void t_ocaml_generator::generate_service(t_service* tservice) { + string f_service_name = get_out_dir() + capitalize(service_name_) + ".ml"; + f_service_.open(f_service_name.c_str()); + string f_service_i_name = get_out_dir() + capitalize(service_name_) + ".mli"; + f_service_i_.open(f_service_i_name.c_str()); + + f_service_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl; + f_service_i_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl; + + /* if (tservice->get_extends() != NULL) { + f_service_ << + "open " << capitalize(tservice->get_extends()->get_name()) << endl; + f_service_i_ << + "open " << capitalize(tservice->get_extends()->get_name()) << endl; + } + */ + f_service_ << "open " << capitalize(program_name_) << "_types" << endl << endl; + + f_service_i_ << "open " << capitalize(program_name_) << "_types" << endl << endl; + + // Generate the three main parts of the service + generate_service_helpers(tservice); + generate_service_interface(tservice); + generate_service_client(tservice); + generate_service_server(tservice); + + // Close service file + f_service_.close(); + f_service_i_.close(); +} + +/** + * Generates helper functions for a service. + * + * @param tservice The service to generate a header definition for + */ +void t_ocaml_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + indent(f_service_) << "(* HELPER FUNCTIONS AND STRUCTURES *)" << endl << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_ocaml_struct_definition(f_service_, ts, false); + generate_ocaml_function_helpers(*f_iter); + } +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_ocaml_generator::generate_ocaml_function_helpers(t_function* tfunction) { + t_struct result(program_, decapitalize(tfunction->get_name()) + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + generate_ocaml_struct_definition(f_service_, &result, false); +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_ocaml_generator::generate_service_interface(t_service* tservice) { + f_service_ << indent() << "class virtual iface =" << endl << "object (self)" << endl; + f_service_i_ << indent() << "class virtual iface :" << endl << "object" << endl; + + indent_up(); + + if (tservice->get_extends() != NULL) { + string extends = type_name(tservice->get_extends()); + indent(f_service_) << "inherit " << extends << ".iface" << endl; + indent(f_service_i_) << "inherit " << extends << ".iface" << endl; + } + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string ft = function_type(*f_iter, true, true); + f_service_ << indent() << "method virtual " << decapitalize((*f_iter)->get_name()) << " : " + << ft << endl; + f_service_i_ << indent() << "method virtual " << decapitalize((*f_iter)->get_name()) << " : " + << ft << endl; + } + indent_down(); + indent(f_service_) << "end" << endl << endl; + indent(f_service_i_) << "end" << endl << endl; +} + +/** + * Generates a service client definition. Note that in OCaml, the client doesn't implement iface. + *This is because + * The client does not (and should not have to) deal with arguments being None. + * + * @param tservice The service to generate a server for. + */ +void t_ocaml_generator::generate_service_client(t_service* tservice) { + string extends = ""; + indent(f_service_) << "class client (iprot : Protocol.t) (oprot : Protocol.t) =" << endl + << "object (self)" << endl; + indent(f_service_i_) << "class client : Protocol.t -> Protocol.t -> " << endl << "object" << endl; + indent_up(); + + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + indent(f_service_) << "inherit " << extends << ".client iprot oprot as super" << endl; + indent(f_service_i_) << "inherit " << extends << ".client" << endl; + } + indent(f_service_) << "val mutable seqid = 0" << endl; + + // Generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* arg_struct = (*f_iter)->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + string funname = (*f_iter)->get_name(); + + // Open function + indent(f_service_) << "method " << function_signature(*f_iter) << " = " << endl; + indent(f_service_i_) << "method " << decapitalize((*f_iter)->get_name()) << " : " + << function_type(*f_iter, true, false) << endl; + indent_up(); + indent(f_service_) << "self#send_" << funname; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << " " << decapitalize((*fld_iter)->get_name()); + } + f_service_ << ";" << endl; + + if (!(*f_iter)->is_oneway()) { + f_service_ << indent(); + f_service_ << "self#recv_" << funname << endl; + } + indent_down(); + + indent(f_service_) << "method private send_" << function_signature(*f_iter) << " = " << endl; + indent_up(); + + std::string argsname = decapitalize((*f_iter)->get_name() + "_args"); + + // Serialize the request header + f_service_ << indent() << "oprot#writeMessageBegin (\"" << (*f_iter)->get_name() << "\", " + << ((*f_iter)->is_oneway() ? "Protocol.ONEWAY" : "Protocol.CALL") << ", seqid);" + << endl; + + f_service_ << indent() << "let args = new " << argsname << " in" << endl; + indent_up(); + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << indent() << "args#set_" << (*fld_iter)->get_name() << " " + << (*fld_iter)->get_name() << ";" << endl; + } + + // Write to the stream + f_service_ << indent() << "args#write oprot;" << endl << indent() << "oprot#writeMessageEnd;" + << endl << indent() << "oprot#getTransport#flush" << endl; + + indent_down(); + indent_down(); + + if (!(*f_iter)->is_oneway()) { + std::string resultname = decapitalize((*f_iter)->get_name() + "_result"); + t_struct noargs(program_); + + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + &noargs); + // Open function + f_service_ << indent() << "method private " << function_signature(&recv_function) << " =" + << endl; + indent_up(); + + // TODO(mcslee): Validate message reply here, seq ids etc. + + f_service_ << indent() << "let (fname, mtype, rseqid) = iprot#readMessageBegin in" << endl; + indent_up(); + f_service_ << indent() << "(if mtype = Protocol.EXCEPTION then" << endl << indent() + << " let x = Application_Exn.read iprot in" << endl; + indent_up(); + f_service_ << indent() << " (iprot#readMessageEnd;" << indent() + << " raise (Application_Exn.E x))" << endl; + indent_down(); + f_service_ << indent() << "else ());" << endl; + string res = "_"; + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + + if (!(*f_iter)->get_returntype()->is_void() || xceptions.size() > 0) { + res = "result"; + } + f_service_ << indent() << "let " << res << " = read_" << resultname << " iprot in" << endl; + indent_up(); + f_service_ << indent() << "iprot#readMessageEnd;" << endl; + + // Careful, only return _result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << indent() << "match result#get_success with Some v -> v | None -> (" << endl; + indent_up(); + } + + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << indent() << "(match result#get_" << (*x_iter)->get_name() + << " with None -> () | Some _v ->" << endl; + indent(f_service_) << " raise (" << capitalize(type_name((*x_iter)->get_type())) + << " _v));" << endl; + } + + // Careful, only return _result if not a void function + if ((*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << "()" << endl; + } else { + f_service_ + << indent() + << "raise (Application_Exn.E (Application_Exn.create Application_Exn.MISSING_RESULT \"" + << (*f_iter)->get_name() << " failed: unknown result\")))" << endl; + indent_down(); + } + + // Close function + indent_down(); + indent_down(); + indent_down(); + } + } + + indent_down(); + indent(f_service_) << "end" << endl << endl; + indent(f_service_i_) << "end" << endl << endl; +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_ocaml_generator::generate_service_server(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + // Generate the header portion + indent(f_service_) << "class processor (handler : iface) =" << endl << indent() << "object (self)" + << endl; + indent(f_service_i_) << "class processor : iface ->" << endl << indent() << "object" << endl; + indent_up(); + + f_service_ << indent() << "inherit Processor.t" << endl << endl; + f_service_i_ << indent() << "inherit Processor.t" << endl << endl; + string extends = ""; + + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + indent(f_service_) << "inherit " + extends + ".processor (handler :> " + extends + ".iface)" + << endl; + indent(f_service_i_) << "inherit " + extends + ".processor" << endl; + } + + if (extends.empty()) { + indent(f_service_) << "val processMap = Hashtbl.create " << functions.size() << endl; + } + indent(f_service_i_) + << "val processMap : (string, int * Protocol.t * Protocol.t -> unit) Hashtbl.t" << endl; + + // Generate the server implementation + indent(f_service_) << "method process iprot oprot =" << endl; + indent(f_service_i_) << "method process : Protocol.t -> Protocol.t -> bool" << endl; + indent_up(); + + f_service_ << indent() << "let (name, typ, seqid) = iprot#readMessageBegin in" << endl; + indent_up(); + // TODO(mcslee): validate message + + // HOT: dictionary function lookup + f_service_ << indent() << "if Hashtbl.mem processMap name then" << endl << indent() + << " (Hashtbl.find processMap name) (seqid, iprot, oprot)" << endl << indent() + << "else (" << endl << indent() << " iprot#skip(Protocol.T_STRUCT);" << endl + << indent() << " iprot#readMessageEnd;" << endl << indent() + << " let x = Application_Exn.create Application_Exn.UNKNOWN_METHOD (\"Unknown " + "function \"^name) in" << endl << indent() + << " oprot#writeMessageBegin(name, Protocol.EXCEPTION, seqid);" << endl << indent() + << " x#write oprot;" << endl << indent() << " oprot#writeMessageEnd;" << endl + << indent() << " oprot#getTransport#flush" << endl << indent() << ");" << endl; + + // Read end of args field, the T_STOP, and the struct close + f_service_ << indent() << "true" << endl; + indent_down(); + indent_down(); + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(tservice, *f_iter); + } + + indent(f_service_) << "initializer" << endl; + indent_up(); + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << indent() << "Hashtbl.add processMap \"" << (*f_iter)->get_name() + << "\" self#process_" << (*f_iter)->get_name() << ";" << endl; + } + indent_down(); + + indent_down(); + indent(f_service_) << "end" << endl << endl; + indent(f_service_i_) << "end" << endl << endl; +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_ocaml_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + (void)tservice; + // Open function + indent(f_service_) << "method private process_" << tfunction->get_name() + << " (seqid, iprot, oprot) =" << endl; + indent_up(); + + string argsname = decapitalize(tfunction->get_name()) + "_args"; + string resultname = decapitalize(tfunction->get_name()) + "_result"; + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + string args = "args"; + if (fields.size() == 0) { + args = "_"; + } + + f_service_ << indent() << "let " << args << " = read_" << argsname << " iprot in" << endl; + indent_up(); + f_service_ << indent() << "iprot#readMessageEnd;" << endl; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + // Declare result for non oneway function + if (!tfunction->is_oneway()) { + f_service_ << indent() << "let result = new " << resultname << " in" << endl; + indent_up(); + } + + // Try block for a function with exceptions + if (xceptions.size() > 0) { + f_service_ << indent() << "(try" << endl; + indent_up(); + } + + f_service_ << indent(); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + f_service_ << "result#set_success "; + } + f_service_ << "(handler#" << tfunction->get_name(); + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + f_service_ << " args#get_" << (*f_iter)->get_name(); + } + f_service_ << ");" << endl; + + if (xceptions.size() > 0) { + indent_down(); + indent(f_service_) << "with" << endl; + indent_up(); + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << indent() << "| " << capitalize(type_name((*x_iter)->get_type())) << " " + << (*x_iter)->get_name() << " -> " << endl; + indent_up(); + indent_up(); + if (!tfunction->is_oneway()) { + f_service_ << indent() << "result#set_" << (*x_iter)->get_name() << " " + << (*x_iter)->get_name() << endl; + } else { + indent(f_service_) << "()"; + } + indent_down(); + indent_down(); + } + indent_down(); + f_service_ << indent() << ");" << endl; + } + + // Shortcut out here for oneway functions + if (tfunction->is_oneway()) { + f_service_ << indent() << "()" << endl; + indent_down(); + indent_down(); + return; + } + + f_service_ << indent() << "oprot#writeMessageBegin (\"" << tfunction->get_name() + << "\", Protocol.REPLY, seqid);" << endl << indent() << "result#write oprot;" << endl + << indent() << "oprot#writeMessageEnd;" << endl << indent() + << "oprot#getTransport#flush" << endl; + + // Close function + indent_down(); + indent_down(); + indent_down(); +} + +/** + * Deserializes a field of any type. + */ +void t_ocaml_generator::generate_deserialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = tfield->get_type(); + + string name = decapitalize(tfield->get_name()); + indent(out) << prefix << "#set_" << name << " "; + generate_deserialize_type(out, type); + out << endl; +} + +/** + * Deserializes a field of any type. + */ +void t_ocaml_generator::generate_deserialize_type(ofstream& out, t_type* type) { + type = get_true_type(type); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE"; + } + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type); + } else if (type->is_container()) { + generate_deserialize_container(out, type); + } else if (type->is_base_type()) { + out << "iprot#"; + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct"; + break; + case t_base_type::TYPE_STRING: + out << "readString"; + break; + case t_base_type::TYPE_BOOL: + out << "readBool"; + break; + case t_base_type::TYPE_I8: + out << "readByte"; + break; + case t_base_type::TYPE_I16: + out << "readI16"; + break; + case t_base_type::TYPE_I32: + out << "readI32"; + break; + case t_base_type::TYPE_I64: + out << "readI64"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble"; + break; + default: + throw "compiler error: no ocaml name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + string ename = capitalize(type->get_name()); + out << "(" << ename << ".of_i iprot#readI32)"; + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE TYPE '%s'\n", type->get_name().c_str()); + } +} + +/** + * Generates an unserializer for a struct, calling read() + */ +void t_ocaml_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct) { + string prefix = ""; + t_program* program = tstruct->get_program(); + if (program != NULL && program != program_) { + prefix = capitalize(program->get_name()) + "_types."; + } + string name = decapitalize(tstruct->get_name()); + out << "(" << prefix << "read_" << name << " iprot)"; +} + +/** + * Serialize a container by writing out the header followed by + * data and then a footer. + */ +void t_ocaml_generator::generate_deserialize_container(ofstream& out, t_type* ttype) { + string size = tmp("_size"); + string ktype = tmp("_ktype"); + string vtype = tmp("_vtype"); + string etype = tmp("_etype"); + string con = tmp("_con"); + + t_field fsize(g_type_i32, size); + t_field fktype(g_type_i8, ktype); + t_field fvtype(g_type_i8, vtype); + t_field fetype(g_type_i8, etype); + + out << endl; + indent_up(); + // Declare variables, read header + if (ttype->is_map()) { + indent(out) << "(let (" << ktype << "," << vtype << "," << size << ") = iprot#readMapBegin in" + << endl; + indent(out) << "let " << con << " = Hashtbl.create " << size << " in" << endl; + indent_up(); + indent(out) << "for i = 1 to " << size << " do" << endl; + indent_up(); + indent(out) << "let _k = "; + generate_deserialize_type(out, ((t_map*)ttype)->get_key_type()); + out << " in" << endl; + indent(out) << "let _v = "; + generate_deserialize_type(out, ((t_map*)ttype)->get_val_type()); + out << " in" << endl; + indent_up(); + indent(out) << "Hashtbl.add " << con << " _k _v" << endl; + indent_down(); + indent_down(); + indent(out) << "done; iprot#readMapEnd; " << con << ")"; + indent_down(); + } else if (ttype->is_set()) { + indent(out) << "(let (" << etype << "," << size << ") = iprot#readSetBegin in" << endl; + indent(out) << "let " << con << " = Hashtbl.create " << size << " in" << endl; + indent_up(); + indent(out) << "for i = 1 to " << size << " do" << endl; + indent_up(); + indent(out) << "Hashtbl.add " << con << " "; + generate_deserialize_type(out, ((t_set*)ttype)->get_elem_type()); + out << " true" << endl; + indent_down(); + indent(out) << "done; iprot#readSetEnd; " << con << ")"; + indent_down(); + } else if (ttype->is_list()) { + indent(out) << "(let (" << etype << "," << size << ") = iprot#readListBegin in" << endl; + indent_up(); + indent(out) << "let " << con << " = (Array.to_list (Array.init " << size << " (fun _ -> "; + generate_deserialize_type(out, ((t_list*)ttype)->get_elem_type()); + out << "))) in" << endl; + indent_up(); + indent(out) << "iprot#readListEnd; " << con << ")"; + indent_down(); + indent_down(); + } + indent_down(); +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_ocaml_generator::generate_serialize_field(ofstream& out, t_field* tfield, string name) { + t_type* type = get_true_type(tfield->get_type()); + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + tfield->get_name(); + } + + if (name.length() == 0) { + name = decapitalize(tfield->get_name()); + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, name); + } else if (type->is_container()) { + generate_serialize_container(out, type, name); + } else if (type->is_base_type() || type->is_enum()) { + + indent(out) << "oprot#"; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + out << "writeString(" << name << ")"; + break; + case t_base_type::TYPE_BOOL: + out << "writeBool(" << name << ")"; + break; + case t_base_type::TYPE_I8: + out << "writeByte(" << name << ")"; + break; + case t_base_type::TYPE_I16: + out << "writeI16(" << name << ")"; + break; + case t_base_type::TYPE_I32: + out << "writeI32(" << name << ")"; + break; + case t_base_type::TYPE_I64: + out << "writeI64(" << name << ")"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble(" << name << ")"; + break; + default: + throw "compiler error: no ocaml name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + string ename = capitalize(type->get_name()); + out << "writeI32(" << ename << ".to_i " << name << ")"; + } + + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type->get_name().c_str()); + } + out << ";" << endl; +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_ocaml_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + (void)tstruct; + indent(out) << prefix << "#write(oprot)"; +} + +void t_ocaml_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + if (ttype->is_map()) { + indent(out) << "oprot#writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ","; + out << type_to_enum(((t_map*)ttype)->get_val_type()) << ","; + out << "Hashtbl.length " << prefix << ");" << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot#writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ","; + out << "Hashtbl.length " << prefix << ");" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot#writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) + << ","; + out << "List.length " << prefix << ");" << endl; + } + + if (ttype->is_map()) { + string kiter = tmp("_kiter"); + string viter = tmp("_viter"); + indent(out) << "Hashtbl.iter (fun " << kiter << " -> fun " << viter << " -> " << endl; + indent_up(); + generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); + indent_down(); + indent(out) << ") " << prefix << ";" << endl; + } else if (ttype->is_set()) { + string iter = tmp("_iter"); + indent(out) << "Hashtbl.iter (fun " << iter << " -> fun _ -> "; + indent_up(); + generate_serialize_set_element(out, (t_set*)ttype, iter); + indent_down(); + indent(out) << ") " << prefix << ";" << endl; + } else if (ttype->is_list()) { + string iter = tmp("_iter"); + indent(out) << "List.iter (fun " << iter << " -> "; + indent_up(); + generate_serialize_list_element(out, (t_list*)ttype, iter); + indent_down(); + indent(out) << ") " << prefix << ";" << endl; + } + + if (ttype->is_map()) { + indent(out) << "oprot#writeMapEnd"; + } else if (ttype->is_set()) { + indent(out) << "oprot#writeSetEnd"; + } else if (ttype->is_list()) { + indent(out) << "oprot#writeListEnd"; + } +} + +/** + * Serializes the members of a map. + * + */ +void t_ocaml_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string kiter, + string viter) { + t_field kfield(tmap->get_key_type(), kiter); + generate_serialize_field(out, &kfield); + + t_field vfield(tmap->get_val_type(), viter); + generate_serialize_field(out, &vfield); +} + +/** + * Serializes the members of a set. + */ +void t_ocaml_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) { + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, &efield); +} + +/** + * Serializes the members of a list. + */ +void t_ocaml_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) { + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, &efield); +} + +/** + * Renders a function signature of the form 'name args' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_ocaml_generator::function_signature(t_function* tfunction, string prefix) { + return prefix + decapitalize(tfunction->get_name()) + " " + + argument_list(tfunction->get_arglist()); +} + +string t_ocaml_generator::function_type(t_function* tfunc, bool method, bool options) { + string result = ""; + + const vector& fields = tfunc->get_arglist()->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result += render_ocaml_type((*f_iter)->get_type()); + if (options) + result += " option"; + result += " -> "; + } + if (fields.empty() && !method) { + result += "unit -> "; + } + result += render_ocaml_type(tfunc->get_returntype()); + return result; +} + +/** + * Renders a field list + */ +string t_ocaml_generator::argument_list(t_struct* tstruct) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += " "; + } + result += (*f_iter)->get_name(); + } + return result; +} + +string t_ocaml_generator::type_name(t_type* ttype) { + string prefix = ""; + t_program* program = ttype->get_program(); + if (program != NULL && program != program_) { + if (!ttype->is_service()) { + prefix = capitalize(program->get_name()) + "_types."; + } + } + + string name = ttype->get_name(); + if (ttype->is_service()) { + name = capitalize(name); + } else { + name = decapitalize(name); + } + return prefix + name; +} + +/** + * Converts the parse type to a Protocol.t_type enum + */ +string t_ocaml_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + return "Protocol.T_VOID"; + case t_base_type::TYPE_STRING: + return "Protocol.T_STRING"; + case t_base_type::TYPE_BOOL: + return "Protocol.T_BOOL"; + case t_base_type::TYPE_I8: + return "Protocol.T_BYTE"; + case t_base_type::TYPE_I16: + return "Protocol.T_I16"; + case t_base_type::TYPE_I32: + return "Protocol.T_I32"; + case t_base_type::TYPE_I64: + return "Protocol.T_I64"; + case t_base_type::TYPE_DOUBLE: + return "Protocol.T_DOUBLE"; + } + } else if (type->is_enum()) { + return "Protocol.T_I32"; + } else if (type->is_struct() || type->is_xception()) { + return "Protocol.T_STRUCT"; + } else if (type->is_map()) { + return "Protocol.T_MAP"; + } else if (type->is_set()) { + return "Protocol.T_SET"; + } else if (type->is_list()) { + return "Protocol.T_LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** + * Converts the parse type to an ocaml type + */ +string t_ocaml_generator::render_ocaml_type(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + return "unit"; + case t_base_type::TYPE_STRING: + return "string"; + case t_base_type::TYPE_BOOL: + return "bool"; + case t_base_type::TYPE_I8: + return "int"; + case t_base_type::TYPE_I16: + return "int"; + case t_base_type::TYPE_I32: + return "Int32.t"; + case t_base_type::TYPE_I64: + return "Int64.t"; + case t_base_type::TYPE_DOUBLE: + return "float"; + } + } else if (type->is_enum()) { + return capitalize(((t_enum*)type)->get_name()) + ".t"; + } else if (type->is_struct() || type->is_xception()) { + return type_name((t_struct*)type); + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + return "(" + render_ocaml_type(ktype) + "," + render_ocaml_type(vtype) + ") Hashtbl.t"; + } else if (type->is_set()) { + t_type* etype = ((t_set*)type)->get_elem_type(); + return "(" + render_ocaml_type(etype) + ",bool) Hashtbl.t"; + } else if (type->is_list()) { + t_type* etype = ((t_list*)type)->get_elem_type(); + return render_ocaml_type(etype) + " list"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +THRIFT_REGISTER_GENERATOR(ocaml, "OCaml", "") diff --git a/compiler/cpp/src/thrift/generate/t_oop_generator.h b/compiler/cpp/src/thrift/generate/t_oop_generator.h new file mode 100644 index 0000000..8fb580d --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_oop_generator.h @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_OOP_GENERATOR_H +#define T_OOP_GENERATOR_H + +#include +#include + +#include "thrift/common.h" +#include "thrift/generate/t_generator.h" + +#include + +/** + * Class with utility methods shared across common object oriented languages. + * Specifically, most of this stuff is for C++/Java. + * + */ +class t_oop_generator : public t_generator { +public: + t_oop_generator(t_program* program) : t_generator(program) {} + + /** + * Scoping, using curly braces! + */ + + void scope_up(std::ostream& out) { + indent(out) << "{" << std::endl; + indent_up(); + } + + void scope_down(std::ostream& out) { + indent_down(); + indent(out) << "}" << std::endl; + } + + std::string upcase_string(std::string original) { + std::transform(original.begin(), original.end(), original.begin(), (int (*)(int))toupper); + return original; + } + + virtual std::string get_enum_class_name(t_type* type) { + std::string package = ""; + t_program* program = type->get_program(); + if (program != NULL && program != program_) { + package = program->get_namespace("java") + "."; + } + return package + type->get_name(); + } + + virtual void generate_java_docstring_comment(std::ofstream& out, std::string contents) { + generate_docstring_comment(out, "/**\n", " * ", contents, " */\n"); + } + + virtual void generate_java_doc(std::ofstream& out, t_field* field) { + if (field->get_type()->is_enum()) { + std::string combined_message = field->get_doc() + "\n@see " + + get_enum_class_name(field->get_type()); + generate_java_docstring_comment(out, combined_message); + } else { + generate_java_doc(out, (t_doc*)field); + } + } + + /** + * Emits a JavaDoc comment if the provided object has a doc in Thrift + */ + virtual void generate_java_doc(std::ofstream& out, t_doc* tdoc) { + if (tdoc->has_doc()) { + generate_java_docstring_comment(out, tdoc->get_doc()); + } + } + + /** + * Emits a JavaDoc comment if the provided function object has a doc in Thrift + */ + virtual void generate_java_doc(std::ofstream& out, t_function* tfunction) { + if (tfunction->has_doc()) { + std::stringstream ss; + ss << tfunction->get_doc(); + const std::vector& fields = tfunction->get_arglist()->get_members(); + std::vector::const_iterator p_iter; + for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { + t_field* p = *p_iter; + ss << "\n@param " << p->get_name(); + if (p->has_doc()) { + ss << " " << p->get_doc(); + } + } + generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n"); + } + } +}; + +#endif diff --git a/compiler/cpp/src/thrift/generate/t_perl_generator.cc b/compiler/cpp/src/thrift/generate/t_perl_generator.cc new file mode 100644 index 0000000..0c05cda --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_perl_generator.cc @@ -0,0 +1,1683 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "thrift/platform.h" +#include "thrift/version.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * PERL code generator. + * + */ +class t_perl_generator : public t_oop_generator { +public: + t_perl_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program), f_types_use_includes_emitted_(false) { + (void)option_string; + std::map::const_iterator iter; + + /* no options yet */ + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + throw "unknown option perl:" + iter->first; + } + + out_dir_base_ = "gen-perl"; + escape_['$'] = "\\$"; + escape_['@'] = "\\@"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + std::string render_const_value(t_type* type, t_const_value* value); + + /** + * Structs! + */ + + void generate_perl_struct(t_struct* tstruct, bool is_exception); + void generate_perl_struct_definition(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false); + void generate_perl_struct_reader(std::ofstream& out, t_struct* tstruct); + void generate_perl_struct_writer(std::ofstream& out, t_struct* tstruct); + void generate_perl_function_helpers(t_function* tfunction); + + /** + * Service-level generation functions + */ + + void generate_service_helpers(t_service* tservice); + void generate_service_interface(t_service* tservice); + void generate_service_rest(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_processor(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* tfunction); + void generate_use_includes(std::ostream& os, bool& done, t_type *type, bool selfish); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, + t_field* tfield, + std::string prefix = "", + bool inclass = false); + + void generate_deserialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_deserialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_deserialize_set_element(std::ofstream& out, t_set* tset, std::string prefix = ""); + + void generate_deserialize_map_element(std::ofstream& out, t_map* tmap, std::string prefix = ""); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix = ""); + + void generate_serialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string kiter, + std::string viter); + + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + + /** + * Helper rendering functions + */ + + std::string perl_includes(); + std::string declare_field(t_field* tfield, bool init = false, bool obj = false); + std::string function_signature(t_function* tfunction, std::string prefix = ""); + std::string argument_list(t_struct* tstruct); + std::string type_to_enum(t_type* ttype); + + std::string autogen_comment() { + return std::string("#\n") + "# Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + + "#\n" + "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "#\n"; + } + + void perl_namespace_dirs(t_program* p, std::list& dirs) { + std::string ns = p->get_namespace("perl"); + std::string::size_type loc; + + if (ns.size() > 0) { + while ((loc = ns.find(".")) != std::string::npos) { + dirs.push_back(ns.substr(0, loc)); + ns = ns.substr(loc + 1); + } + } + + if (ns.size() > 0) { + dirs.push_back(ns); + } + } + + std::string perl_namespace(t_program* p) { + std::string ns = p->get_namespace("perl"); + std::string result = ""; + std::string::size_type loc; + + if (ns.size() > 0) { + while ((loc = ns.find(".")) != std::string::npos) { + result += ns.substr(0, loc); + result += "::"; + ns = ns.substr(loc + 1); + } + + if (ns.size() > 0) { + result += ns + "::"; + } + } + + return result; + } + + std::string get_namespace_out_dir() { + std::string outdir = get_out_dir(); + std::list dirs; + perl_namespace_dirs(program_, dirs); + std::list::iterator it; + for (it = dirs.begin(); it != dirs.end(); it++) { + outdir += *it + "/"; + } + return outdir; + } + +private: + /** + * File streams + */ + std::ofstream f_types_; + std::ofstream f_consts_; + std::ofstream f_helpers_; + std::ofstream f_service_; + + bool f_types_use_includes_emitted_; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_perl_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + + string outdir = get_out_dir(); + std::list dirs; + perl_namespace_dirs(program_, dirs); + std::list::iterator it; + for (it = dirs.begin(); it != dirs.end(); it++) { + outdir += *it + "/"; + MKDIR(outdir.c_str()); + } + + // Make output file + string f_types_name = outdir + "Types.pm"; + f_types_.open(f_types_name.c_str()); + string f_consts_name = outdir + "Constants.pm"; + f_consts_.open(f_consts_name.c_str()); + + // Print header + f_types_ << autogen_comment() << perl_includes(); + + // Print header + f_consts_ << autogen_comment() << "package " << perl_namespace(program_) << "Constants;" << endl + << perl_includes() << endl; +} + +/** + * Prints standard java imports + */ +string t_perl_generator::perl_includes() { + string inc; + + inc = "use 5.10.0;\n"; + inc += "use strict;\n"; + inc += "use warnings;\n"; + inc += "use Thrift::Exception;\n"; + inc += "use Thrift::MessageType;\n"; + inc += "use Thrift::Type;\n\n"; + + return inc; +} + +/** + * Close up (or down) some filez. + */ +void t_perl_generator::close_generator() { + // Close types file + f_types_ << "1;" << endl; + f_types_.close(); + + f_consts_ << "1;" << endl; + f_consts_.close(); +} + +/** + * Generates a typedef. This is not done in PERL, types are all implicit. + * + * @param ttypedef The type definition + */ +void t_perl_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + +/** + * Generates code for an enumerated type. Since define is expensive to lookup + * in PERL, we use a global array for this. + * + * @param tenum The enumeration + */ +void t_perl_generator::generate_enum(t_enum* tenum) { + f_types_ << "package " << perl_namespace(program_) << tenum->get_name() << ";" << endl; + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + f_types_ << "use constant " << (*c_iter)->get_name() << " => " << value << ";" << endl; + } +} + +/** + * Generate a constant value + */ +void t_perl_generator::generate_const(t_const* tconst) { + t_type* type = tconst->get_type(); + string name = tconst->get_name(); + t_const_value* value = tconst->get_value(); + + f_consts_ << "use constant " << name << " => "; + f_consts_ << render_const_value(type, value); + f_consts_ << ";" << endl << endl; +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +string t_perl_generator::render_const_value(t_type* type, t_const_value* value) { + std::ostringstream out; + + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + out << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + out << (value->get_integer() > 0 ? "1" : "0"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + out << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + out << value->get_integer(); + } else { + out << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << value->get_integer(); + } else if (type->is_struct() || type->is_xception()) { + out << "new " << perl_namespace(type->get_program()) << type->get_name() << "({" << endl; + indent_up(); + + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + indent(out) << render_const_value(g_type_string, v_iter->first); + out << " => "; + out << render_const_value(field_type, v_iter->second); + out << ","; + out << endl; + } + indent_down(); + indent(out) << "})"; + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + out << "{" << endl; + indent_up(); + + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + indent(out) << render_const_value(ktype, v_iter->first); + out << " => "; + out << render_const_value(vtype, v_iter->second); + out << "," << endl; + } + indent_down(); + indent(out) << "}"; + } else if (type->is_list() || type->is_set()) { + t_type* etype; + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + out << "[" << endl; + indent_up(); + + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + + indent(out) << render_const_value(etype, *v_iter); + if (type->is_set()) { + out << " => 1"; + } + out << "," << endl; + } + indent_down(); + indent(out) << "]"; + } + return out.str(); +} + +/** + * Make a struct + */ +void t_perl_generator::generate_struct(t_struct* tstruct) { + generate_perl_struct(tstruct, false); +} + +/** + * Generates a struct definition for a thrift exception. Basically the same + * as a struct but extends the Exception class. + * + * @param txception The struct definition + */ +void t_perl_generator::generate_xception(t_struct* txception) { + generate_perl_struct(txception, true); +} + +/** + * Structs can be normal or exceptions. + */ +void t_perl_generator::generate_perl_struct(t_struct* tstruct, bool is_exception) { + generate_use_includes(f_types_, f_types_use_includes_emitted_, tstruct, false); + generate_perl_struct_definition(f_types_, tstruct, is_exception); +} + +/** + * Generates a struct definition for a thrift data type. This is nothing in PERL + * where the objects are all just associative arrays (unless of course we + * decide to start using objects for them...) + * + * @param tstruct The struct definition + */ +void t_perl_generator::generate_perl_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + out << "package " << perl_namespace(tstruct->get_program()) << tstruct->get_name() << ";\n"; + if (is_exception) { + out << "use base qw(Thrift::TException);\n"; + } + + // Create simple acessor methods + out << "use base qw(Class::Accessor);\n"; + + if (members.size() > 0) { + out << perl_namespace(tstruct->get_program()) << tstruct->get_name() << "->mk_accessors( qw( "; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if (!t->is_xception()) { + out << (*m_iter)->get_name() << " "; + } + } + + out << ") );\n"; + } + + out << endl; + + // new() + indent_up(); + out << "sub new {" << endl << indent() << "my $classname = shift;" << endl << indent() + << "my $self = {};" << endl << indent() << "my $vals = shift || {};" << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + string dval = "undef"; + t_type* t = get_true_type((*m_iter)->get_type()); + if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) { + dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value()); + } + out << indent() << "$self->{" << (*m_iter)->get_name() << "} = " << dval << ";" << endl; + } + + // Generate constructor from array + if (members.size() > 0) { + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) { + indent(out) << "$self->{" << (*m_iter)->get_name() + << "} = " << render_const_value(t, (*m_iter)->get_value()) << ";" << endl; + } + } + + out << indent() << "if (UNIVERSAL::isa($vals,'HASH')) {" << endl; + indent_up(); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + out << indent() << "if (defined $vals->{" << (*m_iter)->get_name() << "}) {" << endl + << indent() << " $self->{" << (*m_iter)->get_name() << "} = $vals->{" + << (*m_iter)->get_name() << "};" << endl << indent() << "}" << endl; + } + indent_down(); + out << indent() << "}" << endl; + } + + out << indent() << "return bless ($self, $classname);" << endl; + indent_down(); + out << "}\n\n"; + + out << "sub getName {" << endl << indent() << " return '" << tstruct->get_name() << "';" << endl + << indent() << "}" << endl << endl; + + generate_perl_struct_reader(out, tstruct); + generate_perl_struct_writer(out, tstruct); +} + +/** + * Generates the read() method for a struct + */ +void t_perl_generator::generate_perl_struct_reader(ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out << "sub read {" << endl; + + indent_up(); + + out << indent() << "my ($self, $input) = @_;" << endl << indent() << "my $xfer = 0;" << endl + << indent() << "my $fname;" << endl << indent() << "my $ftype = 0;" << endl << indent() + << "my $fid = 0;" << endl; + + indent(out) << "$xfer += $input->readStructBegin(\\$fname);" << endl; + + // Loop over reading in fields + indent(out) << "while (1) " << endl; + + scope_up(out); + + indent(out) << "$xfer += $input->readFieldBegin(\\$fname, \\$ftype, \\$fid);" << endl; + + // Check for field STOP marker and break + indent(out) << "if ($ftype == Thrift::TType::STOP) {" << endl; + indent_up(); + indent(out) << "last;" << endl; + indent_down(); + indent(out) << "}" << endl; + + // Switch statement on the field we are reading + indent(out) << "SWITCH: for($fid)" << endl; + + scope_up(out); + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + + indent(out) << "/^" << (*f_iter)->get_key() << "$/ && do{"; + indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; + + indent_up(); + generate_deserialize_field(out, *f_iter, "self->"); + indent_down(); + + indent(out) << "} else {" << endl; + + indent(out) << " $xfer += $input->skip($ftype);" << endl; + + out << indent() << "}" << endl << indent() << "last; };" << endl; + } + // In the default case we skip the field + + indent(out) << " $xfer += $input->skip($ftype);" << endl; + + scope_down(out); + + indent(out) << "$xfer += $input->readFieldEnd();" << endl; + + scope_down(out); + + indent(out) << "$xfer += $input->readStructEnd();" << endl; + + indent(out) << "return $xfer;" << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +/** + * Generates the write() method for a struct + */ +void t_perl_generator::generate_perl_struct_writer(ofstream& out, t_struct* tstruct) { + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + out << "sub write {" << endl; + + indent_up(); + indent(out) << "my ($self, $output) = @_;" << endl; + indent(out) << "my $xfer = 0;" << endl; + + indent(out) << "$xfer += $output->writeStructBegin('" << name << "');" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + out << indent() << "if (defined $self->{" << (*f_iter)->get_name() << "}) {" << endl; + indent_up(); + + indent(out) << "$xfer += $output->writeFieldBegin(" + << "'" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type()) + << ", " << (*f_iter)->get_key() << ");" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "self->"); + + indent(out) << "$xfer += $output->writeFieldEnd();" << endl; + + indent_down(); + indent(out) << "}" << endl; + } + + out << indent() << "$xfer += $output->writeFieldStop();" << endl << indent() + << "$xfer += $output->writeStructEnd();" << endl; + + out << indent() << "return $xfer;" << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +/** + * Generates use clauses for included entities + * + * @param os The output stream + * @param done A flag reference to debounce the action + * @param type The type being processed + * @param selfish Flag to indicate if the current namespace types should be "use"d as well. + */ +void t_perl_generator::generate_use_includes(std::ostream& os, bool& done, t_type *type, bool selfish) { + t_program *current = type->get_program(); + if (current && !done) { + std::vector& currInc = current->get_includes(); + std::vector::size_type numInc = currInc.size(); + if (selfish) { + os << "use " << perl_namespace(current) << "Types;" << endl; + } + for (std::vector::size_type i = 0; i < numInc; ++i) { + t_program* incProgram = currInc.at(i); + os << "use " << perl_namespace(incProgram) << "Types;" << endl; + } + os << endl; + done = true; + } +} + +/** + * Generates a thrift service. + * + * @param tservice The service definition + */ +void t_perl_generator::generate_service(t_service* tservice) { + string f_service_name = get_namespace_out_dir() + service_name_ + ".pm"; + f_service_.open(f_service_name.c_str()); + + f_service_ << autogen_comment() << perl_includes(); + + bool done = false; + generate_use_includes(f_service_, done, tservice, true); + + t_service* extends_s = tservice->get_extends(); + if (extends_s != NULL) { + f_service_ << "use " << perl_namespace(extends_s->get_program()) << extends_s->get_name() << ";" + << endl; + } + + f_service_ << endl; + + // Generate the three main parts of the service (well, two for now in PERL) + generate_service_helpers(tservice); + generate_service_interface(tservice); + generate_service_rest(tservice); + generate_service_client(tservice); + generate_service_processor(tservice); + + // Close service file + f_service_ << "1;" << endl; + f_service_.close(); +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_perl_generator::generate_service_processor(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + string extends = ""; + string extends_processor = ""; + t_service* extends_s = tservice->get_extends(); + if (extends_s != NULL) { + extends = perl_namespace(extends_s->get_program()) + extends_s->get_name(); + extends_processor = "use base qw(" + extends + "Processor);"; + } + + indent_up(); + + // Generate the header portion + f_service_ << "package " << perl_namespace(program_) << service_name_ << "Processor;" << endl + << endl << "use strict;" << endl << extends_processor << endl << endl; + + if (extends.empty()) { + f_service_ << "sub new {" << endl; + + indent_up(); + + f_service_ << indent() << "my ($classname, $handler) = @_;" << endl << indent() + << "my $self = {};" << endl; + + f_service_ << indent() << "$self->{handler} = $handler;" << endl; + + f_service_ << indent() << "return bless ($self, $classname);" << endl; + + indent_down(); + + f_service_ << "}" << endl << endl; + } + + // Generate the server implementation + f_service_ << "sub process {" << endl; + indent_up(); + + f_service_ << indent() << "my ($self, $input, $output) = @_;" << endl; + + f_service_ << indent() << "my $rseqid = 0;" << endl << indent() << "my $fname = undef;" << endl + << indent() << "my $mtype = 0;" << endl << endl; + + f_service_ << indent() << "$input->readMessageBegin(\\$fname, \\$mtype, \\$rseqid);" << endl; + + // HOT: check for method implementation + f_service_ << indent() << "my $methodname = 'process_'.$fname;" << endl << indent() + << "if (!$self->can($methodname)) {" << endl; + indent_up(); + + f_service_ << indent() << "$input->skip(Thrift::TType::STRUCT);" << endl << indent() + << "$input->readMessageEnd();" << endl << indent() + << "my $x = new Thrift::TApplicationException('Function '.$fname.' not implemented.', " + "Thrift::TApplicationException::UNKNOWN_METHOD);" << endl << indent() + << "$output->writeMessageBegin($fname, Thrift::TMessageType::EXCEPTION, $rseqid);" << endl + << indent() << "$x->write($output);" << endl << indent() + << "$output->writeMessageEnd();" << endl << indent() + << "$output->getTransport()->flush();" << endl << indent() << "return;" << endl; + + indent_down(); + f_service_ << indent() << "}" << endl << indent() + << "$self->$methodname($rseqid, $input, $output);" << endl << indent() << "return 1;" + << endl; + + indent_down(); + + f_service_ << "}" << endl << endl; + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(tservice, *f_iter); + } +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_perl_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + // Open function + f_service_ << "sub process_" << tfunction->get_name() << " {" << endl; + + indent_up(); + + f_service_ << indent() << "my ($self, $seqid, $input, $output) = @_;" << endl; + + string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_" + + tfunction->get_name() + "_args"; + string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_" + + tfunction->get_name() + "_result"; + + f_service_ << indent() << "my $args = new " << argsname << "();" << endl << indent() + << "$args->read($input);" << endl; + + f_service_ << indent() << "$input->readMessageEnd();" << endl; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + // Declare result for non oneway function + if (!tfunction->is_oneway()) { + f_service_ << indent() << "my $result = new " << resultname << "();" << endl; + } + + // Try block for a function with exceptions + if (xceptions.size() > 0) { + f_service_ << indent() << "eval {" << endl; + indent_up(); + } + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + f_service_ << indent(); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + f_service_ << "$result->{success} = "; + } + f_service_ << "$self->{handler}->" << tfunction->get_name() << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "$args->" << (*f_iter)->get_name(); + } + f_service_ << ");" << endl; + + if (!tfunction->is_oneway() && xceptions.size() > 0) { + indent_down(); + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << indent() << "}; if( UNIVERSAL::isa($@,'" + << perl_namespace((*x_iter)->get_type()->get_program()) + << (*x_iter)->get_type()->get_name() << "') ){ " << endl; + + indent_up(); + f_service_ << indent() << "$result->{" << (*x_iter)->get_name() << "} = $@;" << endl; + f_service_ << indent() << "$@ = undef;" << endl; + indent_down(); + f_service_ << indent(); + } + f_service_ << "}" << endl; + + // catch-all for unexpected exceptions (THRIFT-3191) + f_service_ << indent() << "if ($@) {" << endl; + indent_up(); + f_service_ << indent() << "$@ =~ s/^\\s+|\\s+$//g;" << endl + << indent() << "my $err = new Thrift::TApplicationException(\"Unexpected Exception: \" . $@, Thrift::TApplicationException::INTERNAL_ERROR);" << endl + << indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', Thrift::TMessageType::EXCEPTION, $seqid);" << endl + << indent() << "$err->write($output);" << endl + << indent() << "$output->writeMessageEnd();" << endl + << indent() << "$output->getTransport()->flush();" << endl + << indent() << "$@ = undef;" << endl + << indent() << "return;" << endl; + indent_down(); + f_service_ << indent() << "}" << endl; + } + + // Shortcut out here for oneway functions + if (tfunction->is_oneway()) { + f_service_ << indent() << "return;" << endl; + indent_down(); + f_service_ << "}" << endl; + return; + } + + // Serialize the reply + f_service_ << indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', Thrift::TMessageType::REPLY, $seqid);" << endl + << indent() << "$result->write($output);" << endl + << indent() << "$output->writeMessageEnd();" << endl + << indent() << "$output->getTransport()->flush();" << endl; + + // Close function + indent_down(); + f_service_ << "}" << endl << endl; +} + +/** + * Generates helper functions for a service. + * + * @param tservice The service to generate a header definition for + */ +void t_perl_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + f_service_ << "# HELPER FUNCTIONS AND STRUCTURES" << endl << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + string name = ts->get_name(); + ts->set_name(service_name_ + "_" + name); + generate_perl_struct_definition(f_service_, ts, false); + generate_perl_function_helpers(*f_iter); + ts->set_name(name); + } +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_perl_generator::generate_perl_function_helpers(t_function* tfunction) { + t_struct result(program_, service_name_ + "_" + tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + generate_perl_struct_definition(f_service_, &result, false); +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_perl_generator::generate_service_interface(t_service* tservice) { + string extends_if = ""; + t_service* extends_s = tservice->get_extends(); + if (extends_s != NULL) { + extends_if = "use base qw(" + perl_namespace(extends_s->get_program()) + extends_s->get_name() + + "If);"; + } + + f_service_ << "package " << perl_namespace(program_) << service_name_ << "If;" << endl << endl + << "use strict;" << endl << extends_if << endl << endl; + + indent_up(); + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << "sub " << function_signature(*f_iter) << endl << " die 'implement interface';\n}" + << endl << endl; + } + indent_down(); +} + +/** + * Generates a REST interface + */ +void t_perl_generator::generate_service_rest(t_service* tservice) { + string extends = ""; + string extends_if = ""; + t_service* extends_s = tservice->get_extends(); + if (extends_s != NULL) { + extends = extends_s->get_name(); + extends_if = "use base qw(" + perl_namespace(extends_s->get_program()) + extends_s->get_name() + + "Rest);"; + } + f_service_ << "package " << perl_namespace(program_) << service_name_ << "Rest;" << endl << endl + << "use strict;" << endl << extends_if << endl << endl; + + if (extends.empty()) { + f_service_ << "sub new {" << endl; + + indent_up(); + + f_service_ << indent() << "my ($classname, $impl) = @_;" << endl << indent() + << "my $self ={ impl => $impl };" << endl << endl << indent() + << "return bless($self,$classname);" << endl; + + indent_down(); + + f_service_ << "}" << endl << endl; + } + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << "sub " << (*f_iter)->get_name() << "{" << endl; + + indent_up(); + + f_service_ << indent() << "my ($self, $request) = @_;" << endl << endl; + + const vector& args = (*f_iter)->get_arglist()->get_members(); + vector::const_iterator a_iter; + for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) { + t_type* atype = get_true_type((*a_iter)->get_type()); + string req = "$request->{'" + (*a_iter)->get_name() + "'}"; + f_service_ << indent() << "my $" << (*a_iter)->get_name() << " = (" << req << ") ? " << req + << " : undef;" << endl; + if (atype->is_string() && ((t_base_type*)atype)->is_string_list()) { + f_service_ << indent() << "my @" << (*a_iter)->get_name() << " = split(/,/, $" + << (*a_iter)->get_name() << ");" << endl << indent() << "$" + << (*a_iter)->get_name() << " = \\@" << (*a_iter)->get_name() << endl; + } + } + f_service_ << indent() << "return $self->{impl}->" << (*f_iter)->get_name() << "(" + << argument_list((*f_iter)->get_arglist()) << ");" << endl; + indent_down(); + indent(f_service_) << "}" << endl << endl; + } +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_perl_generator::generate_service_client(t_service* tservice) { + string extends = ""; + string extends_client = ""; + t_service* extends_s = tservice->get_extends(); + if (extends_s != NULL) { + extends = perl_namespace(extends_s->get_program()) + extends_s->get_name(); + extends_client = "use base qw(" + extends + "Client);"; + } + + f_service_ << "package " << perl_namespace(program_) << service_name_ << "Client;" << endl << endl + << extends_client << endl << "use base qw(" << perl_namespace(program_) + << service_name_ << "If);" << endl; + + // Constructor function + f_service_ << "sub new {" << endl; + + indent_up(); + + f_service_ << indent() << "my ($classname, $input, $output) = @_;" << endl << indent() + << "my $self = {};" << endl; + + if (!extends.empty()) { + f_service_ << indent() << "$self = $classname->SUPER::new($input, $output);" << endl; + } else { + f_service_ << indent() << "$self->{input} = $input;" << endl << indent() + << "$self->{output} = defined $output ? $output : $input;" << endl << indent() + << "$self->{seqid} = 0;" << endl; + } + + f_service_ << indent() << "return bless($self,$classname);" << endl; + + indent_down(); + + f_service_ << "}" << endl << endl; + + // Generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* arg_struct = (*f_iter)->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + string funname = (*f_iter)->get_name(); + + // Open function + f_service_ << "sub " << function_signature(*f_iter) << endl; + + indent_up(); + + indent(f_service_) << indent() << "$self->send_" << funname << "("; + + bool first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "$" << (*fld_iter)->get_name(); + } + f_service_ << ");" << endl; + + if (!(*f_iter)->is_oneway()) { + f_service_ << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << "return "; + } + f_service_ << "$self->recv_" << funname << "();" << endl; + } + + indent_down(); + + f_service_ << "}" << endl << endl; + + f_service_ << "sub send_" << function_signature(*f_iter) << endl; + + indent_up(); + + std::string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_" + + (*f_iter)->get_name() + "_args"; + + // Serialize the request header + f_service_ << indent() << "$self->{output}->writeMessageBegin('" << (*f_iter)->get_name() + << "', " << ((*f_iter)->is_oneway() ? "Thrift::TMessageType::ONEWAY" : "Thrift::TMessageType::CALL") + << ", $self->{seqid});" << endl; + + f_service_ << indent() << "my $args = new " << argsname << "();" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << indent() << "$args->{" << (*fld_iter)->get_name() << "} = $" + << (*fld_iter)->get_name() << ";" << endl; + } + + // Write to the stream + f_service_ << indent() << "$args->write($self->{output});" << endl << indent() + << "$self->{output}->writeMessageEnd();" << endl << indent() + << "$self->{output}->getTransport()->flush();" << endl; + + indent_down(); + + f_service_ << "}" << endl; + + if (!(*f_iter)->is_oneway()) { + std::string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_" + + (*f_iter)->get_name() + "_result"; + t_struct noargs(program_); + + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + &noargs); + // Open function + f_service_ << endl << "sub " << function_signature(&recv_function) << endl; + + indent_up(); + + f_service_ << indent() << "my $rseqid = 0;" << endl << indent() << "my $fname;" << endl + << indent() << "my $mtype = 0;" << endl << endl; + + f_service_ << indent() << "$self->{input}->readMessageBegin(\\$fname, \\$mtype, \\$rseqid);" + << endl << indent() << "if ($mtype == Thrift::TMessageType::EXCEPTION) {" << endl + << indent() << " my $x = new Thrift::TApplicationException();" << endl << indent() + << " $x->read($self->{input});" << endl << indent() + << " $self->{input}->readMessageEnd();" << endl << indent() << " die $x;" << endl + << indent() << "}" << endl; + + f_service_ << indent() << "my $result = new " << resultname << "();" << endl << indent() + << "$result->read($self->{input});" << endl; + + f_service_ << indent() << "$self->{input}->readMessageEnd();" << endl << endl; + + // Careful, only return result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << indent() << "if (defined $result->{success} ) {" << endl << indent() + << " return $result->{success};" << endl << indent() << "}" << endl; + } + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << indent() << "if (defined $result->{" << (*x_iter)->get_name() << "}) {" + << endl << indent() << " die $result->{" << (*x_iter)->get_name() << "};" + << endl << indent() << "}" << endl; + } + + // Careful, only return _result if not a void function + if ((*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << "return;" << endl; + } else { + f_service_ << indent() << "die \"" << (*f_iter)->get_name() << " failed: unknown result\";" + << endl; + } + + // Close function + indent_down(); + f_service_ << "}" << endl; + } + } +} + +/** + * Deserializes a field of any type. + */ +void t_perl_generator::generate_deserialize_field(ofstream& out, + t_field* tfield, + string prefix, + bool inclass) { + (void)inclass; + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = tfield->get_name(); + + // Hack for when prefix is defined (always a hash ref) + if (!prefix.empty()) { + name = prefix + "{" + tfield->get_name() + "}"; + } + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name); + } else if (type->is_container()) { + generate_deserialize_container(out, type, name); + } else if (type->is_base_type() || type->is_enum()) { + indent(out) << "$xfer += $input->"; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + out << "readString(\\$" << name << ");"; + break; + case t_base_type::TYPE_BOOL: + out << "readBool(\\$" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "readByte(\\$" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "readI16(\\$" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "readI32(\\$" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "readI64(\\$" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble(\\$" << name << ");"; + break; + default: + throw "compiler error: no PERL name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "readI32(\\$" << name << ");"; + } + out << endl; + + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type->get_name().c_str()); + } +} + +/** + * Generates an unserializer for a variable. This makes two key assumptions, + * first that there is a const char* variable named data that points to the + * buffer for deserialization, and that there is a variable protocol which + * is a reference to a TProtocol serialization object. + */ +void t_perl_generator::generate_deserialize_struct(ofstream& out, + t_struct* tstruct, + string prefix) { + out << indent() << "$" << prefix << " = " << perl_namespace(tstruct->get_program()) + << tstruct->get_name() << "->new();" << endl << indent() << "$xfer += $" << prefix + << "->read($input);" << endl; +} + +void t_perl_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) { + scope_up(out); + + string size = tmp("_size"); + string ktype = tmp("_ktype"); + string vtype = tmp("_vtype"); + string etype = tmp("_etype"); + + t_field fsize(g_type_i32, size); + t_field fktype(g_type_i8, ktype); + t_field fvtype(g_type_i8, vtype); + t_field fetype(g_type_i8, etype); + + out << indent() << "my $" << size << " = 0;" << endl; + + // Declare variables, read header + if (ttype->is_map()) { + out << indent() << "$" << prefix << " = {};" << endl << indent() << "my $" << ktype << " = 0;" + << endl << indent() << "my $" << vtype << " = 0;" << endl; + + out << indent() << "$xfer += $input->readMapBegin(" + << "\\$" << ktype << ", \\$" << vtype << ", \\$" << size << ");" << endl; + + } else if (ttype->is_set()) { + + out << indent() << "$" << prefix << " = {};" << endl << indent() << "my $" << etype << " = 0;" + << endl << indent() << "$xfer += $input->readSetBegin(" + << "\\$" << etype << ", \\$" << size << ");" << endl; + + } else if (ttype->is_list()) { + + out << indent() << "$" << prefix << " = [];" << endl << indent() << "my $" << etype << " = 0;" + << endl << indent() << "$xfer += $input->readListBegin(" + << "\\$" << etype << ", \\$" << size << ");" << endl; + } + + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << "for (my $" << i << " = 0; $" << i << " < $" << size << "; ++$" << i << ")" + << endl; + + scope_up(out); + + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, prefix); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, prefix); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, prefix); + } + + scope_down(out); + + // Read container end + if (ttype->is_map()) { + indent(out) << "$xfer += $input->readMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "$xfer += $input->readSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "$xfer += $input->readListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Generates code to deserialize a map + */ +void t_perl_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) { + string key = tmp("key"); + string val = tmp("val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + indent(out) << declare_field(&fkey, true, true) << endl; + indent(out) << declare_field(&fval, true, true) << endl; + + generate_deserialize_field(out, &fkey); + generate_deserialize_field(out, &fval); + + indent(out) << "$" << prefix << "->{$" << key << "} = $" << val << ";" << endl; +} + +void t_perl_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) { + string elem = tmp("elem"); + t_field felem(tset->get_elem_type(), elem); + + indent(out) << "my $" << elem << " = undef;" << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << "$" << prefix << "->{$" << elem << "} = 1;" << endl; +} + +void t_perl_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix) { + string elem = tmp("elem"); + t_field felem(tlist->get_elem_type(), elem); + + indent(out) << "my $" << elem << " = undef;" << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << "push(@{$" << prefix << "},$" << elem << ");" << endl; +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_perl_generator::generate_serialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = get_true_type(tfield->get_type()); + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, prefix + "{" + tfield->get_name() + "}"); + } else if (type->is_container()) { + generate_serialize_container(out, type, prefix + "{" + tfield->get_name() + "}"); + } else if (type->is_base_type() || type->is_enum()) { + + string name = tfield->get_name(); + + // Hack for when prefix is defined (always a hash ref) + if (!prefix.empty()) + name = prefix + "{" + tfield->get_name() + "}"; + + indent(out) << "$xfer += $output->"; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + out << "writeString($" << name << ");"; + break; + case t_base_type::TYPE_BOOL: + out << "writeBool($" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "writeByte($" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "writeI16($" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "writeI32($" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "writeI64($" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble($" << name << ");"; + break; + default: + throw "compiler error: no PERL name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "writeI32($" << name << ");"; + } + out << endl; + + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", + prefix.c_str(), + tfield->get_name().c_str(), + type->get_name().c_str()); + } +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_perl_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + (void)tstruct; + indent(out) << "$xfer += $" << prefix << "->write($output);" << endl; +} + +/** + * Writes out a container + */ +void t_perl_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + scope_up(out); + + if (ttype->is_map()) { + indent(out) << "$xfer += $output->writeMapBegin(" + << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " + << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " + << "scalar(keys %{$" << prefix << "}));" << endl; + } else if (ttype->is_set()) { + indent(out) << "$xfer += $output->writeSetBegin(" + << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " + << "scalar(@{$" << prefix << "}));" << endl; + + } else if (ttype->is_list()) { + + indent(out) << "$xfer += $output->writeListBegin(" + << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " + << "scalar(@{$" << prefix << "}));" << endl; + } + + scope_up(out); + + if (ttype->is_map()) { + string kiter = tmp("kiter"); + string viter = tmp("viter"); + indent(out) << "while( my ($" << kiter << ",$" << viter << ") = each %{$" << prefix << "}) " + << endl; + + scope_up(out); + generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); + scope_down(out); + + } else if (ttype->is_set()) { + string iter = tmp("iter"); + indent(out) << "foreach my $" << iter << " (@{$" << prefix << "})" << endl; + scope_up(out); + generate_serialize_set_element(out, (t_set*)ttype, iter); + scope_down(out); + + } else if (ttype->is_list()) { + string iter = tmp("iter"); + indent(out) << "foreach my $" << iter << " (@{$" << prefix << "}) " << endl; + scope_up(out); + generate_serialize_list_element(out, (t_list*)ttype, iter); + scope_down(out); + } + + scope_down(out); + + if (ttype->is_map()) { + indent(out) << "$xfer += $output->writeMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "$xfer += $output->writeSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "$xfer += $output->writeListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Serializes the members of a map. + * + */ +void t_perl_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string kiter, + string viter) { + t_field kfield(tmap->get_key_type(), kiter); + generate_serialize_field(out, &kfield); + + t_field vfield(tmap->get_val_type(), viter); + generate_serialize_field(out, &vfield); +} + +/** + * Serializes the members of a set. + */ +void t_perl_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) { + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, &efield); +} + +/** + * Serializes the members of a list. + */ +void t_perl_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) { + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, &efield); +} + +/** + * Declares a field, which may include initialization as necessary. + * + * @param ttype The type + */ +string t_perl_generator::declare_field(t_field* tfield, bool init, bool obj) { + string result = "my $" + tfield->get_name(); + if (init) { + t_type* type = get_true_type(tfield->get_type()); + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + break; + case t_base_type::TYPE_STRING: + result += " = ''"; + break; + case t_base_type::TYPE_BOOL: + result += " = 0"; + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + result += " = 0"; + break; + case t_base_type::TYPE_DOUBLE: + result += " = 0.0"; + break; + default: + throw "compiler error: no PERL initializer for base type " + + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + result += " = 0"; + } else if (type->is_container()) { + result += " = []"; + } else if (type->is_struct() || type->is_xception()) { + if (obj) { + result += " = new " + perl_namespace(type->get_program()) + type->get_name() + "()"; + } else { + result += " = undef"; + } + } + } + return result + ";"; +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_perl_generator::function_signature(t_function* tfunction, string prefix) { + + string str; + + str = prefix + tfunction->get_name() + "{\n"; + str += " my $self = shift;\n"; + + // Need to create perl function arg inputs + const vector& fields = tfunction->get_arglist()->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + str += " my $" + (*f_iter)->get_name() + " = shift;\n"; + } + + return str; +} + +/** + * Renders a field list + */ +string t_perl_generator::argument_list(t_struct* tstruct) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + result += "$" + (*f_iter)->get_name(); + } + return result; +} + +/** + * Converts the parse type to a C++ enum string for the given type. + */ +string t_perl_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "Thrift::TType::STRING"; + case t_base_type::TYPE_BOOL: + return "Thrift::TType::BOOL"; + case t_base_type::TYPE_I8: + return "Thrift::TType::BYTE"; + case t_base_type::TYPE_I16: + return "Thrift::TType::I16"; + case t_base_type::TYPE_I32: + return "Thrift::TType::I32"; + case t_base_type::TYPE_I64: + return "Thrift::TType::I64"; + case t_base_type::TYPE_DOUBLE: + return "Thrift::TType::DOUBLE"; + } + } else if (type->is_enum()) { + return "Thrift::TType::I32"; + } else if (type->is_struct() || type->is_xception()) { + return "Thrift::TType::STRUCT"; + } else if (type->is_map()) { + return "Thrift::TType::MAP"; + } else if (type->is_set()) { + return "Thrift::TType::SET"; + } else if (type->is_list()) { + return "Thrift::TType::LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +THRIFT_REGISTER_GENERATOR(perl, "Perl", "") diff --git a/compiler/cpp/src/thrift/generate/t_php_generator.cc b/compiler/cpp/src/thrift/generate/t_php_generator.cc new file mode 100644 index 0000000..11771c2 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_php_generator.cc @@ -0,0 +1,2679 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +#define NSGLOBAL (nsglobal_.size() ? nsglobal_ : "") +#define NSGLOBAL_A ("\\" + NSGLOBAL) +#define NSGLOBAL_B (NSGLOBAL + "\\") +#define NSGLOBAL_AB ("\\" + NSGLOBAL + "\\") + +/** + * PHP code generator. + * + */ +class t_php_generator : public t_oop_generator { +public: + t_php_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + binary_inline_ = false; + rest_ = false; + phps_ = false; + oop_ = false; + validate_ = false; + json_serializable_ = false; + nsglobal_ = ""; // by default global namespace is empty + psr4_ = false; + for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if (iter->first.compare("inlined") == 0) { + binary_inline_ = true; + } else if (iter->first.compare("rest") == 0) { + rest_ = true; + } else if (iter->first.compare("server") == 0) { + phps_ = true; + } else if (iter->first.compare("oop") == 0) { + oop_ = true; + } else if (iter->first.compare("validate") == 0) { + validate_ = true; + } else if (iter->first.compare("json") == 0) { + json_serializable_ = true; + } else if (iter->first.compare("nsglobal") == 0) { + nsglobal_ = iter->second; + } else if (iter->first.compare("psr4") == 0) { + psr4_ = true; + } else { + throw "unknown option php:" + iter->first; + } + } + + if (oop_ && binary_inline_) { + throw "oop and inlined are mutually exclusive."; + } + + out_dir_base_ = (binary_inline_ ? "gen-phpi" : "gen-php"); + escape_['$'] = "\\$"; + } + + static bool is_valid_namespace(const std::string& sub_namespace); + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_consts(vector consts); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + std::string render_const_value(t_type* type, t_const_value* value); + + /** + * Structs! + */ + + void generate_php_struct(t_struct* tstruct, bool is_exception); + void generate_php_struct_definition(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false, + bool is_result = false); + void generate_php_struct_reader(std::ofstream& out, t_struct* tstruct, bool is_result); + void generate_php_struct_writer(std::ofstream& out, t_struct* tstruct, bool is_result); + void generate_php_function_helpers(t_service* tservice, t_function* tfunction); + void generate_php_struct_required_validator(ofstream& out, + t_struct* tstruct, + std::string method_name, + bool write_mode); + void generate_php_struct_read_validator(ofstream& out, t_struct* tstruct); + void generate_php_struct_write_validator(ofstream& out, t_struct* tstruct); + void generate_php_struct_json_serialize(ofstream& out, t_struct* tstruct, bool is_result); + bool needs_php_write_validator(t_struct* tstruct, bool is_result); + bool needs_php_read_validator(t_struct* tstruct, bool is_result); + int get_php_num_required_fields(const vector& fields, bool write_mode); + + void generate_php_type_spec(std::ofstream& out, t_type* t); + void generate_php_struct_spec(std::ofstream& out, t_struct* tstruct); + + /** + * Service-level generation functions + */ + + void generate_service_helpers(t_service* tservice); + void generate_service_interface(t_service* tservice); + void generate_service_rest(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_processor(t_service* tservice); + void generate_process_function(std::ofstream& out, t_service* tservice, t_function* tfunction); + void generate_service_header(t_service* tservice, std::ofstream& file); + void generate_program_header(std::ofstream& file); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, + t_field* tfield, + std::string prefix = "", + bool inclass = false); + + void generate_deserialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_deserialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_deserialize_set_element(std::ofstream& out, t_set* tset, std::string prefix = ""); + + void generate_deserialize_map_element(std::ofstream& out, t_map* tmap, std::string prefix = ""); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix = ""); + + void generate_serialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string kiter, + std::string viter); + + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + + void generate_php_doc(std::ofstream& out, t_doc* tdoc); + + void generate_php_doc(std::ofstream& out, t_field* tfield); + + void generate_php_doc(std::ofstream& out, t_function* tfunction); + + void generate_php_docstring_comment(std::ofstream& out, string contents); + + /** + * Helper rendering functions + */ + + std::string php_includes(); + std::string declare_field(t_field* tfield, bool init = false, bool obj = false); + std::string function_signature(t_function* tfunction, std::string prefix = ""); + std::string argument_list(t_struct* tstruct, bool addTypeHints = true); + std::string type_to_cast(t_type* ttype); + std::string type_to_enum(t_type* ttype); + std::string type_to_phpdoc(t_type* ttype); + + bool php_is_scalar(t_type *ttype) { + ttype = ttype->get_true_type(); + if(ttype->is_base_type()) { + return true; + } else if(ttype->is_enum()) { + return true; + } else { + return false; + } + } + + std::string php_namespace_base(const t_program* p) { + std::string ns = p->get_namespace("php"); + const char* delimiter = "\\"; + size_t position = ns.find('.'); + while (position != string::npos) { + ns.replace(position, 1, delimiter); + position = ns.find('.', position + 1); + } + return ns; + } + + // general use namespace prefixing: \my\namespace\ or my_namespace_ + string php_namespace(const t_program* p) { + string ns = php_namespace_base(p); + return (nsglobal_.size() ? NSGLOBAL_AB : NSGLOBAL_B) + (ns.size() ? (ns + "\\") : ""); + } + + // return the namespace of a file: + // global\ns\sub\ns or global\ns or sub\ns + string php_namespace_suffix(const t_program* p) { + string ns = php_namespace_base(p); + + return NSGLOBAL + + (ns.size() && NSGLOBAL.size() ? "\\" : "") + + ns; + } + + // add a directory to already existing namespace + string php_namespace_directory(string directory, bool end = true) { + (void)directory; + if (end) { + return ";"; + } else { + return ""; + } + } + + // writing an autload identifier into globa;ls: my\namespace\ or my_namespace_ + string php_namespace_autoload(const t_program* p) { + std::string ns = php_namespace_base(p); + return (nsglobal_.size() ? NSGLOBAL_B : NSGLOBAL) + (ns.size() ? (ns + "\\") : ""); + } + + // declaring a type: typename or my_namespace_typename + string php_namespace_declaration(t_type* t) { return t->get_name(); } + + std::string php_path(t_program* p) { + std::string ns = p->get_namespace("php.path"); + if (ns.empty()) { + return p->get_name(); + } + + // Transform the java-style namespace into a path. + for (std::string::iterator it = ns.begin(); it != ns.end(); ++it) { + if (*it == '.') { + *it = '/'; + } + } + + return ns + '/'; + } + + /** + * Transform class_method into ClassMethod + * + * @param str + * @return stirng + */ + string classify(string str) { + string classe = ""; + + vector x = split(str, '_'); + + for (size_t i = 0; i < x.size(); ++i) { + classe = classe + capitalize(x[i]); + } + + return classe; + } + + /** + * Split method + * @param s + * @param delim + * @param elems + * @return + */ + vector& split(const string& s, char delim, vector& elems) { + stringstream ss(s); + string item; + + while (getline(ss, item, delim)) { + elems.push_back(item); + } + + return elems; + } + + vector split(const string& s, char delim) { + vector elems; + + return split(s, delim, elems); + } + + /** + * Capitalize method + * @param str + * @return + */ + string capitalize(string str) { + string::iterator it(str.begin()); + + if (it != str.end()) + str[0] = toupper((unsigned char)str[0]); + + // while(++it != str.end()) + // { + // *it = tolower((unsigned char)*it); + // } + return str; + } + +private: + /** + * File streams + */ + std::ofstream f_types_; + std::ofstream f_service_; + + std::string package_dir_; + /** + * Generate protocol-independent template? Or Binary inline code? + */ + bool binary_inline_; + + /** + * Generate a REST handler class + */ + bool rest_; + + /** + * Generate stubs for a PHP server + */ + bool phps_; + + /** + * Whether to use OOP base class TBase + */ + bool oop_; + + /** + * Whether to hold each class in separate file to allow PSR4-autoloading + */ + bool psr4_; + + /** + * Whether to generate validator code + */ + bool validate_; + + /** + * Whether to generate JsonSerializable classes + */ + bool json_serializable_; + + /** + * Global namespace for PHP 5.3 + */ + std::string nsglobal_; +}; + +bool t_php_generator::is_valid_namespace(const std::string& sub_namespace) { + return sub_namespace == "path"; +} + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_php_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + + // Create Real directory Namespaces + vector NSx = split(php_namespace_suffix(get_program()), '\\'); + package_dir_ = get_out_dir(); + + for (size_t i = 0; i < NSx.size(); ++i) { + package_dir_ = package_dir_ + "/" + NSx[i] + "/"; + MKDIR(package_dir_.c_str()); + } + + // Prepare output file for all the types in non-psr4 mode + if (!psr4_) { + // Make output file + string f_types_name = package_dir_ + "Types.php"; + f_types_.open(f_types_name.c_str()); + generate_program_header(f_types_); + } +} + +/** + * Prints standard php includes + */ +string t_php_generator::php_includes() { + string includes = "use Thrift\\Base\\TBase;\n" + "use Thrift\\Type\\TType;\n" + "use Thrift\\Type\\TMessageType;\n" + "use Thrift\\Exception\\TException;\n" + "use Thrift\\Exception\\TProtocolException;\n" + "use Thrift\\Protocol\\TProtocol;\n" + "use Thrift\\Protocol\\TBinaryProtocolAccelerated;\n" + "use Thrift\\Exception\\TApplicationException;\n"; + + if (json_serializable_) { + includes += "use JsonSerializable;\n" + "use stdClass;\n"; + } + + return includes + "\n"; +} + +/** + * Close up (or down) some filez. + */ +void t_php_generator::close_generator() { + if (!psr4_) { + // Close types file + f_types_ << endl; + f_types_.close(); + } +} + +/** + * Generates a typedef. This is not done in PHP, types are all implicit. + * + * @param ttypedef The type definition + */ +void t_php_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + +/** + * Generates service header contains namespace suffix and includes inside file specified + */ +void t_php_generator::generate_service_header(t_service* tservice, std::ofstream& file) { + file << "get_program()).empty()) { + file << "namespace " << php_namespace_suffix(tservice->get_program()) << ";" << endl; + } + file << autogen_comment() << php_includes(); + + file << endl; +} + +/** + * Generates program header contains namespace suffix and includes inside file specified + */ +void t_php_generator::generate_program_header(std::ofstream& file) { + file << "get_name() + ".php"; + f_enum.open(f_enum_name.c_str()); + generate_program_header(f_enum); + } + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + + // We're also doing it this way to see how it performs. It's more legible + // code but you can't do things like an 'extract' on it, which is a bit of + // a downer. + generate_php_doc(f_enum, tenum); + f_enum << "final class " << tenum->get_name() << " {" << endl; + indent_up(); + + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + generate_php_doc(f_enum, *c_iter); + indent(f_enum) << "const " << (*c_iter)->get_name() << " = " << value << ";" << endl; + } + + indent(f_enum) << "static public $__names = array(" << endl; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + indent(f_enum) << " " << value << " => '" << (*c_iter)->get_name() << "'," << endl; + } + indent(f_enum) << ");" << endl; + + indent_down(); + + f_enum << "}" << endl << endl; + if (psr4_) { + f_enum.close(); + } +} + +/** + * Generate constant class + * + * Override the one from t_generator + */ +void t_php_generator::generate_consts(vector consts) { + vector::iterator c_iter; + + // Create class only if needed + if (consts.size() > 0) { + + std::ofstream& f_consts = f_types_; + if (psr4_) { + string f_consts_name = package_dir_ + "Constant.php"; + f_consts.open(f_consts_name.c_str()); + generate_program_header(f_consts); + } + f_consts << "final class Constant extends \\Thrift\\Type\\TConstant {" << endl; + + indent_up(); + + // Create static property + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + string name = (*c_iter)->get_name(); + + indent(f_consts) << "static protected $" << name << ";" << endl; + } + + // Create init function + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + string name = (*c_iter)->get_name(); + + f_consts << endl; + + indent(f_consts) << "static protected function init_" << name << "() {" << endl; + indent_up(); + + indent(f_consts) << "return "; + generate_php_doc(f_consts, *c_iter); + f_consts << render_const_value((*c_iter)->get_type(), (*c_iter)->get_value()); + f_consts << ";" << endl; + + indent_down(); + indent(f_consts) << "}" << endl; + } + + indent_down(); + f_consts << "}" << endl << endl; + if (psr4_) { + f_consts.close(); + } + } +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +string t_php_generator::render_const_value(t_type* type, t_const_value* value) { + std::ostringstream out; + type = get_true_type(type); + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + out << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + out << (value->get_integer() > 0 ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + out << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + out << value->get_integer(); + } else { + out << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + indent(out) << value->get_integer(); + } else if (type->is_struct() || type->is_xception()) { + out << "new " << php_namespace(type->get_program()) << type->get_name() << "(array(" << endl; + indent_up(); + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + out << indent(); + out << render_const_value(g_type_string, v_iter->first); + out << " => "; + out << render_const_value(field_type, v_iter->second); + out << "," << endl; + } + indent_down(); + indent(out) << "))"; + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + out << "array(" << endl; + indent_up(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + out << indent(); + out << render_const_value(ktype, v_iter->first); + out << " => "; + out << render_const_value(vtype, v_iter->second); + out << "," << endl; + } + indent_down(); + indent(out) << ")"; + } else if (type->is_list() || type->is_set()) { + t_type* etype; + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + out << "array(" << endl; + indent_up(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + out << indent(); + out << render_const_value(etype, *v_iter); + if (type->is_set()) { + out << " => true"; + } + out << "," << endl; + } + indent_down(); + indent(out) << ")"; + } + return out.str(); +} + +/** + * Make a struct + */ +void t_php_generator::generate_struct(t_struct* tstruct) { + generate_php_struct(tstruct, false); +} + +/** + * Generates a struct definition for a thrift exception. Basically the same + * as a struct but extends the Exception class. + * + * @param txception The struct definition + */ +void t_php_generator::generate_xception(t_struct* txception) { + generate_php_struct(txception, true); +} + +/** + * Structs can be normal or exceptions. + */ +void t_php_generator::generate_php_struct(t_struct* tstruct, bool is_exception) { + std::ofstream& f_struct = f_types_; + if (psr4_) { + string f_struct_name = package_dir_ + tstruct->get_name() + ".php"; + f_struct.open(f_struct_name.c_str()); + generate_program_header(f_struct); + } + generate_php_struct_definition(f_struct, tstruct, is_exception); + if (psr4_) { + f_struct.close(); + } +} + +void t_php_generator::generate_php_type_spec(ofstream& out, t_type* t) { + t = get_true_type(t); + indent(out) << "'type' => " << type_to_enum(t) << "," << endl; + + if (t->is_base_type() || t->is_enum()) { + // Noop, type is all we need + } else if (t->is_struct() || t->is_xception()) { + indent(out) << "'class' => '" << php_namespace(t->get_program()) << t->get_name() << "'," + << endl; + } else if (t->is_map()) { + t_type* ktype = get_true_type(((t_map*)t)->get_key_type()); + t_type* vtype = get_true_type(((t_map*)t)->get_val_type()); + indent(out) << "'ktype' => " << type_to_enum(ktype) << "," << endl; + indent(out) << "'vtype' => " << type_to_enum(vtype) << "," << endl; + indent(out) << "'key' => array(" << endl; + indent_up(); + generate_php_type_spec(out, ktype); + indent_down(); + indent(out) << ")," << endl; + indent(out) << "'val' => array(" << endl; + indent_up(); + generate_php_type_spec(out, vtype); + indent(out) << ")," << endl; + indent_down(); + } else if (t->is_list() || t->is_set()) { + t_type* etype; + if (t->is_list()) { + etype = get_true_type(((t_list*)t)->get_elem_type()); + } else { + etype = get_true_type(((t_set*)t)->get_elem_type()); + } + indent(out) << "'etype' => " << type_to_enum(etype) << "," << endl; + indent(out) << "'elem' => array(" << endl; + indent_up(); + generate_php_type_spec(out, etype); + indent(out) << ")," << endl; + indent_down(); + } else { + throw "compiler error: no type for php struct spec field"; + } +} + +/** + * Generates the struct specification structure, which fully qualifies enough + * type information to generalize serialization routines. + */ +void t_php_generator::generate_php_struct_spec(ofstream& out, t_struct* tstruct) { + indent(out) << "static $_TSPEC = array(" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + indent(out) << (*m_iter)->get_key() << " => array(" << endl; + indent_up(); + out << indent() << "'var' => '" << (*m_iter)->get_name() << "'," << endl; + out << indent() << "'isRequired' => " << ((*m_iter)->get_req() == t_field::T_REQUIRED ? "true" : "false") << "," << endl; + generate_php_type_spec(out, t); + indent(out) << ")," << endl; + indent_down(); + } + + indent_down(); + indent(out) << " );" << endl << endl; +} + +/** + * Generates a struct definition for a thrift data type. This is nothing in PHP + * where the objects are all just associative arrays (unless of course we + * decide to start using objects for them...) + * + * @param tstruct The struct definition + */ +void t_php_generator::generate_php_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool is_result) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + generate_php_doc(out, tstruct); + out << "class " << php_namespace_declaration(tstruct); + if (is_exception) { + out << " extends " + << "TException"; + } else if (oop_) { + out << " extends " + << "TBase"; + } + if (json_serializable_) { + out << " implements JsonSerializable"; + } + out << " {" << endl; + indent_up(); + + out << indent() << "static $isValidate = " << (validate_ ? "true" : "false") << ";" << endl << endl; + + generate_php_struct_spec(out, tstruct); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + string dval = "null"; + t_type* t = get_true_type((*m_iter)->get_type()); + if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) { + dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value()); + } + generate_php_doc(out, *m_iter); + indent(out) << "public $" << (*m_iter)->get_name() << " = " << dval << ";" << endl; + } + + out << endl; + + // Generate constructor from array + string param = (members.size() > 0) ? "$vals=null" : ""; + out << indent() << "public function __construct(" << param << ") {" << endl; + indent_up(); + + if (members.size() > 0) { + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) { + indent(out) << "$this->" << (*m_iter)->get_name() << " = " + << render_const_value(t, (*m_iter)->get_value()) << ";" << endl; + } + } + out << indent() << "if (is_array($vals)) {" << endl; + indent_up(); + if (oop_) { + out << indent() << "parent::__construct(self::$_TSPEC, $vals);" << endl; + } else { + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + out << indent() << "if (isset($vals['" << (*m_iter)->get_name() << "'])) {" << endl + << indent() << " $this->" << (*m_iter)->get_name() << " = $vals['" + << (*m_iter)->get_name() << "'];" << endl << indent() << "}" << endl; + } + } + indent_down(); + out << indent() << "}" << endl; + } + scope_down(out); + out << endl; + + out << indent() << "public function getName() {" << endl << indent() << " return '" + << tstruct->get_name() << "';" << endl << indent() << "}" << endl << endl; + + generate_php_struct_reader(out, tstruct, is_result); + generate_php_struct_writer(out, tstruct, is_result); + if (needs_php_read_validator(tstruct, is_result)) { + generate_php_struct_read_validator(out, tstruct); + } + if (needs_php_write_validator(tstruct, is_result)) { + generate_php_struct_write_validator(out, tstruct); + } + if (json_serializable_) { + generate_php_struct_json_serialize(out, tstruct, is_result); + } + + indent_down(); + out << indent() << "}" << endl << endl; +} + +/** + * Generates the read() method for a struct + */ +void t_php_generator::generate_php_struct_reader(ofstream& out, t_struct* tstruct, bool is_result) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + indent(out) << "public function read($input)" << endl; + scope_up(out); + + if (oop_) { + if (needs_php_read_validator(tstruct, is_result)) { + indent(out) << "$tmp = $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);" + << endl; + indent(out) << "$this->_validateForRead();" << endl; + indent(out) << "return $tmp;" << endl; + } else { + indent(out) << "return $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);" + << endl; + } + scope_down(out); + out << endl; + return; + } + + out << indent() << "$xfer = 0;" << endl << indent() << "$fname = null;" << endl << indent() + << "$ftype = 0;" << endl << indent() << "$fid = 0;" << endl; + + // Declare stack tmp variables + if (!binary_inline_) { + indent(out) << "$xfer += $input->readStructBegin($fname);" << endl; + } + + // Loop over reading in fields + indent(out) << "while (true)" << endl; + + scope_up(out); + + // Read beginning field marker + if (binary_inline_) { + t_field fftype(g_type_i8, "ftype"); + t_field ffid(g_type_i16, "fid"); + generate_deserialize_field(out, &fftype); + out << indent() << "if ($ftype == " + << "TType::STOP) {" << endl << indent() << " break;" << endl << indent() << "}" << endl; + generate_deserialize_field(out, &ffid); + } else { + indent(out) << "$xfer += $input->readFieldBegin($fname, $ftype, $fid);" << endl; + // Check for field STOP marker and break + indent(out) << "if ($ftype == " + << "TType::STOP) {" << endl; + indent_up(); + indent(out) << "break;" << endl; + indent_down(); + indent(out) << "}" << endl; + } + + // Switch statement on the field we are reading + indent(out) << "switch ($fid)" << endl; + + scope_up(out); + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << "case " << (*f_iter)->get_key() << ":" << endl; + indent_up(); + indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; + indent_up(); + generate_deserialize_field(out, *f_iter, "this->"); + indent_down(); + out << indent() << "} else {" << endl; + if (binary_inline_) { + indent(out) << " $xfer += " + << "TProtocol::skipBinary($input, $ftype);" << endl; + } else { + indent(out) << " $xfer += $input->skip($ftype);" << endl; + } + out << indent() << "}" << endl << indent() << "break;" << endl; + indent_down(); + } + + // In the default case we skip the field + indent(out) << "default:" << endl; + if (binary_inline_) { + indent(out) << " $xfer += " + << "TProtocol::skipBinary($input, $ftype);" << endl; + } else { + indent(out) << " $xfer += $input->skip($ftype);" << endl; + } + indent(out) << " break;" << endl; + + scope_down(out); + + if (!binary_inline_) { + // Read field end marker + indent(out) << "$xfer += $input->readFieldEnd();" << endl; + } + + scope_down(out); + + if (!binary_inline_) { + indent(out) << "$xfer += $input->readStructEnd();" << endl; + } + + if (needs_php_read_validator(tstruct, is_result)) { + indent(out) << "$this->_validateForRead();" << endl; + } + + indent(out) << "return $xfer;" << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +/** + * Generates the write() method for a struct + */ +void t_php_generator::generate_php_struct_writer(ofstream& out, t_struct* tstruct, bool is_result) { + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + if (binary_inline_) { + indent(out) << "public function write(&$output) {" << endl; + } else { + indent(out) << "public function write($output) {" << endl; + } + indent_up(); + + if (needs_php_write_validator(tstruct, is_result)) { + indent(out) << "$this->_validateForWrite();" << endl; + } + + if (oop_) { + indent(out) << "return $this->_write('" << tstruct->get_name() << "', self::$_TSPEC, $output);" + << endl; + scope_down(out); + out << endl; + return; + } + + indent(out) << "$xfer = 0;" << endl; + + if (!binary_inline_) { + indent(out) << "$xfer += $output->writeStructBegin('" << name << "');" << endl; + } + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + out << indent() << "if ($this->" << (*f_iter)->get_name() << " !== null) {" << endl; + indent_up(); + + t_type* type = get_true_type((*f_iter)->get_type()); + string expect; + if (type->is_container()) { + expect = "array"; + } else if (type->is_struct()) { + expect = "object"; + } + if (!expect.empty()) { + out << indent() << "if (!is_" << expect << "($this->" << (*f_iter)->get_name() << ")) {" + << endl; + indent_up(); + out << indent() << "throw new " + << "TProtocolException('Bad type in structure.', " + << "TProtocolException::INVALID_DATA);" << endl; + scope_down(out); + } + + // Write field header + if (binary_inline_) { + out << indent() << "$output .= pack('c', " << type_to_enum((*f_iter)->get_type()) << ");" + << endl << indent() << "$output .= pack('n', " << (*f_iter)->get_key() << ");" << endl; + } else { + indent(out) << "$xfer += $output->writeFieldBegin(" + << "'" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type()) + << ", " << (*f_iter)->get_key() << ");" << endl; + } + + // Write field contents + generate_serialize_field(out, *f_iter, "this->"); + + // Write field closer + if (!binary_inline_) { + indent(out) << "$xfer += $output->writeFieldEnd();" << endl; + } + + indent_down(); + indent(out) << "}" << endl; + } + + if (binary_inline_) { + out << indent() << "$output .= pack('c', " + << "TType::STOP);" << endl; + } else { + out << indent() << "$xfer += $output->writeFieldStop();" << endl << indent() + << "$xfer += $output->writeStructEnd();" << endl; + } + + out << indent() << "return $xfer;" << endl; + + indent_down(); + out << indent() << "}" << endl << endl; +} + +void t_php_generator::generate_php_struct_read_validator(ofstream& out, t_struct* tstruct) { + generate_php_struct_required_validator(out, tstruct, "_validateForRead", false); +} + +void t_php_generator::generate_php_struct_write_validator(ofstream& out, t_struct* tstruct) { + generate_php_struct_required_validator(out, tstruct, "_validateForWrite", true); +} + +void t_php_generator::generate_php_struct_required_validator(ofstream& out, + t_struct* tstruct, + std::string method_name, + bool write_mode) { + indent(out) << "private function " << method_name << "() {" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + + if (fields.size() > 0) { + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = (*f_iter); + if (field->get_req() == t_field::T_REQUIRED + || (field->get_req() == t_field::T_OPT_IN_REQ_OUT && write_mode)) { + indent(out) << "if ($this->" << field->get_name() << " === null) {" << endl; + indent_up(); + indent(out) << "throw new TProtocolException('Required field " << tstruct->get_name() << "." + << field->get_name() << " is unset!');" << endl; + indent_down(); + indent(out) << "}" << endl; + } + } + } + + indent_down(); + indent(out) << "}" << endl << endl; +} + +void t_php_generator::generate_php_struct_json_serialize(ofstream& out, + t_struct* tstruct, + bool is_result) { + indent(out) << "public function jsonSerialize() {" << endl; + indent_up(); + + if (needs_php_write_validator(tstruct, is_result)) { + indent(out) << "$this->_validateForWrite();" << endl; + } + + indent(out) << "$json = new stdClass;" << endl; + + const vector& fields = tstruct->get_members(); + + if (fields.size() > 0) { + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = (*f_iter); + t_type* type = field->get_type(); + const string& name = field->get_name(); + if (type->is_map()) { + t_type* key_type = ((t_map*)type)->get_key_type(); + if (!(key_type->is_base_type() || key_type->is_enum())) { + // JSON object keys must be strings. PHP's json_encode() + // function will convert any scalar key to strings, but + // we skip thrift maps with non-scalar keys. + continue; + } + } + indent(out) << "if ($this->" << name << " !== null) {" << endl; + indent_up(); + indent(out) << "$json->" << name << " = "; + if (type->is_map()) { + out << "(object)"; + } else { + out << type_to_cast(type); + } + out << "$this->" << name << ";" << endl; + indent_down(); + indent(out) << "}" << endl; + } + } + + indent(out) << "return $json;" << endl; + indent_down(); + + indent(out) << "}" << endl << endl; +} + +int t_php_generator::get_php_num_required_fields(const vector& fields, bool write_mode) { + int num_req = 0; + + if (fields.size() > 0) { + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED + || ((*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT && write_mode)) { + ++num_req; + } + } + } + return num_req; +} + +bool t_php_generator::needs_php_write_validator(t_struct* tstruct, bool is_result) { + return (validate_ && !is_result && !tstruct->is_union() + && get_php_num_required_fields(tstruct->get_members(), true) > 0); +} + +bool t_php_generator::needs_php_read_validator(t_struct* tstruct, bool is_result) { + return (validate_ && !is_result + && (get_php_num_required_fields(tstruct->get_members(), false) > 0)); +} + +/** + * Generates a thrift service. + * + * @param tservice The service definition + */ +void t_php_generator::generate_service(t_service* tservice) { + if(!psr4_) { + string f_service_name = package_dir_ + service_name_ + ".php"; + f_service_.open(f_service_name.c_str()); + generate_service_header(tservice, f_service_); + } + + // Generate the three main parts of the service (well, two for now in PHP) + generate_service_interface(tservice); + if (rest_) { + generate_service_rest(tservice); + } + generate_service_client(tservice); + generate_service_helpers(tservice); + if (phps_) { + generate_service_processor(tservice); + } + + if(!psr4_) { + // Close service file + f_service_ << endl; + f_service_.close(); + } +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_php_generator::generate_service_processor(t_service* tservice) { + std::ofstream& f_service_processor = f_service_; + if (psr4_) { + string f_service_processor_name = package_dir_ + service_name_ + "Processor.php"; + f_service_processor.open(f_service_processor_name.c_str()); + generate_service_header(tservice, f_service_processor); + } + + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() != NULL) { + extends = tservice->get_extends()->get_name(); + extends_processor = " extends " + php_namespace(tservice->get_extends()->get_program()) + + extends + "Processor"; + } + + // Generate the header portion + f_service_processor << "class " << service_name_ << "Processor" << extends_processor << " {" << endl; + indent_up(); + + if (extends.empty()) { + f_service_processor << indent() << "protected $handler_ = null;" << endl; + } + + f_service_processor << indent() << "public function __construct($handler) {" << endl; + if (extends.empty()) { + f_service_processor << indent() << " $this->handler_ = $handler;" << endl; + } else { + f_service_processor << indent() << " parent::__construct($handler);" << endl; + } + f_service_processor << indent() << "}" << endl << endl; + + // Generate the server implementation + indent(f_service_processor) << "public function process($input, $output) {" << endl; + indent_up(); + + f_service_processor << indent() << "$rseqid = 0;" << endl << indent() << "$fname = null;" << endl + << indent() << "$mtype = 0;" << endl << endl; + + if (binary_inline_) { + t_field ffname(g_type_string, "fname"); + t_field fmtype(g_type_i8, "mtype"); + t_field fseqid(g_type_i32, "rseqid"); + generate_deserialize_field(f_service_processor, &ffname, "", true); + generate_deserialize_field(f_service_processor, &fmtype, "", true); + generate_deserialize_field(f_service_processor, &fseqid, "", true); + } else { + f_service_processor << indent() << "$input->readMessageBegin($fname, $mtype, $rseqid);" << endl; + } + + // HOT: check for method implementation + f_service_processor << indent() << "$methodname = 'process_'.$fname;" << endl << indent() + << "if (!method_exists($this, $methodname)) {" << endl; + if (binary_inline_) { + f_service_processor << indent() << " throw new \\Exception('Function '.$fname.' not implemented.');" + << endl; + } else { + f_service_processor << indent() << " $input->skip(" + << "TType::STRUCT);" << endl << indent() << " $input->readMessageEnd();" << endl + << indent() << " $x = new " + << "TApplicationException('Function '.$fname.' not implemented.', " + << "TApplicationException::UNKNOWN_METHOD);" << endl << indent() + << " $output->writeMessageBegin($fname, " + << "TMessageType::EXCEPTION, $rseqid);" << endl << indent() + << " $x->write($output);" << endl << indent() << " $output->writeMessageEnd();" + << endl << indent() << " $output->getTransport()->flush();" << endl << indent() + << " return;" << endl; + } + f_service_processor << indent() << "}" << endl << indent() + << "$this->$methodname($rseqid, $input, $output);" << endl << indent() + << "return true;" << endl; + indent_down(); + f_service_processor << indent() << "}" << endl << endl; + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(f_service_processor, tservice, *f_iter); + } + + indent_down(); + f_service_processor << "}" << endl; + + if (psr4_) { + f_service_processor.close(); + } +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_php_generator::generate_process_function(std::ofstream& out, t_service* tservice, t_function* tfunction) { + // Open function + indent(out) << "protected function process_" << tfunction->get_name() + << "($seqid, $input, $output) {" << endl; + indent_up(); + + string argsname = php_namespace(tservice->get_program()) + service_name_ + "_" + + tfunction->get_name() + "_args"; + string resultname = php_namespace(tservice->get_program()) + service_name_ + "_" + + tfunction->get_name() + "_result"; + + out << indent() << "$bin_accel = ($input instanceof " + << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_read_binary_after_message_begin');" + << endl; + out << indent() << "if ($bin_accel)" << endl; + scope_up(out); + + out << indent() << "$args = thrift_protocol_read_binary_after_message_begin($input, '" << argsname + << "', $input->isStrictRead());" << endl; + + scope_down(out); + out << indent() << "else" << endl; + scope_up(out); + out << indent() << "$args = new " << argsname << "();" << endl << indent() + << "$args->read($input);" << endl; + if (!binary_inline_) { + out << indent() << "$input->readMessageEnd();" << endl; + } + scope_down(out); + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + // Declare result for non oneway function + if (!tfunction->is_oneway()) { + out << indent() << "$result = new " << resultname << "();" << endl; + } + + // Try block for a function with exceptions + if (xceptions.size() > 0) { + out << indent() << "try {" << endl; + indent_up(); + } + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + out << indent(); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + out << "$result->success = "; + } + out << "$this->handler_->" << tfunction->get_name() << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + out << ", "; + } + out << "$args->" << (*f_iter)->get_name(); + } + out << ");" << endl; + + if (!tfunction->is_oneway() && xceptions.size() > 0) { + indent_down(); + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + out << indent() << "} catch (" + << php_namespace(get_true_type((*x_iter)->get_type())->get_program()) + << (*x_iter)->get_type()->get_name() << " $" << (*x_iter)->get_name() << ") {" + << endl; + if (!tfunction->is_oneway()) { + indent_up(); + out << indent() << "$result->" << (*x_iter)->get_name() << " = $" + << (*x_iter)->get_name() << ";" << endl; + indent_down(); + out << indent(); + } + } + out << "}" << endl; + } + + // Shortcut out here for oneway functions + if (tfunction->is_oneway()) { + out << indent() << "return;" << endl; + indent_down(); + out << indent() << "}" << endl; + return; + } + + out << indent() << "$bin_accel = ($output instanceof " + << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');" + << endl; + + out << indent() << "if ($bin_accel)" << endl; + scope_up(out); + + out << indent() << "thrift_protocol_write_binary($output, '" << tfunction->get_name() + << "', " + << "TMessageType::REPLY, $result, $seqid, $output->isStrictWrite());" << endl; + + scope_down(out); + out << indent() << "else" << endl; + scope_up(out); + + // Serialize the request header + if (binary_inline_) { + out << indent() << "$buff = pack('N', (0x80010000 | " + << "TMessageType::REPLY)); " << endl << indent() << "$buff .= pack('N', strlen('" + << tfunction->get_name() << "'));" << endl << indent() << "$buff .= '" + << tfunction->get_name() << "';" << endl << indent() << "$buff .= pack('N', $seqid);" + << endl << indent() << "$result->write($buff);" << endl << indent() + << "$output->write($buff);" << endl << indent() << "$output->flush();" << endl; + } else { + out << indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', " + << "TMessageType::REPLY, $seqid);" << endl << indent() << "$result->write($output);" + << endl << indent() << "$output->writeMessageEnd();" << endl << indent() + << "$output->getTransport()->flush();" << endl; + } + + scope_down(out); + + // Close function + indent_down(); + out << indent() << "}" << endl; +} + +/** + * Generates helper functions for a service. + * + * @param tservice The service to generate a header definition for + */ +void t_php_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + std::ofstream& f_struct_definition = f_service_; + if (!psr4_) { + f_struct_definition << "// HELPER FUNCTIONS AND STRUCTURES" << endl << endl; + } + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + string name = ts->get_name(); + ts->set_name(service_name_ + "_" + name); + + if (psr4_) { + string f_struct_definition_name = package_dir_ + service_name_ + "_" + name + ".php"; + f_struct_definition.open(f_struct_definition_name.c_str()); + generate_service_header(tservice, f_struct_definition); + } + + generate_php_struct_definition(f_struct_definition, ts); + if (psr4_) { + f_struct_definition.close(); + } + + generate_php_function_helpers(tservice, *f_iter); + ts->set_name(name); + } +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_php_generator::generate_php_function_helpers(t_service* tservice, t_function* tfunction) { + if (!tfunction->is_oneway()) { + t_struct result(program_, service_name_ + "_" + tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + std::ofstream& f_struct_helper = f_service_; + if (psr4_) { + string f_struct_helper_name = package_dir_ + result.get_name() + ".php"; + f_struct_helper.open(f_struct_helper_name.c_str()); + generate_service_header(tservice, f_struct_helper); + } + generate_php_struct_definition(f_struct_helper, &result, false, true); + if (psr4_) { + f_struct_helper.close(); + } + } +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_php_generator::generate_service_interface(t_service* tservice) { + std::ofstream& f_service_interface = f_service_; + if (psr4_) { + string f_service_interface_name = package_dir_ + service_name_ + "If.php"; + f_service_interface.open(f_service_interface_name.c_str()); + generate_service_header(tservice, f_service_interface); + } + + string extends = ""; + string extends_if = ""; + if (tservice->get_extends() != NULL) { + extends = " extends " + php_namespace(tservice->get_extends()->get_program()) + + tservice->get_extends()->get_name(); + extends_if = " extends " + php_namespace(tservice->get_extends()->get_program()) + + tservice->get_extends()->get_name() + "If"; + } + generate_php_doc(f_service_interface, tservice); + f_service_interface << "interface " << php_namespace_declaration(tservice) << "If" << extends_if << " {" + << endl; + indent_up(); + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_php_doc(f_service_interface, *f_iter); + indent(f_service_interface) << "public function " << function_signature(*f_iter) << ";" << endl; + } + indent_down(); + f_service_interface << "}" << endl << endl; + + // Close service interface file + f_service_interface << endl; + if (psr4_) { + f_service_interface.close(); + } +} + +/** + * Generates a REST interface + */ +void t_php_generator::generate_service_rest(t_service* tservice) { + std::ofstream& f_service_rest = f_service_; + if (psr4_) { + string f_service_rest_name = package_dir_ + service_name_ + "Rest.php"; + f_service_rest.open(f_service_rest_name.c_str()); + generate_service_header(tservice, f_service_rest); + } + + string extends = ""; + string extends_if = ""; + if (tservice->get_extends() != NULL) { + extends = " extends " + php_namespace(tservice->get_extends()->get_program()) + + tservice->get_extends()->get_name(); + extends_if = " extends " + php_namespace(tservice->get_extends()->get_program()) + + tservice->get_extends()->get_name() + "Rest"; + } + f_service_rest << "class " << service_name_ << "Rest" << extends_if << " {" << endl; + indent_up(); + + if (extends.empty()) { + f_service_rest << indent() << "protected $impl_;" << endl << endl; + } + + f_service_rest << indent() << "public function __construct($impl) {" << endl << indent() + << " $this->impl_ = $impl;" << endl << indent() << "}" << endl << endl; + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + indent(f_service_rest) << "public function " << (*f_iter)->get_name() << "($request) {" << endl; + indent_up(); + const vector& args = (*f_iter)->get_arglist()->get_members(); + vector::const_iterator a_iter; + for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) { + t_type* atype = get_true_type((*a_iter)->get_type()); + string cast = type_to_cast(atype); + string req = "$request['" + (*a_iter)->get_name() + "']"; + if (atype->is_bool()) { + f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = " << cast << "(!empty(" << req + << ") && (" << req << " !== 'false'));" << endl; + } else { + f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = isset(" << req << ") ? " + << cast << req << " : null;" << endl; + } + if (atype->is_string() && ((t_base_type*)atype)->is_string_list()) { + f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = explode(',', $" + << (*a_iter)->get_name() << ");" << endl; + } else if (atype->is_map() || atype->is_list()) { + f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = json_decode($" + << (*a_iter)->get_name() << ", true);" << endl; + } else if (atype->is_set()) { + f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = array_fill_keys(json_decode($" + << (*a_iter)->get_name() << ", true), 1);" << endl; + } else if (atype->is_struct() || atype->is_xception()) { + f_service_rest << indent() << "if ($" << (*a_iter)->get_name() << " !== null) {" << endl + << indent() << " $" << (*a_iter)->get_name() << " = new " + << php_namespace(atype->get_program()) << atype->get_name() << "(json_decode($" + << (*a_iter)->get_name() << ", true));" << endl << indent() << "}" << endl; + } + } + f_service_rest << indent() << "return $this->impl_->" << (*f_iter)->get_name() << "(" + << argument_list((*f_iter)->get_arglist(), false) << ");" << endl; + indent_down(); + indent(f_service_rest) << "}" << endl << endl; + } + indent_down(); + f_service_rest << "}" << endl << endl; + + // Close service rest file + f_service_rest << endl; + if (psr4_) { + f_service_rest.close(); + } +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_php_generator::generate_service_client(t_service* tservice) { + std::ofstream& f_service_client = f_service_; + if (psr4_) { + string f_service_client_name = package_dir_ + service_name_ + "Client.php"; + f_service_client.open(f_service_client_name.c_str()); + generate_service_header(tservice, f_service_client); + } + + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() != NULL) { + extends = tservice->get_extends()->get_name(); + extends_client = " extends " + php_namespace(tservice->get_extends()->get_program()) + extends + + "Client"; + } + + f_service_client << "class " << php_namespace_declaration(tservice) << "Client" << extends_client + << " implements " << php_namespace(tservice->get_program()) << service_name_ << "If {" + << endl; + indent_up(); + + // Private members + if (extends.empty()) { + f_service_client << indent() << "protected $input_ = null;" << endl << indent() + << "protected $output_ = null;" << endl << endl; + f_service_client << indent() << "protected $seqid_ = 0;" << endl << endl; + } + + // Constructor function + f_service_client << indent() << "public function __construct($input, $output=null) {" << endl; + if (!extends.empty()) { + f_service_client << indent() << " parent::__construct($input, $output);" << endl; + } else { + f_service_client << indent() << " $this->input_ = $input;" << endl << indent() + << " $this->output_ = $output ? $output : $input;" << endl; + } + f_service_client << indent() << "}" << endl << endl; + + // Generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* arg_struct = (*f_iter)->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + string funname = (*f_iter)->get_name(); + + // Open function + indent(f_service_client) << "public function " << function_signature(*f_iter) << endl; + scope_up(f_service_client); + indent(f_service_client) << "$this->send_" << funname << "("; + + bool first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + if (first) { + first = false; + } else { + f_service_client << ", "; + } + f_service_client << "$" << (*fld_iter)->get_name(); + } + f_service_client << ");" << endl; + + if (!(*f_iter)->is_oneway()) { + f_service_client << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_client << "return "; + } + f_service_client << "$this->recv_" << funname << "();" << endl; + } + scope_down(f_service_client); + f_service_client << endl; + + indent(f_service_client) << "public function send_" << function_signature(*f_iter) << endl; + scope_up(f_service_client); + + std::string argsname = php_namespace(tservice->get_program()) + service_name_ + "_" + + (*f_iter)->get_name() + "_args"; + + f_service_client << indent() << "$args = new " << argsname << "();" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_client << indent() << "$args->" << (*fld_iter)->get_name() << " = $" + << (*fld_iter)->get_name() << ";" << endl; + } + + f_service_client << indent() << "$bin_accel = ($this->output_ instanceof " + << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');" + << endl; + + f_service_client << indent() << "if ($bin_accel)" << endl; + scope_up(f_service_client); + + string messageType = (*f_iter)->is_oneway() ? "TMessageType::ONEWAY" : "TMessageType::CALL"; + + f_service_client << indent() << "thrift_protocol_write_binary($this->output_, '" + << (*f_iter)->get_name() << "', " << messageType + << ", $args, $this->seqid_, $this->output_->isStrictWrite());" << endl; + + scope_down(f_service_client); + f_service_client << indent() << "else" << endl; + scope_up(f_service_client); + + // Serialize the request header + if (binary_inline_) { + f_service_client << indent() << "$buff = pack('N', (0x80010000 | " << messageType << "));" << endl + << indent() << "$buff .= pack('N', strlen('" << funname << "'));" << endl + << indent() << "$buff .= '" << funname << "';" << endl << indent() + << "$buff .= pack('N', $this->seqid_);" << endl; + } else { + f_service_client << indent() << "$this->output_->writeMessageBegin('" << (*f_iter)->get_name() + << "', " << messageType << ", $this->seqid_);" << endl; + } + + // Write to the stream + if (binary_inline_) { + f_service_client << indent() << "$args->write($buff);" << endl << indent() + << "$this->output_->write($buff);" << endl << indent() + << "$this->output_->flush();" << endl; + } else { + f_service_client << indent() << "$args->write($this->output_);" << endl << indent() + << "$this->output_->writeMessageEnd();" << endl << indent() + << "$this->output_->getTransport()->flush();" << endl; + } + + scope_down(f_service_client); + + scope_down(f_service_client); + + if (!(*f_iter)->is_oneway()) { + std::string resultname = php_namespace(tservice->get_program()) + service_name_ + "_" + + (*f_iter)->get_name() + "_result"; + t_struct noargs(program_); + + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + &noargs); + // Open function + f_service_client << endl << indent() << "public function " << function_signature(&recv_function) + << endl; + scope_up(f_service_client); + + f_service_client << indent() << "$bin_accel = ($this->input_ instanceof " + << "TBinaryProtocolAccelerated)" + << " && function_exists('thrift_protocol_read_binary');" << endl; + + f_service_client << indent() + << "if ($bin_accel) $result = thrift_protocol_read_binary($this->input_, '" + << resultname << "', $this->input_->isStrictRead());" << endl; + f_service_client << indent() << "else" << endl; + scope_up(f_service_client); + + f_service_client << indent() << "$rseqid = 0;" << endl << indent() << "$fname = null;" << endl + << indent() << "$mtype = 0;" << endl << endl; + + if (binary_inline_) { + t_field ffname(g_type_string, "fname"); + t_field fseqid(g_type_i32, "rseqid"); + f_service_client << indent() << "$ver = unpack('N', $this->input_->readAll(4));" << endl + << indent() << "$ver = $ver[1];" << endl << indent() << "$mtype = $ver & 0xff;" + << endl << indent() << "$ver = $ver & 0xffff0000;" << endl << indent() + << "if ($ver != 0x80010000) throw new " + << "TProtocolException('Bad version identifier: '.$ver, " + << "TProtocolException::BAD_VERSION);" << endl; + generate_deserialize_field(f_service_client, &ffname, "", true); + generate_deserialize_field(f_service_client, &fseqid, "", true); + } else { + f_service_client << indent() << "$this->input_->readMessageBegin($fname, $mtype, $rseqid);" + << endl << indent() << "if ($mtype == " + << "TMessageType::EXCEPTION) {" << endl << indent() << " $x = new " + << "TApplicationException();" << endl << indent() << " $x->read($this->input_);" + << endl << indent() << " $this->input_->readMessageEnd();" << endl << indent() + << " throw $x;" << endl << indent() << "}" << endl; + } + + f_service_client << indent() << "$result = new " << resultname << "();" << endl << indent() + << "$result->read($this->input_);" << endl; + + if (!binary_inline_) { + f_service_client << indent() << "$this->input_->readMessageEnd();" << endl; + } + + scope_down(f_service_client); + + // Careful, only return result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_client << indent() << "if ($result->success !== null) {" << endl << indent() + << " return $result->success;" << endl << indent() << "}" << endl; + } + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_client << indent() << "if ($result->" << (*x_iter)->get_name() << " !== null) {" << endl + << indent() << " throw $result->" << (*x_iter)->get_name() << ";" << endl + << indent() << "}" << endl; + } + + // Careful, only return _result if not a void function + if ((*f_iter)->get_returntype()->is_void()) { + indent(f_service_client) << "return;" << endl; + } else { + f_service_client << indent() << "throw new \\Exception(\"" << (*f_iter)->get_name() + << " failed: unknown result\");" << endl; + } + + // Close function + scope_down(f_service_client); + f_service_client << endl; + } + } + + indent_down(); + f_service_client << "}" << endl << endl; + + // Close service client file + f_service_client << endl; + if (psr4_) { + f_service_client.close(); + } +} + +/** + * Deserializes a field of any type. + */ +void t_php_generator::generate_deserialize_field(ofstream& out, + t_field* tfield, + string prefix, + bool inclass) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = prefix + tfield->get_name(); + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name); + } else { + + if (type->is_container()) { + generate_deserialize_container(out, type, name); + } else if (type->is_base_type() || type->is_enum()) { + + if (binary_inline_) { + std::string itrans = (inclass ? "$this->input_" : "$input"); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + out << indent() << "$len = unpack('N', " << itrans << "->readAll(4));" << endl + << indent() << "$len = $len[1];" << endl << indent() << "if ($len > 0x7fffffff) {" + << endl << indent() << " $len = 0 - (($len - 1) ^ 0xffffffff);" << endl << indent() + << "}" << endl << indent() << "$" << name << " = " << itrans << "->readAll($len);" + << endl; + break; + case t_base_type::TYPE_BOOL: + out << indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" + << endl << indent() << "$" << name << " = (bool)$" << name << "[1];" << endl; + break; + case t_base_type::TYPE_I8: + out << indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" + << endl << indent() << "$" << name << " = $" << name << "[1];" << endl; + break; + case t_base_type::TYPE_I16: + out << indent() << "$val = unpack('n', " << itrans << "->readAll(2));" << endl + << indent() << "$val = $val[1];" << endl << indent() << "if ($val > 0x7fff) {" + << endl << indent() << " $val = 0 - (($val - 1) ^ 0xffff);" << endl << indent() + << "}" << endl << indent() << "$" << name << " = $val;" << endl; + break; + case t_base_type::TYPE_I32: + out << indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl + << indent() << "$val = $val[1];" << endl << indent() << "if ($val > 0x7fffffff) {" + << endl << indent() << " $val = 0 - (($val - 1) ^ 0xffffffff);" << endl << indent() + << "}" << endl << indent() << "$" << name << " = $val;" << endl; + break; + case t_base_type::TYPE_I64: + out << indent() << "$arr = unpack('N2', " << itrans << "->readAll(8));" << endl + << indent() << "if ($arr[1] & 0x80000000) {" << endl << indent() + << " $arr[1] = $arr[1] ^ 0xFFFFFFFF;" << endl << indent() + << " $arr[2] = $arr[2] ^ 0xFFFFFFFF;" << endl << indent() << " $" << name + << " = 0 - $arr[1]*4294967296 - $arr[2] - 1;" << endl << indent() << "} else {" + << endl << indent() << " $" << name << " = $arr[1]*4294967296 + $arr[2];" << endl + << indent() << "}" << endl; + break; + case t_base_type::TYPE_DOUBLE: + out << indent() << "$arr = unpack('d', strrev(" << itrans << "->readAll(8)));" << endl + << indent() << "$" << name << " = $arr[1];" << endl; + break; + default: + throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase) + + tfield->get_name(); + } + } else if (type->is_enum()) { + out << indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl << indent() + << "$val = $val[1];" << endl << indent() << "if ($val > 0x7fffffff) {" << endl + << indent() << " $val = 0 - (($val - 1) ^ 0xffffffff);" << endl << indent() << "}" + << endl << indent() << "$" << name << " = $val;" << endl; + } + } else { + + indent(out) << "$xfer += $input->"; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + out << "readString($" << name << ");"; + break; + case t_base_type::TYPE_BOOL: + out << "readBool($" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "readByte($" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "readI16($" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "readI32($" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "readI64($" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble($" << name << ");"; + break; + default: + throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "readI32($" << name << ");"; + } + out << endl; + } + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type->get_name().c_str()); + } + } +} + +/** + * Generates an unserializer for a variable. This makes two key assumptions, + * first that there is a const char* variable named data that points to the + * buffer for deserialization, and that there is a variable protocol which + * is a reference to a TProtocol serialization object. + */ +void t_php_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + out << indent() << "$" << prefix << " = new " << php_namespace(tstruct->get_program()) + << tstruct->get_name() << "();" << endl << indent() << "$xfer += $" << prefix + << "->read($input);" << endl; +} + +void t_php_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) { + string size = tmp("_size"); + string ktype = tmp("_ktype"); + string vtype = tmp("_vtype"); + string etype = tmp("_etype"); + + t_field fsize(g_type_i32, size); + t_field fktype(g_type_i8, ktype); + t_field fvtype(g_type_i8, vtype); + t_field fetype(g_type_i8, etype); + + out << indent() << "$" << prefix << " = array();" << endl << indent() << "$" << size << " = 0;" + << endl; + + // Declare variables, read header + if (ttype->is_map()) { + out << indent() << "$" << ktype << " = 0;" << endl << indent() << "$" << vtype << " = 0;" + << endl; + if (binary_inline_) { + generate_deserialize_field(out, &fktype); + generate_deserialize_field(out, &fvtype); + generate_deserialize_field(out, &fsize); + } else { + out << indent() << "$xfer += $input->readMapBegin(" + << "$" << ktype << ", $" << vtype << ", $" << size << ");" << endl; + } + } else if (ttype->is_set()) { + if (binary_inline_) { + generate_deserialize_field(out, &fetype); + generate_deserialize_field(out, &fsize); + } else { + out << indent() << "$" << etype << " = 0;" << endl << indent() + << "$xfer += $input->readSetBegin(" + << "$" << etype << ", $" << size << ");" << endl; + } + } else if (ttype->is_list()) { + if (binary_inline_) { + generate_deserialize_field(out, &fetype); + generate_deserialize_field(out, &fsize); + } else { + out << indent() << "$" << etype << " = 0;" << endl << indent() + << "$xfer += $input->readListBegin(" + << "$" << etype << ", $" << size << ");" << endl; + } + } + + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << "for ($" << i << " = 0; $" << i << " < $" << size << "; ++$" << i << ")" << endl; + + scope_up(out); + + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, prefix); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, prefix); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, prefix); + } + + scope_down(out); + + if (!binary_inline_) { + // Read container end + if (ttype->is_map()) { + indent(out) << "$xfer += $input->readMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "$xfer += $input->readSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "$xfer += $input->readListEnd();" << endl; + } + } +} + +/** + * Generates code to deserialize a map + */ +void t_php_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) { + string key = tmp("key"); + string val = tmp("val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + indent(out) << declare_field(&fkey, true, true) << endl; + indent(out) << declare_field(&fval, true, true) << endl; + + generate_deserialize_field(out, &fkey); + generate_deserialize_field(out, &fval); + + indent(out) << "$" << prefix << "[$" << key << "] = $" << val << ";" << endl; +} + +void t_php_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) { + string elem = tmp("elem"); + t_field felem(tset->get_elem_type(), elem); + + indent(out) << "$" << elem << " = null;" << endl; + + generate_deserialize_field(out, &felem); + + t_type* elem_type = tset->get_elem_type(); + if(php_is_scalar(elem_type)) { + indent(out) << "$" << prefix << "[$" << elem << "] = true;" << endl; + } else { + indent(out) << "$" << prefix << "[] = $" << elem << ";" << endl; + } +} + +void t_php_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix) { + string elem = tmp("elem"); + t_field felem(tlist->get_elem_type(), elem); + + indent(out) << "$" << elem << " = null;" << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << "$" << prefix << " []= $" << elem << ";" << endl; +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_php_generator::generate_serialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = get_true_type(tfield->get_type()); + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); + } else if (type->is_container()) { + generate_serialize_container(out, type, prefix + tfield->get_name()); + } else if (type->is_base_type() || type->is_enum()) { + + string name = prefix + tfield->get_name(); + + if (binary_inline_) { + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + out << indent() << "$output .= pack('N', strlen($" << name << "));" << endl << indent() + << "$output .= $" << name << ";" << endl; + break; + case t_base_type::TYPE_BOOL: + out << indent() << "$output .= pack('c', $" << name << " ? 1 : 0);" << endl; + break; + case t_base_type::TYPE_I8: + out << indent() << "$output .= pack('c', $" << name << ");" << endl; + break; + case t_base_type::TYPE_I16: + out << indent() << "$output .= pack('n', $" << name << ");" << endl; + break; + case t_base_type::TYPE_I32: + out << indent() << "$output .= pack('N', $" << name << ");" << endl; + break; + case t_base_type::TYPE_I64: + out << indent() << "$output .= pack('N2', $" << name << " >> 32, $" << name + << " & 0xFFFFFFFF);" << endl; + break; + case t_base_type::TYPE_DOUBLE: + out << indent() << "$output .= strrev(pack('d', $" << name << "));" << endl; + break; + default: + throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << indent() << "$output .= pack('N', $" << name << ");" << endl; + } + } else { + + indent(out) << "$xfer += $output->"; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + out << "writeString($" << name << ");"; + break; + case t_base_type::TYPE_BOOL: + out << "writeBool($" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "writeByte($" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "writeI16($" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "writeI32($" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "writeI64($" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble($" << name << ");"; + break; + default: + throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "writeI32($" << name << ");"; + } + out << endl; + } + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", + prefix.c_str(), + tfield->get_name().c_str(), + type->get_name().c_str()); + } +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_php_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + (void)tstruct; + indent(out) << "$xfer += $" << prefix << "->write($output);" << endl; +} + +/** + * Writes out a container + */ +void t_php_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + scope_up(out); + + if (ttype->is_map()) { + if (binary_inline_) { + out << indent() << "$output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_key_type()) + << ");" << endl << indent() << "$output .= pack('c', " + << type_to_enum(((t_map*)ttype)->get_val_type()) << ");" << endl << indent() + << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl; + } else { + indent(out) << "$output->writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) + << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " + << "count($" << prefix << "));" << endl; + } + } else if (ttype->is_set()) { + if (binary_inline_) { + out << indent() << "$output .= pack('c', " << type_to_enum(((t_set*)ttype)->get_elem_type()) + << ");" << endl << indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" + << endl; + + } else { + indent(out) << "$output->writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) + << ", " + << "count($" << prefix << "));" << endl; + } + } else if (ttype->is_list()) { + if (binary_inline_) { + out << indent() << "$output .= pack('c', " << type_to_enum(((t_list*)ttype)->get_elem_type()) + << ");" << endl << indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" + << endl; + + } else { + indent(out) << "$output->writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) + << ", " + << "count($" << prefix << "));" << endl; + } + } + + scope_up(out); + + if (ttype->is_map()) { + string kiter = tmp("kiter"); + string viter = tmp("viter"); + indent(out) << "foreach ($" << prefix << " as " + << "$" << kiter << " => $" << viter << ")" << endl; + scope_up(out); + generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); + scope_down(out); + } else if (ttype->is_set()) { + string iter = tmp("iter"); + string iter_val = tmp("iter"); + indent(out) << "foreach ($" << prefix << " as $" << iter << " => $" << iter_val << ")" << endl; + scope_up(out); + + t_type* elem_type = ((t_set*)ttype)->get_elem_type(); + if(php_is_scalar(elem_type)) { + generate_serialize_set_element(out, (t_set*)ttype, iter); + } else { + generate_serialize_set_element(out, (t_set*)ttype, iter_val); + } + scope_down(out); + } else if (ttype->is_list()) { + string iter = tmp("iter"); + indent(out) << "foreach ($" << prefix << " as $" << iter << ")" << endl; + scope_up(out); + generate_serialize_list_element(out, (t_list*)ttype, iter); + scope_down(out); + } + + scope_down(out); + + if (!binary_inline_) { + if (ttype->is_map()) { + indent(out) << "$output->writeMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "$output->writeSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "$output->writeListEnd();" << endl; + } + } + + scope_down(out); +} + +/** + * Serializes the members of a map. + * + */ +void t_php_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string kiter, + string viter) { + t_field kfield(tmap->get_key_type(), kiter); + generate_serialize_field(out, &kfield, ""); + + t_field vfield(tmap->get_val_type(), viter); + generate_serialize_field(out, &vfield, ""); +} + +/** + * Serializes the members of a set. + */ +void t_php_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) { + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +/** + * Serializes the members of a list. + */ +void t_php_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) { + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +/** + * Emits a PHPDoc comment for the given contents + */ +void t_php_generator::generate_php_docstring_comment(ofstream& out, string contents) { + generate_docstring_comment(out, "/**\n", " * ", contents, " */\n"); +} + +/** + * Emits a PHPDoc comment if the provided object has a doc in Thrift + */ +void t_php_generator::generate_php_doc(ofstream& out, t_doc* tdoc) { + if (tdoc->has_doc()) { + generate_php_docstring_comment(out, tdoc->get_doc()); + } +} + +/** + * Emits a PHPDoc comment for a field + */ +void t_php_generator::generate_php_doc(ofstream& out, t_field* field) { + stringstream ss; + + // prepend free-style doc if available + if (field->has_doc()) { + ss << field->get_doc() << endl; + } + + // append @var tag + t_type* type = get_true_type(field->get_type()); + ss << "@var " << type_to_phpdoc(type) << endl; + + generate_php_docstring_comment(out, ss.str()); +} + +/** + * Emits a PHPDoc comment for a function + */ +void t_php_generator::generate_php_doc(ofstream& out, t_function* function) { + stringstream ss; + if (function->has_doc()) { + ss << function->get_doc() << endl; + } + + // generate parameter types doc + const vector& args = function->get_arglist()->get_members(); + vector::const_iterator a_iter; + for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) { + t_field* arg = *a_iter; + ss << "@param " << type_to_phpdoc(arg->get_type()) << " $" << arg->get_name(); + if (arg->has_doc()) { + ss << " " << arg->get_doc(); + } + ss << endl; + } + + // generate return type doc + t_type* ret_type = function->get_returntype(); + if (!ret_type->is_void() || ret_type->has_doc()) { + ss << "@return " << type_to_phpdoc(ret_type); + if (ret_type->has_doc()) { + ss << " " << ret_type->get_doc(); + } + ss << endl; + } + + // generate exceptions doc + const vector& excs = function->get_xceptions()->get_members(); + vector::const_iterator e_iter; + for (e_iter = excs.begin(); e_iter != excs.end(); ++e_iter) { + t_field* exc = *e_iter; + ss << "@throws " << type_to_phpdoc(exc->get_type()); + if (exc->has_doc()) { + ss << " " << exc->get_doc(); + } + ss << endl; + } + + generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n"); +} + +/** + * Declares a field, which may include initialization as necessary. + * + * @param ttype The type + */ +string t_php_generator::declare_field(t_field* tfield, bool init, bool obj) { + string result = "$" + tfield->get_name(); + if (init) { + t_type* type = get_true_type(tfield->get_type()); + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + break; + case t_base_type::TYPE_STRING: + result += " = ''"; + break; + case t_base_type::TYPE_BOOL: + result += " = false"; + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + result += " = 0"; + break; + case t_base_type::TYPE_DOUBLE: + result += " = 0.0"; + break; + default: + throw "compiler error: no PHP initializer for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + result += " = 0"; + } else if (type->is_container()) { + result += " = array()"; + } else if (type->is_struct() || type->is_xception()) { + if (obj) { + result += " = new " + php_namespace(type->get_program()) + type->get_name() + "()"; + } else { + result += " = null"; + } + } + } + return result + ";"; +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_php_generator::function_signature(t_function* tfunction, string prefix) { + return prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")"; +} + +/** + * Renders a field list + */ +string t_php_generator::argument_list(t_struct* tstruct, bool addTypeHints) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + + t_type* type = (*f_iter)->get_type(); + + // Set type name + if (addTypeHints) { + if (type->is_struct()) { + string className = php_namespace(type->get_program()) + + php_namespace_directory("Definition", false) + + classify(type->get_name()); + + result += className + " "; + } else if (type->is_container()) { + result += "array "; + } + } + + result += "$" + (*f_iter)->get_name(); + } + return result; +} + +/** + * Gets a typecast string for a particular type. + */ +string t_php_generator::type_to_cast(t_type* type) { + if (type->is_base_type()) { + t_base_type* btype = (t_base_type*)type; + switch (btype->get_base()) { + case t_base_type::TYPE_BOOL: + return "(bool)"; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + return "(int)"; + case t_base_type::TYPE_DOUBLE: + return "(double)"; + case t_base_type::TYPE_STRING: + return "(string)"; + default: + return ""; + } + } else if (type->is_enum()) { + return "(int)"; + } + return ""; +} + +/** + * Converts the parse type to a C++ enum string for the given type. + */ +string t_php_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "TType::STRING"; + case t_base_type::TYPE_BOOL: + return "TType::BOOL"; + case t_base_type::TYPE_I8: + return "TType::BYTE"; + case t_base_type::TYPE_I16: + return "TType::I16"; + case t_base_type::TYPE_I32: + return "TType::I32"; + case t_base_type::TYPE_I64: + return "TType::I64"; + case t_base_type::TYPE_DOUBLE: + return "TType::DOUBLE"; + } + } else if (type->is_enum()) { + return "TType::I32"; + } else if (type->is_struct() || type->is_xception()) { + return "TType::STRUCT"; + } else if (type->is_map()) { + return "TType::MAP"; + } else if (type->is_set()) { + return "TType::SET"; + } else if (type->is_list()) { + return "TType::LST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** + * Converts the parse type to a PHPDoc string for the given type. + */ +string t_php_generator::type_to_phpdoc(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + return "void"; + case t_base_type::TYPE_STRING: + return "string"; + case t_base_type::TYPE_BOOL: + return "bool"; + case t_base_type::TYPE_I8: + return "int"; + case t_base_type::TYPE_I16: + return "int"; + case t_base_type::TYPE_I32: + return "int"; + case t_base_type::TYPE_I64: + return "int"; + case t_base_type::TYPE_DOUBLE: + return "double"; + } + } else if (type->is_enum()) { + return "int"; + } else if (type->is_struct() || type->is_xception()) { + return php_namespace(type->get_program()) + type->get_name(); + } else if (type->is_map()) { + return "array"; + } else if (type->is_set()) { + t_set* tset = static_cast(type); + t_type* t_elem = tset->get_elem_type(); + if (t_elem->is_container()) { + return "(" + type_to_phpdoc(t_elem) + ")[]"; + } else { + return type_to_phpdoc(t_elem) + "[]"; + } + } else if (type->is_list()) { + t_list* tlist = static_cast(type); + t_type* t_elem = tlist->get_elem_type(); + if (t_elem->is_container()) { + return "(" + type_to_phpdoc(t_elem) + ")[]"; + } else { + return type_to_phpdoc(t_elem) + "[]"; + } + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +THRIFT_REGISTER_GENERATOR( + php, + "PHP", + " inlined: Generate PHP inlined files\n" + " server: Generate PHP server stubs\n" + " oop: Generate PHP with object oriented subclasses\n" + " psr4: Generate each PHP class in separate file (allows PSR4 autoloading)\n" + " rest: Generate PHP REST processors\n" + " nsglobal=NAME: Set global namespace\n" + " validate: Generate PHP validator methods\n" + " json: Generate JsonSerializable classes (requires PHP >= 5.4)\n") diff --git a/compiler/cpp/src/thrift/generate/t_py_generator.cc b/compiler/cpp/src/thrift/generate/t_py_generator.cc new file mode 100644 index 0000000..9078da8 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_py_generator.cc @@ -0,0 +1,2743 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "thrift/platform.h" +#include "thrift/version.h" +#include "thrift/generate/t_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * Python code generator. + * + */ +class t_py_generator : public t_generator { +public: + t_py_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_generator(program) { + std::map::const_iterator iter; + + + gen_newstyle_ = true; + gen_utf8strings_ = true; + gen_dynbase_ = false; + gen_slots_ = false; + gen_tornado_ = false; + gen_zope_interface_ = false; + gen_twisted_ = false; + gen_dynamic_ = false; + coding_ = ""; + gen_dynbaseclass_ = ""; + gen_dynbaseclass_exc_ = ""; + gen_dynbaseclass_frozen_ = ""; + import_dynbase_ = ""; + package_prefix_ = ""; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("new_style") == 0) { + pwarning(0, "new_style is enabled by default, so the option will be removed in the near future.\n"); + } else if( iter->first.compare("old_style") == 0) { + gen_newstyle_ = false; + pwarning(0, "old_style is deprecated and may be removed in the future.\n"); + } else if( iter->first.compare("utf8strings") == 0) { + pwarning(0, "utf8strings is enabled by default, so the option will be removed in the near future.\n"); + } else if( iter->first.compare("no_utf8strings") == 0) { + gen_utf8strings_ = false; + } else if( iter->first.compare("slots") == 0) { + gen_slots_ = true; + } else if( iter->first.compare("package_prefix") == 0) { + package_prefix_ = iter->second; + } else if( iter->first.compare("dynamic") == 0) { + gen_dynamic_ = true; + gen_newstyle_ = false; // dynamic is newstyle + if( gen_dynbaseclass_.empty()) { + gen_dynbaseclass_ = "TBase"; + } + if( gen_dynbaseclass_frozen_.empty()) { + gen_dynbaseclass_frozen_ = "TFrozenBase"; + } + if( gen_dynbaseclass_exc_.empty()) { + gen_dynbaseclass_exc_ = "TExceptionBase"; + } + if( import_dynbase_.empty()) { + import_dynbase_ = "from thrift.protocol.TBase import TBase, TFrozenBase, TExceptionBase, TTransport\n"; + } + } else if( iter->first.compare("dynbase") == 0) { + gen_dynbase_ = true; + gen_dynbaseclass_ = (iter->second); + } else if( iter->first.compare("dynfrozen") == 0) { + gen_dynbaseclass_frozen_ = (iter->second); + } else if( iter->first.compare("dynexc") == 0) { + gen_dynbaseclass_exc_ = (iter->second); + } else if( iter->first.compare("dynimport") == 0) { + gen_dynbase_ = true; + import_dynbase_ = (iter->second); + } else if( iter->first.compare("zope.interface") == 0) { + gen_zope_interface_ = true; + } else if( iter->first.compare("twisted") == 0) { + gen_twisted_ = true; + gen_zope_interface_ = true; + } else if( iter->first.compare("tornado") == 0) { + gen_tornado_ = true; + } else if( iter->first.compare("coding") == 0) { + coding_ = iter->second; + } else { + throw "unknown option py:" + iter->first; + } + } + + if (gen_twisted_ && gen_tornado_) { + throw "at most one of 'twisted' and 'tornado' are allowed"; + } + + copy_options_ = option_string; + + if (gen_twisted_) { + out_dir_base_ = "gen-py.twisted"; + } else if (gen_tornado_) { + out_dir_base_ = "gen-py.tornado"; + } else { + out_dir_base_ = "gen-py"; + } + } + + virtual std::string indent_str() const { + return " "; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_forward_declaration(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + std::string render_const_value(t_type* type, t_const_value* value); + + /** + * Struct generation code + */ + + void generate_py_struct(t_struct* tstruct, bool is_exception); + void generate_py_thrift_spec(std::ofstream& out, t_struct* tstruct, bool is_exception); + void generate_py_struct_definition(std::ofstream& out, + t_struct* tstruct, + bool is_xception = false); + void generate_py_struct_reader(std::ofstream& out, t_struct* tstruct); + void generate_py_struct_writer(std::ofstream& out, t_struct* tstruct); + void generate_py_struct_required_validator(std::ofstream& out, t_struct* tstruct); + void generate_py_function_helpers(t_function* tfunction); + + /** + * Service-level generation functions + */ + + void generate_service_helpers(t_service* tservice); + void generate_service_interface(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_remote(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* tfunction); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, + t_field* tfield, + std::string prefix = ""); + + void generate_deserialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_deserialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_deserialize_set_element(std::ofstream& out, t_set* tset, std::string prefix = ""); + + void generate_deserialize_map_element(std::ofstream& out, t_map* tmap, std::string prefix = ""); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix = ""); + + void generate_serialize_field(std::ofstream& out, t_field* tfield, std::string prefix = ""); + + void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_serialize_map_element(std::ofstream& out, + t_map* tmap, + std::string kiter, + std::string viter); + + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + + void generate_python_docstring(std::ofstream& out, t_struct* tstruct); + + void generate_python_docstring(std::ofstream& out, t_function* tfunction); + + void generate_python_docstring(std::ofstream& out, + t_doc* tdoc, + t_struct* tstruct, + const char* subheader); + + void generate_python_docstring(std::ofstream& out, t_doc* tdoc); + + /** + * Helper rendering functions + */ + + std::string py_autogen_comment(); + std::string py_imports(); + std::string render_includes(); + std::string declare_argument(t_field* tfield); + std::string render_field_default_value(t_field* tfield); + std::string type_name(t_type* ttype); + std::string function_signature(t_function* tfunction, bool interface = false); + std::string argument_list(t_struct* tstruct, + std::vector* pre = NULL, + std::vector* post = NULL); + std::string type_to_enum(t_type* ttype); + std::string type_to_spec_args(t_type* ttype); + + static bool is_valid_namespace(const std::string& sub_namespace) { + return sub_namespace == "twisted"; + } + + static std::string get_real_py_module(const t_program* program, bool gen_twisted, std::string package_dir="") { + if (gen_twisted) { + std::string twisted_module = program->get_namespace("py.twisted"); + if (!twisted_module.empty()) { + return twisted_module; + } + } + + std::string real_module = program->get_namespace("py"); + if (real_module.empty()) { + return program->get_name(); + } + return package_dir + real_module; + } + + static bool is_immutable(t_type* ttype) { + return ttype->annotations_.find("python.immutable") != ttype->annotations_.end(); + } + +private: + + /** + * True if we should generate new-style classes. + */ + bool gen_newstyle_; + + /** + * True if we should generate dynamic style classes. + */ + bool gen_dynamic_; + + bool gen_dynbase_; + std::string gen_dynbaseclass_; + std::string gen_dynbaseclass_frozen_; + std::string gen_dynbaseclass_exc_; + + std::string import_dynbase_; + + bool gen_slots_; + + std::string copy_options_; + + /** + * True if we should generate code for use with zope.interface. + */ + bool gen_zope_interface_; + + /** + * True if we should generate Twisted-friendly RPC services. + */ + bool gen_twisted_; + + /** + * True if we should generate code for use with Tornado + */ + bool gen_tornado_; + + /** + * True if strings should be encoded using utf-8. + */ + bool gen_utf8strings_; + + /** + * specify generated file encoding + * eg. # -*- coding: utf-8 -*- + */ + string coding_; + + string package_prefix_; + + /** + * File streams + */ + + std::ofstream f_types_; + std::ofstream f_consts_; + std::ofstream f_service_; + + std::string package_dir_; + std::string module_; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_py_generator::init_generator() { + // Make output directory + string module = get_real_py_module(program_, gen_twisted_); + package_dir_ = get_out_dir(); + module_ = module; + while (true) { + // TODO: Do better error checking here. + MKDIR(package_dir_.c_str()); + std::ofstream init_py((package_dir_ + "/__init__.py").c_str(), std::ios_base::app); + init_py.close(); + if (module.empty()) { + break; + } + string::size_type pos = module.find('.'); + if (pos == string::npos) { + package_dir_ += "/"; + package_dir_ += module; + module.clear(); + } else { + package_dir_ += "/"; + package_dir_ += module.substr(0, pos); + module.erase(0, pos + 1); + } + } + + // Make output file + string f_types_name = package_dir_ + "/" + "ttypes.py"; + f_types_.open(f_types_name.c_str()); + + string f_consts_name = package_dir_ + "/" + "constants.py"; + f_consts_.open(f_consts_name.c_str()); + + string f_init_name = package_dir_ + "/__init__.py"; + ofstream f_init; + f_init.open(f_init_name.c_str()); + f_init << "__all__ = ['ttypes', 'constants'"; + vector services = program_->get_services(); + vector::iterator sv_iter; + for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { + f_init << ", '" << (*sv_iter)->get_name() << "'"; + } + f_init << "]" << endl; + f_init.close(); + + // Print header + f_types_ << py_autogen_comment() << endl + << py_imports() << endl + << render_includes() << endl + << "from thrift.transport import TTransport" << endl + << import_dynbase_; + + f_types_ << "all_structs = []" << endl; + + f_consts_ << + py_autogen_comment() << endl << + py_imports() << endl << + "from .ttypes import *" << endl; +} + +/** + * Renders all the imports necessary for including another Thrift program + */ +string t_py_generator::render_includes() { + const vector& includes = program_->get_includes(); + string result = ""; + for (size_t i = 0; i < includes.size(); ++i) { + result += "import " + get_real_py_module(includes[i], gen_twisted_, package_prefix_) + ".ttypes\n"; + } + return result; +} + +/** + * Autogen'd comment + */ +string t_py_generator::py_autogen_comment() { + string coding; + if (!coding_.empty()) { + coding = "# -*- coding: " + coding_ + " -*-\n"; + } + return coding + std::string("#\n") + "# Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + + "#\n" + "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "#\n" + + "# options string: " + copy_options_ + "\n" + "#\n"; +} + +/** + * Prints standard thrift imports + */ +string t_py_generator::py_imports() { + ostringstream ss; + ss << "from thrift.Thrift import TType, TMessageType, TFrozenDict, TException, " + "TApplicationException" + << endl + << "from thrift.protocol.TProtocol import TProtocolException" + << endl + << "from thrift.TRecursive import fix_spec" + << endl; + + if (gen_utf8strings_) { + ss << endl << "import sys"; + } + return ss.str(); +} + +/** + * Closes the type files + */ +void t_py_generator::close_generator() { + + // Fix thrift_spec definitions for recursive structs. + f_types_ << "fix_spec(all_structs)" << endl; + f_types_ << "del all_structs" << endl; + + // Close types file + f_types_.close(); + f_consts_.close(); +} + +/** + * Generates a typedef. This is not done in Python, types are all implicit. + * + * @param ttypedef The type definition + */ +void t_py_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + +/** + * Generates code for an enumerated type. Done using a class to scope + * the values. + * + * @param tenum The enumeration + */ +void t_py_generator::generate_enum(t_enum* tenum) { + std::ostringstream to_string_mapping, from_string_mapping; + + f_types_ << endl << endl << "class " << tenum->get_name() << (gen_newstyle_ ? "(object)" : "") + << (gen_dynamic_ ? "(" + gen_dynbaseclass_ + ")" : "") << ":" << endl; + indent_up(); + generate_python_docstring(f_types_, tenum); + + to_string_mapping << indent() << "_VALUES_TO_NAMES = {" << endl; + from_string_mapping << indent() << "_NAMES_TO_VALUES = {" << endl; + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + indent(f_types_) << (*c_iter)->get_name() << " = " << value << endl; + + // Dictionaries to/from string names of enums + to_string_mapping << indent() << indent() << value << ": \"" + << escape_string((*c_iter)->get_name()) << "\"," << endl; + from_string_mapping << indent() << indent() << '"' << escape_string((*c_iter)->get_name()) + << "\": " << value << ',' << endl; + } + to_string_mapping << indent() << "}" << endl; + from_string_mapping << indent() << "}" << endl; + + indent_down(); + f_types_ << endl; + f_types_ << to_string_mapping.str() << endl << from_string_mapping.str(); +} + +/** + * Generate a constant value + */ +void t_py_generator::generate_const(t_const* tconst) { + t_type* type = tconst->get_type(); + string name = tconst->get_name(); + t_const_value* value = tconst->get_value(); + + indent(f_consts_) << name << " = " << render_const_value(type, value); + f_consts_ << endl; +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +string t_py_generator::render_const_value(t_type* type, t_const_value* value) { + type = get_true_type(type); + std::ostringstream out; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + out << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + out << (value->get_integer() > 0 ? "True" : "False"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + out << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + out << value->get_integer(); + } else { + out << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << value->get_integer(); + } else if (type->is_struct() || type->is_xception()) { + out << type_name(type) << "(**{" << endl; + indent_up(); + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + indent(out) << render_const_value(g_type_string, v_iter->first) << ": " + << render_const_value(field_type, v_iter->second) << "," << endl; + } + indent_down(); + indent(out) << "})"; + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + if (is_immutable(type)) { + out << "TFrozenDict("; + } + out << "{" << endl; + indent_up(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + indent(out) << render_const_value(ktype, v_iter->first) << ": " + << render_const_value(vtype, v_iter->second) << "," << endl; + } + indent_down(); + indent(out) << "}"; + if (is_immutable(type)) { + out << ")"; + } + } else if (type->is_list() || type->is_set()) { + t_type* etype; + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + if (type->is_set()) { + if (is_immutable(type)) { + out << "frozen"; + } + out << "set("; + } + if (is_immutable(type) || type->is_set()) { + out << "(" << endl; + } else { + out << "[" << endl; + } + indent_up(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + indent(out) << render_const_value(etype, *v_iter) << "," << endl; + } + indent_down(); + if (is_immutable(type) || type->is_set()) { + indent(out) << ")"; + } else { + indent(out) << "]"; + } + if (type->is_set()) { + out << ")"; + } + } else { + throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); + } + + return out.str(); +} + +/** + * Generates the "forward declarations" for python structs. + * These are actually full class definitions so that calls to generate_struct + * can add the thrift_spec field. This is needed so that all thrift_spec + * definitions are grouped at the end of the file to enable co-recursive structs. + */ +void t_py_generator::generate_forward_declaration(t_struct* tstruct) { + generate_py_struct(tstruct, tstruct->is_xception()); +} + +/** + * Generates a python struct + */ +void t_py_generator::generate_struct(t_struct* tstruct) { + generate_py_thrift_spec(f_types_, tstruct, false); +} + +/** + * Generates a struct definition for a thrift exception. Basically the same + * as a struct but extends the Exception class. + * + * @param txception The struct definition + */ +void t_py_generator::generate_xception(t_struct* txception) { + generate_py_thrift_spec(f_types_, txception, true); +} + +/** + * Generates a python struct + */ +void t_py_generator::generate_py_struct(t_struct* tstruct, bool is_exception) { + generate_py_struct_definition(f_types_, tstruct, is_exception); +} + + +/** + * Generate the thrift_spec for a struct + * For example, + * all_structs.append(Recursive) + * Recursive.thrift_spec = ( + * None, # 0 + * (1, TType.LIST, 'Children', (TType.STRUCT, (Recursive, None), False), None, ), # 1 + * ) + */ +void t_py_generator::generate_py_thrift_spec(ofstream& out, + t_struct* tstruct, + bool /*is_exception*/) { + const vector& sorted_members = tstruct->get_sorted_members(); + vector::const_iterator m_iter; + + // Add struct definition to list so thrift_spec can be fixed for recursive structures. + indent(out) << "all_structs.append(" << tstruct->get_name() << ")" << endl; + + if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) { + indent(out) << tstruct->get_name() << ".thrift_spec = (" << endl; + indent_up(); + + int sorted_keys_pos = 0; + for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) { + + for (; sorted_keys_pos != (*m_iter)->get_key(); sorted_keys_pos++) { + indent(out) << "None, # " << sorted_keys_pos << endl; + } + + indent(out) << "(" << (*m_iter)->get_key() << ", " << type_to_enum((*m_iter)->get_type()) + << ", " + << "'" << (*m_iter)->get_name() << "'" + << ", " << type_to_spec_args((*m_iter)->get_type()) << ", " + << render_field_default_value(*m_iter) << ", " + << ")," + << " # " << sorted_keys_pos << endl; + + sorted_keys_pos++; + } + + indent_down(); + indent(out) << ")" << endl; + } else { + indent(out) << tstruct->get_name() << ".thrift_spec = ()" << endl; + } +} + +/** + * Generates a struct definition for a thrift data type. + * + * @param tstruct The struct definition + */ +void t_py_generator::generate_py_struct_definition(ofstream& out, + t_struct* tstruct, + bool is_exception) { + const vector& members = tstruct->get_members(); + const vector& sorted_members = tstruct->get_sorted_members(); + vector::const_iterator m_iter; + + out << endl << endl << "class " << tstruct->get_name(); + if (is_exception) { + if (gen_dynamic_) { + out << "(" << gen_dynbaseclass_exc_ << ")"; + } else { + out << "(TException)"; + } + } else if (gen_dynamic_) { + if (is_immutable(tstruct)) { + out << "(" << gen_dynbaseclass_frozen_ << ")"; + } else { + out << "(" << gen_dynbaseclass_ << ")"; + } + } else if (gen_newstyle_) { + out << "(object)"; + } + out << ":" << endl; + indent_up(); + generate_python_docstring(out, tstruct); + + out << endl; + + /* + Here we generate the structure specification for the fastbinary codec. + These specifications have the following structure: + thrift_spec -> tuple of item_spec + item_spec -> None | (tag, type_enum, name, spec_args, default) + tag -> integer + type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ... + name -> string_literal + default -> None # Handled by __init__ + spec_args -> None # For simple types + | (type_enum, spec_args) # Value type for list/set + | (type_enum, spec_args, type_enum, spec_args) + # Key and value for map + | (class_name, spec_args_ptr) # For struct/exception + class_name -> identifier # Basically a pointer to the class + spec_args_ptr -> expression # just class_name.spec_args + + TODO(dreiss): Consider making this work for structs with negative tags. + */ + + if (gen_slots_) { + indent(out) << "__slots__ = (" << endl; + indent_up(); + for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) { + indent(out) << "'" << (*m_iter)->get_name() << "'," << endl; + } + indent_down(); + indent(out) << ")" << endl << endl; + } + + // TODO(dreiss): Look into generating an empty tuple instead of None + // for structures with no members. + // TODO(dreiss): Test encoding of structs where some inner structs + // don't have thrift_spec. + + if (members.size() > 0) { + out << endl; + out << indent() << "def __init__(self,"; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + out << " " << declare_argument(*m_iter) << ","; + } + out << "):" << endl; + + indent_up(); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + // Initialize fields + t_type* type = (*m_iter)->get_type(); + if (!type->is_base_type() && !type->is_enum() && (*m_iter)->get_value() != NULL) { + indent(out) << "if " << (*m_iter)->get_name() << " is " + << "self.thrift_spec[" << (*m_iter)->get_key() << "][4]:" << endl; + indent_up(); + indent(out) << (*m_iter)->get_name() << " = " << render_field_default_value(*m_iter) + << endl; + indent_down(); + } + + if (is_immutable(tstruct)) { + if (gen_newstyle_ || gen_dynamic_) { + indent(out) << "super(" << tstruct->get_name() << ", self).__setattr__('" + << (*m_iter)->get_name() << "', " << (*m_iter)->get_name() << ")" << endl; + } else { + indent(out) << "self.__dict__['" << (*m_iter)->get_name() + << "'] = " << (*m_iter)->get_name() << endl; + } + } else { + indent(out) << "self." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << endl; + } + } + + indent_down(); + } + + if (is_immutable(tstruct)) { + out << endl; + out << indent() << "def __setattr__(self, *args):" << endl + << indent() << indent_str() << "raise TypeError(\"can't modify immutable instance\")" << endl + << endl; + out << indent() << "def __delattr__(self, *args):" << endl + << indent() << indent_str() << "raise TypeError(\"can't modify immutable instance\")" << endl + << endl; + + // Hash all of the members in order, and also hash in the class + // to avoid collisions for stuff like single-field structures. + out << indent() << "def __hash__(self):" << endl + << indent() << indent_str() << "return hash(self.__class__) ^ hash(("; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + out << "self." << (*m_iter)->get_name() << ", "; + } + + out << "))" << endl; + } + + if (!gen_dynamic_) { + out << endl; + generate_py_struct_reader(out, tstruct); + generate_py_struct_writer(out, tstruct); + } + + // For exceptions only, generate a __str__ method. This is + // because when raised exceptions are printed to the console, __repr__ + // isn't used. See python bug #5882 + if (is_exception) { + out << endl; + out << indent() << "def __str__(self):" << endl + << indent() << indent_str() << "return repr(self)" << endl; + } + + if (!gen_slots_) { + out << endl; + // Printing utilities so that on the command line thrift + // structs look pretty like dictionaries + indent(out) << "def __repr__(self):" << endl; + indent_up(); + out << indent() << "L = ['%s=%r' % (key, value)" << endl + << indent() << " for key, value in self.__dict__.items()]" << endl + << indent() << "return '%s(%s)' % (self.__class__.__name__, ', '.join(L))" << endl + << endl; + indent_down(); + + // Equality and inequality methods that compare by value + out << indent() << "def __eq__(self, other):" << endl; + indent_up(); + out << indent() << "return isinstance(other, self.__class__) and " + "self.__dict__ == other.__dict__" << endl; + indent_down(); + out << endl; + + out << indent() << "def __ne__(self, other):" << endl; + indent_up(); + + out << indent() << "return not (self == other)" << endl; + indent_down(); + } else if (!gen_dynamic_) { + out << endl; + // no base class available to implement __eq__ and __repr__ and __ne__ for us + // so we must provide one that uses __slots__ + indent(out) << "def __repr__(self):" << endl; + indent_up(); + out << indent() << "L = ['%s=%r' % (key, getattr(self, key))" << endl + << indent() << " for key in self.__slots__]" << endl + << indent() << "return '%s(%s)' % (self.__class__.__name__, ', '.join(L))" << endl + << endl; + indent_down(); + + // Equality method that compares each attribute by value and type, walking __slots__ + out << indent() << "def __eq__(self, other):" << endl; + indent_up(); + out << indent() << "if not isinstance(other, self.__class__):" << endl + << indent() << indent_str() << "return False" << endl + << indent() << "for attr in self.__slots__:" << endl + << indent() << indent_str() << "my_val = getattr(self, attr)" << endl + << indent() << indent_str() << "other_val = getattr(other, attr)" << endl + << indent() << indent_str() << "if my_val != other_val:" << endl + << indent() << indent_str() << indent_str() << "return False" << endl + << indent() << "return True" << endl + << endl; + indent_down(); + + out << indent() << "def __ne__(self, other):" << endl + << indent() << indent_str() << "return not (self == other)" << endl; + } + indent_down(); +} + +/** + * Generates the read method for a struct + */ +void t_py_generator::generate_py_struct_reader(ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + if (is_immutable(tstruct)) { + out << indent() << "@classmethod" << endl << indent() << "def read(cls, iprot):" << endl; + } else { + indent(out) << "def read(self, iprot):" << endl; + } + indent_up(); + + const char* id = is_immutable(tstruct) ? "cls" : "self"; + + indent(out) << "if iprot._fast_decode is not None " + "and isinstance(iprot.trans, TTransport.CReadableTransport) " + "and " + << id << ".thrift_spec is not None:" << endl; + indent_up(); + + if (is_immutable(tstruct)) { + indent(out) << "return iprot._fast_decode(None, iprot, [cls, cls.thrift_spec])" << endl; + } else { + indent(out) << "iprot._fast_decode(self, iprot, [self.__class__, self.thrift_spec])" << endl; + indent(out) << "return" << endl; + } + indent_down(); + + indent(out) << "iprot.readStructBegin()" << endl; + + // Loop over reading in fields + indent(out) << "while True:" << endl; + indent_up(); + + // Read beginning field marker + indent(out) << "(fname, ftype, fid) = iprot.readFieldBegin()" << endl; + + // Check for field STOP marker and break + indent(out) << "if ftype == TType.STOP:" << endl; + indent_up(); + indent(out) << "break" << endl; + indent_down(); + + // Switch statement on the field we are reading + bool first = true; + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + out << indent() << "if "; + } else { + out << indent() << "elif "; + } + out << "fid == " << (*f_iter)->get_key() << ":" << endl; + indent_up(); + indent(out) << "if ftype == " << type_to_enum((*f_iter)->get_type()) << ":" << endl; + indent_up(); + if (is_immutable(tstruct)) { + generate_deserialize_field(out, *f_iter); + } else { + generate_deserialize_field(out, *f_iter, "self."); + } + indent_down(); + out << indent() << "else:" << endl << indent() << indent_str() << "iprot.skip(ftype)" << endl; + indent_down(); + } + + // In the default case we skip the field + out << indent() << "else:" << endl << indent() << indent_str() << "iprot.skip(ftype)" << endl; + + // Read field end marker + indent(out) << "iprot.readFieldEnd()" << endl; + + indent_down(); + + indent(out) << "iprot.readStructEnd()" << endl; + + if (is_immutable(tstruct)) { + indent(out) << "return cls(" << endl; + indent_up(); + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << (*f_iter)->get_name() << "=" << (*f_iter)->get_name() << "," << endl; + } + indent_down(); + indent(out) << ")" << endl; + } + + indent_down(); + out << endl; +} + +void t_py_generator::generate_py_struct_writer(ofstream& out, t_struct* tstruct) { + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + indent(out) << "def write(self, oprot):" << endl; + indent_up(); + + indent(out) << "if oprot._fast_encode is not None and self.thrift_spec is not None:" << endl; + indent_up(); + + indent(out) + << "oprot.trans.write(oprot._fast_encode(self, [self.__class__, self.thrift_spec]))" + << endl; + indent(out) << "return" << endl; + indent_down(); + + indent(out) << "oprot.writeStructBegin('" << name << "')" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + // Write field header + indent(out) << "if self." << (*f_iter)->get_name() << " is not None:" << endl; + indent_up(); + indent(out) << "oprot.writeFieldBegin(" + << "'" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type()) + << ", " << (*f_iter)->get_key() << ")" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "self."); + + // Write field closer + indent(out) << "oprot.writeFieldEnd()" << endl; + + indent_down(); + } + + // Write the struct map + out << indent() << "oprot.writeFieldStop()" << endl << indent() << "oprot.writeStructEnd()" + << endl; + + out << endl; + + indent_down(); + generate_py_struct_required_validator(out, tstruct); +} + +void t_py_generator::generate_py_struct_required_validator(ofstream& out, t_struct* tstruct) { + indent(out) << "def validate(self):" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + + if (fields.size() > 0) { + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = (*f_iter); + if (field->get_req() == t_field::T_REQUIRED) { + indent(out) << "if self." << field->get_name() << " is None:" << endl; + indent(out) << indent_str() << "raise TProtocolException(message='Required field " + << field->get_name() << " is unset!')" << endl; + } + } + } + + indent(out) << "return" << endl; + indent_down(); +} + +/** + * Generates a thrift service. + * + * @param tservice The service definition + */ +void t_py_generator::generate_service(t_service* tservice) { + string f_service_name = package_dir_ + "/" + service_name_ + ".py"; + f_service_.open(f_service_name.c_str()); + + f_service_ << py_autogen_comment() << endl << py_imports() << endl; + + if (tservice->get_extends() != NULL) { + f_service_ << "import " + << get_real_py_module(tservice->get_extends()->get_program(), gen_twisted_, package_prefix_) << "." + << tservice->get_extends()->get_name() << endl; + } + + f_service_ << "import logging" << endl + << "from .ttypes import *" << endl + << "from thrift.Thrift import TProcessor" << endl + << "from thrift.transport import TTransport" << endl + << import_dynbase_; + if (gen_zope_interface_) { + f_service_ << "from zope.interface import Interface, implementer" << endl; + } + + if (gen_twisted_) { + f_service_ << "from twisted.internet import defer" << endl + << "from thrift.transport import TTwisted" << endl; + } else if (gen_tornado_) { + f_service_ << "from tornado import gen" << endl; + f_service_ << "from tornado import concurrent" << endl; + } + + f_service_ << "all_structs = []" << endl; + + // Generate the three main parts of the service + generate_service_interface(tservice); + generate_service_client(tservice); + generate_service_server(tservice); + generate_service_helpers(tservice); + generate_service_remote(tservice); + + // Close service file + f_service_ << "fix_spec(all_structs)" << endl + << "del all_structs" << endl << endl; + f_service_.close(); +} + +/** + * Generates helper functions for a service. + * + * @param tservice The service to generate a header definition for + */ +void t_py_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + f_service_ << endl << "# HELPER FUNCTIONS AND STRUCTURES" << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_py_struct_definition(f_service_, ts, false); + generate_py_thrift_spec(f_service_, ts, false); + generate_py_function_helpers(*f_iter); + } +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_py_generator::generate_py_function_helpers(t_function* tfunction) { + if (!tfunction->is_oneway()) { + t_struct result(program_, tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + generate_py_struct_definition(f_service_, &result, false); + generate_py_thrift_spec(f_service_, &result, false); + } +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_py_generator::generate_service_interface(t_service* tservice) { + string extends = ""; + string extends_if = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_if = "(" + extends + ".Iface)"; + } else { + if (gen_zope_interface_) { + extends_if = "(Interface)"; + } else if (gen_newstyle_ || gen_dynamic_ || gen_tornado_) { + extends_if = "(object)"; + } + } + + f_service_ << endl << endl << "class Iface" << extends_if << ":" << endl; + indent_up(); + generate_python_docstring(f_service_, tservice); + vector functions = tservice->get_functions(); + if (functions.empty()) { + f_service_ << indent() << "pass" << endl; + } else { + vector::iterator f_iter; + bool first = true; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << endl; + } + f_service_ << indent() << "def " << function_signature(*f_iter, true) << ":" << endl; + indent_up(); + generate_python_docstring(f_service_, (*f_iter)); + f_service_ << indent() << "pass" << endl; + indent_down(); + } + } + + indent_down(); +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_py_generator::generate_service_client(t_service* tservice) { + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + if (gen_zope_interface_) { + extends_client = "(" + extends + ".Client)"; + } else { + extends_client = extends + ".Client, "; + } + } else { + if (gen_zope_interface_ && (gen_newstyle_ || gen_dynamic_)) { + extends_client = "(object)"; + } + } + + f_service_ << endl << endl; + + if (gen_zope_interface_) { + f_service_ << "@implementer(Iface)" << endl + << "class Client" << extends_client << ":" << endl + << endl; + } else { + f_service_ << "class Client(" << extends_client << "Iface):" << endl; + } + indent_up(); + generate_python_docstring(f_service_, tservice); + + // Constructor function + if (gen_twisted_) { + f_service_ << indent() << "def __init__(self, transport, oprot_factory):" << endl; + } else if (gen_tornado_) { + f_service_ << indent() + << "def __init__(self, transport, iprot_factory, oprot_factory=None):" << endl; + } else { + f_service_ << indent() << "def __init__(self, iprot, oprot=None):" << endl; + } + indent_up(); + if (extends.empty()) { + if (gen_twisted_) { + f_service_ << indent() << "self._transport = transport" << endl + << indent() << "self._oprot_factory = oprot_factory" << endl + << indent() << "self._seqid = 0" << endl + << indent() << "self._reqs = {}" << endl; + } else if (gen_tornado_) { + f_service_ << indent() << "self._transport = transport" << endl + << indent() << "self._iprot_factory = iprot_factory" << endl + << indent() << "self._oprot_factory = (oprot_factory if oprot_factory is not None" + << endl + << indent() << " else iprot_factory)" << endl + << indent() << "self._seqid = 0" << endl + << indent() << "self._reqs = {}" << endl + << indent() << "self._transport.io_loop.spawn_callback(self._start_receiving)" + << endl; + } else { + f_service_ << indent() << "self._iprot = self._oprot = iprot" << endl + << indent() << "if oprot is not None:" << endl + << indent() << indent_str() << "self._oprot = oprot" << endl + << indent() << "self._seqid = 0" << endl; + } + } else { + if (gen_twisted_) { + f_service_ << indent() << extends + << ".Client.__init__(self, transport, oprot_factory)" << endl; + } else if (gen_tornado_) { + f_service_ << indent() << extends + << ".Client.__init__(self, transport, iprot_factory, oprot_factory)" << endl; + } else { + f_service_ << indent() << extends << ".Client.__init__(self, iprot, oprot)" << endl; + } + } + indent_down(); + + if (gen_tornado_ && extends.empty()) { + f_service_ << endl << + indent() << "@gen.engine" << endl << + indent() << "def _start_receiving(self):" << endl; + indent_up(); + indent(f_service_) << "while True:" << endl; + indent_up(); + f_service_ << indent() << "try:" << endl + << indent() << indent_str() << "frame = yield self._transport.readFrame()" << endl + << indent() << "except TTransport.TTransportException as e:" << endl + << indent() << indent_str() << "for future in self._reqs.values():" << endl + << indent() << indent_str() << indent_str() << "future.set_exception(e)" << endl + << indent() << indent_str() << "self._reqs = {}" << endl + << indent() << indent_str() << "return" << endl + << indent() << "tr = TTransport.TMemoryBuffer(frame)" << endl + << indent() << "iprot = self._iprot_factory.getProtocol(tr)" << endl + << indent() << "(fname, mtype, rseqid) = iprot.readMessageBegin()" << endl + << indent() << "method = getattr(self, 'recv_' + fname)" << endl + << indent() << "future = self._reqs.pop(rseqid, None)" << endl + << indent() << "if not future:" << endl + << indent() << indent_str() << "# future has already been discarded" << endl + << indent() << indent_str() << "continue" << endl + << indent() << "try:" << endl + << indent() << indent_str() << "result = method(iprot, mtype, rseqid)" << endl + << indent() << "except Exception as e:" << endl + << indent() << indent_str() << "future.set_exception(e)" << endl + << indent() << "else:" << endl + << indent() << indent_str() << "future.set_result(result)" << endl; + indent_down(); + indent_down(); + } + + // Generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* arg_struct = (*f_iter)->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + string funname = (*f_iter)->get_name(); + + f_service_ << endl; + // Open function + indent(f_service_) << "def " << function_signature(*f_iter, false) << ":" << endl; + indent_up(); + generate_python_docstring(f_service_, (*f_iter)); + if (gen_twisted_) { + indent(f_service_) << "seqid = self._seqid = self._seqid + 1" << endl; + indent(f_service_) << "self._reqs[seqid] = defer.Deferred()" << endl << endl; + indent(f_service_) << "d = defer.maybeDeferred(self.send_" << funname; + + } else if (gen_tornado_) { + indent(f_service_) << "self._seqid += 1" << endl; + if (!(*f_iter)->is_oneway()) { + indent(f_service_) << "future = self._reqs[self._seqid] = concurrent.Future()" << endl; + } + indent(f_service_) << "self.send_" << funname << "("; + + } else { + indent(f_service_) << "self.send_" << funname << "("; + } + + bool first = true; + if (gen_twisted_) { + // we need a leading comma if there are args, since it's called as maybeDeferred(funcname, + // arg) + first = false; + } + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << (*fld_iter)->get_name(); + } + + f_service_ << ")" << endl; + + if (!(*f_iter)->is_oneway()) { + if (gen_twisted_) { + // nothing. See the next block. + } else if (gen_tornado_) { + indent(f_service_) << "return future" << endl; + } else { + f_service_ << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << "return "; + } + f_service_ << "self.recv_" << funname << "()" << endl; + } + } + indent_down(); + + if (gen_twisted_) { + // This block injects the body of the send_<> method for twisted (and a cb/eb pair) + indent_up(); + indent(f_service_) << "d.addCallbacks(" << endl; + + indent_up(); + f_service_ << indent() << "callback=self.cb_send_" << funname << "," << endl << indent() + << "callbackArgs=(seqid,)," << endl << indent() << "errback=self.eb_send_" + << funname << "," << endl << indent() << "errbackArgs=(seqid,))" << endl; + indent_down(); + + indent(f_service_) << "return d" << endl; + indent_down(); + f_service_ << endl; + + indent(f_service_) << "def cb_send_" << funname << "(self, _, seqid):" << endl; + indent_up(); + if ((*f_iter)->is_oneway()) { + // if one-way, fire the deferred & remove it from _reqs + f_service_ << indent() << "d = self._reqs.pop(seqid)" << endl << indent() + << "d.callback(None)" << endl << indent() << "return d" << endl; + } else { + f_service_ << indent() << "return self._reqs[seqid]" << endl; + } + indent_down(); + f_service_ << endl; + + // add an errback to fail the request if the call to send_<> raised an exception + indent(f_service_) << "def eb_send_" << funname << "(self, f, seqid):" << endl; + indent_up(); + f_service_ << indent() << "d = self._reqs.pop(seqid)" << endl << indent() << "d.errback(f)" + << endl << indent() << "return d" << endl; + indent_down(); + } + + f_service_ << endl; + indent(f_service_) << "def send_" << function_signature(*f_iter, false) << ":" << endl; + indent_up(); + + std::string argsname = (*f_iter)->get_name() + "_args"; + std::string messageType = (*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL"; + + // Serialize the request header + if (gen_twisted_ || gen_tornado_) { + f_service_ << indent() << "oprot = self._oprot_factory.getProtocol(self._transport)" << endl + << indent() << "oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', " + << messageType << ", self._seqid)" << endl; + } else { + f_service_ << indent() << "self._oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', " + << messageType << ", self._seqid)" << endl; + } + + f_service_ << indent() << "args = " << argsname << "()" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << indent() << "args." << (*fld_iter)->get_name() << " = " + << (*fld_iter)->get_name() << endl; + } + + // Write to the stream + if (gen_twisted_ || gen_tornado_) { + f_service_ << indent() << "args.write(oprot)" << endl << indent() << "oprot.writeMessageEnd()" + << endl << indent() << "oprot.trans.flush()" << endl; + } else { + f_service_ << indent() << "args.write(self._oprot)" << endl << indent() + << "self._oprot.writeMessageEnd()" << endl << indent() + << "self._oprot.trans.flush()" << endl; + } + + indent_down(); + + if (!(*f_iter)->is_oneway()) { + std::string resultname = (*f_iter)->get_name() + "_result"; + // Open function + f_service_ << endl; + if (gen_twisted_ || gen_tornado_) { + f_service_ << indent() << "def recv_" << (*f_iter)->get_name() + << "(self, iprot, mtype, rseqid):" << endl; + } else { + t_struct noargs(program_); + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + &noargs); + f_service_ << indent() << "def " << function_signature(&recv_function) << ":" << endl; + } + indent_up(); + + // TODO(mcslee): Validate message reply here, seq ids etc. + + if (gen_twisted_) { + f_service_ << indent() << "d = self._reqs.pop(rseqid)" << endl; + } else if (gen_tornado_) { + } else { + f_service_ << indent() << "iprot = self._iprot" << endl << indent() + << "(fname, mtype, rseqid) = iprot.readMessageBegin()" << endl; + } + + f_service_ << indent() << "if mtype == TMessageType.EXCEPTION:" << endl + << indent() << indent_str() << "x = TApplicationException()" << endl; + + if (gen_twisted_) { + f_service_ << indent() << indent_str() << "x.read(iprot)" << endl << indent() + << indent_str() << "iprot.readMessageEnd()" << endl << indent() << indent_str() << "return d.errback(x)" + << endl << indent() << "result = " << resultname << "()" << endl << indent() + << "result.read(iprot)" << endl << indent() << "iprot.readMessageEnd()" << endl; + } else { + f_service_ << indent() << indent_str() << "x.read(iprot)" << endl << indent() + << indent_str() << "iprot.readMessageEnd()" << endl << indent() << indent_str() << "raise x" << endl + << indent() << "result = " << resultname << "()" << endl << indent() + << "result.read(iprot)" << endl << indent() << "iprot.readMessageEnd()" << endl; + } + + // Careful, only return _result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << indent() << "if result.success is not None:" << endl; + if (gen_twisted_) { + f_service_ << indent() << indent_str() << "return d.callback(result.success)" << endl; + } else { + f_service_ << indent() << indent_str() << "return result.success" << endl; + } + } + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + const string& xname = (*x_iter)->get_name(); + f_service_ << indent() << "if result." << xname << " is not None:" << endl; + if (gen_twisted_) { + f_service_ << indent() << indent_str() << "return d.errback(result." << xname << ")" + << endl; + } else { + f_service_ << indent() << indent_str() << "raise result." << xname << "" << endl; + } + } + + // Careful, only return _result if not a void function + if ((*f_iter)->get_returntype()->is_void()) { + if (gen_twisted_) { + f_service_ << indent() << "return d.callback(None)" << endl; + } else { + f_service_ << indent() << "return" << endl; + } + } else { + if (gen_twisted_) { + f_service_ + << indent() + << "return d.errback(TApplicationException(TApplicationException.MISSING_RESULT, \"" + << (*f_iter)->get_name() << " failed: unknown result\"))" << endl; + } else { + f_service_ << indent() + << "raise TApplicationException(TApplicationException.MISSING_RESULT, \"" + << (*f_iter)->get_name() << " failed: unknown result\")" << endl; + } + } + + // Close function + indent_down(); + } + } + + indent_down(); +} + +/** + * Generates a command line tool for making remote requests + * + * @param tservice The service to generate a remote for. + */ +void t_py_generator::generate_service_remote(t_service* tservice) { + vector functions = tservice->get_functions(); + // Get all function from parents + t_service* parent = tservice->get_extends(); + while (parent != NULL) { + vector p_functions = parent->get_functions(); + functions.insert(functions.end(), p_functions.begin(), p_functions.end()); + parent = parent->get_extends(); + } + vector::iterator f_iter; + + string f_remote_name = package_dir_ + "/" + service_name_ + "-remote"; + ofstream f_remote; + f_remote.open(f_remote_name.c_str()); + + f_remote << + "#!/usr/bin/env python" << endl << + py_autogen_comment() << endl << + "import sys" << endl << + "import pprint" << endl << + "if sys.version_info[0] > 2:" << endl << + indent_str() << "from urllib.parse import urlparse" << endl << + "else:" << endl << + indent_str() << "from urlparse import urlparse" << endl << + "from thrift.transport import TTransport, TSocket, TSSLSocket, THttpClient" << endl << + "from thrift.protocol.TBinaryProtocol import TBinaryProtocol" << endl << + endl; + + f_remote << + "from " << module_ << " import " << service_name_ << endl << + "from " << module_ << ".ttypes import *" << endl << + endl; + + f_remote << + "if len(sys.argv) <= 1 or sys.argv[1] == '--help':" << endl << + indent_str() << "print('')" << endl << + indent_str() << "print('Usage: ' + sys.argv[0] + ' [-h host[:port]] [-u url] [-f[ramed]] [-s[sl]] [-novalidate] [-ca_certs certs] [-keyfile keyfile] [-certfile certfile] function [arg1 [arg2...]]')" << endl << + indent_str() << "print('')" << endl << + indent_str() << "print('Functions:')" << endl; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_remote << indent_str() << "print(' " << (*f_iter)->get_returntype()->get_name() << " " + << (*f_iter)->get_name() << "("; + t_struct* arg_struct = (*f_iter)->get_arglist(); + const std::vector& args = arg_struct->get_members(); + vector::const_iterator a_iter; + std::vector::size_type num_args = args.size(); + bool first = true; + for (std::vector::size_type i = 0; i < num_args; ++i) { + if (first) { + first = false; + } else { + f_remote << ", "; + } + f_remote << args[i]->get_type()->get_name() << " " << args[i]->get_name(); + } + f_remote << ")')" << endl; + } + f_remote << indent_str() << "print('')" << endl << indent_str() << "sys.exit(0)" << endl << endl; + + f_remote << "pp = pprint.PrettyPrinter(indent=2)" << endl + << "host = 'localhost'" << endl + << "port = 9090" << endl + << "uri = ''" << endl + << "framed = False" << endl + << "ssl = False" << endl + << "validate = True" << endl + << "ca_certs = None" << endl + << "keyfile = None" << endl + << "certfile = None" << endl + << "http = False" << endl + << "argi = 1" << endl + << endl + << "if sys.argv[argi] == '-h':" << endl + << indent_str() << "parts = sys.argv[argi + 1].split(':')" << endl + << indent_str() << "host = parts[0]" << endl + << indent_str() << "if len(parts) > 1:" << endl + << indent_str() << indent_str() << "port = int(parts[1])" << endl + << indent_str() << "argi += 2" << endl + << endl + << "if sys.argv[argi] == '-u':" << endl + << indent_str() << "url = urlparse(sys.argv[argi + 1])" << endl + << indent_str() << "parts = url[1].split(':')" << endl + << indent_str() << "host = parts[0]" << endl + << indent_str() << "if len(parts) > 1:" << endl + << indent_str() << indent_str() << "port = int(parts[1])" << endl + << indent_str() << "else:" << endl + << indent_str() << indent_str() << "port = 80" << endl + << indent_str() << "uri = url[2]" << endl + << indent_str() << "if url[4]:" << endl + << indent_str() << indent_str() << "uri += '?%s' % url[4]" << endl + << indent_str() << "http = True" << endl + << indent_str() << "argi += 2" << endl + << endl + << "if sys.argv[argi] == '-f' or sys.argv[argi] == '-framed':" << endl + << indent_str() << "framed = True" << endl + << indent_str() << "argi += 1" << endl + << endl + << "if sys.argv[argi] == '-s' or sys.argv[argi] == '-ssl':" << endl + << indent_str() << "ssl = True" << endl + << indent_str() << "argi += 1" << endl + << endl + << "if sys.argv[argi] == '-novalidate':" << endl + << indent_str() << "validate = False" << endl + << indent_str() << "argi += 1" << endl + << endl + << "if sys.argv[argi] == '-ca_certs':" << endl + << indent_str() << "ca_certs = sys.argv[argi+1]" << endl + << indent_str() << "argi += 2" << endl + << endl + << "if sys.argv[argi] == '-keyfile':" << endl + << indent_str() << "keyfile = sys.argv[argi+1]" << endl + << indent_str() << "argi += 2" << endl + << endl + << "if sys.argv[argi] == '-certfile':" << endl + << indent_str() << "certfile = sys.argv[argi+1]" << endl + << indent_str() << "argi += 2" << endl + << endl + << "cmd = sys.argv[argi]" << endl + << "args = sys.argv[argi + 1:]" << endl + << endl + << "if http:" << endl + << indent_str() << "transport = THttpClient.THttpClient(host, port, uri)" << endl + << "else:" << endl + << indent_str() << "if ssl:" << endl + << indent_str() << indent_str() << "socket = TSSLSocket.TSSLSocket(host, port, " + "validate=validate, ca_certs=ca_certs, keyfile=keyfile, certfile=certfile)" + << endl + << indent_str() << "else:" << endl + << indent_str() << indent_str() << "socket = TSocket.TSocket(host, port)" << endl + << indent_str() << "if framed:" << endl + << indent_str() << indent_str() << "transport = TTransport.TFramedTransport(socket)" << endl + << indent_str() << "else:" << endl + << indent_str() << indent_str() << "transport = TTransport.TBufferedTransport(socket)" << endl + << "protocol = TBinaryProtocol(transport)" << endl + << "client = " << service_name_ << ".Client(protocol)" << endl + << "transport.open()" << endl + << endl; + + // Generate the dispatch methods + bool first = true; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_remote << "el"; + } + + t_struct* arg_struct = (*f_iter)->get_arglist(); + const std::vector& args = arg_struct->get_members(); + vector::const_iterator a_iter; + std::vector::size_type num_args = args.size(); + + f_remote << "if cmd == '" << (*f_iter)->get_name() << "':" << endl; + indent_up(); + f_remote << indent() << "if len(args) != " << num_args << ":" << endl + << indent() << indent_str() << "print('" << (*f_iter)->get_name() << " requires " << num_args + << " args')" << endl + << indent() << indent_str() << "sys.exit(1)" << endl + << indent() << "pp.pprint(client." << (*f_iter)->get_name() << "("; + indent_down(); + bool first_arg = true; + for (std::vector::size_type i = 0; i < num_args; ++i) { + if (first_arg) + first_arg = false; + else + f_remote << " "; + if (args[i]->get_type()->is_string()) { + f_remote << "args[" << i << "],"; + } else { + f_remote << "eval(args[" << i << "]),"; + } + } + f_remote << "))" << endl; + + f_remote << endl; + } + + if (functions.size() > 0) { + f_remote << "else:" << endl; + f_remote << indent_str() << "print('Unrecognized method %s' % cmd)" << endl; + f_remote << indent_str() << "sys.exit(1)" << endl; + f_remote << endl; + } + + f_remote << "transport.close()" << endl; + + // Close service file + f_remote.close(); + +#ifndef _MSC_VER + + // Make file executable, love that bitwise OR action + chmod(f_remote_name.c_str(), + S_IRUSR | S_IWUSR | S_IXUSR +#ifndef _WIN32 + | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH +#endif + ); + +#endif // _MSC_VER +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_py_generator::generate_service_server(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_processor = extends + ".Processor, "; + } + + f_service_ << endl << endl; + + // Generate the header portion + if (gen_zope_interface_) { + f_service_ << "@implementer(Iface)" << endl + << "class Processor(" << extends_processor << "TProcessor):" << endl; + } else { + f_service_ << "class Processor(" << extends_processor << "Iface, TProcessor):" << endl; + } + + indent_up(); + + indent(f_service_) << "def __init__(self, handler):" << endl; + indent_up(); + if (extends.empty()) { + if (gen_zope_interface_) { + f_service_ << indent() << "self._handler = Iface(handler)" << endl; + } else { + f_service_ << indent() << "self._handler = handler" << endl; + } + + f_service_ << indent() << "self._processMap = {}" << endl; + } else { + if (gen_zope_interface_) { + f_service_ << indent() << extends << ".Processor.__init__(self, Iface(handler))" << endl; + } else { + f_service_ << indent() << extends << ".Processor.__init__(self, handler)" << endl; + } + } + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << indent() << "self._processMap[\"" << (*f_iter)->get_name() + << "\"] = Processor.process_" << (*f_iter)->get_name() << endl; + } + indent_down(); + f_service_ << endl; + + // Generate the server implementation + f_service_ << indent() << "def process(self, iprot, oprot):" << endl; + indent_up(); + + f_service_ << indent() << "(name, type, seqid) = iprot.readMessageBegin()" << endl; + + // TODO(mcslee): validate message + + // HOT: dictionary function lookup + f_service_ << indent() << "if name not in self._processMap:" << endl; + indent_up(); + f_service_ << indent() << "iprot.skip(TType.STRUCT)" << endl + << indent() << "iprot.readMessageEnd()" << endl + << indent() + << "x = TApplicationException(TApplicationException.UNKNOWN_METHOD, 'Unknown " + "function %s' % (name))" + << endl + << indent() << "oprot.writeMessageBegin(name, TMessageType.EXCEPTION, seqid)" << endl + << indent() << "x.write(oprot)" << endl + << indent() << "oprot.writeMessageEnd()" << endl + << indent() << "oprot.trans.flush()" << endl; + + if (gen_twisted_) { + f_service_ << indent() << "return defer.succeed(None)" << endl; + } else { + f_service_ << indent() << "return" << endl; + } + indent_down(); + + f_service_ << indent() << "else:" << endl; + + if (gen_twisted_ || gen_tornado_) { + f_service_ << indent() << indent_str() + << "return self._processMap[name](self, seqid, iprot, oprot)" << endl; + } else { + f_service_ << indent() << indent_str() << "self._processMap[name](self, seqid, iprot, oprot)" + << endl; + + // Read end of args field, the T_STOP, and the struct close + f_service_ << indent() << "return True" << endl; + } + + indent_down(); + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << endl; + generate_process_function(tservice, *f_iter); + } + + indent_down(); +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_py_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + (void)tservice; + // Open function + if (gen_tornado_) { + f_service_ << indent() << "@gen.coroutine" << endl << indent() << "def process_" + << tfunction->get_name() << "(self, seqid, iprot, oprot):" << endl; + } else { + f_service_ << indent() << "def process_" << tfunction->get_name() + << "(self, seqid, iprot, oprot):" << endl; + } + + indent_up(); + + string argsname = tfunction->get_name() + "_args"; + string resultname = tfunction->get_name() + "_result"; + + f_service_ << indent() << "args = " << argsname << "()" << endl << indent() << "args.read(iprot)" + << endl << indent() << "iprot.readMessageEnd()" << endl; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + // Declare result for non oneway function + if (!tfunction->is_oneway()) { + f_service_ << indent() << "result = " << resultname << "()" << endl; + } + + if (gen_twisted_) { + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + f_service_ << indent() << "d = defer.maybeDeferred(self._handler." << tfunction->get_name() + << ", "; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "args." << (*f_iter)->get_name(); + } + f_service_ << ")" << endl; + + if (tfunction->is_oneway()) { + f_service_ << indent() << "d.addErrback(self.handle_exception_" << tfunction->get_name() + << ", seqid)" << endl; + } else { + f_service_ << indent() << "d.addCallback(self.write_results_success_" << tfunction->get_name() + << ", result, seqid, oprot)" << endl + << indent() << "d.addErrback(self.write_results_exception_" + << tfunction->get_name() << ", result, seqid, oprot)" << endl; + } + f_service_ << indent() << "return d" << endl << endl; + + indent_down(); + + if (tfunction->is_oneway()) { + indent(f_service_) << "def handle_exception_" << tfunction->get_name() + << "(self, error, seqid):" << endl; + } else { + indent(f_service_) << "def write_results_success_" << tfunction->get_name() + << "(self, success, result, seqid, oprot):" << endl; + indent_up(); + f_service_ << indent() << "result.success = success" << endl + << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() + << "\", TMessageType.REPLY, seqid)" << endl + << indent() << "result.write(oprot)" << endl + << indent() << "oprot.writeMessageEnd()" << endl + << indent() << "oprot.trans.flush()" << endl + << endl; + indent_down(); + + indent(f_service_) << "def write_results_exception_" << tfunction->get_name() + << "(self, error, result, seqid, oprot):" << endl; + } + indent_up(); + if (!tfunction->is_oneway()) { + f_service_ << indent() << "msg_type = TMessageType.REPLY" << endl; + } + f_service_ << indent() << "try:" << endl; + + // Kinda absurd + f_service_ << indent() << indent_str() << "error.raiseException()" << endl; + if (!tfunction->is_oneway()) { + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + const string& xname = (*x_iter)->get_name(); + f_service_ << indent() << "except " << type_name((*x_iter)->get_type()) << " as " << xname + << ":" << endl; + indent_up(); + f_service_ << indent() << "result." << xname << " = " << xname << endl; + indent_down(); + } + } + f_service_ << indent() << "except TTransport.TTransportException:" << endl + << indent() << indent_str() << "raise" << endl; + if (!tfunction->is_oneway()) { + f_service_ << indent() << "except TApplicationException as ex:" << endl + << indent() << indent_str() + << "logging.exception('TApplication exception in handler')" << endl + << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl + << indent() << indent_str() << "result = ex" << endl + << indent() << "except Exception:" << endl + << indent() << indent_str() + << "logging.exception('Unexpected exception in handler')" << endl + << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl + << indent() << indent_str() + << "result = TApplicationException(TApplicationException.INTERNAL_ERROR, " + "'Internal error')" + << endl + << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() + << "\", msg_type, seqid)" << endl + << indent() << "result.write(oprot)" << endl + << indent() << "oprot.writeMessageEnd()" << endl + << indent() << "oprot.trans.flush()" << endl; + } else { + f_service_ << indent() << "except Exception:" << endl + << indent() << indent_str() + << "logging.exception('Exception in oneway handler')" << endl; + } + indent_down(); + + } else if (gen_tornado_) { + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + if (!tfunction->is_oneway()) { + indent(f_service_) << "msg_type = TMessageType.REPLY" << endl; + } + f_service_ << indent() << "try:" << endl; + indent_up(); + f_service_ << indent(); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + f_service_ << "result.success = "; + } + f_service_ << "yield gen.maybe_future(self._handler." << tfunction->get_name() << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "args." << (*f_iter)->get_name(); + } + f_service_ << "))" << endl; + + indent_down(); + if (!tfunction->is_oneway()) { + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + const string& xname = (*x_iter)->get_name(); + f_service_ << indent() << "except " << type_name((*x_iter)->get_type()) << " as " << xname + << ":" << endl + << indent() << indent_str() << "result." << xname << " = " << xname << endl; + } + } + f_service_ << indent() << "except TTransport.TTransportException:" << endl + << indent() << indent_str() << "raise" << endl; + if (!tfunction->is_oneway()) { + f_service_ << indent() << "except TApplicationException as ex:" << endl + << indent() << indent_str() + << "logging.exception('TApplication exception in handler')" << endl + << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl + << indent() << indent_str() << "result = ex" << endl + << indent() << "except Exception:" << endl + << indent() << indent_str() + << "logging.exception('Unexpected exception in handler')" << endl + << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl + << indent() << indent_str() + << "result = TApplicationException(TApplicationException.INTERNAL_ERROR, " + "'Internal error')" + << endl; + } else { + f_service_ << indent() << "except Exception:" << endl + << indent() << indent_str() + << "logging.exception('Exception in oneway handler')" << endl; + } + + if (!tfunction->is_oneway()) { + f_service_ << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() + << "\", msg_type, seqid)" << endl + << indent() << "result.write(oprot)" << endl + << indent() << "oprot.writeMessageEnd()" << endl + << indent() << "oprot.trans.flush()" << endl; + } + + // Close function + indent_down(); + + } else { // py + // Try block for a function with exceptions + // It also catches arbitrary exceptions raised by handler method to propagate them to the client + f_service_ << indent() << "try:" << endl; + indent_up(); + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + f_service_ << indent(); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + f_service_ << "result.success = "; + } + f_service_ << "self._handler." << tfunction->get_name() << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "args." << (*f_iter)->get_name(); + } + f_service_ << ")" << endl; + if (!tfunction->is_oneway()) { + f_service_ << indent() << "msg_type = TMessageType.REPLY" << endl; + } + + indent_down(); + f_service_ << indent() + << "except TTransport.TTransportException:" << endl + << indent() << indent_str() << "raise" << endl; + + if (!tfunction->is_oneway()) { + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + const string& xname = (*x_iter)->get_name(); + f_service_ << indent() << "except " << type_name((*x_iter)->get_type()) << " as " << xname + << ":" << endl; + indent_up(); + f_service_ << indent() << "msg_type = TMessageType.REPLY" << endl; + f_service_ << indent() << "result." << xname << " = " << xname << endl; + indent_down(); + } + + f_service_ << indent() << "except TApplicationException as ex:" << endl + << indent() << indent_str() + << "logging.exception('TApplication exception in handler')" << endl + << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl + << indent() << indent_str() << "result = ex" << endl + << indent() << "except Exception:" << endl + << indent() << indent_str() + << "logging.exception('Unexpected exception in handler')" << endl + << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl + << indent() << indent_str() + << "result = TApplicationException(TApplicationException.INTERNAL_ERROR, " + "'Internal error')" + << endl + << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() + << "\", msg_type, seqid)" << endl + << indent() << "result.write(oprot)" << endl + << indent() << "oprot.writeMessageEnd()" << endl + << indent() << "oprot.trans.flush()" << endl; + } else { + f_service_ << indent() << "except Exception:" << endl + << indent() << indent_str() << "logging.exception('Exception in oneway handler')" << endl; + } + + // Close function + indent_down(); + } +} + +/** + * Deserializes a field of any type. + */ +void t_py_generator::generate_deserialize_field(ofstream& out, + t_field* tfield, + string prefix) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = prefix + tfield->get_name(); + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name); + } else if (type->is_container()) { + generate_deserialize_container(out, type, name); + } else if (type->is_base_type() || type->is_enum()) { + indent(out) << name << " = iprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "readBinary()"; + } else if(!gen_utf8strings_) { + out << "readString()"; + } else { + out << "readString().decode('utf-8') if sys.version_info[0] == 2 else iprot.readString()"; + } + break; + case t_base_type::TYPE_BOOL: + out << "readBool()"; + break; + case t_base_type::TYPE_I8: + out << "readByte()"; + break; + case t_base_type::TYPE_I16: + out << "readI16()"; + break; + case t_base_type::TYPE_I32: + out << "readI32()"; + break; + case t_base_type::TYPE_I64: + out << "readI64()"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble()"; + break; + default: + throw "compiler error: no Python name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "readI32()"; + } + out << endl; + + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type->get_name().c_str()); + } +} + +/** + * Generates an unserializer for a struct, calling read() + */ +void t_py_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + if (is_immutable(tstruct)) { + out << indent() << prefix << " = " << type_name(tstruct) << ".read(iprot)" << endl; + } else { + out << indent() << prefix << " = " << type_name(tstruct) << "()" << endl + << indent() << prefix << ".read(iprot)" << endl; + } +} + +/** + * Serialize a container by writing out the header followed by + * data and then a footer. + */ +void t_py_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) { + string size = tmp("_size"); + string ktype = tmp("_ktype"); + string vtype = tmp("_vtype"); + string etype = tmp("_etype"); + + t_field fsize(g_type_i32, size); + t_field fktype(g_type_i8, ktype); + t_field fvtype(g_type_i8, vtype); + t_field fetype(g_type_i8, etype); + + // Declare variables, read header + if (ttype->is_map()) { + out << indent() << prefix << " = {}" << endl << indent() << "(" << ktype << ", " << vtype + << ", " << size << ") = iprot.readMapBegin()" << endl; + } else if (ttype->is_set()) { + out << indent() << prefix << " = set()" << endl << indent() << "(" << etype << ", " << size + << ") = iprot.readSetBegin()" << endl; + } else if (ttype->is_list()) { + out << indent() << prefix << " = []" << endl << indent() << "(" << etype << ", " << size + << ") = iprot.readListBegin()" << endl; + } + + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << + "for " << i << " in range(" << size << "):" << endl; + + indent_up(); + + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, prefix); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, prefix); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, prefix); + } + + indent_down(); + + // Read container end + if (ttype->is_map()) { + indent(out) << "iprot.readMapEnd()" << endl; + if (is_immutable(ttype)) { + indent(out) << prefix << " = TFrozenDict(" << prefix << ")" << endl; + } + } else if (ttype->is_set()) { + indent(out) << "iprot.readSetEnd()" << endl; + if (is_immutable(ttype)) { + indent(out) << prefix << " = frozenset(" << prefix << ")" << endl; + } + } else if (ttype->is_list()) { + if (is_immutable(ttype)) { + indent(out) << prefix << " = tuple(" << prefix << ")" << endl; + } + indent(out) << "iprot.readListEnd()" << endl; + } +} + +/** + * Generates code to deserialize a map + */ +void t_py_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) { + string key = tmp("_key"); + string val = tmp("_val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + generate_deserialize_field(out, &fkey); + generate_deserialize_field(out, &fval); + + indent(out) << prefix << "[" << key << "] = " << val << endl; +} + +/** + * Write a set element + */ +void t_py_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) { + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".add(" << elem << ")" << endl; +} + +/** + * Write a list element + */ +void t_py_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix) { + string elem = tmp("_elem"); + t_field felem(tlist->get_elem_type(), elem); + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".append(" << elem << ")" << endl; +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_py_generator::generate_serialize_field(ofstream& out, t_field* tfield, string prefix) { + t_type* type = get_true_type(tfield->get_type()); + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); + } else if (type->is_container()) { + generate_serialize_container(out, type, prefix + tfield->get_name()); + } else if (type->is_base_type() || type->is_enum()) { + + string name = prefix + tfield->get_name(); + + indent(out) << "oprot."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "writeBinary(" << name << ")"; + } else if (!gen_utf8strings_) { + out << "writeString(" << name << ")"; + } else { + out << "writeString(" << name << ".encode('utf-8') if sys.version_info[0] == 2 else " << name << ")"; + } + break; + case t_base_type::TYPE_BOOL: + out << "writeBool(" << name << ")"; + break; + case t_base_type::TYPE_I8: + out << "writeByte(" << name << ")"; + break; + case t_base_type::TYPE_I16: + out << "writeI16(" << name << ")"; + break; + case t_base_type::TYPE_I32: + out << "writeI32(" << name << ")"; + break; + case t_base_type::TYPE_I64: + out << "writeI64(" << name << ")"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble(" << name << ")"; + break; + default: + throw "compiler error: no Python name for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << "writeI32(" << name << ")"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", + prefix.c_str(), + tfield->get_name().c_str(), + type->get_name().c_str()); + } +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_py_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) { + (void)tstruct; + indent(out) << prefix << ".write(oprot)" << endl; +} + +void t_py_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + if (ttype->is_map()) { + indent(out) << "oprot.writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " + << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " + << "len(" << prefix << "))" << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " + << "len(" << prefix << "))" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) + << ", " + << "len(" << prefix << "))" << endl; + } + + if (ttype->is_map()) { + string kiter = tmp("kiter"); + string viter = tmp("viter"); + indent(out) << "for " << kiter << ", " << viter << " in " << prefix << ".items():" << endl; + indent_up(); + generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); + indent_down(); + } else if (ttype->is_set()) { + string iter = tmp("iter"); + indent(out) << "for " << iter << " in " << prefix << ":" << endl; + indent_up(); + generate_serialize_set_element(out, (t_set*)ttype, iter); + indent_down(); + } else if (ttype->is_list()) { + string iter = tmp("iter"); + indent(out) << "for " << iter << " in " << prefix << ":" << endl; + indent_up(); + generate_serialize_list_element(out, (t_list*)ttype, iter); + indent_down(); + } + + if (ttype->is_map()) { + indent(out) << "oprot.writeMapEnd()" << endl; + } else if (ttype->is_set()) { + indent(out) << "oprot.writeSetEnd()" << endl; + } else if (ttype->is_list()) { + indent(out) << "oprot.writeListEnd()" << endl; + } +} + +/** + * Serializes the members of a map. + * + */ +void t_py_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, + string kiter, + string viter) { + t_field kfield(tmap->get_key_type(), kiter); + generate_serialize_field(out, &kfield, ""); + + t_field vfield(tmap->get_val_type(), viter); + generate_serialize_field(out, &vfield, ""); +} + +/** + * Serializes the members of a set. + */ +void t_py_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) { + t_field efield(tset->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +/** + * Serializes the members of a list. + */ +void t_py_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) { + t_field efield(tlist->get_elem_type(), iter); + generate_serialize_field(out, &efield, ""); +} + +/** + * Generates the docstring for a given struct. + */ +void t_py_generator::generate_python_docstring(ofstream& out, t_struct* tstruct) { + generate_python_docstring(out, tstruct, tstruct, "Attributes"); +} + +/** + * Generates the docstring for a given function. + */ +void t_py_generator::generate_python_docstring(ofstream& out, t_function* tfunction) { + generate_python_docstring(out, tfunction, tfunction->get_arglist(), "Parameters"); +} + +/** + * Generates the docstring for a struct or function. + */ +void t_py_generator::generate_python_docstring(ofstream& out, + t_doc* tdoc, + t_struct* tstruct, + const char* subheader) { + bool has_doc = false; + stringstream ss; + if (tdoc->has_doc()) { + has_doc = true; + ss << tdoc->get_doc(); + } + + const vector& fields = tstruct->get_members(); + if (fields.size() > 0) { + if (has_doc) { + ss << endl; + } + has_doc = true; + ss << subheader << ":\n"; + vector::const_iterator p_iter; + for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { + t_field* p = *p_iter; + ss << " - " << p->get_name(); + if (p->has_doc()) { + ss << ": " << p->get_doc(); + } else { + ss << endl; + } + } + } + + if (has_doc) { + generate_docstring_comment(out, "\"\"\"\n", "", ss.str(), "\"\"\"\n"); + } +} + +/** + * Generates the docstring for a generic object. + */ +void t_py_generator::generate_python_docstring(ofstream& out, t_doc* tdoc) { + if (tdoc->has_doc()) { + generate_docstring_comment(out, "\"\"\"\n", "", tdoc->get_doc(), "\"\"\"\n"); + } +} + +/** + * Declares an argument, which may include initialization as necessary. + * + * @param tfield The field + */ +string t_py_generator::declare_argument(t_field* tfield) { + std::ostringstream result; + result << tfield->get_name() << "="; + if (tfield->get_value() != NULL) { + result << render_field_default_value(tfield); + } else { + result << "None"; + } + return result.str(); +} + +/** + * Renders a field default value, returns None otherwise. + * + * @param tfield The field + */ +string t_py_generator::render_field_default_value(t_field* tfield) { + t_type* type = get_true_type(tfield->get_type()); + if (tfield->get_value() != NULL) { + return render_const_value(type, tfield->get_value()); + } else { + return "None"; + } +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_py_generator::function_signature(t_function* tfunction, bool interface) { + vector pre; + vector post; + string signature = tfunction->get_name() + "("; + + if (!(gen_zope_interface_ && interface)) { + pre.push_back("self"); + } + + signature += argument_list(tfunction->get_arglist(), &pre, &post) + ")"; + return signature; +} + +/** + * Renders a field list + */ +string t_py_generator::argument_list(t_struct* tstruct, vector* pre, vector* post) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + vector::const_iterator s_iter; + bool first = true; + if (pre) { + for (s_iter = pre->begin(); s_iter != pre->end(); ++s_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + result += *s_iter; + } + } + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + result += (*f_iter)->get_name(); + } + if (post) { + for (s_iter = post->begin(); s_iter != post->end(); ++s_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + result += *s_iter; + } + } + return result; +} + +string t_py_generator::type_name(t_type* ttype) { + while (ttype->is_typedef()) { + ttype = ((t_typedef*)ttype)->get_type(); + } + + t_program* program = ttype->get_program(); + if (ttype->is_service()) { + return get_real_py_module(program, gen_twisted_, package_prefix_) + "." + ttype->get_name(); + } + if (program != NULL && program != program_) { + return get_real_py_module(program, gen_twisted_, package_prefix_) + ".ttypes." + ttype->get_name(); + } + return ttype->get_name(); +} + +/** + * Converts the parse type to a Python tyoe + */ +string t_py_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "TType.STRING"; + case t_base_type::TYPE_BOOL: + return "TType.BOOL"; + case t_base_type::TYPE_I8: + return "TType.BYTE"; + case t_base_type::TYPE_I16: + return "TType.I16"; + case t_base_type::TYPE_I32: + return "TType.I32"; + case t_base_type::TYPE_I64: + return "TType.I64"; + case t_base_type::TYPE_DOUBLE: + return "TType.DOUBLE"; + } + } else if (type->is_enum()) { + return "TType.I32"; + } else if (type->is_struct() || type->is_xception()) { + return "TType.STRUCT"; + } else if (type->is_map()) { + return "TType.MAP"; + } else if (type->is_set()) { + return "TType.SET"; + } else if (type->is_list()) { + return "TType.LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** See the comment inside generate_py_struct_definition for what this is. */ +string t_py_generator::type_to_spec_args(t_type* ttype) { + while (ttype->is_typedef()) { + ttype = ((t_typedef*)ttype)->get_type(); + } + + if (ttype->is_binary()) { + return "'BINARY'"; + } else if (gen_utf8strings_ && ttype->is_base_type() + && reinterpret_cast(ttype)->is_string()) { + return "'UTF8'"; + } else if (ttype->is_base_type() || ttype->is_enum()) { + return "None"; + } else if (ttype->is_struct() || ttype->is_xception()) { + return "[" + type_name(ttype) + ", None]"; + } else if (ttype->is_map()) { + return "(" + type_to_enum(((t_map*)ttype)->get_key_type()) + ", " + + type_to_spec_args(((t_map*)ttype)->get_key_type()) + ", " + + type_to_enum(((t_map*)ttype)->get_val_type()) + ", " + + type_to_spec_args(((t_map*)ttype)->get_val_type()) + ", " + + (is_immutable(ttype) ? "True" : "False") + ")"; + + } else if (ttype->is_set()) { + return "(" + type_to_enum(((t_set*)ttype)->get_elem_type()) + ", " + + type_to_spec_args(((t_set*)ttype)->get_elem_type()) + ", " + + (is_immutable(ttype) ? "True" : "False") + ")"; + + } else if (ttype->is_list()) { + return "(" + type_to_enum(((t_list*)ttype)->get_elem_type()) + ", " + + type_to_spec_args(((t_list*)ttype)->get_elem_type()) + ", " + + (is_immutable(ttype) ? "True" : "False") + ")"; + } + + throw "INVALID TYPE IN type_to_spec_args: " + ttype->get_name(); +} + +THRIFT_REGISTER_GENERATOR( + py, + "Python", + " zope.interface: Generate code for use with zope.interface.\n" + " twisted: Generate Twisted-friendly RPC services.\n" + " tornado: Generate code for use with Tornado.\n" + " no_utf8strings: Do not Encode/decode strings using utf8 in the generated code. Basically no effect for Python 3.\n" + " coding=CODING: Add file encoding declare in generated file.\n" + " slots: Generate code using slots for instance members.\n" + " dynamic: Generate dynamic code, less code generated but slower.\n" + " dynbase=CLS Derive generated classes from class CLS instead of TBase.\n" + " dynfrozen=CLS Derive generated immutable classes from class CLS instead of TFrozenBase.\n" + " dynexc=CLS Derive generated exceptions from CLS instead of TExceptionBase.\n" + " dynimport='from foo.bar import CLS'\n" + " Add an import line to generated code to find the dynbase class.\n" + " package_prefix='top.package.'\n" + " Package prefix for generated files.\n" + " old_style: Deprecated. Generate old-style classes.\n") diff --git a/compiler/cpp/src/thrift/generate/t_rb_generator.cc b/compiler/cpp/src/thrift/generate/t_rb_generator.cc new file mode 100644 index 0000000..924f6f6 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_rb_generator.cc @@ -0,0 +1,1263 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "thrift/platform.h" +#include "thrift/version.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * A subclass of std::ofstream that includes indenting functionality. + */ +class t_rb_ofstream : public std::ofstream { +private: + int indent_; + +public: + t_rb_ofstream() : std::ofstream(), indent_(0) {} + explicit t_rb_ofstream(const char* filename, + ios_base::openmode mode = ios_base::out, + int indent = 0) + : std::ofstream(filename, mode), indent_(indent) {} + + t_rb_ofstream& indent() { + for (int i = 0; i < indent_; ++i) { + *this << " "; + } + return *this; + } + + void indent_up() { indent_++; } + void indent_down() { indent_--; } +}; + +/** + * Ruby code generator. + * + */ +class t_rb_generator : public t_oop_generator { +public: + t_rb_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + require_rubygems_ = false; + namespaced_ = false; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("rubygems") == 0) { + require_rubygems_ = true; + } else if( iter->first.compare("namespaced") == 0) { + namespaced_ = true; + } else { + throw "unknown option ruby:" + iter->first; + } + } + + out_dir_base_ = "gen-rb"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_union(t_struct* tunion); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + t_rb_ofstream& render_const_value(t_rb_ofstream& out, t_type* type, t_const_value* value); + + /** + * Struct generation code + */ + + void generate_rb_struct(t_rb_ofstream& out, t_struct* tstruct, bool is_exception); + void generate_rb_struct_required_validator(t_rb_ofstream& out, t_struct* tstruct); + void generate_rb_union(t_rb_ofstream& out, t_struct* tstruct, bool is_exception); + void generate_rb_union_validator(t_rb_ofstream& out, t_struct* tstruct); + void generate_rb_function_helpers(t_function* tfunction); + void generate_rb_simple_constructor(t_rb_ofstream& out, t_struct* tstruct); + void generate_rb_simple_exception_constructor(t_rb_ofstream& out, t_struct* tstruct); + void generate_field_constants(t_rb_ofstream& out, t_struct* tstruct); + void generate_field_constructors(t_rb_ofstream& out, t_struct* tstruct); + void generate_field_defns(t_rb_ofstream& out, t_struct* tstruct); + void generate_field_data(t_rb_ofstream& out, + t_type* field_type, + const std::string& field_name, + t_const_value* field_value, + bool optional); + + /** + * Service-level generation functions + */ + + void generate_service_helpers(t_service* tservice); + void generate_service_interface(t_service* tservice); + void generate_service_client(t_service* tservice); + void generate_service_server(t_service* tservice); + void generate_process_function(t_service* tservice, t_function* tfunction); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(t_rb_ofstream& out, + t_field* tfield, + std::string prefix = "", + bool inclass = false); + + void generate_deserialize_struct(t_rb_ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_deserialize_container(t_rb_ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_deserialize_set_element(t_rb_ofstream& out, t_set* tset, std::string prefix = ""); + + void generate_deserialize_map_element(t_rb_ofstream& out, t_map* tmap, std::string prefix = ""); + + void generate_deserialize_list_element(t_rb_ofstream& out, + t_list* tlist, + std::string prefix = ""); + + void generate_serialize_field(t_rb_ofstream& out, t_field* tfield, std::string prefix = ""); + + void generate_serialize_struct(t_rb_ofstream& out, t_struct* tstruct, std::string prefix = ""); + + void generate_serialize_container(t_rb_ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_serialize_map_element(t_rb_ofstream& out, + t_map* tmap, + std::string kiter, + std::string viter); + + void generate_serialize_set_element(t_rb_ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(t_rb_ofstream& out, t_list* tlist, std::string iter); + + void generate_rdoc(t_rb_ofstream& out, t_doc* tdoc); + + /** + * Helper rendering functions + */ + + std::string rb_autogen_comment(); + std::string render_require_thrift(); + std::string render_includes(); + std::string declare_field(t_field* tfield); + std::string type_name(const t_type* ttype); + std::string full_type_name(const t_type* ttype); + std::string function_signature(t_function* tfunction, std::string prefix = ""); + std::string argument_list(t_struct* tstruct); + std::string type_to_enum(t_type* ttype); + std::string rb_namespace_to_path_prefix(std::string rb_namespace); + + std::vector ruby_modules(const t_program* p) { + std::string ns = p->get_namespace("rb"); + std::vector modules; + if (ns.empty()) { + return modules; + } + + std::string::iterator pos = ns.begin(); + while (true) { + std::string::iterator delim = std::find(pos, ns.end(), '.'); + modules.push_back(capitalize(std::string(pos, delim))); + pos = delim; + if (pos == ns.end()) { + break; + } + ++pos; + } + + return modules; + } + + void begin_namespace(t_rb_ofstream&, std::vector); + void end_namespace(t_rb_ofstream&, std::vector); + +private: + /** + * File streams + */ + + t_rb_ofstream f_types_; + t_rb_ofstream f_consts_; + t_rb_ofstream f_service_; + + std::string namespace_dir_; + std::string require_prefix_; + + /** If true, add a "require 'rubygems'" line to the top of each gen-rb file. */ + bool require_rubygems_; + + /** If true, generate files in idiomatic namespaced directories. */ + bool namespaced_; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_rb_generator::init_generator() { + string subdir = get_out_dir(); + + // Make output directory + MKDIR(subdir.c_str()); + + if (namespaced_) { + require_prefix_ = rb_namespace_to_path_prefix(program_->get_namespace("rb")); + + string dir = require_prefix_; + string::size_type loc; + + while ((loc = dir.find("/")) != string::npos) { + subdir = subdir + dir.substr(0, loc) + "/"; + MKDIR(subdir.c_str()); + dir = dir.substr(loc + 1); + } + } + + namespace_dir_ = subdir; + + // Make output file + string f_types_name = namespace_dir_ + underscore(program_name_) + "_types.rb"; + f_types_.open(f_types_name.c_str()); + + string f_consts_name = namespace_dir_ + underscore(program_name_) + "_constants.rb"; + f_consts_.open(f_consts_name.c_str()); + + // Print header + f_types_ << rb_autogen_comment() << endl << render_require_thrift() << render_includes() << endl; + begin_namespace(f_types_, ruby_modules(program_)); + + f_consts_ << rb_autogen_comment() << endl << render_require_thrift() << "require '" + << require_prefix_ << underscore(program_name_) << "_types'" << endl << endl; + begin_namespace(f_consts_, ruby_modules(program_)); +} + +/** + * Renders the require of thrift itself, and possibly of the rubygems dependency. + */ +string t_rb_generator::render_require_thrift() { + if (require_rubygems_) { + return "require 'rubygems'\nrequire 'thrift'\n"; + } else { + return "require 'thrift'\n"; + } +} + +/** + * Renders all the imports necessary for including another Thrift program + */ +string t_rb_generator::render_includes() { + const vector& includes = program_->get_includes(); + string result = ""; + for (size_t i = 0; i < includes.size(); ++i) { + if (namespaced_) { + t_program* included = includes[i]; + std::string included_require_prefix + = rb_namespace_to_path_prefix(included->get_namespace("rb")); + std::string included_name = included->get_name(); + result += "require '" + included_require_prefix + underscore(included_name) + "_types'\n"; + } else { + result += "require '" + underscore(includes[i]->get_name()) + "_types'\n"; + } + } + if (includes.size() > 0) { + result += "\n"; + } + return result; +} + +/** + * Autogen'd comment + */ +string t_rb_generator::rb_autogen_comment() { + return std::string("#\n") + "# Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + + "#\n" + "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "#\n"; +} + +/** + * Closes the type files + */ +void t_rb_generator::close_generator() { + // Close types file + end_namespace(f_types_, ruby_modules(program_)); + end_namespace(f_consts_, ruby_modules(program_)); + f_types_.close(); + f_consts_.close(); +} + +/** + * Generates a typedef. This is not done in Ruby, types are all implicit. + * + * @param ttypedef The type definition + */ +void t_rb_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + +/** + * Generates code for an enumerated type. Done using a class to scope + * the values. + * + * @param tenum The enumeration + */ +void t_rb_generator::generate_enum(t_enum* tenum) { + f_types_.indent() << "module " << capitalize(tenum->get_name()) << endl; + f_types_.indent_up(); + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + + // Ruby class constants have to be capitalized... omg i am so on the fence + // about languages strictly enforcing capitalization why can't we just all + // agree and play nice. + string name = capitalize((*c_iter)->get_name()); + + generate_rdoc(f_types_, *c_iter); + f_types_.indent() << name << " = " << value << endl; + } + + // Create a hash mapping values back to their names (as strings) since ruby has no native enum + // type + f_types_.indent() << "VALUE_MAP = {"; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + // Populate the hash + int value = (*c_iter)->get_value(); + if (c_iter != constants.begin()) + f_types_ << ", "; + f_types_ << value << " => \"" << capitalize((*c_iter)->get_name()) << "\""; + } + f_types_ << "}" << endl; + + // Create a set with valid values for this enum + f_types_.indent() << "VALID_VALUES = Set.new(["; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + // Populate the set + if (c_iter != constants.begin()) + f_types_ << ", "; + f_types_ << capitalize((*c_iter)->get_name()); + } + f_types_ << "]).freeze" << endl; + + f_types_.indent_down(); + f_types_.indent() << "end" << endl << endl; +} + +/** + * Generate a constant value + */ +void t_rb_generator::generate_const(t_const* tconst) { + t_type* type = tconst->get_type(); + string name = tconst->get_name(); + t_const_value* value = tconst->get_value(); + + name[0] = toupper(name[0]); + + f_consts_.indent() << name << " = "; + render_const_value(f_consts_, type, value) << endl << endl; +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +t_rb_ofstream& t_rb_generator::render_const_value(t_rb_ofstream& out, + t_type* type, + t_const_value* value) { + type = get_true_type(type); + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + out << "%q\"" << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + out << (value->get_integer() > 0 ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + out << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + out << value->get_integer(); + } else { + out << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out.indent() << value->get_integer(); + } else if (type->is_struct() || type->is_xception()) { + out << full_type_name(type) << ".new({" << endl; + out.indent_up(); + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + out.indent(); + render_const_value(out, g_type_string, v_iter->first) << " => "; + render_const_value(out, field_type, v_iter->second) << "," << endl; + } + out.indent_down(); + out.indent() << "})"; + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + out << "{" << endl; + out.indent_up(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + out.indent(); + render_const_value(out, ktype, v_iter->first) << " => "; + render_const_value(out, vtype, v_iter->second) << "," << endl; + } + out.indent_down(); + out.indent() << "}"; + } else if (type->is_list() || type->is_set()) { + t_type* etype; + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + if (type->is_set()) { + out << "Set.new([" << endl; + } else { + out << "[" << endl; + } + out.indent_up(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + out.indent(); + render_const_value(out, etype, *v_iter) << "," << endl; + } + out.indent_down(); + if (type->is_set()) { + out.indent() << "])"; + } else { + out.indent() << "]"; + } + } else { + throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); + } + return out; +} + +/** + * Generates a ruby struct + */ +void t_rb_generator::generate_struct(t_struct* tstruct) { + if (tstruct->is_union()) { + generate_rb_union(f_types_, tstruct, false); + } else { + generate_rb_struct(f_types_, tstruct, false); + } +} + +/** + * Generates a struct definition for a thrift exception. Basically the same + * as a struct but extends the Exception class. + * + * @param txception The struct definition + */ +void t_rb_generator::generate_xception(t_struct* txception) { + generate_rb_struct(f_types_, txception, true); +} + +/** + * Generates a ruby struct + */ +void t_rb_generator::generate_rb_struct(t_rb_ofstream& out, + t_struct* tstruct, + bool is_exception = false) { + generate_rdoc(out, tstruct); + out.indent() << "class " << type_name(tstruct); + if (is_exception) { + out << " < ::Thrift::Exception"; + } + out << endl; + + out.indent_up(); + out.indent() << "include ::Thrift::Struct, ::Thrift::Struct_Union" << endl; + + if (is_exception) { + generate_rb_simple_exception_constructor(out, tstruct); + } + + generate_field_constants(out, tstruct); + generate_field_defns(out, tstruct); + generate_rb_struct_required_validator(out, tstruct); + + out.indent() << "::Thrift::Struct.generate_accessors self" << endl; + + out.indent_down(); + out.indent() << "end" << endl << endl; +} + +/** + * Generates a ruby union + */ +void t_rb_generator::generate_rb_union(t_rb_ofstream& out, + t_struct* tstruct, + bool is_exception = false) { + (void)is_exception; + generate_rdoc(out, tstruct); + out.indent() << "class " << type_name(tstruct) << " < ::Thrift::Union" << endl; + + out.indent_up(); + out.indent() << "include ::Thrift::Struct_Union" << endl; + + generate_field_constructors(out, tstruct); + + generate_field_constants(out, tstruct); + generate_field_defns(out, tstruct); + generate_rb_union_validator(out, tstruct); + + out.indent() << "::Thrift::Union.generate_accessors self" << endl; + + out.indent_down(); + out.indent() << "end" << endl << endl; +} + +void t_rb_generator::generate_field_constructors(t_rb_ofstream& out, t_struct* tstruct) { + + out.indent() << "class << self" << endl; + out.indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (f_iter != fields.begin()) { + out << endl; + } + std::string field_name = (*f_iter)->get_name(); + + out.indent() << "def " << field_name << "(val)" << endl; + out.indent() << " " << tstruct->get_name() << ".new(:" << field_name << ", val)" << endl; + out.indent() << "end" << endl; + } + + out.indent_down(); + out.indent() << "end" << endl; + + out << endl; +} + +void t_rb_generator::generate_rb_simple_exception_constructor(t_rb_ofstream& out, + t_struct* tstruct) { + const vector& members = tstruct->get_members(); + + if (members.size() == 1) { + vector::const_iterator m_iter = members.begin(); + + if ((*m_iter)->get_type()->is_string()) { + string name = (*m_iter)->get_name(); + + out.indent() << "def initialize(message=nil)" << endl; + out.indent_up(); + out.indent() << "super()" << endl; + out.indent() << "self." << name << " = message" << endl; + out.indent_down(); + out.indent() << "end" << endl << endl; + + if (name != "message") { + out.indent() << "def message; " << name << " end" << endl << endl; + } + } + } +} + +void t_rb_generator::generate_field_constants(t_rb_ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + std::string field_name = (*f_iter)->get_name(); + std::string cap_field_name = upcase_string(field_name); + + out.indent() << cap_field_name << " = " << (*f_iter)->get_key() << endl; + } + out << endl; +} + +void t_rb_generator::generate_field_defns(t_rb_ofstream& out, t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out.indent() << "FIELDS = {" << endl; + out.indent_up(); + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (f_iter != fields.begin()) { + out << "," << endl; + } + + // generate the field docstrings within the FIELDS constant. no real better place... + generate_rdoc(out, *f_iter); + + out.indent() << upcase_string((*f_iter)->get_name()) << " => "; + + generate_field_data(out, + (*f_iter)->get_type(), + (*f_iter)->get_name(), + (*f_iter)->get_value(), + (*f_iter)->get_req() == t_field::T_OPTIONAL); + } + out.indent_down(); + out << endl; + out.indent() << "}" << endl << endl; + + out.indent() << "def struct_fields; FIELDS; end" << endl << endl; +} + +void t_rb_generator::generate_field_data(t_rb_ofstream& out, + t_type* field_type, + const std::string& field_name = "", + t_const_value* field_value = NULL, + bool optional = false) { + field_type = get_true_type(field_type); + + // Begin this field's defn + out << "{:type => " << type_to_enum(field_type); + + if (!field_name.empty()) { + out << ", :name => '" << field_name << "'"; + } + + if (field_value != NULL) { + out << ", :default => "; + render_const_value(out, field_type, field_value); + } + + if (!field_type->is_base_type()) { + if (field_type->is_struct() || field_type->is_xception()) { + out << ", :class => " << full_type_name((t_struct*)field_type); + } else if (field_type->is_list()) { + out << ", :element => "; + generate_field_data(out, ((t_list*)field_type)->get_elem_type()); + } else if (field_type->is_map()) { + out << ", :key => "; + generate_field_data(out, ((t_map*)field_type)->get_key_type()); + out << ", :value => "; + generate_field_data(out, ((t_map*)field_type)->get_val_type()); + } else if (field_type->is_set()) { + out << ", :element => "; + generate_field_data(out, ((t_set*)field_type)->get_elem_type()); + } + } else { + if (((t_base_type*)field_type)->is_binary()) { + out << ", :binary => true"; + } + } + + if (optional) { + out << ", :optional => true"; + } + + if (field_type->is_enum()) { + out << ", :enum_class => " << full_type_name(field_type); + } + + // End of this field's defn + out << "}"; +} + +void t_rb_generator::begin_namespace(t_rb_ofstream& out, vector modules) { + for (vector::iterator m_iter = modules.begin(); m_iter != modules.end(); ++m_iter) { + out.indent() << "module " << *m_iter << endl; + out.indent_up(); + } +} + +void t_rb_generator::end_namespace(t_rb_ofstream& out, vector modules) { + for (vector::reverse_iterator m_iter = modules.rbegin(); m_iter != modules.rend(); + ++m_iter) { + out.indent_down(); + out.indent() << "end" << endl; + } +} + +/** + * Generates a thrift service. + * + * @param tservice The service definition + */ +void t_rb_generator::generate_service(t_service* tservice) { + string f_service_name = namespace_dir_ + underscore(service_name_) + ".rb"; + f_service_.open(f_service_name.c_str()); + + f_service_ << rb_autogen_comment() << endl << render_require_thrift(); + + if (tservice->get_extends() != NULL) { + if (namespaced_) { + f_service_ << "require '" << rb_namespace_to_path_prefix( + tservice->get_extends()->get_program()->get_namespace("rb")) + << underscore(tservice->get_extends()->get_name()) << "'" << endl; + } else { + f_service_ << "require '" << require_prefix_ + << underscore(tservice->get_extends()->get_name()) << "'" << endl; + } + } + + f_service_ << "require '" << require_prefix_ << underscore(program_name_) << "_types'" << endl + << endl; + + begin_namespace(f_service_, ruby_modules(tservice->get_program())); + + f_service_.indent() << "module " << capitalize(tservice->get_name()) << endl; + f_service_.indent_up(); + + // Generate the three main parts of the service (well, two for now in PHP) + generate_service_client(tservice); + generate_service_server(tservice); + generate_service_helpers(tservice); + + f_service_.indent_down(); + f_service_.indent() << "end" << endl << endl; + + end_namespace(f_service_, ruby_modules(tservice->get_program())); + + // Close service file + f_service_.close(); +} + +/** + * Generates helper functions for a service. + * + * @param tservice The service to generate a header definition for + */ +void t_rb_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + f_service_.indent() << "# HELPER FUNCTIONS AND STRUCTURES" << endl << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_rb_struct(f_service_, ts); + generate_rb_function_helpers(*f_iter); + } +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_rb_generator::generate_rb_function_helpers(t_function* tfunction) { + t_struct result(program_, tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + generate_rb_struct(f_service_, &result); +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_rb_generator::generate_service_client(t_service* tservice) { + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() != NULL) { + extends = full_type_name(tservice->get_extends()); + extends_client = " < " + extends + "::Client "; + } + + f_service_.indent() << "class Client" << extends_client << endl; + f_service_.indent_up(); + + f_service_.indent() << "include ::Thrift::Client" << endl << endl; + + // Generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* arg_struct = (*f_iter)->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + string funname = (*f_iter)->get_name(); + + // Open function + f_service_.indent() << "def " << function_signature(*f_iter) << endl; + f_service_.indent_up(); + f_service_.indent() << "send_" << funname << "("; + + bool first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << (*fld_iter)->get_name(); + } + f_service_ << ")" << endl; + + if (!(*f_iter)->is_oneway()) { + f_service_.indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << "return "; + } + f_service_ << "recv_" << funname << "()" << endl; + } + f_service_.indent_down(); + f_service_.indent() << "end" << endl; + f_service_ << endl; + + f_service_.indent() << "def send_" << function_signature(*f_iter) << endl; + f_service_.indent_up(); + + std::string argsname = capitalize((*f_iter)->get_name() + "_args"); + std::string messageSendProc = (*f_iter)->is_oneway() ? "send_oneway_message" : "send_message"; + + f_service_.indent() << messageSendProc << "('" << funname << "', " << argsname; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << ", :" << (*fld_iter)->get_name() << " => " << (*fld_iter)->get_name(); + } + + f_service_ << ")" << endl; + + f_service_.indent_down(); + f_service_.indent() << "end" << endl; + + if (!(*f_iter)->is_oneway()) { + std::string resultname = capitalize((*f_iter)->get_name() + "_result"); + t_struct noargs(program_); + + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + &noargs); + // Open function + f_service_ << endl; + f_service_.indent() << "def " << function_signature(&recv_function) << endl; + f_service_.indent_up(); + + // TODO(mcslee): Validate message reply here, seq ids etc. + + f_service_.indent() << "result = receive_message(" << resultname << ")" << endl; + + // Careful, only return _result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_.indent() << "return result.success unless result.success.nil?" << endl; + } + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_.indent() << "raise result." << (*x_iter)->get_name() << " unless result." + << (*x_iter)->get_name() << ".nil?" << endl; + } + + // Careful, only return _result if not a void function + if ((*f_iter)->get_returntype()->is_void()) { + f_service_.indent() << "return" << endl; + } else { + f_service_.indent() << "raise " + "::Thrift::ApplicationException.new(::Thrift::ApplicationException::" + "MISSING_RESULT, '" << (*f_iter)->get_name() + << " failed: unknown result')" << endl; + } + + // Close function + f_service_.indent_down(); + f_service_.indent() << "end" << endl << endl; + } + } + + f_service_.indent_down(); + f_service_.indent() << "end" << endl << endl; +} + +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_rb_generator::generate_service_server(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() != NULL) { + extends = full_type_name(tservice->get_extends()); + extends_processor = " < " + extends + "::Processor "; + } + + // Generate the header portion + f_service_.indent() << "class Processor" << extends_processor << endl; + f_service_.indent_up(); + + f_service_.indent() << "include ::Thrift::Processor" << endl << endl; + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(tservice, *f_iter); + } + + f_service_.indent_down(); + f_service_.indent() << "end" << endl << endl; +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_rb_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + (void)tservice; + // Open function + f_service_.indent() << "def process_" << tfunction->get_name() << "(seqid, iprot, oprot)" << endl; + f_service_.indent_up(); + + string argsname = capitalize(tfunction->get_name()) + "_args"; + string resultname = capitalize(tfunction->get_name()) + "_result"; + + f_service_.indent() << "args = read_args(iprot, " << argsname << ")" << endl; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + // Declare result for non oneway function + if (!tfunction->is_oneway()) { + f_service_.indent() << "result = " << resultname << ".new()" << endl; + } + + // Try block for a function with exceptions + if (xceptions.size() > 0) { + f_service_.indent() << "begin" << endl; + f_service_.indent_up(); + } + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + f_service_.indent(); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + f_service_ << "result.success = "; + } + f_service_ << "@handler." << tfunction->get_name() << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << "args." << (*f_iter)->get_name(); + } + f_service_ << ")" << endl; + + if (!tfunction->is_oneway() && xceptions.size() > 0) { + f_service_.indent_down(); + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_.indent() << "rescue " << full_type_name((*x_iter)->get_type()) << " => " + << (*x_iter)->get_name() << endl; + if (!tfunction->is_oneway()) { + f_service_.indent_up(); + f_service_.indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() + << endl; + f_service_.indent_down(); + } + } + f_service_.indent() << "end" << endl; + } + + // Shortcut out here for oneway functions + if (tfunction->is_oneway()) { + f_service_.indent() << "return" << endl; + f_service_.indent_down(); + f_service_.indent() << "end" << endl << endl; + return; + } + + f_service_.indent() << "write_result(result, oprot, '" << tfunction->get_name() << "', seqid)" + << endl; + + // Close function + f_service_.indent_down(); + f_service_.indent() << "end" << endl << endl; +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_rb_generator::function_signature(t_function* tfunction, string prefix) { + // TODO(mcslee): Nitpicky, no ',' if argument_list is empty + return prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")"; +} + +/** + * Renders a field list + */ +string t_rb_generator::argument_list(t_struct* tstruct) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + result += (*f_iter)->get_name(); + } + return result; +} + +string t_rb_generator::type_name(const t_type* ttype) { + string prefix = ""; + + string name = ttype->get_name(); + if (ttype->is_struct() || ttype->is_xception() || ttype->is_enum()) { + name = capitalize(ttype->get_name()); + } + + return prefix + name; +} + +string t_rb_generator::full_type_name(const t_type* ttype) { + string prefix = "::"; + vector modules = ruby_modules(ttype->get_program()); + for (vector::iterator m_iter = modules.begin(); m_iter != modules.end(); ++m_iter) { + prefix += *m_iter + "::"; + } + return prefix + type_name(ttype); +} + +/** + * Converts the parse type to a Ruby tyoe + */ +string t_rb_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "::Thrift::Types::STRING"; + case t_base_type::TYPE_BOOL: + return "::Thrift::Types::BOOL"; + case t_base_type::TYPE_I8: + return "::Thrift::Types::BYTE"; + case t_base_type::TYPE_I16: + return "::Thrift::Types::I16"; + case t_base_type::TYPE_I32: + return "::Thrift::Types::I32"; + case t_base_type::TYPE_I64: + return "::Thrift::Types::I64"; + case t_base_type::TYPE_DOUBLE: + return "::Thrift::Types::DOUBLE"; + } + } else if (type->is_enum()) { + return "::Thrift::Types::I32"; + } else if (type->is_struct() || type->is_xception()) { + return "::Thrift::Types::STRUCT"; + } else if (type->is_map()) { + return "::Thrift::Types::MAP"; + } else if (type->is_set()) { + return "::Thrift::Types::SET"; + } else if (type->is_list()) { + return "::Thrift::Types::LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +string t_rb_generator::rb_namespace_to_path_prefix(string rb_namespace) { + string namespaces_left = rb_namespace; + string::size_type loc; + + string path_prefix = ""; + + while ((loc = namespaces_left.find(".")) != string::npos) { + path_prefix = path_prefix + underscore(namespaces_left.substr(0, loc)) + "/"; + namespaces_left = namespaces_left.substr(loc + 1); + } + if (namespaces_left.size() > 0) { + path_prefix = path_prefix + underscore(namespaces_left) + "/"; + } + return path_prefix; +} + +void t_rb_generator::generate_rdoc(t_rb_ofstream& out, t_doc* tdoc) { + if (tdoc->has_doc()) { + out.indent(); + generate_docstring_comment(out, "", "# ", tdoc->get_doc(), ""); + } +} + +void t_rb_generator::generate_rb_struct_required_validator(t_rb_ofstream& out, t_struct* tstruct) { + out.indent() << "def validate" << endl; + out.indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = (*f_iter); + if (field->get_req() == t_field::T_REQUIRED) { + out.indent() << "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, " + "'Required field " << field->get_name() << " is unset!')"; + if (field->get_type()->is_bool()) { + out << " if @" << field->get_name() << ".nil?"; + } else { + out << " unless @" << field->get_name(); + } + out << endl; + } + } + + // if field is an enum, check that its value is valid + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* field = (*f_iter); + + if (field->get_type()->is_enum()) { + out.indent() << "unless @" << field->get_name() << ".nil? || " + << full_type_name(field->get_type()) << "::VALID_VALUES.include?(@" + << field->get_name() << ")" << endl; + out.indent_up(); + out.indent() << "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, " + "'Invalid value of field " << field->get_name() << "!')" << endl; + out.indent_down(); + out.indent() << "end" << endl; + } + } + + out.indent_down(); + out.indent() << "end" << endl << endl; +} + +void t_rb_generator::generate_rb_union_validator(t_rb_ofstream& out, t_struct* tstruct) { + out.indent() << "def validate" << endl; + out.indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out.indent() + << "raise(StandardError, 'Union fields are not set.') if get_set_field.nil? || get_value.nil?" + << endl; + + // if field is an enum, check that its value is valid + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + const t_field* field = (*f_iter); + + if (field->get_type()->is_enum()) { + out.indent() << "if get_set_field == :" << field->get_name() << endl; + out.indent() << " raise " + "::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, " + "'Invalid value of field " << field->get_name() << "!') unless " + << full_type_name(field->get_type()) << "::VALID_VALUES.include?(get_value)" + << endl; + out.indent() << "end" << endl; + } + } + + out.indent_down(); + out.indent() << "end" << endl << endl; +} + +THRIFT_REGISTER_GENERATOR( + rb, + "Ruby", + " rubygems: Add a \"require 'rubygems'\" line to the top of each generated file.\n" + " namespaced: Generate files in idiomatic namespaced directories.\n") diff --git a/compiler/cpp/src/thrift/generate/t_rs_generator.cc b/compiler/cpp/src/thrift/generate/t_rs_generator.cc new file mode 100644 index 0000000..28c57f8 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_rs_generator.cc @@ -0,0 +1,3280 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::vector; +using std::set; + +static const string endl("\n"); // avoid ostream << std::endl flushes +static const string SERVICE_RESULT_VARIABLE("result_value"); +static const string RESULT_STRUCT_SUFFIX("Result"); +static const string RUST_RESERVED_WORDS[] = { + "abstract", "alignof", "as", "become", + "box", "break", "const", "continue", + "crate", "do", "else", "enum", + "extern", "false", "final", "fn", + "for", "if", "impl", "in", + "let", "loop", "macro", "match", + "mod", "move", "mut", "offsetof", + "override", "priv", "proc", "pub", + "pure", "ref", "return", "Self", + "self", "sizeof", "static", "struct", + "super", "trait", "true", "type", + "typeof", "unsafe", "unsized", "use", + "virtual", "where", "while", "yield" +}; +const set RUST_RESERVED_WORDS_SET( + RUST_RESERVED_WORDS, + RUST_RESERVED_WORDS + sizeof(RUST_RESERVED_WORDS)/sizeof(RUST_RESERVED_WORDS[0]) +); + +static const string SYNC_CLIENT_GENERIC_BOUND_VARS(""); +static const string SYNC_CLIENT_GENERIC_BOUNDS("where IP: TInputProtocol, OP: TOutputProtocol"); + +// FIXME: extract common TMessageIdentifier function +// FIXME: have to_rust_type deal with Option + +class t_rs_generator : public t_generator { +public: + t_rs_generator( + t_program* program, + const std::map&, + const std::string& + ) : t_generator(program) { + gen_dir_ = get_out_dir(); + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + +private: + // struct type + // T_REGULAR: user-defined struct in the IDL + // T_ARGS: struct used to hold all service-call parameters + // T_RESULT: struct used to hold all service-call returns and exceptions + // T_EXCEPTION: user-defined exception in the IDL + enum e_struct_type { T_REGULAR, T_ARGS, T_RESULT, T_EXCEPTION }; + + // Directory to which generated code is written. + string gen_dir_; + + // File to which generated code is written. + std::ofstream f_gen_; + + // Write the common compiler attributes and module includes to the top of the auto-generated file. + void render_attributes_and_includes(); + + // Create the closure of Rust modules referenced by this service. + void compute_service_referenced_modules(t_service *tservice, set &referenced_modules); + + // Write the rust representation of an enum. + void render_enum_definition(t_enum* tenum, const string& enum_name); + + // Write the impl blocks associated with the traits necessary to convert an enum to/from an i32. + void render_enum_conversion(t_enum* tenum, const string& enum_name); + + // Write the impl block associated with the rust representation of an enum. This includes methods + // to write the enum to a protocol, read it from a protocol, etc. + void render_enum_impl(const string& enum_name); + + // Write a simple rust const value (ie. `pub const FOO: foo...`). + void render_const_value(const string& name, t_type* ttype, t_const_value* tvalue); + + // Write a constant list, set, map or struct. These constants require allocation and cannot be defined + // using a 'pub const'. As a result, I create a holder struct with a single `const_value` method that + // returns the initialized instance. + void render_const_value_holder(const string& name, t_type* ttype, t_const_value* tvalue); + + // Write the actual const value - the right side of a const definition. + void render_const_value(t_type* ttype, t_const_value* tvalue); + + // Write a const struct (returned from `const_value` method). + void render_const_struct(t_type* ttype, t_const_value* tvalue); + + // Write a const list (returned from `const_value` method). + void render_const_list(t_type* ttype, t_const_value* tvalue); + + // Write a const set (returned from `const_value` method). + void render_const_set(t_type* ttype, t_const_value* tvalue); + + // Write a const map (returned from `const_value` method). + void render_const_map(t_type* ttype, t_const_value* tvalue); + + // Write the code to insert constant values into a rust vec or set. The + // `insert_function` is the rust function that we'll use to insert the elements. + void render_container_const_value( + const string& insert_function, + t_type* ttype, + t_const_value* tvalue + ); + + // Write the rust representation of a thrift struct to the generated file. Set `struct_type` to `T_ARGS` + // if rendering the struct used to pack arguments for a service call. When `struct_type` is `T_ARGS` the + // struct and its members have module visibility, and all fields are required. When `struct_type` is + // anything else the struct and its members have public visibility and fields have the visibility set + // in their definition. + void render_struct(const string& struct_name, t_struct* tstruct, t_rs_generator::e_struct_type struct_type); + + // Write the comment block preceding a type definition (and implementation). + void render_type_comment(const string& struct_name); + + // Write the rust representation of a thrift struct. Supports argument structs, result structs, + // user-defined structs and exception structs. The exact struct type to be generated is controlled + // by the `struct_type` parameter, which (among other things) modifies the visibility of the + // written struct and members, controls which trait implementations are generated. + void render_struct_definition( + const string& struct_name, + t_struct* tstruct, + t_rs_generator::e_struct_type struct_type + ); + + // Writes the impl block associated with the rust representation of a struct. At minimum this + // contains the methods to read from a protocol and write to a protocol. Additional methods may + // be generated depending on `struct_type`. + void render_struct_impl( + const string& struct_name, + t_struct* tstruct, + t_rs_generator::e_struct_type struct_type + ); + + // Generate a `fn new(...)` for a struct with name `struct_name` and type `t_struct`. The auto-generated + // code may include generic type parameters to make the constructor more ergonomic. `struct_type` controls + // the visibility of the generated constructor. + void render_struct_constructor( + const string& struct_name, + t_struct* tstruct, + t_rs_generator::e_struct_type struct_type + ); + + // Write the `ok_or` method added to all Thrift service call result structs. You can use this method + // to convert a struct into a `Result` and use it in a `try!` or combinator chain. + void render_result_struct_to_result_method(t_struct* tstruct); + + // Write the implementations for the `Error` and `Debug` traits. These traits are necessary for a + // user-defined exception to be properly handled as Rust errors. + void render_exception_struct_error_trait_impls(const string& struct_name, t_struct* tstruct); + + // Write the implementations for the `Default`. This trait allows you to specify only the fields you want + // and use `..Default::default()` to fill in the rest. + void render_struct_default_trait_impl(const string& struct_name, t_struct* tstruct); + + // Write the function that serializes a struct to its wire representation. If `struct_type` is `T_ARGS` + // then all fields are considered "required", if not, the default optionality is used. + void render_struct_sync_write(t_struct *tstruct, t_rs_generator::e_struct_type struct_type); + + // Helper function that serializes a single struct field to its wire representation. Unpacks the + // variable (since it may be optional) and serializes according to the optionality rules required by `req`. + // Variables in auto-generated code are passed by reference. Since this function may be called in + // contexts where the variable is *already* a reference you can set `field_var_is_ref` to `true` to avoid + // generating an extra, unnecessary `&` that the compiler will have to automatically dereference. + void render_struct_field_sync_write( + const string &field_var, + bool field_var_is_ref, + t_field *tfield, + t_field::e_req req); + + // Write the rust function that serializes a single type (i.e. a i32 etc.) to its wire representation. + // Variables in auto-generated code are passed by reference. Since this function may be called in + // contexts where the variable is *already* a reference you can set `type_var_is_ref` to `true` to avoid + // generating an extra, unnecessary `&` that the compiler will have to automatically dereference. + void render_type_sync_write(const string &type_var, bool type_var_is_ref, t_type *ttype); + + // Write a list to the output protocol. `list_variable` is the variable containing the list + // that will be written to the output protocol. + // Variables in auto-generated code are passed by reference. Since this function may be called in + // contexts where the variable is *already* a reference you can set `list_var_is_ref` to `true` to avoid + // generating an extra, unnecessary `&` that the compiler will have to automatically dereference. + void render_list_sync_write(const string &list_var, bool list_var_is_ref, t_list *tlist); + + // Write a set to the output protocol. `set_variable` is the variable containing the set that will + // be written to the output protocol. + // Variables in auto-generated code are passed by reference. Since this function may be called in + // contexts where the variable is *already* a reference you can set `set_var_is_ref` to `true` to avoid + // generating an extra, unnecessary `&` that the compiler will have to automatically dereference. + void render_set_sync_write(const string &set_var, bool set_var_is_ref, t_set *tset); + + // Write a map to the output protocol. `map_variable` is the variable containing the map that will + // be written to the output protocol. + // Variables in auto-generated code are passed by reference. Since this function may be called in + // contexts where the variable is *already* a reference you can set `map_var_is_ref` to `true` to avoid + // generating an extra, unnecessary `&` that the compiler will have to automatically dereference. + void render_map_sync_write(const string &map_var, bool map_var_is_ref, t_map *tset); + + // Return `true` if we need to dereference ths type when writing an element from a container. + // Iterations on rust containers are performed as follows: `for v in &values { ... }` + // where `v` has type `&RUST_TYPE` All defined functions take primitives by value, so, if the + // rendered code is calling such a function it has to dereference `v`. + bool needs_deref_on_container_write(t_type* ttype); + + // Return the variable (including all dereferences) required to write values from a rust container + // to the output protocol. For example, if you were iterating through a container and using the temp + // variable `v` to represent each element, then `ttype` is the type stored in the container and + // `base_var` is "v". The return value is the actual string you will have to use to properly reference + // the temp variable for writing to the output protocol. + string string_container_write_variable(t_type* ttype, const string& base_var); + + // Write the code to read bytes from the wire into the given `t_struct`. `struct_name` is the + // actual Rust name of the `t_struct`. If `struct_type` is `T_ARGS` then all struct fields are + // necessary. Otherwise, the field's default optionality is used. + void render_struct_sync_read(const string &struct_name, t_struct *tstruct, t_rs_generator::e_struct_type struct_type); + + // Write the rust function that deserializes a single type (i.e. i32 etc.) from its wire representation. + // Set `is_boxed` to `true` if the resulting value should be wrapped in a `Box::new(...)`. + void render_type_sync_read(const string &type_var, t_type *ttype, bool is_boxed = false); + + // Read the wire representation of a list and convert it to its corresponding rust implementation. + // The deserialized list is stored in `list_variable`. + void render_list_sync_read(t_list *tlist, const string &list_variable); + + // Read the wire representation of a set and convert it to its corresponding rust implementation. + // The deserialized set is stored in `set_variable`. + void render_set_sync_read(t_set *tset, const string &set_variable); + + // Read the wire representation of a map and convert it to its corresponding rust implementation. + // The deserialized map is stored in `map_variable`. + void render_map_sync_read(t_map *tmap, const string &map_variable); + + // Return a temporary variable used to store values when deserializing nested containers. + string struct_field_read_temp_variable(t_field* tfield); + + // Top-level function that calls the various render functions necessary to write the rust representation + // of a thrift union (i.e. an enum). + void render_union(t_struct* tstruct); + + // Write the enum corresponding to the Thrift union. + void render_union_definition(const string& union_name, t_struct* tstruct); + + // Write the enum impl (with read/write functions) for the Thrift union. + void render_union_impl(const string& union_name, t_struct* tstruct); + + // Write the `ENUM::write_to_out_protocol` function. + void render_union_sync_write(const string &union_name, t_struct *tstruct); + + // Write the `ENUM::read_from_in_protocol` function. + void render_union_sync_read(const string &union_name, t_struct *tstruct); + + // Top-level function that calls the various render functions necessary to write the rust representation + // of a Thrift client. + void render_sync_client(t_service* tservice); + + // Write the trait with the service-call methods for `tservice`. + void render_sync_client_trait(t_service *tservice); + + // Write the trait to be implemented by the client impl if end users can use it to make service calls. + void render_sync_client_marker_trait(t_service *tservice); + + // Write the code to create the Thrift service sync client struct and its matching 'impl' block. + void render_sync_client_definition_and_impl(const string& client_impl_name); + + // Write the code to create the `SyncClient::new` functions as well as any other functions + // callers would like to use on the Thrift service sync client. + void render_sync_client_lifecycle_functions(const string& client_struct); + + // Write the code to create the impl block for the `TThriftClient` trait. Since generated + // Rust Thrift clients perform all their operations using methods defined in this trait, we + // have to implement it for the client structs. + void render_sync_client_tthriftclient_impl(const string &client_impl_name); + + // Write the marker traits for any service(s) being extended, including the one for the current + // service itself (i.e. `tservice`) + void render_sync_client_marker_trait_impls(t_service *tservice, const string &impl_struct_name); + + // Generate a list of all the traits this Thrift client struct extends. + string sync_client_marker_traits_for_extension(t_service *tservice); + + // Top-level function that writes the code to make the Thrift service calls. + void render_sync_client_process_impl(t_service* tservice); + + // Write the actual function that calls out to the remote service and processes its response. + void render_sync_send_recv_wrapper(t_function* tfunc); + + // Write the `send` functionality for a Thrift service call represented by a `t_service->t_function`. + void render_sync_send(t_function* tfunc); + + // Write the `recv` functionality for a Thrift service call represented by a `t_service->t_function`. + // This method is only rendered if the function is *not* oneway. + void render_sync_recv(t_function* tfunc); + + void render_sync_processor(t_service *tservice); + + void render_sync_handler_trait(t_service *tservice); + void render_sync_processor_definition_and_impl(t_service *tservice); + void render_sync_process_delegation_functions(t_service *tservice); + void render_sync_process_function(t_function *tfunc, const string &handler_type); + void render_process_match_statements(t_service* tservice); + void render_sync_handler_succeeded(t_function *tfunc); + void render_sync_handler_failed(t_function *tfunc); + void render_sync_handler_failed_user_exception_branch(t_function *tfunc); + void render_sync_handler_failed_application_exception_branch(t_function *tfunc, const string &app_err_var); + void render_sync_handler_failed_default_exception_branch(t_function *tfunc); + void render_sync_handler_send_exception_response(t_function *tfunc, const string &err_var); + void render_service_call_structs(t_service* tservice); + void render_result_value_struct(t_function* tfunc); + + string handler_successful_return_struct(t_function* tfunc); + + // Writes the result of `render_rift_error_struct` wrapped in an `Err(thrift::Error(...))`. + void render_rift_error( + const string& error_kind, + const string& error_struct, + const string& sub_error_kind, + const string& error_message + ); + + // Write a thrift::Error variant struct. Error structs take the form: + // ``` + // pub struct error_struct { + // kind: sub_error_kind, + // message: error_message, + // } + // ``` + // A concrete example is: + // ``` + // pub struct ApplicationError { + // kind: ApplicationErrorKind::Unknown, + // message: "This is some error message", + // } + // ``` + void render_rift_error_struct( + const string& error_struct, + const string& sub_error_kind, + const string& error_message + ); + + // Return a string containing all the unpacked service call args given a service call function + // `t_function`. Prepends the args with either `&mut self` or `&self` and includes the arg types + // in the returned string, for example: + // `fn foo(&mut self, field_0: String)`. + string rust_sync_service_call_declaration(t_function* tfunc, bool self_is_mutable); + + // Return a string containing all the unpacked service call args given a service call function + // `t_function`. Only includes the arg names, each of which is prefixed with the optional prefix + // `field_prefix`, for example: `self.field_0`. + string rust_sync_service_call_invocation(t_function* tfunc, const string& field_prefix = ""); + + // Return a string containing all fields in the struct `tstruct` for use in a function declaration. + // Each field is followed by its type, for example: `field_0: String`. + string struct_to_declaration(t_struct* tstruct, t_rs_generator::e_struct_type struct_type); + + // Return a string containing all fields in the struct `tstruct` for use in a function call, + // for example: `field_0: String`. + string struct_to_invocation(t_struct* tstruct, const string& field_prefix = ""); + + // Write the documentation for a struct, service-call or other documentation-annotated element. + void render_rustdoc(t_doc* tdoc); + + // Return `true` if the true type of `ttype` is a thrift double, `false` otherwise. + bool is_double(t_type* ttype); + + // Return a string representing the rust type given a `t_type`. + string to_rust_type(t_type* ttype, bool ordered_float = true); + + // Return a string representing the rift `protocol::TType` given a `t_type`. + string to_rust_field_type_enum(t_type* ttype); + + // Return the default value to be used when initializing a struct field which has `OPT_IN_REQ_OUT` + // optionality. + string opt_in_req_out_value(t_type* ttype); + + // Return `true` if we can write a const of the form `pub const FOO: ...`. + bool can_generate_simple_const(t_type* ttype); + + // Return `true` if we cannot write a standard Rust constant (because the type needs some allocation). + bool can_generate_const_holder(t_type* ttype); + + // Return `true` if this type is a void, and should be represented by the rust `()` type. + bool is_void(t_type* ttype); + + t_field::e_req actual_field_req(t_field* tfield, t_rs_generator::e_struct_type struct_type); + + // Return `true` if this `t_field::e_req` is either `t_field::T_OPTIONAL` or `t_field::T_OPT_IN_REQ_OUT` + // and needs to be wrapped by an `Option`, `false` otherwise. + bool is_optional(t_field::e_req req); + + // Return `true` if the service call has arguments, `false` otherwise. + bool has_args(t_function* tfunc); + + // Return `true` if a service call has non-`()` arguments, `false` otherwise. + bool has_non_void_args(t_function* tfunc); + + // Return `pub ` (notice trailing whitespace!) if the struct should be public, `` (empty string) otherwise. + string visibility_qualifier(t_rs_generator::e_struct_type struct_type); + + // Returns the namespace prefix for a given Thrift service. If the type is defined in the presently-computed + // Thrift program, then an empty string is returned. + string rust_namespace(t_service* tservice); + + // Returns the namespace prefix for a given Thrift type. If the type is defined in the presently-computed + // Thrift program, then an empty string is returned. + string rust_namespace(t_type* ttype); + + // Returns the camel-cased name for a Rust struct type. Handles the case where `tstruct->get_name()` is + // a reserved word. + string rust_struct_name(t_struct* tstruct); + + // Returns the snake-cased name for a Rust field or local variable. Handles the case where + // `tfield->get_name()` is a reserved word. + string rust_field_name(t_field* tstruct); + + // Returns the camel-cased name for a Rust union type. Handles the case where `tstruct->get_name()` is + // a reserved word. + string rust_union_field_name(t_field* tstruct); + + // Converts any variable name into a 'safe' variant that does not clash with any Rust reserved keywords. + string rust_safe_name(const string& name); + + // Return `true` if the name is a reserved Rust keyword, `false` otherwise. + bool is_reserved(const string& name); + + // Return the name of the function that users will invoke to make outgoing service calls. + string service_call_client_function_name(t_function* tfunc); + + // Return the name of the function that users will have to implement to handle incoming service calls. + string service_call_handler_function_name(t_function* tfunc); + + // Return the name of the struct used to pack the return value + // and user-defined exceptions for the thrift service call. + string service_call_result_struct_name(t_function* tfunc); + + string rust_sync_client_marker_trait_name(t_service* tservice); + + // Return the trait name for the sync service client given a `t_service`. + string rust_sync_client_trait_name(t_service* tservice); + + // Return the name for the sync service client struct given a `t_service`. + string rust_sync_client_impl_name(t_service* tservice); + + // Return the trait name that users will have to implement for the server half of a Thrift service. + string rust_sync_handler_trait_name(t_service* tservice); + + // Return the struct name for the server half of a Thrift service. + string rust_sync_processor_name(t_service* tservice); + + // Return the struct name for the struct that contains all the service-call implementations for + // the server half of a Thrift service. + string rust_sync_processor_impl_name(t_service *tservice); + + // Properly uppercase names for use in Rust. + string rust_upper_case(const string& name); + + // Snake-case field, parameter and function names and make them Rust friendly. + string rust_snake_case(const string& name); + + // Camel-case type/variant names and make them Rust friendly. + string rust_camel_case(const string& name); + + // Replace all instances of `search_string` with `replace_string` in `target`. + void string_replace(string& target, const string& search_string, const string& replace_string); +}; + +void t_rs_generator::init_generator() { + // make output directory for this thrift program + MKDIR(gen_dir_.c_str()); + + // create the file into which we're going to write the generated code + string f_gen_name = gen_dir_ + "/" + rust_snake_case(get_program()->get_name()) + ".rs"; + f_gen_.open(f_gen_name.c_str()); + + // header comment + f_gen_ << "// " << autogen_summary() << endl; + f_gen_ << "// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING" << endl; + f_gen_ << endl; + + render_attributes_and_includes(); +} + +void t_rs_generator::render_attributes_and_includes() { + // turn off some compiler/clippy warnings + + // code always includes BTreeMap/BTreeSet/OrderedFloat + f_gen_ << "#![allow(unused_imports)]" << endl; + // code might not include imports from crates + f_gen_ << "#![allow(unused_extern_crates)]" << endl; + // constructors take *all* struct parameters, which can trigger the "too many arguments" warning + // some auto-gen'd types can be deeply nested. clippy recommends factoring them out which is hard to autogen + f_gen_ << "#![cfg_attr(feature = \"cargo-clippy\", allow(too_many_arguments, type_complexity))]" << endl; + // prevent rustfmt from running against this file + // lines are too long, code is (thankfully!) not visual-indented, etc. + f_gen_ << "#![cfg_attr(rustfmt, rustfmt_skip)]" << endl; + f_gen_ << endl; + + // add standard includes + f_gen_ << "extern crate ordered_float;" << endl; + f_gen_ << "extern crate thrift;" << endl; + f_gen_ << "extern crate try_from;" << endl; + f_gen_ << endl; + f_gen_ << "use ordered_float::OrderedFloat;" << endl; + f_gen_ << "use std::cell::RefCell;" << endl; + f_gen_ << "use std::collections::{BTreeMap, BTreeSet};" << endl; + f_gen_ << "use std::convert::From;" << endl; + f_gen_ << "use std::default::Default;" << endl; + f_gen_ << "use std::error::Error;" << endl; + f_gen_ << "use std::fmt;" << endl; + f_gen_ << "use std::fmt::{Display, Formatter};" << endl; + f_gen_ << "use std::rc::Rc;" << endl; + f_gen_ << "use try_from::TryFrom;" << endl; + f_gen_ << endl; + f_gen_ << "use thrift::{ApplicationError, ApplicationErrorKind, ProtocolError, ProtocolErrorKind, TThriftClient};" << endl; + f_gen_ << "use thrift::protocol::{TFieldIdentifier, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, TInputProtocol, TOutputProtocol, TSetIdentifier, TStructIdentifier, TType};" << endl; + f_gen_ << "use thrift::protocol::field_id;" << endl; + f_gen_ << "use thrift::protocol::verify_expected_message_type;" << endl; + f_gen_ << "use thrift::protocol::verify_expected_sequence_number;" << endl; + f_gen_ << "use thrift::protocol::verify_expected_service_call;" << endl; + f_gen_ << "use thrift::protocol::verify_required_field_exists;" << endl; + f_gen_ << "use thrift::server::TProcessor;" << endl; + f_gen_ << endl; + + // add all the program includes + // NOTE: this is more involved than you would expect because of service extension + // Basically, I have to find the closure of all the services and include their modules at the top-level + + set referenced_modules; + + // first, start by adding explicit thrift includes + const vector includes = get_program()->get_includes(); + vector::const_iterator includes_iter; + for(includes_iter = includes.begin(); includes_iter != includes.end(); ++includes_iter) { + referenced_modules.insert((*includes_iter)->get_name()); + } + + // next, recursively iterate through all the services and add the names of any programs they reference + const vector services = get_program()->get_services(); + vector::const_iterator service_iter; + for (service_iter = services.begin(); service_iter != services.end(); ++service_iter) { + compute_service_referenced_modules(*service_iter, referenced_modules); + } + + // finally, write all the "pub use..." declarations + if (!referenced_modules.empty()) { + set::iterator module_iter; + for (module_iter = referenced_modules.begin(); module_iter != referenced_modules.end(); ++module_iter) { + f_gen_ << "use " << rust_snake_case(*module_iter) << ";" << endl; + } + f_gen_ << endl; + } +} + +void t_rs_generator::compute_service_referenced_modules( + t_service *tservice, + set &referenced_modules +) { + t_service* extends = tservice->get_extends(); + if (extends) { + if (extends->get_program() != get_program()) { + referenced_modules.insert(extends->get_program()->get_name()); + } + compute_service_referenced_modules(extends, referenced_modules); + } +} + +void t_rs_generator::close_generator() { + f_gen_.close(); +} + +//----------------------------------------------------------------------------- +// +// Consts +// +// NOTE: consider using macros to generate constants +// +//----------------------------------------------------------------------------- + +// This is worse than it should be because constants +// aren't (sensibly) limited to scalar types +void t_rs_generator::generate_const(t_const* tconst) { + string name = tconst->get_name(); + t_type* ttype = tconst->get_type(); + t_const_value* tvalue = tconst->get_value(); + + if (can_generate_simple_const(ttype)) { + render_const_value(name, ttype, tvalue); + } else if (can_generate_const_holder(ttype)) { + render_const_value_holder(name, ttype, tvalue); + } else { + throw "cannot generate const for " + name; + } +} + +void t_rs_generator::render_const_value(const string& name, t_type* ttype, t_const_value* tvalue) { + if (!can_generate_simple_const(ttype)) { + throw "cannot generate simple rust constant for " + ttype->get_name(); + } + + f_gen_ << "pub const " << rust_upper_case(name) << ": " << to_rust_type(ttype) << " = "; + render_const_value(ttype, tvalue); + f_gen_ << ";" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_const_value_holder(const string& name, t_type* ttype, t_const_value* tvalue) { + if (!can_generate_const_holder(ttype)) { + throw "cannot generate constant holder for " + ttype->get_name(); + } + + string holder_name("Const" + rust_camel_case(name)); + + f_gen_ << indent() << "pub struct " << holder_name << ";" << endl; + f_gen_ << indent() << "impl " << holder_name << " {" << endl; + indent_up(); + + f_gen_ << indent() << "pub fn const_value() -> " << to_rust_type(ttype) << " {" << endl; + indent_up(); + render_const_value(ttype, tvalue); + indent_down(); + f_gen_ << indent() << "}" << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_const_value(t_type* ttype, t_const_value* tvalue) { + if (ttype->is_base_type()) { + t_base_type* tbase_type = (t_base_type*)ttype; + switch (tbase_type->get_base()) { + case t_base_type::TYPE_STRING: + if (tbase_type->is_binary()) { + f_gen_ << "\"" << tvalue->get_string() << "\""<< ".to_owned().into_bytes()"; + } else { + f_gen_ << "\"" << tvalue->get_string() << "\""<< ".to_owned()"; + } + break; + case t_base_type::TYPE_BOOL: + f_gen_ << (tvalue->get_integer() ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + f_gen_ << tvalue->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + f_gen_ << "OrderedFloat::from(" << tvalue->get_double() << " as f64)"; + break; + default: + throw "cannot generate const value for " + t_base_type::t_base_name(tbase_type->get_base()); + } + } else if (ttype->is_typedef()) { + render_const_value(get_true_type(ttype), tvalue); + } else if (ttype->is_enum()) { + f_gen_ << indent() << "{" << endl; + indent_up(); + f_gen_ + << indent() + << to_rust_type(ttype) + << "::try_from(" + << tvalue->get_integer() + << ").expect(\"expecting valid const value\")" + << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + } else if (ttype->is_struct() || ttype->is_xception()) { + render_const_struct(ttype, tvalue); + } else if (ttype->is_container()) { + f_gen_ << indent() << "{" << endl; + indent_up(); + + if (ttype->is_list()) { + render_const_list(ttype, tvalue); + } else if (ttype->is_set()) { + render_const_set(ttype, tvalue); + } else if (ttype->is_map()) { + render_const_map(ttype, tvalue); + } else { + throw "cannot generate const container value for " + ttype->get_name(); + } + + indent_down(); + f_gen_ << indent() << "}" << endl; + } else { + throw "cannot generate const value for " + ttype->get_name(); + } +} + +void t_rs_generator::render_const_struct(t_type* ttype, t_const_value*) { + if (((t_struct*)ttype)->is_union()) { + f_gen_ << indent() << "{" << endl; + indent_up(); + f_gen_ << indent() << "unimplemented!()" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + } else { + f_gen_ << indent() << "{" << endl; + indent_up(); + f_gen_ << indent() << "unimplemented!()" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + } +} + +void t_rs_generator::render_const_list(t_type* ttype, t_const_value* tvalue) { + t_type* elem_type = ((t_list*)ttype)->get_elem_type(); + f_gen_ << indent() << "let mut l: Vec<" << to_rust_type(elem_type) << "> = Vec::new();" << endl; + const vector& elems = tvalue->get_list(); + vector::const_iterator elem_iter; + for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) { + t_const_value* elem_value = (*elem_iter); + render_container_const_value("l.push", elem_type, elem_value); + } + f_gen_ << indent() << "l" << endl; +} + +void t_rs_generator::render_const_set(t_type* ttype, t_const_value* tvalue) { + t_type* elem_type = ((t_set*)ttype)->get_elem_type(); + f_gen_ << indent() << "let mut s: BTreeSet<" << to_rust_type(elem_type) << "> = BTreeSet::new();" << endl; + const vector& elems = tvalue->get_list(); + vector::const_iterator elem_iter; + for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) { + t_const_value* elem_value = (*elem_iter); + render_container_const_value("s.insert", elem_type, elem_value); + } + f_gen_ << indent() << "s" << endl; +} + +void t_rs_generator::render_const_map(t_type* ttype, t_const_value* tvalue) { + t_type* key_type = ((t_map*)ttype)->get_key_type(); + t_type* val_type = ((t_map*)ttype)->get_val_type(); + f_gen_ + << indent() + << "let mut m: BTreeMap<" + << to_rust_type(key_type) << ", " << to_rust_type(val_type) + << "> = BTreeMap::new();" + << endl; + const map& elems = tvalue->get_map(); + map::const_iterator elem_iter; + for (elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) { + t_const_value* key_value = elem_iter->first; + t_const_value* val_value = elem_iter->second; + if (get_true_type(key_type)->is_base_type()) { + f_gen_ << indent() << "let k = "; + render_const_value(key_type, key_value); + f_gen_ << ";" << endl; + } else { + f_gen_ << indent() << "let k = {" << endl; + indent_up(); + render_const_value(key_type, key_value); + indent_down(); + f_gen_ << indent() << "};" << endl; + } + if (get_true_type(val_type)->is_base_type()) { + f_gen_ << indent() << "let v = "; + render_const_value(val_type, val_value); + f_gen_ << ";" << endl; + } else { + f_gen_ << indent() << "let v = {" << endl; + indent_up(); + render_const_value(val_type, val_value); + indent_down(); + f_gen_ << indent() << "};" << endl; + } + f_gen_ << indent() << "m.insert(k, v);" << endl; + } + f_gen_ << indent() << "m" << endl; +} + +void t_rs_generator::render_container_const_value( + const string& insert_function, + t_type* ttype, + t_const_value* tvalue +) { + if (get_true_type(ttype)->is_base_type()) { + f_gen_ << indent() << insert_function << "("; + render_const_value(ttype, tvalue); + f_gen_ << ");" << endl; + } else { + f_gen_ << indent() << insert_function << "(" << endl; + indent_up(); + render_const_value(ttype, tvalue); + indent_down(); + f_gen_ << indent() << ");" << endl; + } +} + +//----------------------------------------------------------------------------- +// +// Typedefs +// +//----------------------------------------------------------------------------- + +void t_rs_generator::generate_typedef(t_typedef* ttypedef) { + std::string actual_type = to_rust_type(ttypedef->get_type()); + f_gen_ << "pub type " << rust_safe_name(ttypedef->get_symbolic()) << " = " << actual_type << ";" << endl; + f_gen_ << endl; +} + +//----------------------------------------------------------------------------- +// +// Enums +// +//----------------------------------------------------------------------------- + +void t_rs_generator::generate_enum(t_enum* tenum) { + string enum_name(rust_camel_case(tenum->get_name())); + render_enum_definition(tenum, enum_name); + render_enum_impl(enum_name); + render_enum_conversion(tenum, enum_name); +} + +void t_rs_generator::render_enum_definition(t_enum* tenum, const string& enum_name) { + render_rustdoc((t_doc*) tenum); + f_gen_ << "#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl; + f_gen_ << "pub enum " << enum_name << " {" << endl; + indent_up(); + + vector constants = tenum->get_constants(); + vector::iterator constants_iter; + for (constants_iter = constants.begin(); constants_iter != constants.end(); ++constants_iter) { + t_enum_value* val = (*constants_iter); + render_rustdoc((t_doc*) val); + f_gen_ + << indent() + << uppercase(val->get_name()) + << " = " + << val->get_value() + << "," + << endl; + } + + indent_down(); + f_gen_ << "}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_enum_impl(const string& enum_name) { + f_gen_ << "impl " << enum_name << " {" << endl; + indent_up(); + + f_gen_ + << indent() + << "pub fn write_to_out_protocol(&self, o_prot: &mut TOutputProtocol) -> thrift::Result<()> {" + << endl; + indent_up(); + f_gen_ << indent() << "o_prot.write_i32(*self as i32)" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + + f_gen_ + << indent() + << "pub fn read_from_in_protocol(i_prot: &mut TInputProtocol) -> thrift::Result<" << enum_name << "> {" + << endl; + indent_up(); + + f_gen_ << indent() << "let enum_value = i_prot.read_i32()?;" << endl; + f_gen_ << indent() << enum_name << "::try_from(enum_value)"; + + indent_down(); + f_gen_ << indent() << "}" << endl; + + indent_down(); + f_gen_ << "}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_enum_conversion(t_enum* tenum, const string& enum_name) { + f_gen_ << "impl TryFrom for " << enum_name << " {" << endl; + indent_up(); + + f_gen_ << indent() << "type Err = thrift::Error;"; + + f_gen_ << indent() << "fn try_from(i: i32) -> Result {" << endl; + indent_up(); + + f_gen_ << indent() << "match i {" << endl; + indent_up(); + + vector constants = tenum->get_constants(); + vector::iterator constants_iter; + for (constants_iter = constants.begin(); constants_iter != constants.end(); ++constants_iter) { + t_enum_value* val = (*constants_iter); + f_gen_ + << indent() + << val->get_value() + << " => Ok(" << enum_name << "::" << uppercase(val->get_name()) << ")," + << endl; + } + f_gen_ << indent() << "_ => {" << endl; + indent_up(); + render_rift_error( + "Protocol", + "ProtocolError", + "ProtocolErrorKind::InvalidData", + "format!(\"cannot convert enum constant {} to " + enum_name + "\", i)" + ); + indent_down(); + f_gen_ << indent() << "}," << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; + + indent_down(); + f_gen_ << "}" << endl; + f_gen_ << endl; +} + +//----------------------------------------------------------------------------- +// +// Structs, Unions and Exceptions +// +//----------------------------------------------------------------------------- + +void t_rs_generator::generate_xception(t_struct* txception) { + render_struct(rust_struct_name(txception), txception, t_rs_generator::T_EXCEPTION); +} + +void t_rs_generator::generate_struct(t_struct* tstruct) { + if (tstruct->is_union()) { + render_union(tstruct); + } else if (tstruct->is_struct()) { + render_struct(rust_struct_name(tstruct), tstruct, t_rs_generator::T_REGULAR); + } else { + throw "cannot generate struct for exception"; + } +} + +void t_rs_generator::render_struct( + const string& struct_name, + t_struct* tstruct, + t_rs_generator::e_struct_type struct_type +) { + render_type_comment(struct_name); + render_struct_definition(struct_name, tstruct, struct_type); + render_struct_impl(struct_name, tstruct, struct_type); + if (struct_type == t_rs_generator::T_REGULAR || struct_type == t_rs_generator::T_EXCEPTION) { + render_struct_default_trait_impl(struct_name, tstruct); + } + if (struct_type == t_rs_generator::T_EXCEPTION) { + render_exception_struct_error_trait_impls(struct_name, tstruct); + } +} + +void t_rs_generator::render_struct_definition( + const string& struct_name, + t_struct* tstruct, + t_rs_generator::e_struct_type struct_type +) { + render_rustdoc((t_doc*) tstruct); + f_gen_ << "#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl; + f_gen_ << visibility_qualifier(struct_type) << "struct " << struct_name << " {" << endl; + + // render the members + vector members = tstruct->get_sorted_members(); + if (!members.empty()) { + indent_up(); + + vector::iterator members_iter; + for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* member = (*members_iter); + t_field::e_req member_req = actual_field_req(member, struct_type); + + string rust_type = to_rust_type(member->get_type()); + rust_type = is_optional(member_req) ? "Option<" + rust_type + ">" : rust_type; + + render_rustdoc((t_doc*) member); + f_gen_ + << indent() + << visibility_qualifier(struct_type) + << rust_field_name(member) << ": " << rust_type << "," + << endl; + } + + indent_down(); + } + + f_gen_ << "}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_exception_struct_error_trait_impls(const string& struct_name, t_struct* tstruct) { + // error::Error trait + f_gen_ << "impl Error for " << struct_name << " {" << endl; + indent_up(); + f_gen_ << indent() << "fn description(&self) -> &str {" << endl; + indent_up(); + f_gen_ << indent() << "\"" << "remote service threw " << tstruct->get_name() << "\"" << endl; // use *original* name + indent_down(); + f_gen_ << indent() << "}" << endl; + indent_down(); + f_gen_ << "}" << endl; + f_gen_ << endl; + + // convert::From trait + f_gen_ << "impl From<" << struct_name << "> for thrift::Error {" << endl; + indent_up(); + f_gen_ << indent() << "fn from(e: " << struct_name << ") -> Self {" << endl; + indent_up(); + f_gen_ << indent() << "thrift::Error::User(Box::new(e))" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + indent_down(); + f_gen_ << "}" << endl; + f_gen_ << endl; + + // fmt::Display trait + f_gen_ << "impl Display for " << struct_name << " {" << endl; + indent_up(); + f_gen_ << indent() << "fn fmt(&self, f: &mut Formatter) -> fmt::Result {" << endl; + indent_up(); + f_gen_ << indent() << "self.description().fmt(f)" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + indent_down(); + f_gen_ << "}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_struct_default_trait_impl(const string& struct_name, t_struct* tstruct) { + bool has_required_field = false; + + const vector& members = tstruct->get_sorted_members(); + vector::const_iterator members_iter; + for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* member = *members_iter; + if (!is_optional(member->get_req())) { + has_required_field = true; + break; + } + } + + if (has_required_field) { + return; + } + + f_gen_ << "impl Default for " << struct_name << " {" << endl; + indent_up(); + f_gen_ << indent() << "fn default() -> Self {" << endl; + indent_up(); + + if (members.empty()) { + f_gen_ << indent() << struct_name << "{}" << endl; + } else { + f_gen_ << indent() << struct_name << "{" << endl; + indent_up(); + for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field *member = (*members_iter); + string member_name(rust_field_name(member)); + f_gen_ << indent() << member_name << ": " << opt_in_req_out_value(member->get_type()) << "," << endl; + } + indent_down(); + f_gen_ << indent() << "}" << endl; + } + + indent_down(); + f_gen_ << indent() << "}" << endl; + indent_down(); + f_gen_ << "}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_struct_impl( + const string& struct_name, + t_struct* tstruct, + t_rs_generator::e_struct_type struct_type +) { + f_gen_ << "impl " << struct_name << " {" << endl; + indent_up(); + + if (struct_type == t_rs_generator::T_REGULAR || struct_type == t_rs_generator::T_EXCEPTION) { + render_struct_constructor(struct_name, tstruct, struct_type); + } + + render_struct_sync_read(struct_name, tstruct, struct_type); + render_struct_sync_write(tstruct, struct_type); + + if (struct_type == t_rs_generator::T_RESULT) { + render_result_struct_to_result_method(tstruct); + } + + indent_down(); + f_gen_ << "}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_struct_constructor( + const string& struct_name, + t_struct* tstruct, + t_rs_generator::e_struct_type struct_type +) { + const vector& members = tstruct->get_sorted_members(); + vector::const_iterator members_iter; + + // build the convenience type parameters that allows us to pass unwrapped values to a constructor and + // have them automatically converted into Option + bool first_arg = true; + + ostringstream generic_type_parameters; + ostringstream generic_type_qualifiers; + for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* member = (*members_iter); + t_field::e_req member_req = actual_field_req(member, struct_type); + + if (is_optional(member_req)) { + if (first_arg) { + first_arg = false; + } else { + generic_type_parameters << ", "; + generic_type_qualifiers << ", "; + } + generic_type_parameters << "F" << member->get_key(); + generic_type_qualifiers << "F" << member->get_key() << ": Intoget_type()) << ">>"; + } + } + + string type_parameter_string = generic_type_parameters.str(); + if (type_parameter_string.length() != 0) { + type_parameter_string = "<" + type_parameter_string + ">"; + } + + string type_qualifier_string = generic_type_qualifiers.str(); + if (type_qualifier_string.length() != 0) { + type_qualifier_string = "where " + type_qualifier_string + " "; + } + + // now build the actual constructor arg list + // when we're building this list we have to use the type parameters in place of the actual type names + // if necessary + ostringstream args; + first_arg = true; + for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* member = (*members_iter); + t_field::e_req member_req = actual_field_req(member, struct_type); + string member_name(rust_field_name(member)); + + if (first_arg) { + first_arg = false; + } else { + args << ", "; + } + + if (is_optional(member_req)) { + args << member_name << ": " << "F" << member->get_key(); + } else { + args << member_name << ": " << to_rust_type(member->get_type()); + } + } + + string arg_string = args.str(); + + string visibility(visibility_qualifier(struct_type)); + f_gen_ + << indent() + << visibility + << "fn new" + << type_parameter_string + << "(" + << arg_string + << ") -> " + << struct_name + << " " + << type_qualifier_string + << "{" + << endl; + indent_up(); + + if (members.size() == 0) { + f_gen_ << indent() << struct_name << " {}" << endl; + } else { + f_gen_ << indent() << struct_name << " {" << endl; + indent_up(); + + for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* member = (*members_iter); + t_field::e_req member_req = actual_field_req(member, struct_type); + string member_name(rust_field_name(member)); + + if (is_optional(member_req)) { + f_gen_ << indent() << member_name << ": " << member_name << ".into()," << endl; + } else { + f_gen_ << indent() << member_name << ": " << member_name << "," << endl; + } + } + + indent_down(); + f_gen_ << indent() << "}" << endl; + } + + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +void t_rs_generator::render_result_struct_to_result_method(t_struct* tstruct) { + // we don't use the rust struct name in this method, just the service call name + string service_call_name = tstruct->get_name(); + + // check that we actually have a result + size_t index = service_call_name.find(RESULT_STRUCT_SUFFIX, 0); + if (index == std::string::npos) { + throw "result struct " + service_call_name + " missing result suffix"; + } else { + service_call_name.replace(index, 6, ""); + } + + const vector& members = tstruct->get_sorted_members(); + vector::const_iterator members_iter; + + // find out what the call's expected return type was + string rust_return_type = "()"; + for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* member = (*members_iter); + if (member->get_name() == SERVICE_RESULT_VARIABLE) { // don't have to check safe name here + rust_return_type = to_rust_type(member->get_type()); + break; + } + } + + // NOTE: ideally I would generate the branches and render them separately + // I tried this however, and the resulting code was harder to understand + // maintaining a rendered branch count (while a little ugly) got me the + // rendering I wanted with code that was reasonably understandable + + f_gen_ << indent() << "fn ok_or(self) -> thrift::Result<" << rust_return_type << "> {" << endl; + indent_up(); + + int rendered_branch_count = 0; + + // render the exception branches + for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* tfield = (*members_iter); + if (tfield->get_name() != SERVICE_RESULT_VARIABLE) { // don't have to check safe name here + string field_name("self." + rust_field_name(tfield)); + string branch_statement = rendered_branch_count == 0 ? "if" : "} else if"; + + f_gen_ << indent() << branch_statement << " " << field_name << ".is_some() {" << endl; + indent_up(); + f_gen_ << indent() << "Err(thrift::Error::User(Box::new(" << field_name << ".unwrap())))" << endl; + indent_down(); + + rendered_branch_count++; + } + } + + // render the return value branches + if (rust_return_type == "()") { + if (rendered_branch_count == 0) { + // we have the unit return and this service call has no user-defined + // exceptions. this means that we've a trivial return (happens with oneways) + f_gen_ << indent() << "Ok(())" << endl; + } else { + // we have the unit return, but there are user-defined exceptions + // if we've gotten this far then we have the default return (i.e. call successful) + f_gen_ << indent() << "} else {" << endl; + indent_up(); + f_gen_ << indent() << "Ok(())" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + } + } else { + string branch_statement = rendered_branch_count == 0 ? "if" : "} else if"; + f_gen_ << indent() << branch_statement << " self." << SERVICE_RESULT_VARIABLE << ".is_some() {" << endl; + indent_up(); + f_gen_ << indent() << "Ok(self." << SERVICE_RESULT_VARIABLE << ".unwrap())" << endl; + indent_down(); + f_gen_ << indent() << "} else {" << endl; + indent_up(); + // if we haven't found a valid return value *or* a user exception + // then we're in trouble; return a default error + render_rift_error( + "Application", + "ApplicationError", + "ApplicationErrorKind::MissingResult", + "\"no result received for " + service_call_name + "\"" + ); + indent_down(); + f_gen_ << indent() << "}" << endl; + } + + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +void t_rs_generator::render_union(t_struct* tstruct) { + string union_name(rust_struct_name(tstruct)); + render_type_comment(union_name); + render_union_definition(union_name, tstruct); + render_union_impl(union_name, tstruct); +} + +void t_rs_generator::render_union_definition(const string& union_name, t_struct* tstruct) { + const vector& members = tstruct->get_sorted_members(); + if (members.empty()) { + throw "cannot generate rust enum with 0 members"; // may be valid thrift, but it's invalid rust + } + + f_gen_ << "#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl; + f_gen_ << "pub enum " << union_name << " {" << endl; + indent_up(); + + vector::const_iterator member_iter; + for(member_iter = members.begin(); member_iter != members.end(); ++member_iter) { + t_field* tfield = (*member_iter); + f_gen_ + << indent() + << rust_union_field_name(tfield) + << "(" << to_rust_type(tfield->get_type()) << ")," + << endl; + } + + indent_down(); + f_gen_ << "}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_union_impl(const string& union_name, t_struct* tstruct) { + f_gen_ << "impl " << union_name << " {" << endl; + indent_up(); + + render_union_sync_read(union_name, tstruct); + render_union_sync_write(union_name, tstruct); + + indent_down(); + f_gen_ << "}" << endl; + f_gen_ << endl; +} + +//----------------------------------------------------------------------------- +// +// Sync Struct Write +// +//----------------------------------------------------------------------------- + +void t_rs_generator::render_struct_sync_write( + t_struct *tstruct, + t_rs_generator::e_struct_type struct_type +) { + f_gen_ + << indent() + << visibility_qualifier(struct_type) + << "fn write_to_out_protocol(&self, o_prot: &mut TOutputProtocol) -> thrift::Result<()> {" + << endl; + indent_up(); + + // write struct header to output protocol + // note: use the *original* struct name here + f_gen_ << indent() << "let struct_ident = TStructIdentifier::new(\"" + tstruct->get_name() + "\");" << endl; + f_gen_ << indent() << "o_prot.write_struct_begin(&struct_ident)?;" << endl; + + // write struct members to output protocol + vector members = tstruct->get_sorted_members(); + if (!members.empty()) { + vector::iterator members_iter; + for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* member = (*members_iter); + t_field::e_req member_req = actual_field_req(member, struct_type); + string member_var("self." + rust_field_name(member)); + render_struct_field_sync_write(member_var, false, member, member_req); + } + } + + // write struct footer to output protocol + f_gen_ << indent() << "o_prot.write_field_stop()?;" << endl; + f_gen_ << indent() << "o_prot.write_struct_end()" << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +void t_rs_generator::render_union_sync_write(const string &union_name, t_struct *tstruct) { + f_gen_ + << indent() + << "pub fn write_to_out_protocol(&self, o_prot: &mut TOutputProtocol) -> thrift::Result<()> {" + << endl; + indent_up(); + + // write struct header to output protocol + // note: use the *original* struct name here + f_gen_ << indent() << "let struct_ident = TStructIdentifier::new(\"" + tstruct->get_name() + "\");" << endl; + f_gen_ << indent() << "o_prot.write_struct_begin(&struct_ident)?;" << endl; + + // write the enum field to the output protocol + vector members = tstruct->get_sorted_members(); + if (!members.empty()) { + f_gen_ << indent() << "match *self {" << endl; + indent_up(); + vector::iterator members_iter; + for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* member = (*members_iter); + t_field::e_req member_req = t_field::T_REQUIRED; + t_type* ttype = member->get_type(); + string match_var((ttype->is_base_type() && !ttype->is_string()) ? "f" : "ref f"); + f_gen_ + << indent() + << union_name << "::" << rust_union_field_name(member) + << "(" << match_var << ") => {" + << endl; + indent_up(); + render_struct_field_sync_write("f", true, member, member_req); + indent_down(); + f_gen_ << indent() << "}," << endl; + } + indent_down(); + f_gen_ << indent() << "}" << endl; + } + + // write struct footer to output protocol + f_gen_ << indent() << "o_prot.write_field_stop()?;" << endl; + f_gen_ << indent() << "o_prot.write_struct_end()" << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +void t_rs_generator::render_struct_field_sync_write( + const string &field_var, + bool field_var_is_ref, + t_field *tfield, + t_field::e_req req +) { + t_type* field_type = tfield->get_type(); + t_type* actual_type = get_true_type(field_type); + + ostringstream field_stream; + field_stream + << "TFieldIdentifier::new(" + << "\"" << tfield->get_name() << "\"" << ", " // note: use *original* name + << to_rust_field_type_enum(field_type) << ", " + << tfield->get_key() << ")"; + string field_ident_string = field_stream.str(); + + if (is_optional(req)) { + string let_var((actual_type->is_base_type() && !actual_type->is_string()) ? "fld_var" : "ref fld_var"); + f_gen_ << indent() << "if let Some(" << let_var << ") = " << field_var << " {" << endl; + indent_up(); + f_gen_ << indent() << "o_prot.write_field_begin(&" << field_ident_string << ")?;" << endl; + render_type_sync_write("fld_var", true, field_type); + f_gen_ << indent() << "o_prot.write_field_end()?;" << endl; + f_gen_ << indent() << "()" << endl; // FIXME: remove this extraneous '()' + indent_down(); + f_gen_ << indent() << "} else {" << endl; // FIXME: remove else branch + indent_up(); + /* FIXME: rethink how I deal with OPT_IN_REQ_OUT + if (req == t_field::T_OPT_IN_REQ_OUT) { + f_gen_ << indent() << "let field_ident = " << field_ident_string << ";" << endl; + f_gen_ << indent() << "o_prot.write_field_begin(&field_ident)?;" << endl; + f_gen_ << indent() << "o_prot.write_field_end()?;" << endl; + }*/ + f_gen_ << indent() << "()" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + } else { + f_gen_ << indent() << "o_prot.write_field_begin(&" << field_ident_string << ")?;" << endl; + render_type_sync_write(field_var, field_var_is_ref, tfield->get_type()); + f_gen_ << indent() << "o_prot.write_field_end()?;" << endl; + } +} + +void t_rs_generator::render_type_sync_write(const string &type_var, bool type_var_is_ref, t_type *ttype) { + if (ttype->is_base_type()) { + t_base_type* tbase_type = (t_base_type*)ttype; + switch (tbase_type->get_base()) { + case t_base_type::TYPE_VOID: + throw "cannot write field of type TYPE_VOID to output protocol"; + case t_base_type::TYPE_STRING: { + string ref(type_var_is_ref ? "" : "&"); + if (tbase_type->is_binary()) { + f_gen_ << indent() << "o_prot.write_bytes(" + ref + type_var + ")?;" << endl; + } else { + f_gen_ << indent() << "o_prot.write_string(" + ref + type_var + ")?;" << endl; + } + return; + } + case t_base_type::TYPE_BOOL: + f_gen_ << indent() << "o_prot.write_bool(" + type_var + ")?;" << endl; + return; + case t_base_type::TYPE_I8: + f_gen_ << indent() << "o_prot.write_i8(" + type_var + ")?;" << endl; + return; + case t_base_type::TYPE_I16: + f_gen_ << indent() << "o_prot.write_i16(" + type_var + ")?;" << endl; + return; + case t_base_type::TYPE_I32: + f_gen_ << indent() << "o_prot.write_i32(" + type_var + ")?;" << endl; + return; + case t_base_type::TYPE_I64: + f_gen_ << indent() << "o_prot.write_i64(" + type_var + ")?;" << endl; + return; + case t_base_type::TYPE_DOUBLE: + f_gen_ << indent() << "o_prot.write_double(" + type_var + ".into())?;" << endl; + return; + } + } else if (ttype->is_typedef()) { + t_typedef* ttypedef = (t_typedef*) ttype; + render_type_sync_write(type_var, type_var_is_ref, ttypedef->get_type()); + return; + } else if (ttype->is_enum() || ttype->is_struct() || ttype->is_xception()) { + f_gen_ << indent() << type_var + ".write_to_out_protocol(o_prot)?;" << endl; + return; + } else if (ttype->is_map()) { + render_map_sync_write(type_var, type_var_is_ref, (t_map *) ttype); + return; + } else if (ttype->is_set()) { + render_set_sync_write(type_var, type_var_is_ref, (t_set *) ttype); + return; + } else if (ttype->is_list()) { + render_list_sync_write(type_var, type_var_is_ref, (t_list *) ttype); + return; + } + + throw "cannot write unsupported type " + ttype->get_name(); +} + +void t_rs_generator::render_list_sync_write(const string &list_var, bool list_var_is_ref, t_list *tlist) { + t_type* elem_type = tlist->get_elem_type(); + + f_gen_ + << indent() + << "o_prot.write_list_begin(" + << "&TListIdentifier::new(" + << to_rust_field_type_enum(elem_type) << ", " + << list_var << ".len() as i32" << ")" + << ")?;" + << endl; + + string ref(list_var_is_ref ? "" : "&"); + f_gen_ << indent() << "for e in " << ref << list_var << " {" << endl; + indent_up(); + render_type_sync_write(string_container_write_variable(elem_type, "e"), true, elem_type); + f_gen_ << indent() << "o_prot.write_list_end()?;" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +void t_rs_generator::render_set_sync_write(const string &set_var, bool set_var_is_ref, t_set *tset) { + t_type* elem_type = tset->get_elem_type(); + + f_gen_ + << indent() + << "o_prot.write_set_begin(" + << "&TSetIdentifier::new(" + << to_rust_field_type_enum(elem_type) << ", " + << set_var << ".len() as i32" << ")" + << ")?;" + << endl; + + string ref(set_var_is_ref ? "" : "&"); + f_gen_ << indent() << "for e in " << ref << set_var << " {" << endl; + indent_up(); + render_type_sync_write(string_container_write_variable(elem_type, "e"), true, elem_type); + f_gen_ << indent() << "o_prot.write_set_end()?;" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +void t_rs_generator::render_map_sync_write(const string &map_var, bool map_var_is_ref, t_map *tmap) { + t_type* key_type = tmap->get_key_type(); + t_type* val_type = tmap->get_val_type(); + + f_gen_ + << indent() + << "o_prot.write_map_begin(" + << "&TMapIdentifier::new(" + << to_rust_field_type_enum(key_type) << ", " + << to_rust_field_type_enum(val_type) << ", " + << map_var << ".len() as i32)" + << ")?;" + << endl; + + string ref(map_var_is_ref ? "" : "&"); + f_gen_ << indent() << "for (k, v) in " << ref << map_var << " {" << endl; + indent_up(); + render_type_sync_write(string_container_write_variable(key_type, "k"), true, key_type); + render_type_sync_write(string_container_write_variable(val_type, "v"), true, val_type); + f_gen_ << indent() << "o_prot.write_map_end()?;" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +string t_rs_generator::string_container_write_variable(t_type* ttype, const string& base_var) { + bool type_needs_deref = needs_deref_on_container_write(ttype); + bool type_is_double = is_double(ttype); + + string write_variable; + + if (type_is_double && type_needs_deref) { + write_variable = "(*" + base_var + ")"; + } else if (type_needs_deref) { + write_variable = "*" + base_var; + } else { + write_variable = base_var; + } + + return write_variable; +} + +bool t_rs_generator::needs_deref_on_container_write(t_type* ttype) { + ttype = get_true_type(ttype); + return ttype->is_base_type() && !ttype->is_string(); +} + +//----------------------------------------------------------------------------- +// +// Sync Struct Read +// +//----------------------------------------------------------------------------- + +void t_rs_generator::render_struct_sync_read( + const string &struct_name, + t_struct *tstruct, t_rs_generator::e_struct_type struct_type +) { + f_gen_ + << indent() + << visibility_qualifier(struct_type) + << "fn read_from_in_protocol(i_prot: &mut TInputProtocol) -> thrift::Result<" << struct_name << "> {" + << endl; + + indent_up(); + + f_gen_ << indent() << "i_prot.read_struct_begin()?;" << endl; + + // create temporary variables: one for each field in the struct + const vector members = tstruct->get_sorted_members(); + vector::const_iterator members_iter; + for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* member = (*members_iter); + t_field::e_req member_req = actual_field_req(member, struct_type); + + f_gen_ + << indent() + << "let mut " << struct_field_read_temp_variable(member) + << ": Option<" << to_rust_type(member->get_type()) << "> = "; + if (member_req == t_field::T_OPT_IN_REQ_OUT) { + f_gen_ << opt_in_req_out_value(member->get_type()) << ";"; + } else { + f_gen_ << "None;"; + } + f_gen_ << endl; + } + + // now loop through the fields we've received + f_gen_ << indent() << "loop {" << endl; // start loop + indent_up(); + + // break out if you've found the Stop field + f_gen_ << indent() << "let field_ident = i_prot.read_field_begin()?;" << endl; + f_gen_ << indent() << "if field_ident.field_type == TType::Stop {" << endl; + indent_up(); + f_gen_ << indent() << "break;" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + + // now read all the fields found + f_gen_ << indent() << "let field_id = field_id(&field_ident)?;" << endl; + f_gen_ << indent() << "match field_id {" << endl; // start match + indent_up(); + + for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* tfield = (*members_iter); + f_gen_ << indent() << tfield->get_key() << " => {" << endl; + indent_up(); + render_type_sync_read("val", tfield->get_type()); + f_gen_ << indent() << struct_field_read_temp_variable(tfield) << " = Some(val);" << endl; + indent_down(); + f_gen_ << indent() << "}," << endl; + } + + // default case (skip fields) + f_gen_ << indent() << "_ => {" << endl; + indent_up(); + f_gen_ << indent() << "i_prot.skip(field_ident.field_type)?;" << endl; + indent_down(); + f_gen_ << indent() << "}," << endl; + + indent_down(); + f_gen_ << indent() << "};" << endl; // finish match + f_gen_ << indent() << "i_prot.read_field_end()?;" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; // finish loop + f_gen_ << indent() << "i_prot.read_struct_end()?;" << endl; // read message footer from the wire + + // verify that all required fields exist + for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* tfield = (*members_iter); + t_field::e_req req = actual_field_req(tfield, struct_type); + if (!is_optional(req)) { + f_gen_ + << indent() + << "verify_required_field_exists(" + << "\"" << struct_name << "." << rust_field_name(tfield) << "\"" + << ", " + << "&" << struct_field_read_temp_variable(tfield) + << ")?;" << endl; + } + } + + // construct the struct + if (members.size() == 0) { + f_gen_ << indent() << "let ret = " << struct_name << " {};" << endl; + } else { + f_gen_ << indent() << "let ret = " << struct_name << " {" << endl; + indent_up(); + + for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* tfield = (*members_iter); + t_field::e_req req = actual_field_req(tfield, struct_type); + string field_name(rust_field_name(tfield)); + string field_key = struct_field_read_temp_variable(tfield); + if (is_optional(req)) { + f_gen_ << indent() << field_name << ": " << field_key << "," << endl; + } else { + f_gen_ + << indent() + << field_name + << ": " + << field_key + << ".expect(\"auto-generated code should have checked for presence of required fields\")" + << "," + << endl; + } + } + + indent_down(); + f_gen_ << indent() << "};" << endl; + } + + // return the constructed value + f_gen_ << indent() << "Ok(ret)" << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +void t_rs_generator::render_union_sync_read(const string &union_name, t_struct *tstruct) { + f_gen_ + << indent() + << "pub fn read_from_in_protocol(i_prot: &mut TInputProtocol) -> thrift::Result<" << union_name << "> {" + << endl; + indent_up(); + + // create temporary variables to hold the + // completed union as well as a count of fields read + f_gen_ << indent() << "let mut ret: Option<" << union_name << "> = None;" << endl; + f_gen_ << indent() << "let mut received_field_count = 0;" << endl; + + // read the struct preamble + f_gen_ << indent() << "i_prot.read_struct_begin()?;" << endl; + + // now loop through the fields we've received + f_gen_ << indent() << "loop {" << endl; // start loop + indent_up(); + + // break out if you've found the Stop field + f_gen_ << indent() << "let field_ident = i_prot.read_field_begin()?;" << endl; + f_gen_ << indent() << "if field_ident.field_type == TType::Stop {" << endl; + indent_up(); + f_gen_ << indent() << "break;" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + + // now read all the fields found + f_gen_ << indent() << "let field_id = field_id(&field_ident)?;" << endl; + f_gen_ << indent() << "match field_id {" << endl; // start match + indent_up(); + + const vector members = tstruct->get_sorted_members(); + vector::const_iterator members_iter; + for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* member = (*members_iter); + f_gen_ << indent() << member->get_key() << " => {" << endl; + indent_up(); + render_type_sync_read("val", member->get_type()); + f_gen_ << indent() << "if ret.is_none() {" << endl; + indent_up(); + f_gen_ + << indent() + << "ret = Some(" << union_name << "::" << rust_union_field_name(member) << "(val));" + << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + f_gen_ << indent() << "received_field_count += 1;" << endl; + indent_down(); + f_gen_ << indent() << "}," << endl; + } + + // default case (skip fields) + f_gen_ << indent() << "_ => {" << endl; + indent_up(); + f_gen_ << indent() << "i_prot.skip(field_ident.field_type)?;" << endl; + f_gen_ << indent() << "received_field_count += 1;" << endl; + indent_down(); + f_gen_ << indent() << "}," << endl; + + indent_down(); + f_gen_ << indent() << "};" << endl; // finish match + f_gen_ << indent() << "i_prot.read_field_end()?;" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; // finish loop + f_gen_ << indent() << "i_prot.read_struct_end()?;" << endl; // finish reading message from wire + + // return the value or an error + f_gen_ << indent() << "if received_field_count == 0 {" << endl; + indent_up(); + render_rift_error( + "Protocol", + "ProtocolError", + "ProtocolErrorKind::InvalidData", + "\"received empty union from remote " + union_name + "\"" + ); + indent_down(); + f_gen_ << indent() << "} else if received_field_count > 1 {" << endl; + indent_up(); + render_rift_error( + "Protocol", + "ProtocolError", + "ProtocolErrorKind::InvalidData", + "\"received multiple fields for union from remote " + union_name + "\"" + ); + indent_down(); + f_gen_ << indent() << "} else {" << endl; + indent_up(); + f_gen_ << indent() << "Ok(ret.expect(\"return value should have been constructed\"))" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +// Construct the rust representation of all supported types from the wire. +void t_rs_generator::render_type_sync_read(const string &type_var, t_type *ttype, bool is_boxed) { + if (ttype->is_base_type()) { + t_base_type* tbase_type = (t_base_type*)ttype; + switch (tbase_type->get_base()) { + case t_base_type::TYPE_VOID: + throw "cannot read field of type TYPE_VOID from input protocol"; + case t_base_type::TYPE_STRING: + if (tbase_type->is_binary()) { + f_gen_ << indent() << "let " << type_var << " = i_prot.read_bytes()?;" << endl; + } else { + f_gen_ << indent() << "let " << type_var << " = i_prot.read_string()?;" << endl; + } + return; + case t_base_type::TYPE_BOOL: + f_gen_ << indent() << "let " << type_var << " = i_prot.read_bool()?;" << endl; + return; + case t_base_type::TYPE_I8: + f_gen_ << indent() << "let " << type_var << " = i_prot.read_i8()?;" << endl; + return; + case t_base_type::TYPE_I16: + f_gen_ << indent() << "let " << type_var << " = i_prot.read_i16()?;" << endl; + return; + case t_base_type::TYPE_I32: + f_gen_ << indent() << "let " << type_var << " = i_prot.read_i32()?;" << endl; + return; + case t_base_type::TYPE_I64: + f_gen_ << indent() << "let " << type_var << " = i_prot.read_i64()?;" << endl; + return; + case t_base_type::TYPE_DOUBLE: + f_gen_ << indent() << "let " << type_var << " = OrderedFloat::from(i_prot.read_double()?);" << endl; + return; + } + } else if (ttype->is_typedef()) { + // FIXME: not a fan of separate `is_boxed` parameter + // This is problematic because it's an optional parameter, and only comes + // into play once. The core issue is that I lose an important piece of type + // information (whether the type is a fwd ref) by unwrapping the typedef'd + // type and making the recursive call using it. I can't modify or wrap the + // generated string after the fact because it's written directly into the file, + // so I have to pass this parameter along. Going with this approach because it + // seems like the lowest-cost option to easily support recursive types. + t_typedef* ttypedef = (t_typedef*)ttype; + render_type_sync_read(type_var, ttypedef->get_type(), ttypedef->is_forward_typedef()); + return; + } else if (ttype->is_enum() || ttype->is_struct() || ttype->is_xception()) { + string read_call(to_rust_type(ttype) + "::read_from_in_protocol(i_prot)?"); + read_call = is_boxed ? "Box::new(" + read_call + ")" : read_call; + f_gen_ + << indent() + << "let " << type_var << " = " << read_call << ";" + << endl; + return; + } else if (ttype->is_map()) { + render_map_sync_read((t_map *) ttype, type_var); + return; + } else if (ttype->is_set()) { + render_set_sync_read((t_set *) ttype, type_var); + return; + } else if (ttype->is_list()) { + render_list_sync_read((t_list *) ttype, type_var); + return; + } + + throw "cannot read unsupported type " + ttype->get_name(); +} + +// Construct the rust representation of a list from the wire. +void t_rs_generator::render_list_sync_read(t_list *tlist, const string &list_var) { + t_type* elem_type = tlist->get_elem_type(); + + f_gen_ << indent() << "let list_ident = i_prot.read_list_begin()?;" << endl; + f_gen_ + << indent() + << "let mut " << list_var << ": " << to_rust_type((t_type*) tlist) + << " = Vec::with_capacity(list_ident.size as usize);" + << endl; + f_gen_ << indent() << "for _ in 0..list_ident.size {" << endl; + + indent_up(); + + string list_elem_var = tmp("list_elem_"); + render_type_sync_read(list_elem_var, elem_type); + f_gen_ << indent() << list_var << ".push(" << list_elem_var << ");" << endl; + + indent_down(); + + f_gen_ << indent() << "}" << endl; + f_gen_ << indent() << "i_prot.read_list_end()?;" << endl; +} + +// Construct the rust representation of a set from the wire. +void t_rs_generator::render_set_sync_read(t_set *tset, const string &set_var) { + t_type* elem_type = tset->get_elem_type(); + + f_gen_ << indent() << "let set_ident = i_prot.read_set_begin()?;" << endl; + f_gen_ + << indent() + << "let mut " << set_var << ": " << to_rust_type((t_type*) tset) + << " = BTreeSet::new();" + << endl; + f_gen_ << indent() << "for _ in 0..set_ident.size {" << endl; + + indent_up(); + + string set_elem_var = tmp("set_elem_"); + render_type_sync_read(set_elem_var, elem_type); + f_gen_ << indent() << set_var << ".insert(" << set_elem_var << ");" << endl; + + indent_down(); + + f_gen_ << indent() << "}" << endl; + f_gen_ << indent() << "i_prot.read_set_end()?;" << endl; +} + +// Construct the rust representation of a map from the wire. +void t_rs_generator::render_map_sync_read(t_map *tmap, const string &map_var) { + t_type* key_type = tmap->get_key_type(); + t_type* val_type = tmap->get_val_type(); + + f_gen_ << indent() << "let map_ident = i_prot.read_map_begin()?;" << endl; + f_gen_ + << indent() + << "let mut " << map_var << ": " << to_rust_type((t_type*) tmap) + << " = BTreeMap::new();" + << endl; + f_gen_ << indent() << "for _ in 0..map_ident.size {" << endl; + + indent_up(); + + string key_elem_var = tmp("map_key_"); + render_type_sync_read(key_elem_var, key_type); + string val_elem_var = tmp("map_val_"); + render_type_sync_read(val_elem_var, val_type); + f_gen_ << indent() << map_var << ".insert(" << key_elem_var << ", " << val_elem_var << ");" << endl; + + indent_down(); + + f_gen_ << indent() << "}" << endl; + f_gen_ << indent() << "i_prot.read_map_end()?;" << endl; +} + +string t_rs_generator::struct_field_read_temp_variable(t_field* tfield) { + std::ostringstream foss; + foss << "f_" << tfield->get_key(); + return foss.str(); +} + +//----------------------------------------------------------------------------- +// +// Sync Client +// +//----------------------------------------------------------------------------- + +void t_rs_generator::generate_service(t_service* tservice) { + render_sync_client(tservice); + render_sync_processor(tservice); + render_service_call_structs(tservice); +} + +void t_rs_generator::render_service_call_structs(t_service* tservice) { + const std::vector functions = tservice->get_functions(); + std::vector::const_iterator func_iter; + + // thrift args for service calls are packed + // into a struct that's transmitted over the wire, so + // generate structs for those too + // + // thrift returns are *also* packed into a struct + // that's passed over the wire, so, generate the struct + // for that too. Note that this result struct *also* + // contains the exceptions as well + for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { + t_function* tfunc = (*func_iter); + render_struct(rust_struct_name(tfunc->get_arglist()), tfunc->get_arglist(), t_rs_generator::T_ARGS); + if (!tfunc->is_oneway()) { + render_result_value_struct(tfunc); + } + } +} + +void t_rs_generator::render_sync_client(t_service* tservice) { + string client_impl_name(rust_sync_client_impl_name(tservice)); + + render_type_comment(tservice->get_name() + " service client"); // note: use *original* name + render_sync_client_trait(tservice); + render_sync_client_marker_trait(tservice); + render_sync_client_definition_and_impl(client_impl_name); + render_sync_client_tthriftclient_impl(client_impl_name); + render_sync_client_marker_trait_impls(tservice, client_impl_name); f_gen_ << endl; + render_sync_client_process_impl(tservice); +} + +void t_rs_generator::render_sync_client_trait(t_service *tservice) { + string extension = ""; + if (tservice->get_extends()) { + t_service* extends = tservice->get_extends(); + extension = " : " + rust_namespace(extends) + rust_sync_client_trait_name(extends); + } + + render_rustdoc((t_doc*) tservice); + f_gen_ << "pub trait " << rust_sync_client_trait_name(tservice) << extension << " {" << endl; + indent_up(); + + const std::vector functions = tservice->get_functions(); + std::vector::const_iterator func_iter; + for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { + t_function* tfunc = (*func_iter); + string func_name = service_call_client_function_name(tfunc); + string func_args = rust_sync_service_call_declaration(tfunc, true); + string func_return = to_rust_type(tfunc->get_returntype()); + render_rustdoc((t_doc*) tfunc); + f_gen_ << indent() << "fn " << func_name << func_args << " -> thrift::Result<" << func_return << ">;" << endl; + } + + indent_down(); + f_gen_ << indent() << "}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_sync_client_marker_trait(t_service *tservice) { + f_gen_ << indent() << "pub trait " << rust_sync_client_marker_trait_name(tservice) << " {}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_sync_client_marker_trait_impls(t_service *tservice, const string &impl_struct_name) { + f_gen_ + << indent() + << "impl " + << SYNC_CLIENT_GENERIC_BOUND_VARS + << " " + << rust_namespace(tservice) << rust_sync_client_marker_trait_name(tservice) + << " for " + << impl_struct_name << SYNC_CLIENT_GENERIC_BOUND_VARS + << " " + << SYNC_CLIENT_GENERIC_BOUNDS + << " {}" + << endl; + + t_service* extends = tservice->get_extends(); + if (extends) { + render_sync_client_marker_trait_impls(extends, impl_struct_name); + } +} + +void t_rs_generator::render_sync_client_definition_and_impl(const string& client_impl_name) { + + // render the definition for the client struct + f_gen_ + << "pub struct " + << client_impl_name + << SYNC_CLIENT_GENERIC_BOUND_VARS + << " " + << SYNC_CLIENT_GENERIC_BOUNDS + << " {" + << endl; + indent_up(); + f_gen_ << indent() << "_i_prot: IP," << endl; + f_gen_ << indent() << "_o_prot: OP," << endl; + f_gen_ << indent() << "_sequence_number: i32," << endl; + indent_down(); + f_gen_ << "}" << endl; + f_gen_ << endl; + + // render the struct implementation + // this includes the new() function as well as the helper send/recv methods for each service call + f_gen_ + << "impl " + << SYNC_CLIENT_GENERIC_BOUND_VARS + << " " + << client_impl_name + << SYNC_CLIENT_GENERIC_BOUND_VARS + << " " + << SYNC_CLIENT_GENERIC_BOUNDS + << " {" + << endl; + indent_up(); + render_sync_client_lifecycle_functions(client_impl_name); + indent_down(); + f_gen_ << "}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_sync_client_lifecycle_functions(const string& client_struct) { + f_gen_ + << indent() + << "pub fn new(input_protocol: IP, output_protocol: OP) -> " + << client_struct + << SYNC_CLIENT_GENERIC_BOUND_VARS + << " {" + << endl; + indent_up(); + + f_gen_ + << indent() + << client_struct + << " { _i_prot: input_protocol, _o_prot: output_protocol, _sequence_number: 0 }" + << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +void t_rs_generator::render_sync_client_tthriftclient_impl(const string &client_impl_name) { + f_gen_ + << indent() + << "impl " + << SYNC_CLIENT_GENERIC_BOUND_VARS + << " TThriftClient for " + << client_impl_name + << SYNC_CLIENT_GENERIC_BOUND_VARS + << " " + << SYNC_CLIENT_GENERIC_BOUNDS + << " {" << endl; + indent_up(); + + f_gen_ << indent() << "fn i_prot_mut(&mut self) -> &mut TInputProtocol { &mut self._i_prot }" << endl; + f_gen_ << indent() << "fn o_prot_mut(&mut self) -> &mut TOutputProtocol { &mut self._o_prot }" << endl; + f_gen_ << indent() << "fn sequence_number(&self) -> i32 { self._sequence_number }" << endl; + f_gen_ + << indent() + << "fn increment_sequence_number(&mut self) -> i32 { self._sequence_number += 1; self._sequence_number }" + << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_sync_client_process_impl(t_service* tservice) { + string marker_extension = "" + sync_client_marker_traits_for_extension(tservice); + + f_gen_ + << "impl " + << rust_sync_client_trait_name(tservice) + << " for C {" << endl; + indent_up(); + + const std::vector functions = tservice->get_functions(); + std::vector::const_iterator func_iter; + for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { + t_function* func = (*func_iter); + render_sync_send_recv_wrapper(func); + } + + indent_down(); + f_gen_ << "}" << endl; + f_gen_ << endl; +} + +string t_rs_generator::sync_client_marker_traits_for_extension(t_service *tservice) { + string marker_extension; + + t_service* extends = tservice->get_extends(); + if (extends) { + marker_extension = " + " + rust_namespace(extends) + rust_sync_client_marker_trait_name(extends); + marker_extension = marker_extension + sync_client_marker_traits_for_extension(extends); + } + + return marker_extension; +} + +void t_rs_generator::render_sync_send_recv_wrapper(t_function* tfunc) { + string func_name = service_call_client_function_name(tfunc); + string func_decl_args = rust_sync_service_call_declaration(tfunc, true); + string func_call_args = rust_sync_service_call_invocation(tfunc); + string func_return = to_rust_type(tfunc->get_returntype()); + + f_gen_ + << indent() + << "fn " << func_name << func_decl_args << " -> thrift::Result<" << func_return + << "> {" + << endl; + indent_up(); + + f_gen_ << indent() << "(" << endl; + indent_up(); + render_sync_send(tfunc); + indent_down(); + f_gen_ << indent() << ")?;" << endl; + if (tfunc->is_oneway()) { + f_gen_ << indent() << "Ok(())" << endl; + } else { + render_sync_recv(tfunc); + } + + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +void t_rs_generator::render_sync_send(t_function* tfunc) { + f_gen_ << indent() << "{" << endl; + indent_up(); + + // increment the sequence number and generate the call header + string message_type = tfunc->is_oneway() ? "TMessageType::OneWay" : "TMessageType::Call"; + f_gen_ << indent() << "self.increment_sequence_number();" << endl; + f_gen_ + << indent() + << "let message_ident = " + << "TMessageIdentifier::new(\"" << tfunc->get_name() << "\", " // note: use *original* name + << message_type << ", " + << "self.sequence_number());" + << endl; + // pack the arguments into the containing struct that we'll write out over the wire + // note that this struct is generated even if we have 0 args + ostringstream struct_definition; + vector members = tfunc->get_arglist()->get_sorted_members(); + vector::iterator members_iter; + for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* member = (*members_iter); + string member_name(rust_field_name(member)); + struct_definition << member_name << ": " << member_name << ", "; + } + string struct_fields = struct_definition.str(); + if (struct_fields.size() > 0) { + struct_fields = struct_fields.substr(0, struct_fields.size() - 2); // strip trailing comma + } + f_gen_ + << indent() + << "let call_args = " + << rust_struct_name(tfunc->get_arglist()) + << " { " + << struct_fields + << " };" + << endl; + // write everything over the wire + f_gen_ << indent() << "self.o_prot_mut().write_message_begin(&message_ident)?;" << endl; + f_gen_ << indent() << "call_args.write_to_out_protocol(self.o_prot_mut())?;" << endl; // written even if we have 0 args + f_gen_ << indent() << "self.o_prot_mut().write_message_end()?;" << endl; + f_gen_ << indent() << "self.o_prot_mut().flush()" << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +void t_rs_generator::render_sync_recv(t_function* tfunc) { + f_gen_ << indent() << "{" << endl; + indent_up(); + + f_gen_ << indent() << "let message_ident = self.i_prot_mut().read_message_begin()?;" << endl; + f_gen_ << indent() << "verify_expected_sequence_number(self.sequence_number(), message_ident.sequence_number)?;" << endl; + f_gen_ << indent() << "verify_expected_service_call(\"" << tfunc->get_name() <<"\", &message_ident.name)?;" << endl; // note: use *original* name + // FIXME: replace with a "try" block + f_gen_ << indent() << "if message_ident.message_type == TMessageType::Exception {" << endl; + indent_up(); + f_gen_ << indent() << "let remote_error = thrift::Error::read_application_error_from_in_protocol(self.i_prot_mut())?;" << endl; + f_gen_ << indent() << "self.i_prot_mut().read_message_end()?;" << endl; + f_gen_ << indent() << "return Err(thrift::Error::Application(remote_error))" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + f_gen_ << indent() << "verify_expected_message_type(TMessageType::Reply, message_ident.message_type)?;" << endl; + f_gen_ << indent() << "let result = " << service_call_result_struct_name(tfunc) << "::read_from_in_protocol(self.i_prot_mut())?;" << endl; + f_gen_ << indent() << "self.i_prot_mut().read_message_end()?;" << endl; + f_gen_ << indent() << "result.ok_or()" << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +string t_rs_generator::rust_sync_service_call_declaration(t_function* tfunc, bool self_is_mutable) { + ostringstream func_args; + + if (self_is_mutable) { + func_args << "(&mut self"; + } else { + func_args << "(&self"; + } + + if (has_args(tfunc)) { + func_args << ", "; // put comma after "self" + func_args << struct_to_declaration(tfunc->get_arglist(), T_ARGS); + } + + func_args << ")"; + return func_args.str(); +} + +string t_rs_generator::rust_sync_service_call_invocation(t_function* tfunc, const string& field_prefix) { + ostringstream func_args; + func_args << "("; + + if (has_args(tfunc)) { + func_args << struct_to_invocation(tfunc->get_arglist(), field_prefix); + } + + func_args << ")"; + return func_args.str(); +} + +string t_rs_generator::struct_to_declaration(t_struct* tstruct, t_rs_generator::e_struct_type struct_type) { + ostringstream args; + + bool first_arg = true; + std::vector fields = tstruct->get_sorted_members(); + std::vector::iterator field_iter; + for (field_iter = fields.begin(); field_iter != fields.end(); ++field_iter) { + t_field* tfield = (*field_iter); + t_field::e_req field_req = actual_field_req(tfield, struct_type); + string rust_type = to_rust_type(tfield->get_type()); + rust_type = is_optional(field_req) ? "Option<" + rust_type + ">" : rust_type; + + if (first_arg) { + first_arg = false; + } else { + args << ", "; + } + + args << rust_field_name(tfield) << ": " << rust_type; + } + + return args.str(); +} + +string t_rs_generator::struct_to_invocation(t_struct* tstruct, const string& field_prefix) { + ostringstream args; + + bool first_arg = true; + std::vector fields = tstruct->get_sorted_members(); + std::vector::iterator field_iter; + for (field_iter = fields.begin(); field_iter != fields.end(); ++field_iter) { + t_field* tfield = (*field_iter); + + if (first_arg) { + first_arg = false; + } else { + args << ", "; + } + + args << field_prefix << rust_field_name(tfield); + } + + return args.str(); +} + +void t_rs_generator::render_result_value_struct(t_function* tfunc) { + string result_struct_name = service_call_result_struct_name(tfunc); + t_struct result(program_, result_struct_name); + + t_field return_value(tfunc->get_returntype(), SERVICE_RESULT_VARIABLE, 0); + return_value.set_req(t_field::T_OPTIONAL); + if (!tfunc->get_returntype()->is_void()) { + result.append(&return_value); + } + + t_struct* exceptions = tfunc->get_xceptions(); + const vector& exception_types = exceptions->get_members(); + vector::const_iterator exception_iter; + for(exception_iter = exception_types.begin(); exception_iter != exception_types.end(); ++exception_iter) { + t_field* exception_type = *exception_iter; + exception_type->set_req(t_field::T_OPTIONAL); + result.append(exception_type); + } + + render_struct(result_struct_name, &result, t_rs_generator::T_RESULT); +} + +//----------------------------------------------------------------------------- +// +// Sync Processor +// +//----------------------------------------------------------------------------- + +void t_rs_generator::render_sync_processor(t_service *tservice) { + render_type_comment(tservice->get_name() + " service processor"); // note: use *original* name + render_sync_handler_trait(tservice); + render_sync_processor_definition_and_impl(tservice); +} + +void t_rs_generator::render_sync_handler_trait(t_service *tservice) { + string extension = ""; + if (tservice->get_extends() != NULL) { + t_service* extends = tservice->get_extends(); + extension = " : " + rust_namespace(extends) + rust_sync_handler_trait_name(extends); + } + + const std::vector functions = tservice->get_functions(); + std::vector::const_iterator func_iter; + + render_rustdoc((t_doc*) tservice); + f_gen_ << "pub trait " << rust_sync_handler_trait_name(tservice) << extension << " {" << endl; + indent_up(); + for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { + t_function* tfunc = (*func_iter); + string func_name = service_call_handler_function_name(tfunc); + string func_args = rust_sync_service_call_declaration(tfunc, false); + string func_return = to_rust_type(tfunc->get_returntype()); + render_rustdoc((t_doc*) tfunc); + f_gen_ + << indent() + << "fn " + << func_name << func_args + << " -> thrift::Result<" << func_return << ">;" + << endl; + } + indent_down(); + f_gen_ << indent() << "}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_sync_processor_definition_and_impl(t_service *tservice) { + string service_processor_name = rust_sync_processor_name(tservice); + string handler_trait_name = rust_sync_handler_trait_name(tservice); + + // struct + f_gen_ + << indent() + << "pub struct " << service_processor_name + << " {" + << endl; + indent_up(); + f_gen_ << indent() << "handler: H," << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + f_gen_ << endl; + + // delegating impl + f_gen_ + << indent() + << "impl " + << service_processor_name + << " {" + << endl; + indent_up(); + f_gen_ << indent() << "pub fn new(handler: H) -> " << service_processor_name << " {" << endl; + indent_up(); + f_gen_ << indent() << service_processor_name << " {" << endl; + indent_up(); + f_gen_ << indent() << "handler: handler," << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + indent_down(); + f_gen_ << indent() << "}" << endl; + render_sync_process_delegation_functions(tservice); + indent_down(); + f_gen_ << indent() << "}" << endl; + f_gen_ << endl; + + // actual impl + string service_actual_processor_name = rust_sync_processor_impl_name(tservice); + f_gen_ << indent() << "pub struct " << service_actual_processor_name << ";" << endl; + f_gen_ << endl; + f_gen_ << indent() << "impl " << service_actual_processor_name << " {" << endl; + indent_up(); + + vector functions = tservice->get_functions(); + vector::iterator func_iter; + for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { + t_function* tfunc = (*func_iter); + render_sync_process_function(tfunc, handler_trait_name); + } + + indent_down(); + f_gen_ << indent() << "}" << endl; + f_gen_ << endl; + + // processor impl + f_gen_ + << indent() + << "impl TProcessor for " + << service_processor_name + << " {" + << endl; + indent_up(); + + f_gen_ + << indent() + << "fn process(&self, i_prot: &mut TInputProtocol, o_prot: &mut TOutputProtocol) -> thrift::Result<()> {" + << endl; + indent_up(); + + f_gen_ << indent() << "let message_ident = i_prot.read_message_begin()?;" << endl; + + f_gen_ << indent() << "let res = match &*message_ident.name {" << endl; // [sigh] explicit deref coercion + indent_up(); + render_process_match_statements(tservice); + f_gen_ << indent() << "method => {" << endl; + indent_up(); + render_rift_error( + "Application", + "ApplicationError", + "ApplicationErrorKind::UnknownMethod", + "format!(\"unknown method {}\", method)" + ); + indent_down(); + f_gen_ << indent() << "}," << endl; + + indent_down(); + f_gen_ << indent() << "};" << endl; + f_gen_ << indent() << "thrift::server::handle_process_result(&message_ident, res, o_prot)" << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; + f_gen_ << endl; +} + +void t_rs_generator::render_sync_process_delegation_functions(t_service *tservice) { + string actual_processor(rust_namespace(tservice) + rust_sync_processor_impl_name(tservice)); + + vector functions = tservice->get_functions(); + vector::iterator func_iter; + for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { + t_function* tfunc = (*func_iter); + string function_name("process_" + rust_snake_case(tfunc->get_name())); + f_gen_ + << indent() + << "fn " << function_name + << "(&self, " + << "incoming_sequence_number: i32, " + << "i_prot: &mut TInputProtocol, " + << "o_prot: &mut TOutputProtocol) " + << "-> thrift::Result<()> {" + << endl; + indent_up(); + + f_gen_ + << indent() + << actual_processor + << "::" << function_name + << "(" + << "&self.handler, " + << "incoming_sequence_number, " + << "i_prot, " + << "o_prot" + << ")" + << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; + } + + t_service* extends = tservice->get_extends(); + if (extends) { + render_sync_process_delegation_functions(extends); + } +} + +void t_rs_generator::render_process_match_statements(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator func_iter; + for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { + t_function* tfunc = (*func_iter); + f_gen_ << indent() << "\"" << tfunc->get_name() << "\"" << " => {" << endl; // note: use *original* name + indent_up(); + f_gen_ + << indent() + << "self.process_" << rust_snake_case(tfunc->get_name()) + << "(message_ident.sequence_number, i_prot, o_prot)" + << endl; + indent_down(); + f_gen_ << indent() << "}," << endl; + } + + t_service* extends = tservice->get_extends(); + if (extends) { + render_process_match_statements(extends); + } +} + +void t_rs_generator::render_sync_process_function(t_function *tfunc, const string &handler_type) { + string sequence_number_param("incoming_sequence_number"); + string output_protocol_param("o_prot"); + + if (tfunc->is_oneway()) { + sequence_number_param = "_"; + output_protocol_param = "_"; + } + + f_gen_ + << indent() + << "pub fn process_" << rust_snake_case(tfunc->get_name()) + << "" + << "(handler: &H, " + << sequence_number_param << ": i32, " + << "i_prot: &mut TInputProtocol, " + << output_protocol_param << ": &mut TOutputProtocol) " + << "-> thrift::Result<()> {" + << endl; + + indent_up(); + + // *always* read arguments from the input protocol + f_gen_ + << indent() + << "let " + << (has_non_void_args(tfunc) ? "args" : "_") + << " = " + << rust_struct_name(tfunc->get_arglist()) + << "::read_from_in_protocol(i_prot)?;" + << endl; + + f_gen_ + << indent() + << "match handler." + << service_call_handler_function_name(tfunc) + << rust_sync_service_call_invocation(tfunc, "args.") + << " {" + << endl; // start match + indent_up(); + + // handler succeeded + string handler_return_variable = tfunc->is_oneway() || tfunc->get_returntype()->is_void() ? "_" : "handler_return"; + f_gen_ << indent() << "Ok(" << handler_return_variable << ") => {" << endl; + indent_up(); + render_sync_handler_succeeded(tfunc); + indent_down(); + f_gen_ << indent() << "}," << endl; + // handler failed + f_gen_ << indent() << "Err(e) => {" << endl; + indent_up(); + render_sync_handler_failed(tfunc); + indent_down(); + f_gen_ << indent() << "}," << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; // end match + + indent_down(); + f_gen_ << indent() << "}" << endl; // end function +} + +void t_rs_generator::render_sync_handler_succeeded(t_function *tfunc) { + if (tfunc->is_oneway()) { + f_gen_ << indent() << "Ok(())" << endl; + } else { + f_gen_ + << indent() + << "let message_ident = TMessageIdentifier::new(" + << "\"" << tfunc->get_name() << "\", " // note: use *original* name + << "TMessageType::Reply, " + << "incoming_sequence_number);" + << endl; + f_gen_ << indent() << "o_prot.write_message_begin(&message_ident)?;" << endl; + f_gen_ << indent() << "let ret = " << handler_successful_return_struct(tfunc) <<";" << endl; + f_gen_ << indent() << "ret.write_to_out_protocol(o_prot)?;" << endl; + f_gen_ << indent() << "o_prot.write_message_end()?;" << endl; + f_gen_ << indent() << "o_prot.flush()" << endl; + } +} + +void t_rs_generator::render_sync_handler_failed(t_function *tfunc) { + string err_var("e"); + + f_gen_ << indent() << "match " << err_var << " {" << endl; + indent_up(); + + // if there are any user-defined exceptions for this service call handle them first + if (tfunc->get_xceptions() != NULL && tfunc->get_xceptions()->get_sorted_members().size() > 0) { + string user_err_var("usr_err"); + f_gen_ << indent() << "thrift::Error::User(" << user_err_var << ") => {" << endl; + indent_up(); + render_sync_handler_failed_user_exception_branch(tfunc); + indent_down(); + f_gen_ << indent() << "}," << endl; + } + + // application error + string app_err_var("app_err"); + f_gen_ << indent() << "thrift::Error::Application(" << app_err_var << ") => {" << endl; + indent_up(); + render_sync_handler_failed_application_exception_branch(tfunc, app_err_var); + indent_down(); + f_gen_ << indent() << "}," << endl; + + // default case + f_gen_ << indent() << "_ => {" << endl; + indent_up(); + render_sync_handler_failed_default_exception_branch(tfunc); + indent_down(); + f_gen_ << indent() << "}," << endl; + + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +void t_rs_generator::render_sync_handler_failed_user_exception_branch(t_function *tfunc) { + if (tfunc->get_xceptions() == NULL || tfunc->get_xceptions()->get_sorted_members().empty()) { + throw "cannot render user exception branches if no user exceptions defined"; + } + + const vector txceptions = tfunc->get_xceptions()->get_sorted_members(); + vector::const_iterator xception_iter; + int branches_rendered = 0; + + // run through all user-defined exceptions + for (xception_iter = txceptions.begin(); xception_iter != txceptions.end(); ++xception_iter) { + t_field* xception_field = (*xception_iter); + + string if_statement(branches_rendered == 0 ? "if usr_err" : "} else if usr_err"); + string exception_type(to_rust_type(xception_field->get_type())); + f_gen_ << indent() << if_statement << ".downcast_ref::<" << exception_type << ">().is_some() {" << endl; + indent_up(); + + f_gen_ + << indent() + << "let err = usr_err.downcast::<" << exception_type << ">().expect(\"downcast already checked\");" + << endl; + + // render the members of the return struct + ostringstream members; + + bool has_result_variable = !(tfunc->is_oneway() || tfunc->get_returntype()->is_void()); + if (has_result_variable) { + members << SERVICE_RESULT_VARIABLE << ": None, "; + } + + vector::const_iterator xception_members_iter; + for(xception_members_iter = txceptions.begin(); xception_members_iter != txceptions.end(); ++xception_members_iter) { + t_field* member = (*xception_members_iter); + string member_name(rust_field_name(member)); + if (member == xception_field) { + members << member_name << ": Some(*err), "; + } else { + members << member_name << ": None, "; + } + } + + string member_string = members.str(); + member_string.replace(member_string.size() - 2, 2, " "); // trim trailing comma + + // now write out the return struct + f_gen_ + << indent() + << "let ret_err = " + << service_call_result_struct_name(tfunc) + << "{ " << member_string << "};" + << endl; + + f_gen_ + << indent() + << "let message_ident = " + << "TMessageIdentifier::new(" + << "\"" << tfunc->get_name() << "\", " // note: use *original* name + << "TMessageType::Reply, " + << "incoming_sequence_number);" + << endl; + f_gen_ << indent() << "o_prot.write_message_begin(&message_ident)?;" << endl; + f_gen_ << indent() << "ret_err.write_to_out_protocol(o_prot)?;" << endl; + f_gen_ << indent() << "o_prot.write_message_end()?;" << endl; + f_gen_ << indent() << "o_prot.flush()" << endl; + + indent_down(); + + branches_rendered++; + } + + // the catch all, if somehow it was a user exception that we don't support + f_gen_ << indent() << "} else {" << endl; + indent_up(); + + // FIXME: same as default block below + + f_gen_ << indent() << "let ret_err = {" << endl; + indent_up(); + render_rift_error_struct("ApplicationError", "ApplicationErrorKind::Unknown", "usr_err.description()"); + indent_down(); + f_gen_ << indent() << "};" << endl; + render_sync_handler_send_exception_response(tfunc, "ret_err"); + + indent_down(); + f_gen_ << indent() << "}" << endl; +} + +void t_rs_generator::render_sync_handler_failed_application_exception_branch( + t_function *tfunc, + const string &app_err_var +) { + if (tfunc->is_oneway()) { + f_gen_ << indent() << "Err(thrift::Error::Application(" << app_err_var << "))" << endl; + } else { + render_sync_handler_send_exception_response(tfunc, app_err_var); + } +} + +void t_rs_generator::render_sync_handler_failed_default_exception_branch(t_function *tfunc) { + f_gen_ << indent() << "let ret_err = {" << endl; + indent_up(); + render_rift_error_struct("ApplicationError", "ApplicationErrorKind::Unknown", "e.description()"); + indent_down(); + f_gen_ << indent() << "};" << endl; + if (tfunc->is_oneway()) { + f_gen_ << indent() << "Err(thrift::Error::Application(ret_err))" << endl; + } else { + render_sync_handler_send_exception_response(tfunc, "ret_err"); + } +} + +void t_rs_generator::render_sync_handler_send_exception_response(t_function *tfunc, const string &err_var) { + f_gen_ + << indent() + << "let message_ident = TMessageIdentifier::new(" + << "\"" << tfunc->get_name() << "\", " // note: use *original* name + << "TMessageType::Exception, " + << "incoming_sequence_number);" + << endl; + f_gen_ << indent() << "o_prot.write_message_begin(&message_ident)?;" << endl; + f_gen_ << indent() << "thrift::Error::write_application_error_to_out_protocol(&" << err_var << ", o_prot)?;" << endl; + f_gen_ << indent() << "o_prot.write_message_end()?;" << endl; + f_gen_ << indent() << "o_prot.flush()" << endl; +} + +string t_rs_generator::handler_successful_return_struct(t_function* tfunc) { + int member_count = 0; + ostringstream return_struct; + + return_struct << service_call_result_struct_name(tfunc) << " { "; + + // actual return + if (!tfunc->get_returntype()->is_void()) { + return_struct << "result_value: Some(handler_return)"; + member_count++; + } + + // any user-defined exceptions + if (tfunc->get_xceptions() != NULL) { + t_struct* txceptions = tfunc->get_xceptions(); + const vector members = txceptions->get_sorted_members(); + vector::const_iterator members_iter; + for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { + t_field* xception_field = (*members_iter); + if (member_count > 0) { return_struct << ", "; } + return_struct << rust_field_name(xception_field) << ": None"; + member_count++; + } + } + + return_struct << " }"; + + return return_struct.str(); +} + +//----------------------------------------------------------------------------- +// +// Utility +// +//----------------------------------------------------------------------------- + +void t_rs_generator::render_type_comment(const string& type_name) { + f_gen_ << "//" << endl; + f_gen_ << "// " << type_name << endl; + f_gen_ << "//" << endl; + f_gen_ << endl; +} + +// NOTE: do *not* put in an extra newline after doc is generated. +// This is because rust docs have to abut the line they're documenting. +void t_rs_generator::render_rustdoc(t_doc* tdoc) { + if (!tdoc->has_doc()) { + return; + } + + generate_docstring_comment(f_gen_, "", "/// ", tdoc->get_doc(), ""); +} + +void t_rs_generator::render_rift_error( + const string& error_kind, + const string& error_struct, + const string& sub_error_kind, + const string& error_message +) { + f_gen_ << indent() << "Err(" << endl; + indent_up(); + f_gen_ << indent() << "thrift::Error::" << error_kind << "(" << endl; + indent_up(); + render_rift_error_struct(error_struct, sub_error_kind, error_message); + indent_down(); + f_gen_ << indent() << ")" << endl; + indent_down(); + f_gen_ << indent() << ")" << endl; +} + +void t_rs_generator::render_rift_error_struct( + const string& error_struct, + const string& sub_error_kind, + const string& error_message +) { + f_gen_ << indent() << error_struct << "::new(" << endl; + indent_up(); + f_gen_ << indent() << sub_error_kind << "," << endl; + f_gen_ << indent() << error_message << endl; + indent_down(); + f_gen_ << indent() << ")" << endl; +} + +bool t_rs_generator::is_double(t_type* ttype) { + ttype = get_true_type(ttype); + if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + if (tbase == t_base_type::TYPE_DOUBLE) { + return true; + } + } + + return false; +} + +string t_rs_generator::to_rust_type(t_type* ttype, bool ordered_float) { + // ttype = get_true_type(ttype); <-- recurses through as many typedef layers as necessary + if (ttype->is_base_type()) { + t_base_type* tbase_type = ((t_base_type*)ttype); + switch (tbase_type->get_base()) { + case t_base_type::TYPE_VOID: + return "()"; + case t_base_type::TYPE_STRING: + if (tbase_type->is_binary()) { + return "Vec"; + } else { + return "String"; + } + case t_base_type::TYPE_BOOL: + return "bool"; + case t_base_type::TYPE_I8: + return "i8"; + case t_base_type::TYPE_I16: + return "i16"; + case t_base_type::TYPE_I32: + return "i32"; + case t_base_type::TYPE_I64: + return "i64"; + case t_base_type::TYPE_DOUBLE: + if (ordered_float) { + return "OrderedFloat"; + } else { + return "f64"; + } + } + } else if (ttype->is_typedef()) { + t_typedef* ttypedef = (t_typedef*)ttype; + string rust_type = rust_namespace(ttype) + ttypedef->get_symbolic(); + rust_type = ttypedef->is_forward_typedef() ? "Box<" + rust_type + ">" : rust_type; + return rust_type; + } else if (ttype->is_enum()) { + return rust_namespace(ttype) + ttype->get_name(); + } else if (ttype->is_struct() || ttype->is_xception()) { + return rust_namespace(ttype) + rust_camel_case(ttype->get_name()); + } else if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + return "BTreeMap<" + to_rust_type(tmap->get_key_type()) + ", " + to_rust_type(tmap->get_val_type()) + ">"; + } else if (ttype->is_set()) { + t_set* tset = (t_set*)ttype; + return "BTreeSet<" + to_rust_type(tset->get_elem_type()) + ">"; + } else if (ttype->is_list()) { + t_list* tlist = (t_list*)ttype; + return "Vec<" + to_rust_type(tlist->get_elem_type()) + ">"; + } + + throw "cannot find rust type for " + ttype->get_name(); +} + +string t_rs_generator::to_rust_field_type_enum(t_type* ttype) { + ttype = get_true_type(ttype); + if (ttype->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "will not generate protocol::TType for TYPE_VOID"; + case t_base_type::TYPE_STRING: // both strings and binary are actually encoded as TType::String + return "TType::String"; + case t_base_type::TYPE_BOOL: + return "TType::Bool"; + case t_base_type::TYPE_I8: + return "TType::I08"; + case t_base_type::TYPE_I16: + return "TType::I16"; + case t_base_type::TYPE_I32: + return "TType::I32"; + case t_base_type::TYPE_I64: + return "TType::I64"; + case t_base_type::TYPE_DOUBLE: + return "TType::Double"; + } + } else if (ttype->is_enum()) { + return "TType::I32"; + } else if (ttype->is_struct() || ttype->is_xception()) { + return "TType::Struct"; + } else if (ttype->is_map()) { + return "TType::Map"; + } else if (ttype->is_set()) { + return "TType::Set"; + } else if (ttype->is_list()) { + return "TType::List"; + } + + throw "cannot find TType for " + ttype->get_name(); +} + +string t_rs_generator::opt_in_req_out_value(t_type* ttype) { + ttype = get_true_type(ttype); + if (ttype->is_base_type()) { + t_base_type* tbase_type = ((t_base_type*)ttype); + switch (tbase_type->get_base()) { + case t_base_type::TYPE_VOID: + throw "cannot generate OPT_IN_REQ_OUT value for void"; + case t_base_type::TYPE_STRING: + if (tbase_type->is_binary()) { + return "Some(Vec::new())"; + } else { + return "Some(\"\".to_owned())"; + } + case t_base_type::TYPE_BOOL: + return "Some(false)"; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + return "Some(0)"; + case t_base_type::TYPE_DOUBLE: + return "Some(OrderedFloat::from(0.0))"; + } + + } else if (ttype->is_enum() || ttype->is_struct() || ttype->is_xception()) { + return "None"; + } else if (ttype->is_list()) { + return "Some(Vec::new())"; + } else if (ttype->is_set()) { + return "Some(BTreeSet::new())"; + } else if (ttype->is_map()) { + return "Some(BTreeMap::new())"; + } + + throw "cannot generate opt-in-req-out value for type " + ttype->get_name(); +} + +bool t_rs_generator::can_generate_simple_const(t_type* ttype) { + t_type* actual_type = get_true_type(ttype); + if (actual_type->is_base_type()) { + t_base_type* tbase_type = (t_base_type*)actual_type; + return !(tbase_type->get_base() == t_base_type::TYPE_DOUBLE); + } else { + return false; + } +} + +bool t_rs_generator::can_generate_const_holder(t_type* ttype) { + t_type* actual_type = get_true_type(ttype); + return !can_generate_simple_const(actual_type) && !actual_type->is_service(); +} + +bool t_rs_generator::is_void(t_type* ttype) { + return ttype->is_base_type() && ((t_base_type*)ttype)->get_base() == t_base_type::TYPE_VOID; +} + +bool t_rs_generator::is_optional(t_field::e_req req) { + return req == t_field::T_OPTIONAL || req == t_field::T_OPT_IN_REQ_OUT; +} + +t_field::e_req t_rs_generator::actual_field_req(t_field* tfield, t_rs_generator::e_struct_type struct_type) { + return struct_type == t_rs_generator::T_ARGS ? t_field::T_REQUIRED : tfield->get_req(); +} + +bool t_rs_generator::has_args(t_function* tfunc) { + return tfunc->get_arglist() != NULL && !tfunc->get_arglist()->get_sorted_members().empty(); +} + +bool t_rs_generator::has_non_void_args(t_function* tfunc) { + bool has_non_void_args = false; + + const vector args = tfunc->get_arglist()->get_sorted_members(); + vector::const_iterator args_iter; + for (args_iter = args.begin(); args_iter != args.end(); ++args_iter) { + t_field* tfield = (*args_iter); + if (!tfield->get_type()->is_void()) { + has_non_void_args = true; + break; + } + } + + return has_non_void_args; +} + +string t_rs_generator::visibility_qualifier(t_rs_generator::e_struct_type struct_type) { + switch(struct_type) { + case t_rs_generator::T_ARGS: + case t_rs_generator::T_RESULT: + return ""; + default: + return "pub "; + } +} + +string t_rs_generator::rust_namespace(t_service* tservice) { + if (tservice->get_program()->get_name() != get_program()->get_name()) { + return rust_snake_case(tservice->get_program()->get_name()) + "::"; + } else { + return ""; + } +} + +string t_rs_generator::rust_namespace(t_type* ttype) { + if (ttype->get_program()->get_name() != get_program()->get_name()) { + return rust_snake_case(ttype->get_program()->get_name()) + "::"; + } else { + return ""; + } +} + +bool t_rs_generator::is_reserved(const string& name) { + return RUST_RESERVED_WORDS_SET.find(name) != RUST_RESERVED_WORDS_SET.end(); +} + +string t_rs_generator::rust_struct_name(t_struct* tstruct) { + string base_struct_name(rust_camel_case(tstruct->get_name())); + return rust_safe_name(base_struct_name); +} + +string t_rs_generator::rust_field_name(t_field* tfield) { + string base_field_name(rust_snake_case(tfield->get_name())); + return rust_safe_name(base_field_name); +} + +string t_rs_generator::rust_union_field_name(t_field* tfield) { + string base_field_name(rust_camel_case(tfield->get_name())); + return rust_safe_name(base_field_name); +} + +string t_rs_generator::rust_safe_name(const string& name) { + if (is_reserved(name)) { + return name + "_"; + } else { + return name; + } +} + +string t_rs_generator::service_call_client_function_name(t_function* tfunc) { + return rust_snake_case(tfunc->get_name()); +} + +string t_rs_generator::service_call_handler_function_name(t_function* tfunc) { + return "handle_" + rust_snake_case(tfunc->get_name()); +} + +string t_rs_generator::service_call_result_struct_name(t_function* tfunc) { + return rust_camel_case(tfunc->get_name()) + RESULT_STRUCT_SUFFIX; +} + +string t_rs_generator::rust_sync_client_marker_trait_name(t_service* tservice) { + return "T" + rust_camel_case(tservice->get_name()) + "SyncClientMarker"; +} + +string t_rs_generator::rust_sync_client_trait_name(t_service* tservice) { + return "T" + rust_camel_case(tservice->get_name()) + "SyncClient"; +} + +string t_rs_generator::rust_sync_client_impl_name(t_service* tservice) { + return rust_camel_case(tservice->get_name()) + "SyncClient"; +} + +string t_rs_generator::rust_sync_handler_trait_name(t_service* tservice) { + return rust_camel_case(tservice->get_name()) + "SyncHandler"; +} + +string t_rs_generator::rust_sync_processor_name(t_service* tservice) { + return rust_camel_case(tservice->get_name()) + "SyncProcessor"; +} + +string t_rs_generator::rust_sync_processor_impl_name(t_service *tservice) { + return "T" + rust_camel_case(tservice->get_name()) + "ProcessFunctions"; +} + +string t_rs_generator::rust_upper_case(const string& name) { + string str(uppercase(underscore(name))); + string_replace(str, "__", "_"); + return str; +} + +string t_rs_generator::rust_snake_case(const string& name) { + string str(decapitalize(underscore(name))); + string_replace(str, "__", "_"); + return str; +} + +string t_rs_generator::rust_camel_case(const string& name) { + string str(capitalize(camelcase(name))); + string_replace(str, "_", ""); + return str; +} + +void t_rs_generator::string_replace(string& target, const string& search_string, const string& replace_string) { + if (target.empty()) { + return; + } + + size_t match_len = search_string.length(); + size_t replace_len = replace_string.length(); + + size_t search_idx = 0; + size_t match_idx; + while ((match_idx = target.find(search_string, search_idx)) != string::npos) { + target.replace(match_idx, match_len, replace_string); + search_idx = match_idx + replace_len; + } +} + +THRIFT_REGISTER_GENERATOR( + rs, + "Rust", + "\n") // no Rust-generator-specific options diff --git a/compiler/cpp/src/thrift/generate/t_st_generator.cc b/compiler/cpp/src/thrift/generate/t_st_generator.cc new file mode 100644 index 0000000..69ed776 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_st_generator.cc @@ -0,0 +1,1056 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "thrift/platform.h" +#include "thrift/version.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * Smalltalk code generator. + * + */ +class t_st_generator : public t_oop_generator { +public: + t_st_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + temporary_var = 0; + std::map::const_iterator iter; + + /* no options yet */ + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + throw "unknown option st:" + iter->first; + } + + out_dir_base_ = "gen-st"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + void generate_class_side_definition(); + void generate_force_consts(); + + std::string render_const_value(t_type* type, t_const_value* value); + + /** + * Struct generation code + */ + + void generate_st_struct(std::ofstream& out, t_struct* tstruct, bool is_exception); + void generate_accessors(std::ofstream& out, t_struct* tstruct); + + /** + * Service-level generation functions + */ + + void generate_service_client(t_service* tservice); + + void generate_send_method(t_function* tfunction); + void generate_recv_method(t_function* tfunction); + + std::string map_reader(t_map* tmap); + std::string list_reader(t_list* tlist); + std::string set_reader(t_set* tset); + std::string struct_reader(t_struct* tstruct, std::string clsName); + + std::string map_writer(t_map* tmap, std::string name); + std::string list_writer(t_list* tlist, std::string name); + std::string set_writer(t_set* tset, std::string name); + std::string struct_writer(t_struct* tstruct, std::string fname); + + std::string write_val(t_type* t, std::string fname); + std::string read_val(t_type* t); + + /** + * Helper rendering functions + */ + + std::string st_autogen_comment(); + + void st_class_def(std::ofstream& out, std::string name); + void st_method(std::ofstream& out, std::string cls, std::string name); + void st_method(std::ofstream& out, std::string cls, std::string name, std::string category); + void st_close_method(std::ofstream& out); + void st_class_method(std::ofstream& out, std::string cls, std::string name); + void st_class_method(std::ofstream& out, std::string cls, std::string name, std::string category); + void st_setter(std::ofstream& out, std::string cls, std::string name, std::string type); + void st_getter(std::ofstream& out, std::string cls, std::string name); + void st_accessors(std::ofstream& out, std::string cls, std::string name, std::string type); + + std::string class_name(); + static bool is_valid_namespace(const std::string& sub_namespace); + std::string client_class_name(); + std::string prefix(std::string name); + std::string declare_field(t_field* tfield); + std::string type_name(t_type* ttype); + + std::string function_signature(t_function* tfunction); + std::string argument_list(t_struct* tstruct); + std::string function_types_comment(t_function* fn); + + std::string type_to_enum(t_type* ttype); + std::string a_type(t_type* type); + bool is_vowel(char c); + std::string temp_name(); + std::string generated_category(); + +private: + /** + * File streams + */ + int temporary_var; + std::ofstream f_; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_st_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + + temporary_var = 0; + + // Make output file + string f_name = get_out_dir() + "/" + program_name_ + ".st"; + f_.open(f_name.c_str()); + + // Print header + f_ << st_autogen_comment() << endl; + + st_class_def(f_, program_name_); + generate_class_side_definition(); + + // Generate enums + vector enums = program_->get_enums(); + vector::iterator en_iter; + for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { + generate_enum(*en_iter); + } +} + +string t_st_generator::class_name() { + return capitalize(program_name_); +} + +bool t_st_generator::is_valid_namespace(const std::string& sub_namespace) { + return sub_namespace == "prefix" || sub_namespace == "category"; +} + +string t_st_generator::prefix(string class_name) { + string prefix = program_->get_namespace("smalltalk.prefix"); + string name = capitalize(class_name); + name = prefix.empty() ? name : (prefix + name); + return name; +} + +string t_st_generator::client_class_name() { + return capitalize(service_name_) + "Client"; +} + +/** + * Autogen'd comment + */ +string t_st_generator::st_autogen_comment() { + return std::string("'") + "Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + "\n" + + "DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "'!\n"; +} + +void t_st_generator::generate_force_consts() { + f_ << prefix(class_name()) << " enums keysAndValuesDo: [:k :v | " << prefix(class_name()) + << " enums at: k put: v value].!" << endl; + + f_ << prefix(class_name()) << " constants keysAndValuesDo: [:k :v | " << prefix(class_name()) + << " constants at: k put: v value].!" << endl; +} + +void t_st_generator::close_generator() { + generate_force_consts(); + f_.close(); +} + +string t_st_generator::generated_category() { + string cat = program_->get_namespace("smalltalk.category"); + // For compatibility with the Thrift grammar, the category must + // be punctuated by dots. Replaces them with dashes here. + for (string::iterator iter = cat.begin(); iter != cat.end(); ++iter) { + if (*iter == '.') { + *iter = '-'; + } + } + return cat.size() ? cat : "Generated-" + class_name(); +} + +/** + * Generates a typedef. This is not done in Smalltalk, types are all implicit. + * + * @param ttypedef The type definition + */ +void t_st_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + +void t_st_generator::st_class_def(std::ofstream& out, string name) { + out << "Object subclass: #" << prefix(name) << endl; + indent_up(); + out << indent() << "instanceVariableNames: ''" << endl << indent() << "classVariableNames: ''" + << endl << indent() << "poolDictionaries: ''" << endl << indent() << "category: '" + << generated_category() << "'!" << endl << endl; +} + +void t_st_generator::st_method(std::ofstream& out, string cls, string name) { + st_method(out, cls, name, "as yet uncategorized"); +} + +void t_st_generator::st_class_method(std::ofstream& out, string cls, string name) { + st_method(out, cls + " class", name); +} + +void t_st_generator::st_class_method(std::ofstream& out, string cls, string name, string category) { + st_method(out, cls, name, category); +} + +void t_st_generator::st_method(std::ofstream& out, string cls, string name, string category) { + char timestr[50]; + time_t rawtime; + struct tm* tinfo; + + time(&rawtime); + tinfo = localtime(&rawtime); + strftime(timestr, 50, "%m/%d/%Y %H:%M", tinfo); + + out << "!" << prefix(cls) << " methodsFor: '" + category + "' stamp: 'thrift " << timestr + << "'!\n" << name << endl; + + indent_up(); + out << indent(); +} + +void t_st_generator::st_close_method(std::ofstream& out) { + out << "! !" << endl << endl; + indent_down(); +} + +void t_st_generator::st_setter(std::ofstream& out, + string cls, + string name, + string type = "anObject") { + st_method(out, cls, name + ": " + type); + out << name << " := " + type; + st_close_method(out); +} + +void t_st_generator::st_getter(std::ofstream& out, string cls, string name) { + st_method(out, cls, name + ""); + out << "^ " << name; + st_close_method(out); +} + +void t_st_generator::st_accessors(std::ofstream& out, + string cls, + string name, + string type = "anObject") { + st_setter(out, cls, name, type); + st_getter(out, cls, name); +} + +void t_st_generator::generate_class_side_definition() { + f_ << prefix(class_name()) << " class" << endl << "\tinstanceVariableNames: 'constants enums'!" + << endl << endl; + + st_accessors(f_, class_name() + " class", "enums"); + st_accessors(f_, class_name() + " class", "constants"); + + f_ << prefix(class_name()) << " enums: Dictionary new!" << endl; + f_ << prefix(class_name()) << " constants: Dictionary new!" << endl; + + f_ << endl; +} + +/** + * Generates code for an enumerated type. Done using a class to scope + * the values. + * + * @param tenum The enumeration + */ +void t_st_generator::generate_enum(t_enum* tenum) { + string cls_name = program_name_ + capitalize(tenum->get_name()); + + f_ << prefix(class_name()) << " enums at: '" << tenum->get_name() << "' put: [" + << "(Dictionary new " << endl; + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + f_ << "\tat: '" << (*c_iter)->get_name() << "' put: " << value << ";" << endl; + } + + f_ << "\tyourself)]!" << endl << endl; +} + +/** + * Generate a constant value + */ +void t_st_generator::generate_const(t_const* tconst) { + t_type* type = tconst->get_type(); + string name = tconst->get_name(); + t_const_value* value = tconst->get_value(); + + f_ << prefix(class_name()) << " constants at: '" << name << "' put: [" + << render_const_value(type, value) << "]!" << endl << endl; +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +string t_st_generator::render_const_value(t_type* type, t_const_value* value) { + type = get_true_type(type); + std::ostringstream out; + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + out << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + out << (value->get_integer() > 0 ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + out << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + out << value->get_integer(); + } else { + out << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + indent(out) << value->get_integer(); + } else if (type->is_struct() || type->is_xception()) { + out << "(" << capitalize(type->get_name()) << " new " << endl; + indent_up(); + + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + + out << indent() << v_iter->first->get_string() << ": " + << render_const_value(field_type, v_iter->second) << ";" << endl; + } + out << indent() << "yourself)"; + + indent_down(); + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + out << "(Dictionary new" << endl; + indent_up(); + indent_up(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + out << indent() << indent(); + out << "at: " << render_const_value(ktype, v_iter->first); + out << " put: "; + out << render_const_value(vtype, v_iter->second); + out << ";" << endl; + } + out << indent() << indent() << "yourself)"; + indent_down(); + indent_down(); + } else if (type->is_list() || type->is_set()) { + t_type* etype; + if (type->is_list()) { + etype = ((t_list*)type)->get_elem_type(); + } else { + etype = ((t_set*)type)->get_elem_type(); + } + if (type->is_set()) { + out << "(Set new" << endl; + } else { + out << "(OrderedCollection new" << endl; + } + indent_up(); + indent_up(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + out << indent() << indent(); + out << "add: " << render_const_value(etype, *v_iter); + out << ";" << endl; + } + out << indent() << indent() << "yourself)"; + indent_down(); + indent_down(); + } else { + throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); + } + return out.str(); +} + +/** + * Generates a Smalltalk struct + */ +void t_st_generator::generate_struct(t_struct* tstruct) { + generate_st_struct(f_, tstruct, false); +} + +/** + * Generates a struct definition for a thrift exception. Basically the same + * as a struct but extends the Exception class. + * + * @param txception The struct definition + */ +void t_st_generator::generate_xception(t_struct* txception) { + generate_st_struct(f_, txception, true); +} + +/** + * Generates a smalltalk class to represent a struct + */ +void t_st_generator::generate_st_struct(std::ofstream& out, + t_struct* tstruct, + bool is_exception = false) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + if (is_exception) + out << "Error"; + else + out << "Object"; + + out << " subclass: #" << prefix(type_name(tstruct)) << endl << "\tinstanceVariableNames: '"; + + if (members.size() > 0) { + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (m_iter != members.begin()) + out << " "; + out << camelcase((*m_iter)->get_name()); + } + } + + out << "'\n" + << "\tclassVariableNames: ''\n" + << "\tpoolDictionaries: ''\n" + << "\tcategory: '" << generated_category() << "'!\n\n"; + + generate_accessors(out, tstruct); +} + +bool t_st_generator::is_vowel(char c) { + switch (tolower(c)) { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + return true; + } + return false; +} + +string t_st_generator::a_type(t_type* type) { + string prefix; + + if (is_vowel(type_name(type)[0])) + prefix = "an"; + else + prefix = "a"; + + return prefix + capitalize(type_name(type)); +} + +void t_st_generator::generate_accessors(std::ofstream& out, t_struct* tstruct) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + string type; + string prefix; + + if (members.size() > 0) { + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + st_accessors(out, + capitalize(type_name(tstruct)), + camelcase((*m_iter)->get_name()), + a_type((*m_iter)->get_type())); + } + out << endl; + } +} + +/** + * Generates a thrift service. + * + * @param tservice The service definition + */ +void t_st_generator::generate_service(t_service* tservice) { + generate_service_client(tservice); + // generate_service_server(tservice); +} + +string t_st_generator::temp_name() { + std::ostringstream out; + out << "temp" << temporary_var++; + return out.str(); +} + +string t_st_generator::map_writer(t_map* tmap, string fname) { + std::ostringstream out; + string key = temp_name(); + string val = temp_name(); + + out << "[oprot writeMapBegin: (TMap new keyType: " << type_to_enum(tmap->get_key_type()) + << "; valueType: " << type_to_enum(tmap->get_val_type()) << "; size: " << fname << " size)." + << endl; + indent_up(); + + out << indent() << fname << " keysAndValuesDo: [:" << key << " :" << val << " |" << endl; + indent_up(); + + out << indent() << write_val(tmap->get_key_type(), key) << "." << endl << indent() + << write_val(tmap->get_val_type(), val); + indent_down(); + + out << "]." << endl << indent() << "oprot writeMapEnd] value"; + indent_down(); + + return out.str(); +} + +string t_st_generator::map_reader(t_map* tmap) { + std::ostringstream out; + string desc = temp_name(); + string val = temp_name(); + + out << "[|" << desc << " " << val << "| " << endl; + indent_up(); + + out << indent() << desc << " := iprot readMapBegin." << endl << indent() << val + << " := Dictionary new." << endl << indent() << desc << " size timesRepeat: [" << endl; + + indent_up(); + out << indent() << val << " at: " << read_val(tmap->get_key_type()) + << " put: " << read_val(tmap->get_val_type()); + indent_down(); + + out << "]." << endl << indent() << "iprot readMapEnd." << endl << indent() << val << "] value"; + indent_down(); + + return out.str(); +} + +string t_st_generator::list_writer(t_list* tlist, string fname) { + std::ostringstream out; + string val = temp_name(); + + out << "[oprot writeListBegin: (TList new elemType: " << type_to_enum(tlist->get_elem_type()) + << "; size: " << fname << " size)." << endl; + indent_up(); + + out << indent() << fname << " do: [:" << val << "|" << endl; + indent_up(); + + out << indent() << write_val(tlist->get_elem_type(), val) << endl; + indent_down(); + + out << "]." << endl << indent() << "oprot writeListEnd] value"; + indent_down(); + + return out.str(); +} + +string t_st_generator::list_reader(t_list* tlist) { + std::ostringstream out; + string desc = temp_name(); + string val = temp_name(); + + out << "[|" << desc << " " << val << "| " << desc << " := iprot readListBegin." << endl; + indent_up(); + + out << indent() << val << " := OrderedCollection new." << endl << indent() << desc + << " size timesRepeat: [" << endl; + + indent_up(); + out << indent() << val << " add: " << read_val(tlist->get_elem_type()); + indent_down(); + + out << "]." << endl << indent() << "iprot readListEnd." << endl << indent() << val << "] value"; + indent_down(); + + return out.str(); +} + +string t_st_generator::set_writer(t_set* tset, string fname) { + std::ostringstream out; + string val = temp_name(); + + out << "[oprot writeSetBegin: (TSet new elemType: " << type_to_enum(tset->get_elem_type()) + << "; size: " << fname << " size)." << endl; + indent_up(); + + out << indent() << fname << " do: [:" << val << "|" << endl; + indent_up(); + + out << indent() << write_val(tset->get_elem_type(), val) << endl; + indent_down(); + + out << "]." << endl << indent() << "oprot writeSetEnd] value"; + indent_down(); + + return out.str(); +} + +string t_st_generator::set_reader(t_set* tset) { + std::ostringstream out; + string desc = temp_name(); + string val = temp_name(); + + out << "[|" << desc << " " << val << "| " << desc << " := iprot readSetBegin." << endl; + indent_up(); + + out << indent() << val << " := Set new." << endl << indent() << desc << " size timesRepeat: [" + << endl; + + indent_up(); + out << indent() << val << " add: " << read_val(tset->get_elem_type()); + indent_down(); + + out << "]." << endl << indent() << "iprot readSetEnd." << endl << indent() << val << "] value"; + indent_down(); + + return out.str(); +} + +string t_st_generator::struct_writer(t_struct* tstruct, string sname) { + std::ostringstream out; + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator fld_iter; + + out << "[oprot writeStructBegin: " + << "(TStruct new name: '" + tstruct->get_name() + "')." << endl; + indent_up(); + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + bool optional = (*fld_iter)->get_req() == t_field::T_OPTIONAL; + string fname = camelcase((*fld_iter)->get_name()); + string accessor = sname + " " + camelcase(fname); + + if (optional) { + out << indent() << accessor << " ifNotNil: [" << endl; + indent_up(); + } + + out << indent() << "oprot writeFieldBegin: (TField new name: '" << fname + << "'; type: " << type_to_enum((*fld_iter)->get_type()) + << "; id: " << (*fld_iter)->get_key() << ")." << endl; + + out << indent() << write_val((*fld_iter)->get_type(), accessor) << "." << endl << indent() + << "oprot writeFieldEnd"; + + if (optional) { + out << "]"; + indent_down(); + } + + out << "." << endl; + } + + out << indent() << "oprot writeFieldStop; writeStructEnd] value"; + indent_down(); + + return out.str(); +} + +string t_st_generator::struct_reader(t_struct* tstruct, string clsName = "") { + std::ostringstream out; + const vector& fields = tstruct->get_members(); + vector::const_iterator fld_iter; + string val = temp_name(); + string desc = temp_name(); + string found = temp_name(); + + if (clsName.size() == 0) { + clsName = tstruct->get_name(); + } + + out << "[|" << desc << " " << val << "|" << endl; + indent_up(); + + // This is nasty, but without it we'll break things by prefixing TResult. + string name = ((capitalize(clsName) == "TResult") ? capitalize(clsName) : prefix(clsName)); + out << indent() << val << " := " << name << " new." << endl; + + out << indent() << "iprot readStructBegin." << endl << indent() << "[" << desc + << " := iprot readFieldBegin." << endl << indent() << desc + << " type = TType stop] whileFalse: [|" << found << "|" << endl; + indent_up(); + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + out << indent() << desc << " id = " << (*fld_iter)->get_key() << " ifTrue: [" << endl; + indent_up(); + + out << indent() << found << " := true." << endl << indent() << val << " " + << camelcase((*fld_iter)->get_name()) << ": " << read_val((*fld_iter)->get_type()); + indent_down(); + + out << "]." << endl; + } + + out << indent() << found << " ifNil: [iprot skip: " << desc << " type]]." << endl; + indent_down(); + + out << indent() << "oprot readStructEnd." << endl << indent() << val << "] value"; + indent_down(); + + return out.str(); +} + +string t_st_generator::write_val(t_type* t, string fname) { + t = get_true_type(t); + + if (t->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)t)->get_base(); + switch (tbase) { + case t_base_type::TYPE_DOUBLE: + return "iprot writeDouble: " + fname + " asFloat"; + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + return "iprot write" + capitalize(type_name(t)) + ": " + fname + " asInteger"; + default: + return "iprot write" + capitalize(type_name(t)) + ": " + fname; + } + } else if (t->is_map()) { + return map_writer((t_map*)t, fname); + } else if (t->is_struct() || t->is_xception()) { + return struct_writer((t_struct*)t, fname); + } else if (t->is_list()) { + return list_writer((t_list*)t, fname); + } else if (t->is_set()) { + return set_writer((t_set*)t, fname); + } else if (t->is_enum()) { + return "iprot writeI32: " + fname; + } else { + throw "Sorry, I don't know how to write this: " + type_name(t); + } +} + +string t_st_generator::read_val(t_type* t) { + t = get_true_type(t); + + if (t->is_base_type()) { + return "iprot read" + capitalize(type_name(t)); + } else if (t->is_map()) { + return map_reader((t_map*)t); + } else if (t->is_struct() || t->is_xception()) { + return struct_reader((t_struct*)t); + } else if (t->is_list()) { + return list_reader((t_list*)t); + } else if (t->is_set()) { + return set_reader((t_set*)t); + } else if (t->is_enum()) { + return "iprot readI32"; + } else { + throw "Sorry, I don't know how to read this: " + type_name(t); + } +} + +void t_st_generator::generate_send_method(t_function* function) { + string funname = function->get_name(); + string signature = function_signature(function); + t_struct* arg_struct = function->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + + st_method(f_, client_class_name(), "send" + capitalize(signature)); + f_ << "oprot writeMessageBegin:" << endl; + indent_up(); + + f_ << indent() << "(TCallMessage new" << endl; + indent_up(); + + f_ << indent() << "name: '" << funname << "'; " << endl << indent() << "seqid: self nextSeqid)." + << endl; + indent_down(); + indent_down(); + + f_ << indent() << "oprot writeStructBegin: " + << "(TStruct new name: '" + capitalize(camelcase(funname)) + "_args')." << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + string fname = camelcase((*fld_iter)->get_name()); + + f_ << indent() << "oprot writeFieldBegin: (TField new name: '" << fname + << "'; type: " << type_to_enum((*fld_iter)->get_type()) << "; id: " << (*fld_iter)->get_key() + << ")." << endl; + + f_ << indent() << write_val((*fld_iter)->get_type(), fname) << "." << endl << indent() + << "oprot writeFieldEnd." << endl; + } + + f_ << indent() << "oprot writeFieldStop; writeStructEnd; writeMessageEnd." << endl; + f_ << indent() << "oprot transport flush"; + + st_close_method(f_); +} + +// We only support receiving TResult structures (so this won't work on the server side) +void t_st_generator::generate_recv_method(t_function* function) { + string funname = camelcase(function->get_name()); + string signature = function_signature(function); + + t_struct result(program_, "TResult"); + t_field success(function->get_returntype(), "success", 0); + result.append(&success); + + t_struct* xs = function->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + // duplicate the field, but call it "exception"... we don't need a dynamic name + t_field* exception = new t_field((*f_iter)->get_type(), "exception", (*f_iter)->get_key()); + result.append(exception); + } + + st_method(f_, client_class_name(), "recv" + capitalize(funname)); + f_ << "| f msg res | " << endl << indent() << "msg := oprot readMessageBegin." << endl << indent() + << "self validateRemoteMessage: msg." << endl << indent() + << "res := " << struct_reader(&result) << "." << endl << indent() << "oprot readMessageEnd." + << endl << indent() << "oprot transport flush." << endl << indent() + << "res exception ifNotNil: [res exception signal]." << endl << indent() << "^ res"; + st_close_method(f_); +} + +string t_st_generator::function_types_comment(t_function* fn) { + std::ostringstream out; + const vector& fields = fn->get_arglist()->get_members(); + vector::const_iterator f_iter; + + out << "\""; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + out << camelcase((*f_iter)->get_name()) << ": " << type_name((*f_iter)->get_type()); + if ((f_iter + 1) != fields.end()) { + out << ", "; + } + } + + out << "\""; + + return out.str(); +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_st_generator::generate_service_client(t_service* tservice) { + string extends = ""; + string extends_client = "TClient"; + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_client = extends + "Client"; + } + + f_ << extends_client << " subclass: #" << prefix(client_class_name()) << endl + << "\tinstanceVariableNames: ''\n" + << "\tclassVariableNames: ''\n" + << "\tpoolDictionaries: ''\n" + << "\tcategory: '" << generated_category() << "'!\n\n"; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string funname = camelcase((*f_iter)->get_name()); + string signature = function_signature(*f_iter); + + st_method(f_, client_class_name(), signature); + f_ << function_types_comment(*f_iter) << endl << indent() << "self send" + << capitalize(signature) << "." << endl; + + if (!(*f_iter)->is_oneway()) { + f_ << indent() << "^ self recv" << capitalize(funname) << " success " << endl; + } + + st_close_method(f_); + + generate_send_method(*f_iter); + if (!(*f_iter)->is_oneway()) { + generate_recv_method(*f_iter); + } + } +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_st_generator::function_signature(t_function* tfunction) { + return camelcase(tfunction->get_name()) + capitalize(argument_list(tfunction->get_arglist())); +} + +/** + * Renders a field list + */ +string t_st_generator::argument_list(t_struct* tstruct) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += " "; + } + string name = camelcase((*f_iter)->get_name()); + result += name + ": " + name; + } + return result; +} + +string t_st_generator::type_name(t_type* ttype) { + string prefix = ""; + t_program* program = ttype->get_program(); + if (program != NULL && program != program_) { + if (!ttype->is_service()) { + prefix = program->get_name() + "_types."; + } + } + + string name = ttype->get_name(); + if (ttype->is_struct() || ttype->is_xception()) { + name = capitalize(ttype->get_name()); + } + + return prefix + name; +} + +/* Convert t_type to Smalltalk type code */ +string t_st_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "TType string"; + case t_base_type::TYPE_BOOL: + return "TType bool"; + case t_base_type::TYPE_I8: + return "TType byte"; + case t_base_type::TYPE_I16: + return "TType i16"; + case t_base_type::TYPE_I32: + return "TType i32"; + case t_base_type::TYPE_I64: + return "TType i64"; + case t_base_type::TYPE_DOUBLE: + return "TType double"; + } + } else if (type->is_enum()) { + return "TType i32"; + } else if (type->is_struct() || type->is_xception()) { + return "TType struct"; + } else if (type->is_map()) { + return "TType map"; + } else if (type->is_set()) { + return "TType set"; + } else if (type->is_list()) { + return "TType list"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +THRIFT_REGISTER_GENERATOR(st, "Smalltalk", "") diff --git a/compiler/cpp/src/thrift/generate/t_swift_generator.cc b/compiler/cpp/src/thrift/generate/t_swift_generator.cc new file mode 100644 index 0000000..87dd2f0 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_swift_generator.cc @@ -0,0 +1,2209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ostream; +using std::ofstream; +using std::ostringstream; +using std::set; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * Swift code generator. + * + * Designed from the Objective-C (aka Cocoa) generator. + */ +class t_swift_generator : public t_oop_generator { +public: + t_swift_generator(t_program* program, + const map& parsed_options, + const string& option_string) + : t_oop_generator(program) { + (void)option_string; + map::const_iterator iter; + + log_unexpected_ = false; + async_clients_ = false; + promise_kit_ = false; + debug_descriptions_ = false; + + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("log_unexpected") == 0) { + log_unexpected_ = true; + } else if( iter->first.compare("async_clients") == 0) { + async_clients_ = true; + } else if( iter->first.compare("promise_kit") == 0) { + promise_kit_ = true; + } else if( iter->first.compare("debug_descriptions") == 0) { + debug_descriptions_ = true; + } else { + throw "unknown option swift:" + iter->first; + } + } + + out_dir_base_ = "gen-swift"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + void generate_consts(vector consts); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + + void print_const_value(ostream& out, + string name, + t_type* type, + t_const_value* value, + bool defval = false, + bool is_property = false); + void render_const_value(ostream& out, + t_type* type, + t_const_value* value); + + void generate_swift_struct(ofstream& out, + t_struct* tstruct, + bool is_private); + void generate_swift_struct_init(ofstream& out, + t_struct* tstruct, + bool all, + bool is_private); + + void generate_swift_struct_implementation(ofstream& out, + t_struct* tstruct, + bool is_result, + bool is_private); + void generate_swift_struct_hashable_extension(ofstream& out, + t_struct* tstruct, + bool is_private); + void generate_swift_struct_equatable_extension(ofstream& out, + t_struct* tstruct, + bool is_private); + void generate_swift_struct_thrift_extension(ofstream& out, + t_struct* tstruct, + bool is_result, + bool is_private); + void generate_swift_struct_reader(ofstream& out, t_struct* tstruct, bool is_private); + void generate_swift_struct_writer(ofstream& out,t_struct* tstruct, bool is_private); + void generate_swift_struct_result_writer(ofstream& out, t_struct* tstruct); + void generate_swift_struct_printable_extension(ofstream& out, t_struct* tstruct); + + string function_result_helper_struct_type(t_service *tservice, t_function* tfunction); + string function_args_helper_struct_type(t_service* tservice, t_function* tfunction); + void generate_function_helpers(t_service *tservice, t_function* tfunction); + + /** + * Service-level generation functions + */ + + void generate_swift_service_protocol(ofstream& out, t_service* tservice); + void generate_swift_service_protocol_async(ofstream& out, t_service* tservice); + + void generate_swift_service_client(ofstream& out, t_service* tservice); + void generate_swift_service_client_async(ofstream& out, t_service* tservice); + + void generate_swift_service_client_send_function_implementation(ofstream& out, + t_service* tservice, + t_function* tfunction, + bool needs_protocol); + void generate_swift_service_client_send_function_invocation(ofstream& out, t_function* tfunction); + void generate_swift_service_client_send_async_function_invocation(ofstream& out, + t_function* tfunction); + void generate_swift_service_client_recv_function_implementation(ofstream& out, + t_service* tservice, + t_function* tfunction, + bool needs_protocol); + void generate_swift_service_client_implementation(ofstream& out, t_service* tservice); + void generate_swift_service_client_async_implementation(ofstream& out, t_service* tservice); + + void generate_swift_service_server(ofstream& out, t_service* tservice); + void generate_swift_service_server_implementation(ofstream& out, t_service* tservice); + void generate_swift_service_helpers(t_service* tservice); + + /** + * Helper rendering functions + */ + + string swift_imports(); + string swift_thrift_imports(); + string type_name(t_type* ttype, bool is_optional=false, bool is_forced=false); + string base_type_name(t_base_type* tbase); + string declare_property(t_field* tfield, bool is_private); + string function_signature(t_function* tfunction); + string async_function_signature(t_function* tfunction); + string promise_function_signature(t_function* tfunction); + string function_name(t_function* tfunction); + string argument_list(t_struct* tstruct, string protocol_name, bool is_internal); + string type_to_enum(t_type* ttype, bool qualified=false); + string maybe_escape_identifier(const string& identifier); + void populate_reserved_words(); + +private: + + void block_open(ostream& out) { + out << " {" << endl; + indent_up(); + } + + void block_close(ostream& out, bool end_line=true) { + indent_down(); + indent(out) << "}"; + if (end_line) out << endl; + } + + + bool field_is_optional(t_field* tfield) { + return tfield->get_req() == t_field::T_OPTIONAL; + } + + bool struct_has_required_fields(t_struct* tstruct) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (!field_is_optional(*m_iter)) { + return true; + } + } + return false; + } + + bool struct_has_optional_fields(t_struct* tstruct) { + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (field_is_optional(*m_iter)) { + return true; + } + } + return false; + } + + string constants_declarations_; + + /** + * File streams + */ + + ofstream f_decl_; + ofstream f_impl_; + + bool log_unexpected_; + bool async_clients_; + bool promise_kit_; + bool debug_descriptions_; + + set swift_reserved_words_; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + */ +void t_swift_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + + populate_reserved_words(); + + // we have a .swift declarations file... + string f_decl_name = capitalize(program_name_) + ".swift"; + string f_decl_fullname = get_out_dir() + f_decl_name; + f_decl_.open(f_decl_fullname.c_str()); + + f_decl_ << autogen_comment() << endl; + + f_decl_ << swift_imports() << swift_thrift_imports() << endl; + + // ...and a .swift implementation extensions file + string f_impl_name = capitalize(program_name_) + "+Exts.swift"; + string f_impl_fullname = get_out_dir() + f_impl_name; + f_impl_.open(f_impl_fullname.c_str()); + + f_impl_ << autogen_comment() << endl; + + f_impl_ << swift_imports() << swift_thrift_imports() << endl; + +} + +/** + * Prints standard Cocoa imports + * + * @return List of imports for Cocoa libraries + */ +string t_swift_generator::swift_imports() { + + vector includes_list; + includes_list.push_back("Foundation"); + + ostringstream includes; + + vector::const_iterator i_iter; + for (i_iter=includes_list.begin(); i_iter!=includes_list.end(); ++i_iter) { + includes << "import " << *i_iter << endl; + } + + includes << endl; + + return includes.str(); +} + +/** + * Prints Thrift runtime imports + * + * @return List of imports necessary for Thrift runtime + */ +string t_swift_generator::swift_thrift_imports() { + + vector includes_list; + includes_list.push_back("Thrift"); + + if (promise_kit_) { + includes_list.push_back("PromiseKit"); + } + + ostringstream includes; + + vector::const_iterator i_iter; + for (i_iter=includes_list.begin(); i_iter!=includes_list.end(); ++i_iter) { + includes << "import " << *i_iter << endl; + } + + includes << endl; + + return includes.str(); +} + +/** + * Finish up generation. + */ +void t_swift_generator::close_generator() { + // stick our constants declarations at the end of the header file + // since they refer to things we are defining. + f_decl_ << constants_declarations_ << endl; +} + +/** + * Generates a typedef. This is just a simple 1-liner in Swift + * + * @param ttypedef The type definition + */ +void t_swift_generator::generate_typedef(t_typedef* ttypedef) { + f_decl_ << indent() << "public typealias " << ttypedef->get_symbolic() + << " = " << type_name(ttypedef->get_type()) << endl; + f_decl_ << endl; +} + +/** + * Generates code for an enumerated type. In Swift, this is + * essentially the same as the thrift definition itself, using + * Swift syntax. + * + * @param tenum The enumeration + */ +void t_swift_generator::generate_enum(t_enum* tenum) { + f_decl_ << indent() << "public enum " << tenum->get_name() << " : Int32"; + block_open(f_decl_); + + vector constants = tenum->get_constants(); + vector::iterator c_iter; + + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + f_decl_ << indent() << "case " << (*c_iter)->get_name() + << " = " << (*c_iter)->get_value() << endl; + } + + f_decl_ << endl; + f_decl_ << indent() << "public init() { self.init(rawValue: " << constants.front()->get_value() << ")! }" << endl; + + block_close(f_decl_); + f_decl_ << endl; + + f_impl_ << indent() << "extension " << tenum->get_name() << " : TEnum"; + block_open(f_impl_); + + f_impl_ << endl; + + f_impl_ << indent() << "public static func readValueFromProtocol(proto: TProtocol) throws -> " << tenum->get_name(); + block_open(f_impl_); + f_impl_ << indent() << "var raw = Int32()" << endl + << indent() << "try proto.readI32(&raw)" << endl + << indent() << "return " << tenum->get_name() << "(rawValue: raw)!" << endl; + block_close(f_impl_); + f_impl_ << endl; + + f_impl_ << indent() << "public static func writeValue(value: " << tenum->get_name() << ", toProtocol proto: TProtocol) throws"; + block_open(f_impl_); + f_impl_ << indent() << "try proto.writeI32(value.rawValue)" << endl; + block_close(f_impl_); + f_impl_ << endl; + + block_close(f_impl_); + f_impl_ << endl; +} + +/** + * Generates public constants for all Thrift constants. + * + * @param consts Constants to generate + */ +void t_swift_generator::generate_consts(vector consts) { + + ostringstream const_interface; + + // Public constants for base types & strings + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + t_type* type = (*c_iter)->get_type(); + const_interface << "public let " << capitalize((*c_iter)->get_name()) << " : " << type_name(type) << " = "; + render_const_value(const_interface, type, (*c_iter)->get_value()); + const_interface << endl << endl; + } + + // this gets spit into the header file in ::close_generator + constants_declarations_ = const_interface.str(); + +} + +/** + * Generates a struct definition for a thrift data type. This is a struct + * with public members. Optional types are used for optional properties to + * allow them to be tested for availability. Separate inits are included for + * required properties & all properties. + * + * Generates extensions to provide conformance to TStruct, TSerializable, + * Hashable & Equatable + * + * @param tstruct The struct definition + */ +void t_swift_generator::generate_struct(t_struct* tstruct) { + generate_swift_struct(f_decl_, tstruct, false); + generate_swift_struct_implementation(f_impl_, tstruct, false, false); +} + +/** + * Exceptions are structs, but they conform to ErrorType + * + * @param tstruct The struct definition + */ +void t_swift_generator::generate_xception(t_struct* txception) { + generate_swift_struct(f_decl_, txception, false); + generate_swift_struct_implementation(f_impl_, txception, false, false); +} + +/** + * Generate the interface for a struct. Only properties and + * init methods are included. + * + * @param tstruct The struct definition + * @param is_private + * Is the struct public or private + */ +void t_swift_generator::generate_swift_struct(ofstream& out, + t_struct* tstruct, + bool is_private) { + + string visibility = is_private ? "private" : "public"; + + out << indent() << visibility << " final class " << tstruct->get_name(); + + if (tstruct->is_xception()) { + out << " : ErrorType"; + } + + block_open(out); + + // properties + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + out << endl; + out << indent() << declare_property(*m_iter, is_private) << endl; + } + + out << endl; + + // init + + indent(out) << visibility << " init()"; + block_open(out); + block_close(out); + + out << endl; + + if (struct_has_required_fields(tstruct)) { + generate_swift_struct_init(out, tstruct, false, is_private); + } + if (struct_has_optional_fields(tstruct)) { + generate_swift_struct_init(out, tstruct, true, is_private); + } + + block_close(out); + + out << endl; +} + +/** + * Generate struct init for properties + * + * @param tstruct The structure definition + * @param all Generate init with all or just required properties + * @param is_private + * Is the initializer public or private + */ +void t_swift_generator::generate_swift_struct_init(ofstream& out, + t_struct* tstruct, + bool all, + bool is_private) { + + string visibility = is_private ? "private" : "public"; + + indent(out) << visibility << " init("; + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + bool first=true; + for (m_iter = members.begin(); m_iter != members.end();) { + if (all || !field_is_optional(*m_iter)) { + if (first) { + first = false; + } + else { + out << ", "; + } + out << (*m_iter)->get_name() << ": " + << maybe_escape_identifier(type_name((*m_iter)->get_type(), field_is_optional(*m_iter))); + } + ++m_iter; + } + out << ")"; + + block_open(out); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (all || (*m_iter)->get_req() == t_field::T_REQUIRED || (*m_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) { + out << indent() << "self." << maybe_escape_identifier((*m_iter)->get_name()) << " = " + << maybe_escape_identifier((*m_iter)->get_name()) << endl; + } + } + + block_close(out); + + out << endl; +} + +/** + * Generate the hashable protocol implmentation + * + * @param tstruct The structure definition + * @param is_private + * Is the struct public or private + */ +void t_swift_generator::generate_swift_struct_hashable_extension(ofstream& out, + t_struct* tstruct, + bool is_private) { + + string visibility = is_private ? "private" : "public"; + + indent(out) << "extension " << tstruct->get_name() << " : Hashable"; + + block_open(out); + + out << endl; + + indent(out) << visibility << " var hashValue : Int"; + + block_open(out); + + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + if (!members.empty()) { + indent(out) << "let prime = 31" << endl; + indent(out) << "var result = 1" << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_field* tfield = *m_iter; + string accessor = field_is_optional(tfield) ? "?." : "."; + string defaultor = field_is_optional(tfield) ? " ?? 0" : ""; + indent(out) << "result = prime &* result &+ (" << maybe_escape_identifier(tfield->get_name()) << accessor + << "hashValue" << defaultor << ")" << endl; + } + + indent(out) << "return result" << endl; + } + else { + indent(out) << "return 31" << endl; + } + + block_close(out); + + out << endl; + + block_close(out); + + out << endl; +} + +/** + * Generate the equatable protocol implementation + * + * @param tstruct The structure definition + * @param is_private + * Is the struct public or private + */ +void t_swift_generator::generate_swift_struct_equatable_extension(ofstream& out, + t_struct* tstruct, + bool is_private) { + + string visibility = is_private ? "private" : "public"; + + indent(out) << visibility << " func ==(lhs: " << type_name(tstruct) << ", rhs: " << type_name(tstruct) << ") -> Bool"; + + block_open(out); + + indent(out) << "return"; + + const vector& members = tstruct->get_members(); + vector::const_iterator m_iter; + + if (members.size()) { + + out << endl; + + indent_up(); + + for (m_iter = members.begin(); m_iter != members.end();) { + t_field* tfield = *m_iter; + indent(out) << "(lhs." << maybe_escape_identifier(tfield->get_name()) + << " ?== rhs." << maybe_escape_identifier(tfield->get_name()) << ")"; + if (++m_iter != members.end()) { + out << " &&"; + } + out << endl; + } + + indent_down(); + + } + else { + out << " true" << endl; + } + + block_close(out); + + out << endl; +} + +/** + * Generate struct implementation. Produces extensions that + * fulfill the requisite protocols to complete the value. + * + * @param tstruct The struct definition + * @param is_result + * If this is a result it needs a different writer + * @param is_private + * Is the struct public or private + */ +void t_swift_generator::generate_swift_struct_implementation(ofstream& out, + t_struct* tstruct, + bool is_result, + bool is_private) { + + generate_swift_struct_equatable_extension(out, tstruct, is_private); + + if (!is_private && !is_result) { + generate_swift_struct_printable_extension(out, tstruct); + } + + generate_swift_struct_hashable_extension(out, tstruct, is_private); + generate_swift_struct_thrift_extension(out, tstruct, is_result, is_private); + + out << endl << endl; +} + +/** + * Generate the TStruct protocol implementation. + * + * @param tstruct The structure definition + * @param is_result + * Is the struct a result value + * @param is_private + * Is the struct public or private + */ +void t_swift_generator::generate_swift_struct_thrift_extension(ofstream& out, + t_struct* tstruct, + bool is_result, + bool is_private) { + + indent(out) << "extension " << tstruct->get_name() << " : TStruct"; + + block_open(out); + + out << endl; + + generate_swift_struct_reader(out, tstruct, is_private); + + if (is_result) { + generate_swift_struct_result_writer(out, tstruct); + } + else { + generate_swift_struct_writer(out, tstruct, is_private); + } + + block_close(out); + + out << endl; +} + +/** + * Generates a function to read a struct from + * from a protocol. (TStruct compliance) + * + * @param tstruct The structure definition + * @param is_private + * Is the struct public or private + */ +void t_swift_generator::generate_swift_struct_reader(ofstream& out, + t_struct* tstruct, + bool is_private) { + + string visibility = is_private ? "private" : "public"; + + indent(out) << visibility << " static func readValueFromProtocol(__proto: TProtocol) throws -> " + << tstruct->get_name(); + + block_open(out); + + out << endl; + + indent(out) << "try __proto.readStructBegin()" << endl << endl; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool optional = field_is_optional(*f_iter); + indent(out) << "var " << maybe_escape_identifier((*f_iter)->get_name()) << " : " + << type_name((*f_iter)->get_type(), optional, !optional) << endl; + } + + out << endl; + + // Loop over reading in fields + indent(out) << "fields: while true"; + + block_open(out); + + out << endl; + + indent(out) << "let (_, fieldType, fieldID) = try __proto.readFieldBegin()" << endl << endl; + indent(out) << "switch (fieldID, fieldType)"; + + block_open(out); + + indent(out) << "case (_, .STOP):" << endl; + indent_up(); + indent(out) << "break fields" << endl << endl; + indent_down(); + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + + indent(out) << "case (" << (*f_iter)->get_key() << ", " << type_to_enum((*f_iter)->get_type()) << "):" << endl; + indent_up(); + indent(out) << maybe_escape_identifier((*f_iter)->get_name()) << " = try __proto.readValue() as " + << type_name((*f_iter)->get_type()) << endl << endl; + indent_down(); + + } + + indent(out) << "case let (_, unknownType):" << endl; + indent_up(); + indent(out) << "try __proto.skipType(unknownType)" << endl; + indent_down(); + + block_close(out); + + out << endl; + + // Read field end marker + indent(out) << "try __proto.readFieldEnd()" << endl; + + block_close(out); + + out << endl; + + indent(out) << "try __proto.readStructEnd()" << endl; + + out << endl; + + if (struct_has_required_fields(tstruct)) { + // performs various checks (e.g. check that all required fields are set) + indent(out) << "// Required fields" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (field_is_optional(*f_iter)) { + continue; + } + indent(out) << "try __proto.validateValue(" << (*f_iter)->get_name() << ", " + << "named: \"" << (*f_iter)->get_name() << "\")" << endl; + } + } + + out << endl; + + indent(out) << "return " << tstruct->get_name() << "("; + for (f_iter = fields.begin(); f_iter != fields.end();) { + out << (*f_iter)->get_name() << ": " << maybe_escape_identifier((*f_iter)->get_name()); + if (++f_iter != fields.end()) { + out << ", "; + } + } + out << ")" << endl; + + block_close(out); + + out << endl; +} + +/** + * Generates a function to write a struct to + * a protocol. (TStruct compliance) + * + * @param tstruct The structure definition + * @param is_private + * Is the struct public or private + */ +void t_swift_generator::generate_swift_struct_writer(ofstream& out, + t_struct* tstruct, + bool is_private) { + + string visibility = is_private ? "private" : "public"; + + indent(out) << visibility << " static func writeValue(__value: " << tstruct->get_name() << ", toProtocol __proto: TProtocol) throws"; + + block_open(out); + + out << endl; + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + indent(out) << "try __proto.writeStructBeginWithName(\"" << name << "\")" << endl; + + out << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field *tfield = *f_iter; + + bool optional = field_is_optional(tfield); + if (optional) { + indent(out) << "if let " << maybe_escape_identifier(tfield->get_name()) + << " = __value." << maybe_escape_identifier(tfield->get_name()); + block_open(out); + } + + indent(out) << "try __proto.writeFieldValue(" + << (optional ? "" : "__value.") << maybe_escape_identifier(tfield->get_name()) << ", " + << "name: \"" << tfield->get_name() << "\", " + << "type: " << type_to_enum(tfield->get_type()) << ", " + << "id: " << tfield->get_key() << ")" << endl; + + if (optional) { + block_close(out); + } + + out << endl; + } + + indent(out) << "try __proto.writeFieldStop()" << endl << endl; + + indent(out) << "try __proto.writeStructEnd()" << endl; + + block_close(out); + + out << endl; +} + +/** + * Generates a function to read a struct from + * from a protocol. (TStruct compliance) + * + * This is specifically a function result. Only + * the first available field is written. + * + * @param tstruct The structure definition + */ +void t_swift_generator::generate_swift_struct_result_writer(ofstream& out, t_struct* tstruct) { + + indent(out) << "private static func writeValue(__value: " << tstruct->get_name() << ", toProtocol __proto: TProtocol) throws"; + + block_open(out); + + out << endl; + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + indent(out) << "try __proto.writeStructBeginWithName(\"" << name << "\")" << endl; + + out << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field *tfield = *f_iter; + + indent(out) << "if let result = __value." << (*f_iter)->get_name(); + + block_open(out); + + indent(out) << "try __proto.writeFieldValue(result, " + << "name: \"" << tfield->get_name() << "\", " + << "type: " << type_to_enum(tfield->get_type()) << ", " + << "id: " << tfield->get_key() << ")" << endl; + + block_close(out); + } + // Write the struct map + indent(out) << "try __proto.writeFieldStop()" << endl << endl; + + indent(out) << "try __proto.writeStructEnd()" << endl; + + block_close(out); + + out << endl; +} + +/** + * Generates a description method for the given struct + * + * @param tstruct The struct definition + */ +void t_swift_generator::generate_swift_struct_printable_extension(ofstream& out, t_struct* tstruct) { + + // Allow use of debugDescription so the app can add description via a cateogory/extension + + indent(out) << "extension " << tstruct->get_name() << " : " + << (debug_descriptions_ ? "CustomDebugStringConvertible" : "CustomStringConvertible"); + + block_open(out); + + out << endl; + + indent(out) << "public var description : String"; + + block_open(out); + + indent(out) << "var desc = \"" << tstruct->get_name() << "(\"" << endl; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end();) { + indent(out) << "desc += \"" << (*f_iter)->get_name() + << "=\\(self." << maybe_escape_identifier((*f_iter)->get_name()) << ")"; + if (++f_iter != fields.end()) { + out << ", "; + } + out << "\"" << endl; + } + indent(out) << "desc += \")\"" << endl; + indent(out) << "return desc" << endl; + + block_close(out); + + out << endl; + + block_close(out); + + out << endl; +} + +/** + * Generates a thrift service. In Swift this consists of a + * protocol definition and a client (with it's implementation + * separated into exts file). + * + * @param tservice The service definition + */ +void t_swift_generator::generate_service(t_service* tservice) { + + generate_swift_service_protocol(f_decl_, tservice); + generate_swift_service_client(f_decl_, tservice); + if (async_clients_) { + generate_swift_service_protocol_async(f_decl_, tservice); + generate_swift_service_client_async(f_decl_, tservice); + } + generate_swift_service_server(f_decl_, tservice); + + generate_swift_service_helpers(tservice); + + generate_swift_service_client_implementation(f_impl_, tservice); + if (async_clients_) { + generate_swift_service_client_async_implementation(f_impl_, tservice); + } + generate_swift_service_server_implementation(f_impl_, tservice); +} + +/** + * Generates structs for all the service return types + * + * @param tservice The service + */ +void t_swift_generator::generate_swift_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + + t_struct* ts = (*f_iter)->get_arglist(); + + string qname = function_args_helper_struct_type(tservice, *f_iter); + + t_struct qname_ts = t_struct(ts->get_program(), qname); + + const vector& members = ts->get_members(); + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + qname_ts.append(*m_iter); + } + + generate_swift_struct(f_impl_, &qname_ts, true); + generate_swift_struct_implementation(f_impl_, &qname_ts, false, true); + generate_function_helpers(tservice, *f_iter); + } +} + +string t_swift_generator::function_result_helper_struct_type(t_service *tservice, t_function* tfunction) { + if (tfunction->is_oneway()) { + return tservice->get_name() + "_" + tfunction->get_name(); + } else { + return tservice->get_name() + "_" + tfunction->get_name() + "_result"; + } +} + +string t_swift_generator::function_args_helper_struct_type(t_service *tservice, t_function* tfunction) { + return tservice->get_name() + "_" + tfunction->get_name() + "_args"; +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_swift_generator::generate_function_helpers(t_service *tservice, t_function* tfunction) { + if (tfunction->is_oneway()) { + return; + } + + // create a result struct with a success field of the return type, + // and a field for each type of exception thrown + t_struct result(program_, function_result_helper_struct_type(tservice, tfunction)); + if (!tfunction->get_returntype()->is_void()) { + t_field* success = new t_field(tfunction->get_returntype(), "success", 0); + success->set_req(t_field::T_OPTIONAL); + result.append(success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field *x = *f_iter; + t_field *ox = new t_field(x->get_type(), x->get_name(), x->get_key()); + ox->set_req(t_field::T_OPTIONAL); + result.append(ox); + } + + // generate the result struct + generate_swift_struct(f_impl_, &result, true); + generate_swift_struct_implementation(f_impl_, &result, true, true); + + for (f_iter = result.get_members().begin(); f_iter != result.get_members().end(); ++f_iter) { + delete *f_iter; + } +} + +/** + * Generates a service protocol definition. + * + * @param tservice The service to generate a protocol definition for + */ +void t_swift_generator::generate_swift_service_protocol(ofstream& out, t_service* tservice) { + + indent(out) << "public protocol " << tservice->get_name(); + + block_open(out); + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + out << endl; + indent(out) << function_signature(*f_iter) << " // exceptions: "; + t_struct* xs = (*f_iter)->get_xceptions(); + const vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + out << type_name((*x_iter)->get_type()) + ", "; + } + out << endl; + } + + block_close(out); + + out << endl; +} + +/** + * Generates an asynchronous service protocol definition. + * + * @param tservice The service to generate a protocol definition for + */ +void t_swift_generator::generate_swift_service_protocol_async(ofstream& out, t_service* tservice) { + + indent(out) << "public protocol " << tservice->get_name() << "Async"; + + block_open(out); + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + out << endl; + indent(out) << async_function_signature(*f_iter) << endl; + if (promise_kit_) { + indent(out) << promise_function_signature(*f_iter) << endl; + } + out << endl; + } + + block_close(out); + + out << endl; +} + +/** + * Generates a service client interface definition. + * + * @param tservice The service to generate a client interface definition for + */ +void t_swift_generator::generate_swift_service_client(ofstream& out, + t_service* tservice) { + + indent(out) << "public class " << tservice->get_name() << "Client /* : " << tservice->get_name() << " */"; + + block_open(out); + + out << endl; + + indent(out) << "let __inProtocol : TProtocol" << endl << endl; + + indent(out) << "let __outProtocol : TProtocol" << endl << endl; + + indent(out) << "public init(inoutProtocol: TProtocol)"; + + block_open(out); + + indent(out) << "__inProtocol = inoutProtocol" << endl; + + indent(out) << "__outProtocol = inoutProtocol" << endl; + + block_close(out); + + out << endl; + + indent(out) << "public init(inProtocol: TProtocol, outProtocol: TProtocol)"; + + block_open(out); + + indent(out) << "__inProtocol = inProtocol" << endl; + + indent(out) << "__outProtocol = outProtocol" << endl; + + block_close(out); + + out << endl; + + block_close(out); + + out << endl; +} + +/** + * Generates a service client interface definition. + * + * @param tservice The service to generate a client interface definition for + */ +void t_swift_generator::generate_swift_service_client_async(ofstream& out, + t_service* tservice) { + + indent(out) << "public class " << tservice->get_name() << "AsyncClient /* : " << tservice->get_name() << " */"; + + block_open(out); + + out << endl; + + indent(out) << "let __protocolFactory : TProtocolFactory" << endl << endl; + + indent(out) << "let __transportFactory : TAsyncTransportFactory" << endl << endl; + + indent(out) << "public init(protocolFactory: TProtocolFactory, transportFactory: TAsyncTransportFactory)"; + + block_open(out); + + indent(out) << "__protocolFactory = protocolFactory" << endl; + + indent(out) << "__transportFactory = transportFactory" << endl; + + block_close(out); + + out << endl; + + block_close(out); + + out << endl; +} + +/** + * Generates a service server interface definition. In other words, + * the TProcess implementation for the service definition. + * + * @param tservice The service to generate a client interface definition for + */ +void t_swift_generator::generate_swift_service_server(ofstream& out, + t_service* tservice) { + + indent(out) << "public class " << tservice->get_name() << "Processor : NSObject /* " << tservice->get_name() << " */"; + + block_open(out); + + out << endl; + + out << indent() << "typealias ProcessorHandlerDictionary = " + << "[String: (Int, TProtocol, TProtocol, " << tservice->get_name() << ") throws -> Void]" << endl + << endl + << indent() << "let service : " << tservice->get_name() << endl + << endl + << indent() << "public init(service: " << tservice->get_name() << ")"; + block_open(out); + indent(out) << "self.service = service" << endl; + block_close(out); + + out << endl; + + block_close(out); + + out << endl; +} + +/** + * Generates a function that will send the arguments + * for a service function via a protocol. + * + * @param tservice The service to generate + * @param tfunction The function to generate + * @param needs_protocol + * Wether the first parameter must be a protocol or if + * the protocol is to be assumed + */ +void t_swift_generator::generate_swift_service_client_send_function_implementation(ofstream& out, + t_service *tservice, + t_function* tfunction, + bool needs_protocol) { + + string funname = tfunction->get_name(); + + t_function send_function(g_type_bool, + "send_" + tfunction->get_name(), + tfunction->get_arglist()); + + string argsname = function_args_helper_struct_type(tservice, tfunction); + t_struct* arg_struct = tfunction->get_arglist(); + + // Open function + indent(out) << "private func " << send_function.get_name() << "(" << argument_list(tfunction->get_arglist(), needs_protocol ? "__outProtocol" : "", true) << ") throws"; + block_open(out); + + out << endl; + + // Serialize the request + indent(out) << "try __outProtocol.writeMessageBeginWithName(\"" << funname << "\", " + << "type: " << (tfunction->is_oneway() ? ".ONEWAY" : ".CALL") << ", " + << "sequenceID: 0)" << endl; + + out << endl; + + indent(out) << "let __args = " << argsname << "("; + + // write out function parameters + + const vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end();) { + t_field *tfield = (*f_iter); + out << tfield->get_name() << ": " << tfield->get_name(); + if (++f_iter != fields.end()) { + out << ", "; + } + } + out << ")" << endl; + indent(out) << "try " << argsname << ".writeValue(__args, toProtocol: __outProtocol)" << endl << endl; + + indent(out) << "try __outProtocol.writeMessageEnd()" << endl; + + block_close(out); + + out << endl; +} + +/** + * Generates a function that will recv the result for a + * service function via a protocol. + * + * @param tservice The service to generate + * @param tfunction The function to generate + * @param needs_protocol + * Wether the first parameter must be a protocol or if + * the protocol is to be assumed + */ +void t_swift_generator::generate_swift_service_client_recv_function_implementation(ofstream& out, + t_service* tservice, + t_function* tfunction, + bool needs_protocol) { + + // Open function + indent(out) << "private func recv_" << tfunction->get_name() << "("; + + if (needs_protocol) { + out << "__inProtocol: TProtocol"; + } + + out << ") throws"; + + if (!tfunction->get_returntype()->is_void()) { + out << " -> " << type_name(tfunction->get_returntype()); + } + + block_open(out); + + // check for an exception + + out << endl; + + indent(out) << "try __inProtocol.readResultMessageBegin() " << endl << endl; + + string resultname = function_result_helper_struct_type(tservice, tfunction); + indent(out); + if (!tfunction->get_returntype()->is_void() || !tfunction->get_xceptions()->get_members().empty()) { + out << "let __result = "; + } + out << "try " << resultname << ".readValueFromProtocol(__inProtocol)" << endl << endl; + + indent(out) << "try __inProtocol.readMessageEnd()" << endl << endl; + + // Careful, only return _result if not a void function + if (!tfunction->get_returntype()->is_void()) { + indent(out) << "if let __success = __result.success"; + block_open(out); + indent(out) << "return __success" << endl; + block_close(out); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + indent(out) << "if let " << (*x_iter)->get_name() << " = __result." << (*x_iter)->get_name(); + block_open(out); + indent(out) << "throw " << (*x_iter)->get_name() << endl; + block_close(out); + } + + // If you get here it's an exception, unless a void function + if (!tfunction->get_returntype()->is_void()) { + indent(out) << "throw NSError(" << endl; + indent_up(); + indent(out) << "domain: TApplicationErrorDomain, " << endl; + indent(out) << "code: Int(TApplicationError.MissingResult.rawValue)," << endl; + indent(out) << "userInfo: [TApplicationErrorMethodKey: \"" << tfunction->get_name() << "\"])" << endl; + indent_down(); + } + + // Close function + block_close(out); + + out << endl; +} + +/** + * Generates an invocation of a given the send function for the + * service function. + * + * @param tfunction The service to generate an implementation for + */ +void t_swift_generator::generate_swift_service_client_send_function_invocation(ofstream& out, + t_function* tfunction) { + + indent(out) << "try send_" << tfunction->get_name() << "("; + + t_struct* arg_struct = tfunction->get_arglist(); + + const vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end();) { + out << (*f_iter)->get_name() << ": " << (*f_iter)->get_name(); + if (++f_iter != fields.end()) { + out << ", "; + } + } + + out << ")" << endl; +} + +/** + * Generates an invocation of a given the send function for the + * service function. This is for asynchronous protocols. + * + * @param tfunction The service to generate an implementation for + */ +void t_swift_generator::generate_swift_service_client_send_async_function_invocation(ofstream& out, + t_function* tfunction) { + + t_struct* arg_struct = tfunction->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + indent(out) << "try send_" << tfunction->get_name() << "(__protocol"; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + out << ", " << (*f_iter)->get_name() << ": " << (*f_iter)->get_name(); + } + + out << ")" << endl; +} + +/** + * Generates a service client protocol implementation via extension. + * + * @param tservice The service to generate an implementation for + */ +void t_swift_generator::generate_swift_service_client_implementation(ofstream& out, + t_service* tservice) { + + string name = tservice->get_name() + "Client"; + + indent(out) << "extension " << name << " : " << tservice->get_name(); + + block_open(out); + + out << endl; + + // generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + + generate_swift_service_client_send_function_implementation(out, tservice, *f_iter, false); + + if (!(*f_iter)->is_oneway()) { + generate_swift_service_client_recv_function_implementation(out, tservice, *f_iter, false); + } + + // Open function + indent(out) << "public " << function_signature(*f_iter); + + block_open(out); + + out << endl; + + generate_swift_service_client_send_function_invocation(out, *f_iter); + + out << endl; + + indent(out) << "try __outProtocol.transport().flush()" << endl << endl; + + if (!(*f_iter)->is_oneway()) { + if ((*f_iter)->get_returntype()->is_void()) { + indent(out) << "try recv_" << (*f_iter)->get_name() << "()" << endl; + } else { + indent(out) << "return try recv_" << (*f_iter)->get_name() << "()" << endl; + } + } + + block_close(out); + + out << endl; + } + + block_close(out); + + out << endl; +} + +/** + * Generates a service asynchronous client protocol implementation via extension. + * + * @param tservice The service to generate an implementation for + */ +void t_swift_generator::generate_swift_service_client_async_implementation(ofstream& out, + t_service* tservice) { + + string name = tservice->get_name() + "AsyncClient"; + string protocol_name = tservice->get_name() + "Async"; + + indent(out) << "extension " << name << " : " << protocol_name; + + block_open(out); + + out << endl; + + // generate client method implementations + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + + generate_swift_service_client_send_function_implementation(out, tservice, *f_iter, true); + + if (!(*f_iter)->is_oneway()) { + generate_swift_service_client_recv_function_implementation(out, tservice, *f_iter, true); + } + + indent(out) << "public " << async_function_signature(*f_iter); + block_open(out); + + out << endl; + + out << indent() << "let __transport = __transportFactory.newTransport()" << endl + << indent() << "let __protocol = __protocolFactory.newProtocolOnTransport(__transport)" << endl + << endl; + + generate_swift_service_client_send_async_function_invocation(out, *f_iter); + + out << endl; + + indent(out) << "__transport.flushWithCompletion("; + + if ((*f_iter)->is_oneway()) { + out << "success, failure: failure)" << endl; + } + else { + block_open(out); + indent(out) << "do"; + block_open(out); + + indent(out); + if (!(*f_iter)->get_returntype()->is_void()) { + out << "let result = "; + } + out << "try self.recv_" << (*f_iter)->get_name() << "(__protocol)" << endl; + + out << indent() << "success("; + if (!(*f_iter)->get_returntype()->is_void()) { + out << "result"; + } + out << ")" << endl; + + block_close(out); + indent(out) << "catch let error"; + block_open(out); + indent(out) << "failure(error as NSError)" << endl; + block_close(out); + block_close(out); + indent(out) << ", failure: failure)" << endl; + } + + + block_close(out); + + out << endl; + + // Promise function + if (promise_kit_) { + + indent(out) << "public " << promise_function_signature(*f_iter); + block_open(out); + + out << indent() << "let (__promise, __fulfill, __reject) = Promise<" << type_name((*f_iter)->get_returntype()) << ">.pendingPromise()" << endl << endl + << indent() << "let __transport = __transportFactory.newTransport()" << endl + << indent() << "let __protocol = __protocolFactory.newProtocolOnTransport(__transport)" << endl + << endl; + + generate_swift_service_client_send_async_function_invocation(out, *f_iter); + + out << endl; + + indent(out) << "__transport.flushWithCompletion("; + + if ((*f_iter)->is_oneway()) { + out << "{ __fulfill() }, failure: { __reject($0) })" << endl; + } + else { + block_open(out); + indent(out) << "do"; + block_open(out); + + indent(out); + if (!(*f_iter)->get_returntype()->is_void()) { + out << "let result = "; + } + out << "try self.recv_" << (*f_iter)->get_name() << "(__protocol)" << endl; + + out << indent() << "__fulfill("; + if (!(*f_iter)->get_returntype()->is_void()) { + out << "result"; + } + out << ")" << endl; + + block_close(out); + indent(out) << "catch let error"; + block_open(out); + indent(out) << "__reject(error)" << endl; + block_close(out); + block_close(out); + + indent(out) << ", failure: { error in " << endl; + indent_up(); + indent(out) << "__reject(error)" << endl; + indent_down(); + indent(out) << "})" << endl; + } + + indent(out) << "return __promise" << endl; + + block_close(out); + + out << endl; + + } + + } + + block_close(out); + + out << endl; +} + +/** + * Generates a service server implementation. + * + * Implemented by generating a block for each service function that + * handles the processing of that function. The blocks are stored in + * a map and looked up via function/message name. + * + * @param tservice The service to generate an implementation for + */ +void t_swift_generator::generate_swift_service_server_implementation(ofstream& out, + t_service* tservice) { + + string name = tservice->get_name() + "Processor"; + + indent(out) << "extension " << name << " : TProcessor"; + block_open(out); + + out << endl; + + indent(out) << "static let processorHandlers : ProcessorHandlerDictionary ="; + block_open(out); + + out << endl; + + out << indent() << "var processorHandlers = ProcessorHandlerDictionary()" << endl << endl; + + // generate method map for routing incoming calls + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + + t_function* tfunction = *f_iter; + + string args_type = function_args_helper_struct_type(tservice, *f_iter); + + out << indent() << "processorHandlers[\"" << tfunction->get_name() << "\"] = { sequenceID, inProtocol, outProtocol, handler in" << endl + << endl; + + indent_up(); + out << indent() << "let args = try " << args_type << ".readValueFromProtocol(inProtocol)" << endl + << endl + << indent() << "try inProtocol.readMessageEnd()" << endl + << endl; + + if (!tfunction->is_oneway() ) { + string result_type = function_result_helper_struct_type(tservice, tfunction); + indent(out) << "var result = " << result_type << "()" << endl; + + indent(out) << "do"; + block_open(out); + + indent(out); + if (!tfunction->get_returntype()->is_void()) { + out << "result.success = "; + } + out << "try handler." << function_name(tfunction) << "("; + + t_struct* arg_struct = tfunction->get_arglist(); + const vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + for (f_iter = fields.begin(); f_iter != fields.end();) { + string fieldName = (*f_iter)->get_name(); + if (f_iter != fields.begin()) { + out << fieldName << ": "; + } + out << "args." << fieldName; + if (++f_iter != fields.end()) { + out << ", "; + } + } + + out << ")" << endl; + + block_close(out); + + t_struct* xs = tfunction->get_xceptions(); + const vector& xfields = xs->get_members(); + vector::const_iterator x_iter; + + for (x_iter = xfields.begin(); x_iter != xfields.end(); ++x_iter) { + indent(out) << "catch let error as " << (*x_iter)->get_type()->get_name(); + block_open(out); + indent(out) << "result." << (*x_iter)->get_name() << " = error" << endl; + block_close(out); + } + + indent(out) << "catch let error"; + block_open(out); + out << indent() << "throw error" << endl; + block_close(out); + + out << endl; + + if (!tfunction->is_oneway()) { + out << indent() << "try outProtocol.writeMessageBeginWithName(\"" << tfunction->get_name() << "\", type: .REPLY, sequenceID: sequenceID)" << endl + << indent() << "try " << result_type << ".writeValue(result, toProtocol: outProtocol)" << endl + << indent() << "try outProtocol.writeMessageEnd()" << endl; + } + } + block_close(out); + + } + + indent(out) << "return processorHandlers" << endl; + + block_close(out,false); + out << "()" << endl; + + out << endl; + + indent(out) << "public func processOnInputProtocol(inProtocol: TProtocol, outputProtocol outProtocol: TProtocol) throws"; + block_open(out); + + out << endl; + + out << indent() << "let (messageName, _, sequenceID) = try inProtocol.readMessageBegin()" << endl + << endl + << indent() << "if let processorHandler = " << name << ".processorHandlers[messageName]"; + block_open(out); + out << indent() << "do"; + block_open(out); + out << indent() << "try processorHandler(sequenceID, inProtocol, outProtocol, service)" << endl; + block_close(out); + out << indent() << "catch let error as NSError"; + block_open(out); + out << indent() << "try outProtocol.writeExceptionForMessageName(messageName, sequenceID: sequenceID, ex: error)" << endl; + block_close(out); + block_close(out); + out << indent() << "else"; + block_open(out); + out << indent() << "try inProtocol.skipType(.STRUCT)" << endl + << indent() << "try inProtocol.readMessageEnd()" << endl + << indent() << "try outProtocol.writeExceptionForMessageName(messageName," << endl; + indent_up(); + out << indent() << "sequenceID: sequenceID," << endl + << indent() << "ex: NSError(" << endl; + indent_up(); + out << indent() << "domain: TApplicationErrorDomain, " << endl + << indent() << "code: Int(TApplicationError.UnknownMethod.rawValue), " << endl + << indent() << "userInfo: [TApplicationErrorMethodKey: messageName]))" << endl; + indent_down(); + indent_down(); + block_close(out); + + block_close(out); + + block_close(out); + out << endl; +} + +/** + * Returns an Swift name + * + * @param ttype The type + * @param class_ref Do we want a Class reference istead of a type reference? + * @return Swift type name, i.e. Dictionary + */ +string t_swift_generator::type_name(t_type* ttype, bool is_optional, bool is_forced) { + string result; + if (ttype->is_base_type()) { + result = base_type_name((t_base_type*)ttype); + } else if (ttype->is_map()) { + t_map *map = (t_map *)ttype; + result = "TMap<" + type_name(map->get_key_type()) + ", " + type_name(map->get_val_type()) + ">"; + } else if (ttype->is_set()) { + t_set *set = (t_set *)ttype; + result = "TSet<" + type_name(set->get_elem_type()) + ">"; + } else if (ttype->is_list()) { + t_list *list = (t_list *)ttype; + result = "TList<" + type_name(list->get_elem_type()) + ">"; + } + else { + result = ttype->get_name(); + } + + if (is_optional) { + result += "?"; + } + + if (is_forced) { + result += "!"; + } + + return result; +} + +/** + * Returns the Swift type that corresponds to the thrift type. + * + * @param tbase The base type + */ +string t_swift_generator::base_type_name(t_base_type* type) { + t_base_type::t_base tbase = type->get_base(); + + switch (tbase) { + case t_base_type::TYPE_VOID: + return "Void"; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + return "TBinary"; + } else { + return "String"; + } + case t_base_type::TYPE_BOOL: + return "Bool"; + case t_base_type::TYPE_I8: + return "Int8"; + case t_base_type::TYPE_I16: + return "Int16"; + case t_base_type::TYPE_I32: + return "Int32"; + case t_base_type::TYPE_I64: + return "Int64"; + case t_base_type::TYPE_DOUBLE: + return "Double"; + default: + throw "compiler error: no Swift name for base type " + t_base_type::t_base_name(tbase); + } +} + +/** + * Renders full constant value (as would be seen after an '=') + * + */ +void t_swift_generator::render_const_value(ostream& out, + t_type* type, + t_const_value* value) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + out << "\"" << get_escaped_string(value) << "\""; + break; + case t_base_type::TYPE_BOOL: + out << ((value->get_integer() > 0) ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + out << type_name(type) << "(" << value->get_integer() << ")"; + break; + case t_base_type::TYPE_DOUBLE: + out << type_name(type) << "("; + if (value->get_type() == t_const_value::CV_INTEGER) { + out << value->get_integer(); + } else { + out << value->get_double(); + } + out << ")"; + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + out << value->get_identifier(); + } else if (type->is_struct() || type->is_xception()) { + + out << type_name(type) << "("; + + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + + const map& val = value->get_map(); + map::const_iterator v_iter; + + for (f_iter = fields.begin(); f_iter != fields.end();) { + t_field* tfield = *f_iter; + t_const_value* value = NULL; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + if (tfield->get_name() == v_iter->first->get_string()) { + value = v_iter->second; + } + } + + if (value) { + out << tfield->get_name() << ": "; + render_const_value(out, tfield->get_type(), value); + } + else if (!field_is_optional(tfield)) { + throw "constant error: required field " + type->get_name() + "." + tfield->get_name() + " has no value"; + } + + if (++f_iter != fields.end()) { + out << ", "; + } + } + + out << ")"; + + } else if (type->is_map()) { + + out << "["; + + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + + const map& val = value->get_map(); + map::const_iterator v_iter; + + for (v_iter = val.begin(); v_iter != val.end();) { + + render_const_value(out, ktype, v_iter->first); + out << ": "; + render_const_value(out, vtype, v_iter->second); + + if (++v_iter != val.end()) { + out << ", "; + } + } + + out << "]"; + + } else if (type->is_list()) { + + out << "["; + + t_type* etype = ((t_list*)type)->get_elem_type(); + + const map& val = value->get_map(); + map::const_iterator v_iter; + + for (v_iter = val.begin(); v_iter != val.end();) { + + render_const_value(out, etype, v_iter->first); + + if (++v_iter != val.end()) { + out << ", "; + } + } + + out << "]"; + + } else if (type->is_set()) { + + out << "["; + + t_type* etype = ((t_set*)type)->get_elem_type(); + + const map& val = value->get_map(); + map::const_iterator v_iter; + + for (v_iter = val.begin(); v_iter != val.end();) { + + render_const_value(out, etype, v_iter->first); + + if (++v_iter != val.end()) { + out << ", "; + } + } + + out << "]"; + + } else { + throw "compiler error: no const of type " + type->get_name(); + } + +} + +/** + * Declares an Swift property. + * + * @param tfield The field to declare a property for + */ +string t_swift_generator::declare_property(t_field* tfield, bool is_private) { + + string visibility = is_private ? "private" : "public"; + + ostringstream render; + + render << visibility << " var " << maybe_escape_identifier(tfield->get_name()); + + if (field_is_optional(tfield)) { + render << " : " << type_name(tfield->get_type(), true); + } + else { + render << " = " << type_name(tfield->get_type(), false) << "()"; + } + + return render.str(); +} + +/** + * Renders a function signature + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_swift_generator::function_signature(t_function* tfunction) { + + string result = "func " + function_name(tfunction); + + result += "(" + argument_list(tfunction->get_arglist(), "", false) + ") throws"; + + t_type* ttype = tfunction->get_returntype(); + if (!ttype->is_void()) { + result += " -> " + type_name(ttype); + } + + return result; +} + +/** + * Renders a function signature that returns asynchronously via blocks. + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_swift_generator::async_function_signature(t_function* tfunction) { + t_type* ttype = tfunction->get_returntype(); + t_struct* targlist = tfunction->get_arglist(); + string response_param = "(" + ((ttype->is_void()) ? "" : type_name(ttype)) + ") -> Void"; + string result = "func " + function_name(tfunction); + result += "(" + argument_list(tfunction->get_arglist(), "", false) + + (targlist->get_members().size() ? ", " : "") + + "success: " + response_param + ", " + + "failure: (NSError) -> Void) throws"; + return result; +} + +/** + * Renders a function signature that returns asynchronously via promises. + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_swift_generator::promise_function_signature(t_function* tfunction) { + return "func " + function_name(tfunction) + "(" + argument_list(tfunction->get_arglist(), "", false) + ") throws " + + "-> Promise<" + type_name(tfunction->get_returntype()) + ">"; +} + +/** + * Renders a verbose function name suitable for a Swift method + */ +string t_swift_generator::function_name(t_function* tfunction) { + string name = tfunction->get_name(); + if (!tfunction->get_arglist()->get_members().empty()) { + string first_arg = tfunction->get_arglist()->get_members().front()->get_name(); + if (name.size() < first_arg.size() || + lowercase(name.substr(name.size()-first_arg.size())) != lowercase(first_arg)) { + name += "With" + capitalize(tfunction->get_arglist()->get_members()[0]->get_name()); + } + } + return name; +} + +/** + * Renders a Swift method argument list + */ +string t_swift_generator::argument_list(t_struct* tstruct, string protocol_name, bool is_internal) { + string result = ""; + bool include_protocol = !protocol_name.empty(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + if (include_protocol) { + result += protocol_name + ": TProtocol"; + if (!fields.empty()) { + result += ", "; + } + } + else if (!fields.empty() && is_internal) { + // Force first argument to be named + result += fields.front()->get_name() + " "; + } + + for (f_iter = fields.begin(); f_iter != fields.end();) { + t_field* arg = *f_iter; + result += arg->get_name() + ": " + type_name(arg->get_type()); + + if (++f_iter != fields.end()) { + result += ", "; + } + } + return result; +} + +/** + * https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html + * + */ + +void t_swift_generator::populate_reserved_words() { + swift_reserved_words_.insert("Self"); + swift_reserved_words_.insert("associatedtype"); + swift_reserved_words_.insert("defer"); + swift_reserved_words_.insert("deinit"); + swift_reserved_words_.insert("dynamicType"); + swift_reserved_words_.insert("enum"); + swift_reserved_words_.insert("extension"); + swift_reserved_words_.insert("fallthrough"); + swift_reserved_words_.insert("false"); + swift_reserved_words_.insert("func"); + swift_reserved_words_.insert("guard"); + swift_reserved_words_.insert("init"); + swift_reserved_words_.insert("inout"); + swift_reserved_words_.insert("internal"); + swift_reserved_words_.insert("let"); + swift_reserved_words_.insert("operator"); + swift_reserved_words_.insert("protocol"); + swift_reserved_words_.insert("repeat"); + swift_reserved_words_.insert("rethrows"); + swift_reserved_words_.insert("struct"); + swift_reserved_words_.insert("subscript"); + swift_reserved_words_.insert("throws"); + swift_reserved_words_.insert("true"); + swift_reserved_words_.insert("typealias"); + swift_reserved_words_.insert("where"); +} + +string t_swift_generator::maybe_escape_identifier(const string& identifier) { + if (swift_reserved_words_.find(identifier) != swift_reserved_words_.end()) { + return "`" + identifier + "`"; + } + return identifier; +} + +/** + * Converts the parse type to a Swift TType enumeration. + */ +string t_swift_generator::type_to_enum(t_type* type, bool qualified) { + type = get_true_type(type); + + string result = qualified ? "TType." : "."; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return result + "STRING"; + case t_base_type::TYPE_BOOL: + return result + "BOOL"; + case t_base_type::TYPE_I8: + return result + "BYTE"; + case t_base_type::TYPE_I16: + return result + "I16"; + case t_base_type::TYPE_I32: + return result + "I32"; + case t_base_type::TYPE_I64: + return result + "I64"; + case t_base_type::TYPE_DOUBLE: + return result + "DOUBLE"; + } + } else if (type->is_enum()) { + return result + "I32"; + } else if (type->is_struct() || type->is_xception()) { + return result + "STRUCT"; + } else if (type->is_map()) { + return result + "MAP"; + } else if (type->is_set()) { + return result + "SET"; + } else if (type->is_list()) { + return result + "LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + + +THRIFT_REGISTER_GENERATOR( + swift, + "Swift", + " log_unexpected: Log every time an unexpected field ID or type is encountered.\n" + " debug_descriptions:\n" + " Allow use of debugDescription so the app can add description via a cateogory/extension\n" + " async_clients: Generate clients which invoke asynchronously via block syntax.\n" + " promise_kit: Generate clients which invoke asynchronously via promises.\n") diff --git a/compiler/cpp/src/thrift/generate/t_xml_generator.cc b/compiler/cpp/src/thrift/generate/t_xml_generator.cc new file mode 100644 index 0000000..e7e01fd --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_xml_generator.cc @@ -0,0 +1,692 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_generator.h" + +using std::map; +using std::ofstream; +using std::ostream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; +using std::stack; +using std::set; + +static const string endl = "\n"; +static const string quot = "\""; + +static const string default_ns_prefix = "http://thrift.apache.org/xml/ns/"; + +/** + * This generator creates an XML model of the parsed IDL tree, and is designed + * to make it easy to use this file as the input for other template engines, + * such as XSLT. To this end, the generated XML is slightly more verbose than + * you might expect... for example, references to "id" types (such as structs, + * unions, etc) always specify the name of the IDL document, even if the type + * is defined in the same document as the reference. + */ +class t_xml_generator : public t_generator { +public: + t_xml_generator( t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + should_merge_includes_ = false; + should_use_default_ns_ = true; + should_use_namespaces_ = true; + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("merge") == 0) { + should_merge_includes_ = true; + } else if( iter->first.compare("no_default_ns") == 0) { + should_use_default_ns_ = false; + } else if( iter->first.compare("no_namespaces") == 0) { + should_use_namespaces_ = false; + } else { + throw "unknown option xml:" + iter->first; + } + } + + out_dir_base_ = "gen-xml"; + } + + virtual ~t_xml_generator() {} + + void init_generator(); + void close_generator(); + void generate_program(); + + void iterate_program(t_program* program); + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_function(t_function* tfunc); + void generate_field(t_field* field); + + void generate_service(t_service* tservice); + void generate_struct(t_struct* tstruct); + + void generate_annotations(std::map annotations); + +private: + bool should_merge_includes_; + bool should_use_default_ns_; + bool should_use_namespaces_; + + std::ofstream f_xml_; + + std::set programs_; + std::stack elements_; + bool top_element_is_empty; + bool top_element_is_open; + + string target_namespace(t_program* program); + void write_element_start(const string name); + void close_top_element(); + void write_element_end(); + void write_attribute(string key, string val); + void write_int_attribute(string key, int val); + string escape_xml_string(const string& input); + + void write_xml_comment(string msg); + + void write_type(t_type* ttype); + void write_doc(t_doc* tdoc); + + template + string number_to_string(T t) { + std::ostringstream out; + out.imbue(std::locale::classic()); + out.precision(std::numeric_limits::digits10); + out << t; + return out.str(); + } + + template + void write_number(T n) { + f_xml_ << number_to_string(n); + } + + template + void write_element_number(string name, T n) { + write_element_string(name, number_to_string(n)); + } + + string get_type_name(t_type* ttype); + + void generate_constant(t_const* con); + + void write_element_string(string name, string value); + void write_value(t_type* tvalue); + void write_const_value(t_const_value* value); + virtual std::string xml_autogen_comment() { + return std::string("\n") + " * Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + + " *\n" + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n"; + } +}; + +void t_xml_generator::init_generator() { + MKDIR(get_out_dir().c_str()); + + string f_xml_name = get_out_dir() + program_->get_name() + ".xml"; + f_xml_.open(f_xml_name.c_str()); + + top_element_is_open = false; +} + +string t_xml_generator::target_namespace(t_program* program) { + std::map map; + std::map::iterator iter; + map = program->get_namespace_annotations("xml"); + if ((iter = map.find("targetNamespace")) != map.end()) { + return iter->second; + } + map = program->get_namespaces(); + if ((iter = map.find("xml")) != map.end()) { + return default_ns_prefix + iter->second; + } + map = program->get_namespace_annotations("*"); + if ((iter = map.find("xml.targetNamespace")) != map.end()) { + return iter->second; + } + map = program->get_namespaces(); + if ((iter = map.find("*")) != map.end()) { + return default_ns_prefix + iter->second; + } + return default_ns_prefix + program->get_name(); +} + +void t_xml_generator::write_xml_comment(string msg) { + close_top_element(); + // TODO: indent any EOLs that may occur with msg + // TODO: proper msg escaping needed? + f_xml_ << indent() << "" << endl; + top_element_is_empty = false; +} + +void t_xml_generator::close_top_element() { + if( top_element_is_open) { + top_element_is_open = false; + if (elements_.size() > 0 && top_element_is_empty) { + f_xml_ << ">" << endl; + } + } +} + +void t_xml_generator::write_element_start(string name) { + if (should_use_namespaces_ && !should_use_default_ns_) { + name = "idl:" + name; + } + close_top_element(); + f_xml_ << indent() << "<" << name; + elements_.push(name); + top_element_is_empty = true; + top_element_is_open = true; + indent_up(); +} + +void t_xml_generator::write_element_end() { + indent_down(); + if (top_element_is_empty && top_element_is_open) { + f_xml_ << " />" << endl; + } else { + f_xml_ << indent() << "" << endl; + } + top_element_is_empty = false; + elements_.pop(); +} + +void t_xml_generator::write_attribute(string key, string val) { + f_xml_ << " " << key << "=\"" << escape_xml_string(val) << "\""; +} + +void t_xml_generator::write_int_attribute(string key, int val) { + write_attribute(key, number_to_string(val)); +} + +void t_xml_generator::write_element_string(string name, string val) { + if (should_use_namespaces_ && !should_use_default_ns_) { + name = "idl:" + name; + } + close_top_element(); + top_element_is_empty = false; + f_xml_ << indent() + << "<" << name << ">" << escape_xml_string(val) << "" + << endl; +} + +string t_xml_generator::escape_xml_string(const string& input) { + std::ostringstream ss; + for (std::string::const_iterator iter = input.begin(); iter != input.end(); iter++) { + switch (*iter) { + case '&': + ss << "&"; + break; + case '"': + ss << """; + break; + case '\'': + ss << "'"; + break; + case '<': + ss << "<"; + break; + case '>': + ss << ">"; + break; + default: + ss << *iter; + break; + } + } + return ss.str(); +} + +void t_xml_generator::close_generator() { + f_xml_.close(); +} + +void t_xml_generator::generate_program() { + + init_generator(); + + write_element_start("idl"); + if (should_use_namespaces_) { + if (should_use_default_ns_) { + write_attribute("xmlns", "http://thrift.apache.org/xml/idl"); + } + write_attribute("xmlns:idl", "http://thrift.apache.org/xml/idl"); + } + + write_xml_comment( xml_autogen_comment()); + + iterate_program(program_); + + write_element_end(); + + close_generator(); + +} + +void t_xml_generator::iterate_program(t_program* program) { + + write_element_start("document"); + write_attribute("name", program->get_name()); + if (should_use_namespaces_) { + const string targetNamespace = target_namespace(program); + write_attribute("targetNamespace", targetNamespace); + write_attribute("xmlns:" + program->get_name(), targetNamespace); + } + write_doc(program); + + const vector includes = program->get_includes(); + vector::const_iterator inc_it; + for (inc_it = includes.begin(); inc_it != includes.end(); ++inc_it) { + write_element_start("include"); + write_attribute("name", (*inc_it)->get_name()); + write_element_end(); + } + + const map& namespaces = program->get_namespaces(); + map::const_iterator ns_it; + for (ns_it = namespaces.begin(); ns_it != namespaces.end(); ++ns_it) { + write_element_start("namespace"); + write_attribute("name", ns_it->first); + write_attribute("value", ns_it->second); + generate_annotations(program->get_namespace_annotations(ns_it->first)); + write_element_end(); + } + + // TODO: can constants have annotations? + vector consts = program->get_consts(); + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + generate_constant(*c_iter); + } + + vector typedefs = program->get_typedefs(); + vector::iterator td_iter; + for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { + generate_typedef(*td_iter); + } + + vector enums = program->get_enums(); + vector::iterator en_iter; + for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { + generate_enum(*en_iter); + } + + vector objects = program->get_objects(); + vector::iterator o_iter; + for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { + if ((*o_iter)->is_xception()) { + generate_xception(*o_iter); + } else { + generate_struct(*o_iter); + } + } + + vector services = program->get_services(); + vector::iterator sv_iter; + for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { + generate_service(*sv_iter); + } + + write_element_end(); + + if (should_merge_includes_) { + programs_.insert(program->get_name()); + const vector programs = program->get_includes(); + vector::const_iterator prog_it; + for (prog_it = programs.begin(); prog_it != programs.end(); ++prog_it) { + if (!programs_.count((*prog_it)->get_name())) { + iterate_program(*prog_it); + } + } + } + +} + +void t_xml_generator::generate_typedef(t_typedef* ttypedef) { + write_element_start("typedef"); + write_attribute("name", ttypedef->get_name()); + write_doc(ttypedef); + write_type(ttypedef->get_true_type()); + generate_annotations(ttypedef->annotations_); + write_element_end(); + return; +} + +void t_xml_generator::write_type(t_type* ttype) { + const string type = get_type_name(ttype); + write_attribute("type", type); + if (type == "id") { + write_attribute("type-module", ttype->get_program()->get_name()); + write_attribute("type-id", ttype->get_name()); + } else if (type == "list") { + t_type* etype = ((t_list*)ttype)->get_elem_type(); + write_element_start("elemType"); + write_type(etype); + write_element_end(); + } else if (type == "set") { + t_type* etype = ((t_set*)ttype)->get_elem_type(); + write_element_start("elemType"); + write_type(etype); + write_element_end(); + } else if (type == "map") { + t_type* ktype = ((t_map*)ttype)->get_key_type(); + write_element_start("keyType"); + write_type(ktype); + write_element_end(); + t_type* vtype = ((t_map*)ttype)->get_val_type(); + write_element_start("valueType"); + write_type(vtype); + write_element_end(); + } +} + +void t_xml_generator::write_doc(t_doc* tdoc) { + if (tdoc->has_doc()) { + string doc = tdoc->get_doc(); + // for some reason there always seems to be a trailing newline on doc + // comments; loop below naively tries to strip off trailing cr/lf + int n = 0; + for (string::reverse_iterator i = doc.rbegin(); i != doc.rend(); i++,n++) { + if (*i != '\n' || *i == '\r') { + if (n > 0) { + doc.erase(doc.length() - n); + } + break; + } + } + write_attribute("doc", doc); + } +} + +void t_xml_generator::generate_annotations( + std::map annotations) { + std::map::iterator iter; + for (iter = annotations.begin(); iter != annotations.end(); ++iter) { + write_element_start("annotation"); + write_attribute("key", iter->first); + write_attribute("value", iter->second); + write_element_end(); + } +} + +void t_xml_generator::generate_constant(t_const* con) { + write_element_start("const"); + write_attribute("name", con->get_name()); + write_doc(con); + write_type(con->get_type()); + write_const_value(con->get_value()); + write_element_end(); +} + +void t_xml_generator::write_const_value(t_const_value* value) { + + switch (value->get_type()) { + + case t_const_value::CV_IDENTIFIER: + case t_const_value::CV_INTEGER: + write_element_number("int", value->get_integer()); + break; + + case t_const_value::CV_DOUBLE: + write_element_number("double", value->get_double()); + break; + + case t_const_value::CV_STRING: + write_element_string("string", value->get_string()); + break; + + case t_const_value::CV_LIST: { + write_element_start("list"); + std::vector list = value->get_list(); + std::vector::iterator lit; + for (lit = list.begin(); lit != list.end(); ++lit) { + write_element_start("entry"); + write_const_value(*lit); + write_element_end(); + } + write_element_end(); + break; + } + + case t_const_value::CV_MAP: { + write_element_start("map"); + std::map map = value->get_map(); + std::map::iterator mit; + for (mit = map.begin(); mit != map.end(); ++mit) { + write_element_start("entry"); + write_element_start("key"); + write_const_value(mit->first); + write_element_end(); + write_element_start("value"); + write_const_value(mit->second); + write_element_end(); + write_element_end(); + } + write_element_end(); + break; + } + + default: + indent_up(); + f_xml_ << indent() << "" << endl; + indent_down(); + break; + } + +} + +void t_xml_generator::generate_enum(t_enum* tenum) { + + write_element_start("enum"); + write_attribute("name", tenum->get_name()); + write_doc(tenum); + + vector values = tenum->get_constants(); + vector::iterator val_iter; + for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) { + t_enum_value* val = (*val_iter); + write_element_start("member"); + write_attribute("name", val->get_name()); + write_int_attribute("value", val->get_value()); + write_doc(val); + generate_annotations(val->annotations_); + write_element_end(); + } + + generate_annotations(tenum->annotations_); + + write_element_end(); + +} + +void t_xml_generator::generate_struct(t_struct* tstruct) { + + string tagname = "struct"; + if (tstruct->is_union()) { + tagname = "union"; + } else if (tstruct->is_xception()) { + tagname = "exception"; + } + + write_element_start(tagname); + write_attribute("name", tstruct->get_name()); + write_doc(tstruct); + vector members = tstruct->get_members(); + vector::iterator mem_iter; + for (mem_iter = members.begin(); mem_iter != members.end(); mem_iter++) { + write_element_start("field"); + generate_field(*mem_iter); + write_element_end(); + } + + generate_annotations(tstruct->annotations_); + + write_element_end(); + +} + +void t_xml_generator::generate_field(t_field* field) { + write_attribute("name", field->get_name()); + write_int_attribute("field-id", field->get_key()); + write_doc(field); + string requiredness; + switch (field->get_req()) { + case t_field::T_REQUIRED: + requiredness = "required"; + break; + case t_field::T_OPTIONAL: + requiredness = "optional"; + break; + default: + requiredness = ""; + break; + } + if (requiredness != "") { + write_attribute("required", requiredness); + } + write_type(field->get_type()); + if (field->get_value()) { + write_element_start("default"); + write_const_value(field->get_value()); + write_element_end(); + } + generate_annotations(field->annotations_); +} + +void t_xml_generator::generate_service(t_service* tservice) { + + write_element_start("service"); + write_attribute("name", tservice->get_name()); + + if (should_use_namespaces_) { + string prog_ns = target_namespace(tservice->get_program()); + if (*prog_ns.rbegin() != '/') { + prog_ns.push_back('/'); + } + const string tns = prog_ns + tservice->get_name(); + write_attribute("targetNamespace", tns); + write_attribute("xmlns:tns", tns); + } + + if (tservice->get_extends()) { + const t_service* extends = tservice->get_extends(); + write_attribute("parent-module", extends->get_program()->get_name()); + write_attribute("parent-id", extends->get_name()); + } + + write_doc(tservice); + + vector functions = tservice->get_functions(); + vector::iterator fn_iter = functions.begin(); + for (; fn_iter != functions.end(); fn_iter++) { + generate_function(*fn_iter); + } + + generate_annotations(tservice->annotations_); + + write_element_end(); + +} + +void t_xml_generator::generate_function(t_function* tfunc) { + + write_element_start("method"); + + write_attribute("name", tfunc->get_name()); + if (tfunc->is_oneway()) { + write_attribute("oneway", "true"); + } + + write_doc(tfunc); + + write_element_start("returns"); + write_type(tfunc->get_returntype()); + write_element_end(); + + vector members = tfunc->get_arglist()->get_members(); + vector::iterator mem_iter = members.begin(); + for (; mem_iter != members.end(); mem_iter++) { + write_element_start("arg"); + generate_field(*mem_iter); + write_element_end(); + } + + vector excepts = tfunc->get_xceptions()->get_members(); + vector::iterator ex_iter = excepts.begin(); + for (; ex_iter != excepts.end(); ex_iter++) { + write_element_start("throws"); + generate_field(*ex_iter); + write_element_end(); + } + + generate_annotations(tfunc->annotations_); + + write_element_end(); + +} + +string t_xml_generator::get_type_name(t_type* ttype) { + if (ttype->is_list()) { + return "list"; + } + if (ttype->is_set()) { + return "set"; + } + if (ttype->is_map()) { + return "map"; + } + if ((ttype->is_enum() )|| + (ttype->is_struct() )|| + (ttype->is_typedef() )|| + (ttype->is_xception())){ + return "id"; + } + if (ttype->is_base_type()) { + t_base_type* tbasetype = (t_base_type*)ttype; + if (tbasetype->is_binary() ) { + return "binary"; + } + return t_base_type::t_base_name(tbasetype->get_base()); + } + return "(unknown)"; +} + +THRIFT_REGISTER_GENERATOR( + xml, + "XML", + " merge: Generate output with included files merged\n" + " no_default_ns: Omit default xmlns and add idl: prefix to all elements\n" + " no_namespaces: Do not add namespace definitions to the XML model\n") diff --git a/compiler/cpp/src/thrift/generate/t_xsd_generator.cc b/compiler/cpp/src/thrift/generate/t_xsd_generator.cc new file mode 100644 index 0000000..fa51ba0 --- /dev/null +++ b/compiler/cpp/src/thrift/generate/t_xsd_generator.cc @@ -0,0 +1,376 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include "thrift/version.h" +#include "thrift/platform.h" +#include "thrift/generate/t_generator.h" + +using std::map; +using std::ofstream; +using std::ostream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * XSD generator, creates an XSD for the base types etc. + * + */ +class t_xsd_generator : public t_generator { +public: + t_xsd_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + /* no options yet */ + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + throw "unknown option xsd:" + iter->first; + } + + out_dir_base_ = "gen-xsd"; + } + + virtual ~t_xsd_generator() {} + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum) { (void)tenum; } + + void generate_service(t_service* tservice); + void generate_struct(t_struct* tstruct); + +private: + void generate_element(std::ostream& out, + std::string name, + t_type* ttype, + t_struct* attrs = NULL, + bool optional = false, + bool nillable = false, + bool list_element = false); + + std::string ns(std::string in, std::string ns) { return ns + ":" + in; } + + std::string xsd(std::string in) { return ns(in, "xsd"); } + + std::string type_name(t_type* ttype); + std::string base_type_name(t_base_type::t_base tbase); + + virtual std::string xml_autogen_comment() { + return std::string("\n"; + } + + /** + * Output xsd/php file + */ + std::ofstream f_xsd_; + std::ofstream f_php_; + + /** + * Output string stream + */ + std::ostringstream s_xsd_types_; +}; + +void t_xsd_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + + // Make output file + string f_php_name = get_out_dir() + program_->get_name() + "_xsd.php"; + f_php_.open(f_php_name.c_str()); + + f_php_ << "" << endl; + f_php_.close(); +} + +void t_xsd_generator::generate_typedef(t_typedef* ttypedef) { + indent(s_xsd_types_) << "get_name() << "\">" << endl; + indent_up(); + if (ttypedef->get_type()->is_string() && ((t_base_type*)ttypedef->get_type())->is_string_enum()) { + indent(s_xsd_types_) << "get_type()) << "\">" + << endl; + indent_up(); + const vector& values = ((t_base_type*)ttypedef->get_type())->get_string_enum_vals(); + vector::const_iterator v_iter; + for (v_iter = values.begin(); v_iter != values.end(); ++v_iter) { + indent(s_xsd_types_) << "" << endl; + } + indent_down(); + indent(s_xsd_types_) << "" << endl; + } else { + indent(s_xsd_types_) << "get_type()) << "\" />" + << endl; + } + indent_down(); + indent(s_xsd_types_) << "" << endl << endl; +} + +void t_xsd_generator::generate_struct(t_struct* tstruct) { + vector::const_iterator m_iter; + const vector& members = tstruct->get_members(); + bool xsd_all = tstruct->get_xsd_all(); + + indent(s_xsd_types_) << "get_name() << "\">" << endl; + indent_up(); + if (xsd_all) { + indent(s_xsd_types_) << "" << endl; + } else { + indent(s_xsd_types_) << "" << endl; + } + indent_up(); + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + generate_element(s_xsd_types_, + (*m_iter)->get_name(), + (*m_iter)->get_type(), + (*m_iter)->get_xsd_attrs(), + (*m_iter)->get_xsd_optional() || xsd_all, + (*m_iter)->get_xsd_nillable()); + } + + indent_down(); + if (xsd_all) { + indent(s_xsd_types_) << "" << endl; + } else { + indent(s_xsd_types_) << "" << endl; + } + indent_down(); + indent(s_xsd_types_) << "" << endl << endl; +} + +void t_xsd_generator::generate_element(ostream& out, + string name, + t_type* ttype, + t_struct* attrs, + bool optional, + bool nillable, + bool list_element) { + string sminOccurs = (optional || list_element) ? " minOccurs=\"0\"" : ""; + string smaxOccurs = list_element ? " maxOccurs=\"unbounded\"" : ""; + string soptional = sminOccurs + smaxOccurs; + string snillable = nillable ? " nillable=\"true\"" : ""; + + if (ttype->is_void() || ttype->is_list()) { + indent(out) << "" << endl; + indent_up(); + if (attrs == NULL && ttype->is_void()) { + indent(out) << "" << endl; + } else { + indent(out) << "" << endl; + indent_up(); + if (ttype->is_list()) { + indent(out) << "" << endl; + indent_up(); + string subname; + t_type* subtype = ((t_list*)ttype)->get_elem_type(); + if (subtype->is_base_type() || subtype->is_container()) { + subname = name + "_elt"; + } else { + subname = type_name(subtype); + } + f_php_ << "$GLOBALS['" << program_->get_name() << "_xsd_elt_" << name << "'] = '" << subname + << "';" << endl; + generate_element(out, subname, subtype, NULL, false, false, true); + indent_down(); + indent(out) << "" << endl; + indent(out) << "" << endl; + } + if (attrs != NULL) { + const vector& members = attrs->get_members(); + vector::const_iterator a_iter; + for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) { + indent(out) << "get_name() << "\" type=\"" + << type_name((*a_iter)->get_type()) << "\" />" << endl; + } + } + indent_down(); + indent(out) << "" << endl; + } + indent_down(); + indent(out) << "" << endl; + } else { + if (attrs == NULL) { + indent(out) << "" + << endl; + } else { + // Wow, all this work for a SIMPLE TYPE with attributes?!?!?! + indent(out) << "" + << endl; + indent_up(); + indent(out) << "" << endl; + indent_up(); + indent(out) << "" << endl; + indent_up(); + indent(out) << "" << endl; + indent_up(); + const vector& members = attrs->get_members(); + vector::const_iterator a_iter; + for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) { + indent(out) << "get_name() << "\" type=\"" + << type_name((*a_iter)->get_type()) << "\" />" << endl; + } + indent_down(); + indent(out) << "" << endl; + indent_down(); + indent(out) << "" << endl; + indent_down(); + indent(out) << "" << endl; + indent_down(); + indent(out) << "" << endl; + } + } +} + + +void t_xsd_generator::generate_service(t_service* tservice) { + // Make output file + string f_xsd_name = get_out_dir() + tservice->get_name() + ".xsd"; + f_xsd_.open(f_xsd_name.c_str()); + + string ns = program_->get_namespace("xsd"); + const std::map annot = program_->get_namespace_annotations("xsd"); + const std::map::const_iterator uri = annot.find("uri"); + if (uri != annot.end()) { + ns = uri->second; + } + if (ns.size() > 0) { + ns = " targetNamespace=\"" + ns + "\" xmlns=\"" + ns + "\" " + + "elementFormDefault=\"qualified\""; + } + + // Print the XSD header + f_xsd_ << "" << endl + << "" << endl + << xml_autogen_comment() + << endl; + + // Print out the type definitions + indent(f_xsd_) << s_xsd_types_.str(); + + // Keep a list of all the possible exceptions that might get thrown + map all_xceptions; + + // List the elements that you might actually get + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string elemname = (*f_iter)->get_name() + "_response"; + t_type* returntype = (*f_iter)->get_returntype(); + generate_element(f_xsd_, elemname, returntype); + f_xsd_ << endl; + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + all_xceptions[(*x_iter)->get_name()] = (t_struct*)((*x_iter)->get_type()); + } + } + + map::iterator ax_iter; + for (ax_iter = all_xceptions.begin(); ax_iter != all_xceptions.end(); ++ax_iter) { + generate_element(f_xsd_, ax_iter->first, ax_iter->second); + } + + // Close the XSD document + f_xsd_ << endl << "" << endl; + f_xsd_.close(); +} + +string t_xsd_generator::type_name(t_type* ttype) { + if (ttype->is_typedef()) { + return ttype->get_name(); + } + + if (ttype->is_base_type()) { + return xsd(base_type_name(((t_base_type*)ttype)->get_base())); + } + + if (ttype->is_enum()) { + return xsd("int"); + } + + if (ttype->is_struct() || ttype->is_xception()) { + return ttype->get_name(); + } + + return "container"; +} + +/** + * Returns the XSD type that corresponds to the thrift type. + * + * @param tbase The base type + * @return Explicit XSD type, i.e. xsd:string + */ +string t_xsd_generator::base_type_name(t_base_type::t_base tbase) { + switch (tbase) { + case t_base_type::TYPE_VOID: + return "void"; + case t_base_type::TYPE_STRING: + return "string"; + case t_base_type::TYPE_BOOL: + return "boolean"; + case t_base_type::TYPE_I8: + return "byte"; + case t_base_type::TYPE_I16: + return "short"; + case t_base_type::TYPE_I32: + return "int"; + case t_base_type::TYPE_I64: + return "long"; + case t_base_type::TYPE_DOUBLE: + return "decimal"; + default: + throw "compiler error: no XSD base type name for base type " + t_base_type::t_base_name(tbase); + } +} + +THRIFT_REGISTER_GENERATOR(xsd, "XSD", "") diff --git a/compiler/cpp/src/thrift/globals.h b/compiler/cpp/src/thrift/globals.h new file mode 100644 index 0000000..961c6ef --- /dev/null +++ b/compiler/cpp/src/thrift/globals.h @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_GLOBALS_H +#define T_GLOBALS_H + +#include +#include +#include +#include +#include + +/** + * This module contains all the global variables (slap on the wrist) that are + * shared throughout the program. The reason for this is to facilitate simple + * interaction between the parser and the rest of the program. Before calling + * yyparse(), the main.cc program will make necessary adjustments to these + * global variables such that the parser does the right thing and puts entries + * into the right containers, etc. + * + */ + +/** + * Hooray for forward declaration of types! + */ + +class t_program; +class t_scope; +class t_type; + +/** + * Parsing mode, two passes up in this gin rummy! + */ + +enum PARSE_MODE { INCLUDES = 1, PROGRAM = 2 }; + +/** + * Strictness level + */ +extern int g_strict; + +/** + * The master program parse tree. This is accessed from within the parser code + * to build up the program elements. + */ +extern t_program* g_program; + +/** + * The scope that we are currently parsing into + */ +extern t_scope* g_scope; + +/** + * The parent scope to also load symbols into + */ +extern t_scope* g_parent_scope; + +/** + * The prefix for the parent scope entries + */ +extern std::string g_parent_prefix; + +/** + * The parsing pass that we are on. We do different things on each pass. + */ +extern PARSE_MODE g_parse_mode; + +/** + * Global time string, used in formatting error messages etc. + */ +extern char* g_time_str; + +/** + * The last parsed doctext comment. + */ +extern char* g_doctext; + +/** + * The location of the last parsed doctext comment. + */ +extern int g_doctext_lineno; + +/** + * Status of program level doctext candidate + */ +enum PROGDOCTEXT_STATUS { + INVALID = 0, + STILL_CANDIDATE = 1, // the text may or may not be the program doctext + ALREADY_PROCESSED = 2, // doctext has been used and is no longer available + ABSOLUTELY_SURE = 3, // this is the program doctext + NO_PROGRAM_DOCTEXT = 4 // there is no program doctext +}; + +/** + * The program level doctext. Stored separately to make parsing easier. + */ +extern char* g_program_doctext_candidate; +extern int g_program_doctext_lineno; +extern PROGDOCTEXT_STATUS g_program_doctext_status; + +/** + * Whether or not negative field keys are accepted. + * + * When a field does not have a user-specified key, thrift automatically + * assigns a negative value. However, this is fragile since changes to the + * file may unintentionally change the key numbering, resulting in a new + * protocol that is not backwards compatible. + * + * When g_allow_neg_field_keys is enabled, users can explicitly specify + * negative keys. This way they can write a .thrift file with explicitly + * specified keys that is still backwards compatible with older .thrift files + * that did not specify key values. + */ +extern int g_allow_neg_field_keys; + +/** + * Whether or not 64-bit constants will generate a warning. + * + * Some languages don't support 64-bit constants, but many do, so we can + * suppress this warning for projects that don't use any non-64-bit-safe + * languages. + */ +extern int g_allow_64bit_consts; + +#endif diff --git a/compiler/cpp/src/thrift/logging.cc b/compiler/cpp/src/thrift/logging.cc new file mode 100644 index 0000000..f821f5f --- /dev/null +++ b/compiler/cpp/src/thrift/logging.cc @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Logging functions copied from main.cc to avoid link errors for plugins + */ + +#include "thrift/logging.h" +#include "thrift/globals.h" +#include +#include +#include + +// TODO: make plugins accept log options from main compiler +int g_debug = 0; +int g_warn = 1; +int g_verbose = 0; + +void pdebug(const char* fmt, ...) { + if (g_debug == 0) { + return; + } + va_list args; + // printf("[PARSE:%d] ", yylineno); + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + printf("\n"); +} + +void pverbose(const char* fmt, ...) { + if (g_verbose == 0) { + return; + } + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} + +void pwarning(int level, const char* fmt, ...) { + if (g_warn < level) { + return; + } + va_list args; + // printf("[WARNING:%s:%d] ", g_curpath.c_str(), yylineno); + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + printf("\n"); +} + +void failure(const char* fmt, ...) { + va_list args; + // fprintf(stderr, "[FAILURE:%s:%d] ", g_curpath.c_str(), yylineno); + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + printf("\n"); + exit(1); +} diff --git a/compiler/cpp/src/thrift/logging.h b/compiler/cpp/src/thrift/logging.h new file mode 100644 index 0000000..ebefbf2 --- /dev/null +++ b/compiler/cpp/src/thrift/logging.h @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_LOGGING_H +#define T_LOGGING_H + +extern int g_debug; +extern int g_warn; +extern int g_verbose; + +/** + * Parse debugging output, used to print helpful info + */ +void pdebug(const char* fmt, ...); + +/** + * Parser warning + */ +void pwarning(int level, const char* fmt, ...); + +/** + * Print verbose output message + */ +void pverbose(const char* fmt, ...); + +/** + * Failure! + */ +void failure(const char* fmt, ...); + +#endif diff --git a/compiler/cpp/src/thrift/main.cc b/compiler/cpp/src/thrift/main.cc new file mode 100644 index 0000000..8421840 --- /dev/null +++ b/compiler/cpp/src/thrift/main.cc @@ -0,0 +1,1307 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * thrift - a lightweight cross-language rpc/serialization tool + * + * This file contains the main compiler engine for Thrift, which invokes the + * scanner/parser to build the thrift object tree. The interface generation + * code for each language lives in a file by the language name under the + * generate/ folder, and all parse structures live in parse/ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include /* for GetFullPathName */ +#endif + +// Careful: must include globals first for extern definitions +#include "thrift/common.h" +#include "thrift/globals.h" + +#include "thrift/platform.h" +#include "thrift/main.h" +#include "thrift/parse/t_program.h" +#include "thrift/parse/t_scope.h" +#include "thrift/generate/t_generator.h" +#include "thrift/audit/t_audit.h" +#ifdef THRIFT_ENABLE_PLUGIN +#include "thrift/plugin/plugin_output.h" +#endif + +#include "thrift/version.h" + +using namespace std; + +/** + * Global program tree + */ +t_program* g_program; + +/** + * Global scope + */ +t_scope* g_scope; + +/** + * Parent scope to also parse types + */ +t_scope* g_parent_scope; + +/** + * Prefix for putting types in parent scope + */ +string g_parent_prefix; + +/** + * Parsing pass + */ +PARSE_MODE g_parse_mode; + +/** + * Current directory of file being parsed + */ +string g_curdir; + +/** + * Current file being parsed + */ +string g_curpath; + +/** + * Search path for inclusions + */ +vector g_incl_searchpath; + +/** + * Global debug state + */ +int g_debug = 0; + +/** + * Strictness level + */ +int g_strict = 127; + +/** + * Warning level + */ +int g_warn = 1; + +/** + * Verbose output + */ +int g_verbose = 0; + +/** + * Global time string + */ +char* g_time_str; + +/** + * The last parsed doctext comment. + */ +char* g_doctext; + +/** + * The First doctext comment + */ +char* g_program_doctext_candidate; + +/** + * Whether or not negative field keys are accepted. + */ +int g_allow_neg_field_keys; + +/** + * Whether or not 64-bit constants will generate a warning. + */ +int g_allow_64bit_consts = 0; + +/** + * Flags to control code generation + */ +bool gen_recurse = false; + +/** + * Flags to control thrift audit + */ +bool g_audit = false; + +/** + * Flag to control return status + */ +bool g_return_failure = false; +bool g_audit_fatal = true; +bool g_generator_failure = false; + +/** + * Win32 doesn't have realpath, so use fallback implementation in that case, + * otherwise this just calls through to realpath + */ +char* saferealpath(const char* path, char* resolved_path) { +#ifdef _WIN32 + char buf[MAX_PATH]; + char* basename; + DWORD len = GetFullPathName(path, MAX_PATH, buf, &basename); + if (len == 0 || len > MAX_PATH - 1) { + strcpy(resolved_path, path); + } else { + strcpy(resolved_path, buf); + } + + // Replace backslashes with forward slashes so the + // rest of the code behaves correctly. + size_t resolved_len = strlen(resolved_path); + for (size_t i = 0; i < resolved_len; i++) { + if (resolved_path[i] == '\\') { + resolved_path[i] = '/'; + } + } + return resolved_path; +#else + return realpath(path, resolved_path); +#endif +} + +bool check_is_directory(const char* dir_name) { +#ifdef _WIN32 + DWORD attributes = ::GetFileAttributesA(dir_name); + if (attributes == INVALID_FILE_ATTRIBUTES) { + fprintf(stderr, + "Output directory %s is unusable: GetLastError() = %ld\n", + dir_name, + GetLastError()); + return false; + } + if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) { + fprintf(stderr, "Output directory %s exists but is not a directory\n", dir_name); + return false; + } + return true; +#else + struct stat sb; + if (stat(dir_name, &sb) < 0) { + fprintf(stderr, "Output directory %s is unusable: %s\n", dir_name, strerror(errno)); + return false; + } + if (!S_ISDIR(sb.st_mode)) { + fprintf(stderr, "Output directory %s exists but is not a directory\n", dir_name); + return false; + } + return true; +#endif +} + +/** + * Report an error to the user. This is called yyerror for historical + * reasons (lex and yacc expect the error reporting routine to be called + * this). Call this function to report any errors to the user. + * yyerror takes printf style arguments. + * + * @param fmt C format string followed by additional arguments + */ +void yyerror(const char* fmt, ...) { + va_list args; + fprintf(stderr, "[ERROR:%s:%d] (last token was '%s')\n", g_curpath.c_str(), yylineno, yytext); + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + + fprintf(stderr, "\n"); +} + +/** + * Prints a debug message from the parser. + * + * @param fmt C format string followed by additional arguments + */ +void pdebug(const char* fmt, ...) { + if (g_debug == 0) { + return; + } + va_list args; + printf("[PARSE:%d] ", yylineno); + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + printf("\n"); +} + +/** + * Prints a verbose output mode message + * + * @param fmt C format string followed by additional arguments + */ +void pverbose(const char* fmt, ...) { + if (g_verbose == 0) { + return; + } + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} + +/** + * Prints a warning message + * + * @param fmt C format string followed by additional arguments + */ +void pwarning(int level, const char* fmt, ...) { + if (g_warn < level) { + return; + } + va_list args; + printf("[WARNING:%s:%d] ", g_curpath.c_str(), yylineno); + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + printf("\n"); +} + +/** + * Prints a failure message and exits + * + * @param fmt C format string followed by additional arguments + */ +void failure(const char* fmt, ...) { + va_list args; + fprintf(stderr, "[FAILURE:%s:%d] ", g_curpath.c_str(), yylineno); + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + printf("\n"); + exit(1); +} + +/** + * Converts a string filename into a thrift program name + */ +string program_name(string filename) { + string::size_type slash = filename.rfind("/"); + if (slash != string::npos) { + filename = filename.substr(slash + 1); + } + string::size_type dot = filename.rfind("."); + if (dot != string::npos) { + filename = filename.substr(0, dot); + } + return filename; +} + +/** + * Gets the directory path of a filename + */ +string directory_name(string filename) { + string::size_type slash = filename.rfind("/"); + // No slash, just use the current directory + if (slash == string::npos) { + return "."; + } + return filename.substr(0, slash); +} + +/** + * Finds the appropriate file path for the given filename + */ +string include_file(string filename) { + // Absolute path? Just try that + if (filename[0] == '/') { + // Realpath! + char rp[THRIFT_PATH_MAX]; + // cppcheck-suppress uninitvar + if (saferealpath(filename.c_str(), rp) == NULL) { + pwarning(0, "Cannot open include file %s\n", filename.c_str()); + return std::string(); + } + + // Stat this file + struct stat finfo; + if (stat(rp, &finfo) == 0) { + return rp; + } + } else { // relative path, start searching + // new search path with current dir global + vector sp = g_incl_searchpath; + sp.insert(sp.begin(), g_curdir); + + // iterate through paths + vector::iterator it; + for (it = sp.begin(); it != sp.end(); it++) { + string sfilename = *(it) + "/" + filename; + + // Realpath! + char rp[THRIFT_PATH_MAX]; + // cppcheck-suppress uninitvar + if (saferealpath(sfilename.c_str(), rp) == NULL) { + continue; + } + + // Stat this files + struct stat finfo; + if (stat(rp, &finfo) == 0) { + return rp; + } + } + } + + // Uh oh + pwarning(0, "Could not find include file %s\n", filename.c_str()); + return std::string(); +} + +/** + * Clears any previously stored doctext string. + * Also prints a warning if we are discarding information. + */ +void clear_doctext() { + if (g_doctext != NULL) { + pwarning(2, "Uncaptured doctext at on line %d.", g_doctext_lineno); + } + free(g_doctext); + g_doctext = NULL; +} + +/** + * Reset program doctext information after processing a file + */ +void reset_program_doctext_info() { + if (g_program_doctext_candidate != NULL) { + free(g_program_doctext_candidate); + g_program_doctext_candidate = NULL; + } + g_program_doctext_lineno = 0; + g_program_doctext_status = INVALID; + pdebug("%s", "program doctext set to INVALID"); +} + +/** + * We are sure the program doctext candidate is really the program doctext. + */ +void declare_valid_program_doctext() { + if ((g_program_doctext_candidate != NULL) && (g_program_doctext_status == STILL_CANDIDATE)) { + g_program_doctext_status = ABSOLUTELY_SURE; + pdebug("%s", "program doctext set to ABSOLUTELY_SURE"); + } else { + g_program_doctext_status = NO_PROGRAM_DOCTEXT; + pdebug("%s", "program doctext set to NO_PROGRAM_DOCTEXT"); + } +} + +/** + * Cleans up text commonly found in doxygen-like comments + * + * Warning: if you mix tabs and spaces in a non-uniform way, + * you will get what you deserve. + */ +char* clean_up_doctext(char* doctext) { + // Convert to C++ string, and remove Windows's carriage returns. + string docstring = doctext; + docstring.erase(remove(docstring.begin(), docstring.end(), '\r'), docstring.end()); + + // Separate into lines. + vector lines; + string::size_type pos = string::npos; + string::size_type last; + while (true) { + last = (pos == string::npos) ? 0 : pos + 1; + pos = docstring.find('\n', last); + if (pos == string::npos) { + // First bit of cleaning. If the last line is only whitespace, drop it. + string::size_type nonwhite = docstring.find_first_not_of(" \t", last); + if (nonwhite != string::npos) { + lines.push_back(docstring.substr(last)); + } + break; + } + lines.push_back(docstring.substr(last, pos - last)); + } + + // A very profound docstring. + if (lines.empty()) { + return NULL; + } + + // Clear leading whitespace from the first line. + pos = lines.front().find_first_not_of(" \t"); + lines.front().erase(0, pos); + + // If every nonblank line after the first has the same number of spaces/tabs, + // then a star, remove them. + bool have_prefix = true; + bool found_prefix = false; + string::size_type prefix_len = 0; + vector::iterator l_iter; + for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) { + if (l_iter->empty()) { + continue; + } + + pos = l_iter->find_first_not_of(" \t"); + if (!found_prefix) { + if (pos != string::npos) { + if (l_iter->at(pos) == '*') { + found_prefix = true; + prefix_len = pos; + } else { + have_prefix = false; + break; + } + } else { + // Whitespace-only line. Truncate it. + l_iter->clear(); + } + } else if (l_iter->size() > pos && l_iter->at(pos) == '*' && pos == prefix_len) { + // Business as usual. + } else if (pos == string::npos) { + // Whitespace-only line. Let's truncate it for them. + l_iter->clear(); + } else { + // The pattern has been broken. + have_prefix = false; + break; + } + } + + // If our prefix survived, delete it from every line. + if (have_prefix) { + // Get the star too. + prefix_len++; + for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) { + l_iter->erase(0, prefix_len); + } + } + + // Now delete the minimum amount of leading whitespace from each line. + prefix_len = string::npos; + for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) { + if (l_iter->empty()) { + continue; + } + pos = l_iter->find_first_not_of(" \t"); + if (pos != string::npos && (prefix_len == string::npos || pos < prefix_len)) { + prefix_len = pos; + } + } + + // If our prefix survived, delete it from every line. + if (prefix_len != string::npos) { + for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) { + l_iter->erase(0, prefix_len); + } + } + + // Remove trailing whitespace from every line. + for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) { + pos = l_iter->find_last_not_of(" \t"); + if (pos != string::npos && pos != l_iter->length() - 1) { + l_iter->erase(pos + 1); + } + } + + // If the first line is empty, remove it. + // Don't do this earlier because a lot of steps skip the first line. + if (lines.front().empty()) { + lines.erase(lines.begin()); + } + + // Now rejoin the lines and copy them back into doctext. + docstring.clear(); + for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) { + docstring += *l_iter; + docstring += '\n'; + } + + // assert(docstring.length() <= strlen(doctext)); may happen, see THRIFT-1755 + if (docstring.length() <= strlen(doctext)) { + strcpy(doctext, docstring.c_str()); + } else { + free(doctext); // too short + doctext = strdup(docstring.c_str()); + } + return doctext; +} + +/** Set to true to debug docstring parsing */ +static bool dump_docs = false; + +/** + * Dumps docstrings to stdout + * Only works for top-level definitions and the whole program doc + * (i.e., not enum constants, struct fields, or functions. + */ +void dump_docstrings(t_program* program) { + string progdoc = program->get_doc(); + if (!progdoc.empty()) { + printf("Whole program doc:\n%s\n", progdoc.c_str()); + } + const vector& typedefs = program->get_typedefs(); + vector::const_iterator t_iter; + for (t_iter = typedefs.begin(); t_iter != typedefs.end(); ++t_iter) { + t_typedef* td = *t_iter; + if (td->has_doc()) { + printf("typedef %s:\n%s\n", td->get_name().c_str(), td->get_doc().c_str()); + } + } + const vector& enums = program->get_enums(); + vector::const_iterator e_iter; + for (e_iter = enums.begin(); e_iter != enums.end(); ++e_iter) { + t_enum* en = *e_iter; + if (en->has_doc()) { + printf("enum %s:\n%s\n", en->get_name().c_str(), en->get_doc().c_str()); + } + } + const vector& consts = program->get_consts(); + vector::const_iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + t_const* co = *c_iter; + if (co->has_doc()) { + printf("const %s:\n%s\n", co->get_name().c_str(), co->get_doc().c_str()); + } + } + const vector& structs = program->get_structs(); + vector::const_iterator s_iter; + for (s_iter = structs.begin(); s_iter != structs.end(); ++s_iter) { + t_struct* st = *s_iter; + if (st->has_doc()) { + printf("struct %s:\n%s\n", st->get_name().c_str(), st->get_doc().c_str()); + } + } + const vector& xceptions = program->get_xceptions(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + t_struct* xn = *x_iter; + if (xn->has_doc()) { + printf("xception %s:\n%s\n", xn->get_name().c_str(), xn->get_doc().c_str()); + } + } + const vector& services = program->get_services(); + vector::const_iterator v_iter; + for (v_iter = services.begin(); v_iter != services.end(); ++v_iter) { + t_service* sv = *v_iter; + if (sv->has_doc()) { + printf("service %s:\n%s\n", sv->get_name().c_str(), sv->get_doc().c_str()); + } + } +} + +/** + * Emits a warning on list, binary type is typically a much better choice. + */ +void check_for_list_of_bytes(t_type* list_elem_type) { + if ((g_parse_mode == PROGRAM) && (list_elem_type != NULL) && list_elem_type->is_base_type()) { + t_base_type* tbase = (t_base_type*)list_elem_type; + if (tbase->get_base() == t_base_type::TYPE_I8) { + pwarning(1, "Consider using the more efficient \"binary\" type instead of \"list\"."); + } + } +} + +static bool g_byte_warning_emitted = false; + +/** + * Emits a one-time warning on byte type, promoting the new i8 type instead + */ +void emit_byte_type_warning() { + if (!g_byte_warning_emitted) { + pwarning(1, + "The \"byte\" type is a compatibility alias for \"i8\". Use \"i8\" to emphasize the " + "signedness of this type.\n"); + g_byte_warning_emitted = true; + } +} + +/** + * Prints deprecation notice for old NS declarations that are no longer supported + * If new_form is NULL, old_form is assumed to be a language identifier, such as "cpp" + * If new_form is not NULL, both arguments are used exactly as given + */ +void error_unsupported_namespace_decl(const char* old_form, const char* new_form) { + const char* remainder = ""; + if( new_form == NULL) { + new_form = old_form; + remainder = "_namespace"; + } + failure("Unsupported declaration '%s%s'. Use 'namespace %s' instead.", old_form, remainder, new_form); +} + +/** + * Prints the version number + */ +void version() { + printf("Thrift version %s\n", THRIFT_VERSION); +} + +/** + * Display the usage message and then exit with an error code. + */ +void usage() { + fprintf(stderr, "Usage: thrift [options] file\n\n"); + fprintf(stderr, "Use thrift -help for a list of options\n"); + exit(1); +} + +/** + * Diplays the help message and then exits with an error code. + */ +void help() { + fprintf(stderr, "Usage: thrift [options] file\n"); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -version Print the compiler version\n"); + fprintf(stderr, " -o dir Set the output directory for gen-* packages\n"); + fprintf(stderr, " (default: current directory)\n"); + fprintf(stderr, " -out dir Set the ouput location for generated files.\n"); + fprintf(stderr, " (no gen-* folder will be created)\n"); + fprintf(stderr, " -I dir Add a directory to the list of directories\n"); + fprintf(stderr, " searched for include directives\n"); + fprintf(stderr, " -nowarn Suppress all compiler warnings (BAD!)\n"); + fprintf(stderr, " -strict Strict compiler warnings on\n"); + fprintf(stderr, " -v[erbose] Verbose mode\n"); + fprintf(stderr, " -r[ecurse] Also generate included files\n"); + fprintf(stderr, " -debug Parse debug trace to stdout\n"); + fprintf(stderr, + " --allow-neg-keys Allow negative field keys (Used to " + "preserve protocol\n"); + fprintf(stderr, " compatibility with older .thrift files)\n"); + fprintf(stderr, " --allow-64bit-consts Do not print warnings about using 64-bit constants\n"); + fprintf(stderr, " --gen STR Generate code with a dynamically-registered generator.\n"); + fprintf(stderr, " STR has the form language[:key1=val1[,key2[,key3=val3]]].\n"); + fprintf(stderr, " Keys and values are options passed to the generator.\n"); + fprintf(stderr, " Many options will not require values.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Options related to audit operation\n"); + fprintf(stderr, " --audit OldFile Old Thrift file to be audited with 'file'\n"); + fprintf(stderr, " -Iold dir Add a directory to the list of directories\n"); + fprintf(stderr, " searched for include directives for old thrift file\n"); + fprintf(stderr, " -Inew dir Add a directory to the list of directories\n"); + fprintf(stderr, " searched for include directives for new thrift file\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Available generators (and options):\n"); + + t_generator_registry::gen_map_t gen_map = t_generator_registry::get_generator_map(); + t_generator_registry::gen_map_t::iterator iter; + for (iter = gen_map.begin(); iter != gen_map.end(); ++iter) { + fprintf(stderr, + " %s (%s):\n", + iter->second->get_short_name().c_str(), + iter->second->get_long_name().c_str()); + fprintf(stderr, "%s", iter->second->get_documentation().c_str()); + } + exit(1); +} + +/** + * You know, when I started working on Thrift I really thought it wasn't going + * to become a programming language because it was just a generator and it + * wouldn't need runtime type information and all that jazz. But then we + * decided to add constants, and all of a sudden that means runtime type + * validation and inference, except the "runtime" is the code generator + * runtime. + */ +void validate_const_rec(std::string name, t_type* type, t_const_value* value) { + if (type->is_void()) { + throw "type error: cannot declare a void const: " + name; + } + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + if (value->get_type() != t_const_value::CV_STRING) { + throw "type error: const \"" + name + "\" was declared as string"; + } + break; + case t_base_type::TYPE_BOOL: + if (value->get_type() != t_const_value::CV_INTEGER) { + throw "type error: const \"" + name + "\" was declared as bool"; + } + break; + case t_base_type::TYPE_I8: + if (value->get_type() != t_const_value::CV_INTEGER) { + throw "type error: const \"" + name + "\" was declared as byte"; + } + break; + case t_base_type::TYPE_I16: + if (value->get_type() != t_const_value::CV_INTEGER) { + throw "type error: const \"" + name + "\" was declared as i16"; + } + break; + case t_base_type::TYPE_I32: + if (value->get_type() != t_const_value::CV_INTEGER) { + throw "type error: const \"" + name + "\" was declared as i32"; + } + break; + case t_base_type::TYPE_I64: + if (value->get_type() != t_const_value::CV_INTEGER) { + throw "type error: const \"" + name + "\" was declared as i64"; + } + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() != t_const_value::CV_INTEGER + && value->get_type() != t_const_value::CV_DOUBLE) { + throw "type error: const \"" + name + "\" was declared as double"; + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase) + name; + } + } else if (type->is_enum()) { + if (value->get_type() != t_const_value::CV_IDENTIFIER) { + throw "type error: const \"" + name + "\" was declared as enum"; + } + + // see if there's a dot in the identifier + std::string name_portion = value->get_identifier_name(); + + const vector& enum_values = ((t_enum*)type)->get_constants(); + vector::const_iterator c_iter; + bool found = false; + + for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { + if ((*c_iter)->get_name() == name_portion) { + found = true; + break; + } + } + if (!found) { + throw "type error: const " + name + " was declared as type " + type->get_name() + + " which is an enum, but " + value->get_identifier() + + " is not a valid value for that enum"; + } + } else if (type->is_struct() || type->is_xception()) { + if (value->get_type() != t_const_value::CV_MAP) { + throw "type error: const \"" + name + "\" was declared as struct/xception"; + } + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + if (v_iter->first->get_type() != t_const_value::CV_STRING) { + throw "type error: " + name + " struct key must be string"; + } + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + + validate_const_rec(name + "." + v_iter->first->get_string(), field_type, v_iter->second); + } + } else if (type->is_map()) { + t_type* k_type = ((t_map*)type)->get_key_type(); + t_type* v_type = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + validate_const_rec(name + "", k_type, v_iter->first); + validate_const_rec(name + "", v_type, v_iter->second); + } + } else if (type->is_list() || type->is_set()) { + t_type* e_type; + if (type->is_list()) { + e_type = ((t_list*)type)->get_elem_type(); + } else { + e_type = ((t_set*)type)->get_elem_type(); + } + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + validate_const_rec(name + "", e_type, *v_iter); + } + } +} + +/** + * Check simple identifier names + * It's easier to do it this way instead of rewriting the whole grammar etc. + */ +void validate_simple_identifier(const char* identifier) { + string name(identifier); + if (name.find(".") != string::npos) { + yyerror("Identifier %s can't have a dot.", identifier); + exit(1); + } +} + +/** + * Check the type of the parsed const information against its declared type + */ +void validate_const_type(t_const* c) { + validate_const_rec(c->get_name(), c->get_type(), c->get_value()); +} + +/** + * Check the type of a default value assigned to a field. + */ +void validate_field_value(t_field* field, t_const_value* cv) { + validate_const_rec(field->get_name(), field->get_type(), cv); +} + +/** + * Check that all the elements of a throws block are actually exceptions. + */ +bool validate_throws(t_struct* throws) { + const vector& members = throws->get_members(); + vector::const_iterator m_iter; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (!t_generator::get_true_type((*m_iter)->get_type())->is_xception()) { + return false; + } + } + return true; +} + +/** + * Skips UTF-8 BOM if there is one + */ +bool skip_utf8_bom(FILE* f) { + + // pretty straightforward, but works + if (fgetc(f) == 0xEF) { + if (fgetc(f) == 0xBB) { + if (fgetc(f) == 0xBF) { + return true; + } + } + } + + rewind(f); + return false; +} + +/** + * Parses a program + */ +void parse(t_program* program, t_program* parent_program) { + // Get scope file path + string path = program->get_path(); + + // Set current dir global, which is used in the include_file function + g_curdir = directory_name(path); + g_curpath = path; + + // Open the file + // skip UTF-8 BOM if there is one + yyin = fopen(path.c_str(), "r"); + if (yyin == 0) { + failure("Could not open input file: \"%s\"", path.c_str()); + } + if (skip_utf8_bom(yyin)) + pverbose("Skipped UTF-8 BOM at %s\n", path.c_str()); + + // Create new scope and scan for includes + pverbose("Scanning %s for includes\n", path.c_str()); + g_parse_mode = INCLUDES; + g_program = program; + g_scope = program->scope(); + try { + yylineno = 1; + if (yyparse() != 0) { + failure("Parser error during include pass."); + } + } catch (string x) { + failure(x.c_str()); + } + fclose(yyin); + + // Recursively parse all the include programs + vector& includes = program->get_includes(); + vector::iterator iter; + for (iter = includes.begin(); iter != includes.end(); ++iter) { + parse(*iter, program); + } + + // reset program doctext status before parsing a new file + reset_program_doctext_info(); + + // Parse the program file + g_parse_mode = PROGRAM; + g_program = program; + g_scope = program->scope(); + g_parent_scope = (parent_program != NULL) ? parent_program->scope() : NULL; + g_parent_prefix = program->get_name() + "."; + g_curpath = path; + + // Open the file + // skip UTF-8 BOM if there is one + yyin = fopen(path.c_str(), "r"); + if (yyin == 0) { + failure("Could not open input file: \"%s\"", path.c_str()); + } + if (skip_utf8_bom(yyin)) + pverbose("Skipped UTF-8 BOM at %s\n", path.c_str()); + + pverbose("Parsing %s for types\n", path.c_str()); + yylineno = 1; + try { + if (yyparse() != 0) { + failure("Parser error during types pass."); + } + } catch (string x) { + failure(x.c_str()); + } + fclose(yyin); +} + +/** + * Generate code + */ +void generate(t_program* program, const vector& generator_strings) { + // Oooohh, recursive code generation, hot!! + if (gen_recurse) { + const vector& includes = program->get_includes(); + for (size_t i = 0; i < includes.size(); ++i) { + // Propagate output path from parent to child programs + includes[i]->set_out_path(program->get_out_path(), program->is_out_path_absolute()); + + generate(includes[i], generator_strings); + } + } + + // Generate code! + try { + pverbose("Program: %s\n", program->get_path().c_str()); + + if (dump_docs) { + dump_docstrings(program); + } + + vector::const_iterator iter; + for (iter = generator_strings.begin(); iter != generator_strings.end(); ++iter) { + t_generator* generator = t_generator_registry::get_generator(program, *iter); + + if (generator == NULL) { +#ifdef THRIFT_ENABLE_PLUGIN + switch (plugin_output::delegateToPlugin(program, *iter)) { + case plugin_output::PLUGIN_NOT_FOUND: + pwarning(1, "Unable to get a generator for \"%s\".\n", iter->c_str()); + g_generator_failure = true; + break; + case plugin_output::PLUGIN_FAILURE: + pwarning(1, "Plugin generator for \"%s\" failed.\n", iter->c_str()); + g_generator_failure = true; + break; + case plugin_output::PLUGIN_SUCCEESS: + break; + default: + assert(false); + break; + } +#else + pwarning(1, "Unable to get a generator for \"%s\".\n", iter->c_str()); + g_generator_failure = true; +#endif + } else if (generator) { + pverbose("Generating \"%s\"\n", iter->c_str()); + generator->generate_program(); + delete generator; + } + } + } catch (string s) { + failure("Error: %s\n", s.c_str()); + } catch (const char* exc) { + failure("Error: %s\n", exc); + } +} + +void audit(t_program* new_program, + t_program* old_program, + string new_thrift_include_path, + string old_thrift_include_path) { + vector temp_incl_searchpath = g_incl_searchpath; + if (!old_thrift_include_path.empty()) { + g_incl_searchpath.push_back(old_thrift_include_path); + } + + parse(old_program, NULL); + + g_incl_searchpath = temp_incl_searchpath; + if (!new_thrift_include_path.empty()) { + g_incl_searchpath.push_back(new_thrift_include_path); + } + + parse(new_program, NULL); + + compare_namespace(new_program, old_program); + compare_services(new_program->get_services(), old_program->get_services()); + compare_enums(new_program->get_enums(), old_program->get_enums()); + compare_structs(new_program->get_structs(), old_program->get_structs()); + compare_structs(new_program->get_xceptions(), old_program->get_xceptions()); + compare_consts(new_program->get_consts(), old_program->get_consts()); +} + +/** + * Parse it up.. then spit it back out, in pretty much every language. Alright + * not that many languages, but the cool ones that we care about. + */ +int main(int argc, char** argv) { + int i; + std::string out_path; + bool out_path_is_absolute = false; + + // Setup time string + time_t now = time(NULL); + g_time_str = ctime(&now); + + // Check for necessary arguments, you gotta have at least a filename and + // an output language flag + if (argc < 2) { + usage(); + } + + vector generator_strings; + string old_thrift_include_path; + string new_thrift_include_path; + string old_input_file; + + // Set the current path to a dummy value to make warning messages clearer. + g_curpath = "arguments"; + + // Hacky parameter handling... I didn't feel like using a library sorry! + for (i = 1; i < argc - 1; i++) { + char* arg; + + arg = strtok(argv[i], " "); + while (arg != NULL) { + // Treat double dashes as single dashes + if (arg[0] == '-' && arg[1] == '-') { + ++arg; + } + + if (strcmp(arg, "-help") == 0) { + help(); + } else if (strcmp(arg, "-version") == 0) { + version(); + exit(0); + } else if (strcmp(arg, "-debug") == 0) { + g_debug = 1; + } else if (strcmp(arg, "-nowarn") == 0) { + g_warn = 0; + } else if (strcmp(arg, "-strict") == 0) { + g_strict = 255; + g_warn = 2; + } else if (strcmp(arg, "-v") == 0 || strcmp(arg, "-verbose") == 0) { + g_verbose = 1; + } else if (strcmp(arg, "-r") == 0 || strcmp(arg, "-recurse") == 0) { + gen_recurse = true; + } else if (strcmp(arg, "-allow-neg-keys") == 0) { + g_allow_neg_field_keys = true; + } else if (strcmp(arg, "-allow-64bit-consts") == 0) { + g_allow_64bit_consts = true; + } else if (strcmp(arg, "-gen") == 0) { + arg = argv[++i]; + if (arg == NULL) { + fprintf(stderr, "Missing generator specification\n"); + usage(); + } + generator_strings.push_back(arg); + } else if (strcmp(arg, "-I") == 0) { + // An argument of "-I\ asdf" is invalid and has unknown results + arg = argv[++i]; + + if (arg == NULL) { + fprintf(stderr, "Missing Include directory\n"); + usage(); + } + g_incl_searchpath.push_back(arg); + } else if ((strcmp(arg, "-o") == 0) || (strcmp(arg, "-out") == 0)) { + out_path_is_absolute = (strcmp(arg, "-out") == 0) ? true : false; + arg = argv[++i]; + if (arg == NULL) { + fprintf(stderr, "-o: missing output directory\n"); + usage(); + } + out_path = arg; + +#ifdef _WIN32 + // strip out trailing \ on Windows + std::string::size_type last = out_path.length() - 1; + if (out_path[last] == '\\') { + out_path.erase(last); + } +#endif + if (!check_is_directory(out_path.c_str())) + return -1; + } else if (strcmp(arg, "-audit") == 0) { + g_audit = true; + arg = argv[++i]; + if (arg == NULL) { + fprintf(stderr, "Missing old thrift file name for audit operation\n"); + usage(); + } + char old_thrift_file_rp[THRIFT_PATH_MAX]; + + // cppcheck-suppress uninitvar + if (saferealpath(arg, old_thrift_file_rp) == NULL) { + failure("Could not open input file with realpath: %s", arg); + } + old_input_file = string(old_thrift_file_rp); + } else if (strcmp(arg, "-audit-nofatal") == 0) { + g_audit_fatal = false; + } else if (strcmp(arg, "-Iold") == 0) { + arg = argv[++i]; + if (arg == NULL) { + fprintf(stderr, "Missing Include directory for old thrift file\n"); + usage(); + } + old_thrift_include_path = string(arg); + } else if (strcmp(arg, "-Inew") == 0) { + arg = argv[++i]; + if (arg == NULL) { + fprintf(stderr, "Missing Include directory for new thrift file\n"); + usage(); + } + new_thrift_include_path = string(arg); + } else { + fprintf(stderr, "Unrecognized option: %s\n", arg); + usage(); + } + + // Tokenize more + arg = strtok(NULL, " "); + } + } + + // display help + if ((strcmp(argv[argc - 1], "-help") == 0) || (strcmp(argv[argc - 1], "--help") == 0)) { + help(); + } + + // if you're asking for version, you have a right not to pass a file + if ((strcmp(argv[argc - 1], "-version") == 0) || (strcmp(argv[argc - 1], "--version") == 0)) { + version(); + exit(0); + } + + // Initialize global types + initGlobals(); + + if (g_audit) { + // Audit operation + + if (old_input_file.empty()) { + fprintf(stderr, "Missing file name of old thrift file for audit\n"); + usage(); + } + + char new_thrift_file_rp[THRIFT_PATH_MAX]; + if (argv[i] == NULL) { + fprintf(stderr, "Missing file name of new thrift file for audit\n"); + usage(); + } + // cppcheck-suppress uninitvar + if (saferealpath(argv[i], new_thrift_file_rp) == NULL) { + failure("Could not open input file with realpath: %s", argv[i]); + } + string new_input_file(new_thrift_file_rp); + + t_program new_program(new_input_file); + t_program old_program(old_input_file); + + audit(&new_program, &old_program, new_thrift_include_path, old_thrift_include_path); + + } else { + // Generate options + + // You gotta generate something! + if (generator_strings.empty()) { + fprintf(stderr, "No output language(s) specified\n"); + usage(); + } + + // Real-pathify it + char rp[THRIFT_PATH_MAX]; + if (argv[i] == NULL) { + fprintf(stderr, "Missing file name\n"); + usage(); + } + // cppcheck-suppress uninitvar + if (saferealpath(argv[i], rp) == NULL) { + failure("Could not open input file with realpath: %s", argv[i]); + } + string input_file(rp); + + // Instance of the global parse tree + t_program* program = new t_program(input_file); + if (out_path.size()) { + program->set_out_path(out_path, out_path_is_absolute); + } + + // Compute the cpp include prefix. + // infer this from the filename passed in + string input_filename = argv[i]; + string include_prefix; + + string::size_type last_slash = string::npos; + if ((last_slash = input_filename.rfind("/")) != string::npos) { + include_prefix = input_filename.substr(0, last_slash); + } + + program->set_include_prefix(include_prefix); + + // Parse it! + parse(program, NULL); + + // The current path is not really relevant when we are doing generation. + // Reset the variable to make warning messages clearer. + g_curpath = "generation"; + // Reset yylineno for the heck of it. Use 1 instead of 0 because + // That is what shows up during argument parsing. + yylineno = 1; + + // Generate it! + generate(program, generator_strings); + delete program; + } + + // Clean up. Who am I kidding... this program probably orphans heap memory + // all over the place, but who cares because it is about to exit and it is + // all referenced and used by this wacky parse tree up until now anyways. + clearGlobals(); + + // Finished + if (g_return_failure && g_audit_fatal) { + exit(2); + } + if (g_generator_failure) { + exit(3); + } + // Finished + return 0; +} diff --git a/compiler/cpp/src/thrift/main.h b/compiler/cpp/src/thrift/main.h new file mode 100644 index 0000000..54abb03 --- /dev/null +++ b/compiler/cpp/src/thrift/main.h @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_MAIN_H +#define T_MAIN_H + +#include +#include + +#include "thrift/logging.h" + +#include "thrift/parse/t_const.h" +#include "thrift/parse/t_field.h" + +/** + * Defined in the flex library + */ + +extern "C" { int yylex(void); } + +int yyparse(void); + +/** + * Expected to be defined by Flex/Bison + */ +void yyerror(const char* fmt, ...); + +/** + * Check simple identifier names + */ +void validate_simple_identifier(const char* identifier); + +/** + * Check constant types + */ +void validate_const_type(t_const* c); + +/** + * Check constant types + */ +void validate_field_value(t_field* field, t_const_value* cv); + +/** + * Check members of a throws block + */ +bool validate_throws(t_struct* throws); + +/** + * Converts a string filename into a thrift program name + */ +std::string program_name(std::string filename); + +/** + * Gets the directory path of a filename + */ +std::string directory_name(std::string filename); + +/** + * Get the absolute path for an include file + */ +std::string include_file(std::string filename); + +/** + * Clears any previously stored doctext string. + */ +void clear_doctext(); + +/** + * Cleans up text commonly found in doxygen-like comments + */ +char* clean_up_doctext(char* doctext); + +/** + * We are sure the program doctext candidate is really the program doctext. + */ +void declare_valid_program_doctext(); + +/** + * Emits a warning on list, binary type is typically a much better choice. + */ +void check_for_list_of_bytes(t_type* list_elem_type); + +/** + * Emits a one-time warning on byte type, promoting the new i8 type instead + */ +void emit_byte_type_warning(); + +/** + * Prints deprecation notice for old NS declarations that are no longer supported + * If new_form is NULL, old_form is assumed to be a language identifier, such as "cpp" + * If new_form is not NULL, both arguments are used exactly as given + */ +void error_unsupported_namespace_decl(const char* old_form, const char* new_form = NULL); + +/** + * Flex utilities + */ + +extern int yylineno; +extern char yytext[]; +extern std::FILE* yyin; + +#endif diff --git a/compiler/cpp/src/thrift/parse/parse.cc b/compiler/cpp/src/thrift/parse/parse.cc new file mode 100644 index 0000000..01f7637 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/parse.cc @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "thrift/parse/t_type.h" +#include "thrift/parse/t_typedef.h" + +#include "thrift/main.h" + +t_type* t_type::get_true_type() { + t_type* type = this; + while (type->is_typedef()) { + type = ((t_typedef*)type)->get_type(); + } + return type; +} + +const t_type* t_type::get_true_type() const { + const t_type* type = this; + while (type->is_typedef()) { + type = ((t_typedef*)type)->get_type(); + } + return type; +} diff --git a/compiler/cpp/src/thrift/parse/t_base_type.h b/compiler/cpp/src/thrift/parse/t_base_type.h new file mode 100644 index 0000000..71398ba --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_base_type.h @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_BASE_TYPE_H +#define T_BASE_TYPE_H + +#include +#include "thrift/parse/t_type.h" + +/** + * A thrift base type, which must be one of the defined enumerated types inside + * this definition. + * + */ +class t_base_type : public t_type { +public: + /** + * Enumeration of thrift base types + */ + enum t_base { + TYPE_VOID, + TYPE_STRING, + TYPE_BOOL, + TYPE_I8, + TYPE_I16, + TYPE_I32, + TYPE_I64, + TYPE_DOUBLE + }; + + t_base_type(std::string name, t_base base) + : t_type(name), base_(base), string_list_(false), binary_(false), string_enum_(false) {} + + t_base get_base() const { return base_; } + + bool is_void() const { return base_ == TYPE_VOID; } + + bool is_string() const { return base_ == TYPE_STRING; } + + bool is_bool() const { return base_ == TYPE_BOOL; } + + void set_string_list(bool val) { string_list_ = val; } + + bool is_string_list() const { return string_list_ && (base_ == TYPE_STRING); } + + void set_binary(bool val) { binary_ = val; } + + bool is_binary() const { return binary_ && (base_ == TYPE_STRING); } + + void set_string_enum(bool val) { string_enum_ = val; } + + bool is_string_enum() const { return string_enum_ && base_ == TYPE_STRING; } + + void add_string_enum_val(std::string val) { string_enum_vals_.push_back(val); } + + const std::vector& get_string_enum_vals() const { return string_enum_vals_; } + + bool is_base_type() const { return true; } + + static std::string t_base_name(t_base tbase) { + switch (tbase) { + case TYPE_VOID: + return "void"; + break; + case TYPE_STRING: + return "string"; + break; + case TYPE_BOOL: + return "bool"; + break; + case TYPE_I8: + return "i8"; + break; + case TYPE_I16: + return "i16"; + break; + case TYPE_I32: + return "i32"; + break; + case TYPE_I64: + return "i64"; + break; + case TYPE_DOUBLE: + return "double"; + break; + default: + return "(unknown)"; + break; + } + } + +private: + t_base base_; + + bool string_list_; + bool binary_; + bool string_enum_; + std::vector string_enum_vals_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_const.h b/compiler/cpp/src/thrift/parse/t_const.h new file mode 100644 index 0000000..3c08e0d --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_const.h @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_CONST_H +#define T_CONST_H + +#include "thrift/parse/t_type.h" +#include "thrift/parse/t_const_value.h" + +/** + * A const is a constant value defined across languages that has a type and + * a value. The trick here is that the declared type might not match the type + * of the value object, since that is not determined until after parsing the + * whole thing out. + * + */ +class t_const : public t_doc { +public: + t_const(t_type* type, std::string name, t_const_value* value) + : type_(type), name_(name), value_(value) {} + + t_type* get_type() const { return type_; } + + std::string get_name() const { return name_; } + + t_const_value* get_value() const { return value_; } + +private: + t_type* type_; + std::string name_; + t_const_value* value_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_const_value.h b/compiler/cpp/src/thrift/parse/t_const_value.h new file mode 100644 index 0000000..fc2f648 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_const_value.h @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_CONST_VALUE_H +#define T_CONST_VALUE_H + +#include "thrift/parse/t_enum.h" +#include +#include +#include +#include + +namespace plugin_output { +template +void convert(From*, To&); +} + +/** + * A const value is something parsed that could be a map, set, list, struct + * or whatever. + * + */ +class t_const_value { +public: + enum t_const_value_type { CV_INTEGER, CV_DOUBLE, CV_STRING, CV_MAP, CV_LIST, CV_IDENTIFIER, CV_UNKNOWN }; + + t_const_value() : intVal_(0), doubleVal_(0.0f), enum_((t_enum*)0), valType_(CV_UNKNOWN) {} + + t_const_value(int64_t val) : doubleVal_(0.0f), enum_((t_enum*)0), valType_(CV_UNKNOWN) { set_integer(val); } + + t_const_value(std::string val) : intVal_(0), doubleVal_(0.0f), enum_((t_enum*)0), valType_(CV_UNKNOWN) { set_string(val); } + + void set_string(std::string val) { + valType_ = CV_STRING; + stringVal_ = val; + } + + std::string get_string() const { return stringVal_; } + + void set_integer(int64_t val) { + valType_ = CV_INTEGER; + intVal_ = val; + } + + int64_t get_integer() const { + if (valType_ == CV_IDENTIFIER) { + if (enum_ == NULL) { + throw "have identifier \"" + get_identifier() + "\", but unset enum on line!"; + } + std::string identifier = get_identifier(); + std::string::size_type dot = identifier.rfind('.'); + if (dot != std::string::npos) { + identifier = identifier.substr(dot + 1); + } + t_enum_value* val = enum_->get_constant_by_name(identifier); + if (val == NULL) { + throw "Unable to find enum value \"" + identifier + "\" in enum \"" + enum_->get_name() + + "\""; + } + return val->get_value(); + } else { + return intVal_; + } + } + + void set_double(double val) { + valType_ = CV_DOUBLE; + doubleVal_ = val; + } + + double get_double() const { return doubleVal_; } + + void set_map() { valType_ = CV_MAP; } + + void add_map(t_const_value* key, t_const_value* val) { mapVal_[key] = val; } + + const std::map& get_map() const { return mapVal_; } + + void set_list() { valType_ = CV_LIST; } + + void add_list(t_const_value* val) { listVal_.push_back(val); } + + const std::vector& get_list() const { return listVal_; } + + void set_identifier(std::string val) { + valType_ = CV_IDENTIFIER; + identifierVal_ = val; + } + + std::string get_identifier() const { return identifierVal_; } + + std::string get_identifier_name() const { + std::string ret = get_identifier(); + size_t s = ret.find('.'); + if (s == std::string::npos) { + throw "error: identifier " + ret + " is unqualified!"; + } + ret = ret.substr(s + 1); + s = ret.find('.'); + if (s != std::string::npos) { + ret = ret.substr(s + 1); + } + return ret; + } + + std::string get_identifier_with_parent() const { + std::string ret = get_identifier(); + size_t s = ret.find('.'); + if (s == std::string::npos) { + throw "error: identifier " + ret + " is unqualified!"; + } + size_t s2 = ret.find('.', s + 1); + if (s2 != std::string::npos) { + ret = ret.substr(s + 1); + } + return ret; + } + + void set_enum(t_enum* tenum) { enum_ = tenum; } + + t_const_value_type get_type() const { if (valType_ == CV_UNKNOWN) { throw std::string("unknown t_const_value"); } return valType_; } + +private: + std::map mapVal_; + std::vector listVal_; + std::string stringVal_; + int64_t intVal_; + double doubleVal_; + std::string identifierVal_; + t_enum* enum_; + + t_const_value_type valType_; + + // to read enum_ + template + friend void plugin_output::convert(From*, To&); +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_container.h b/compiler/cpp/src/thrift/parse/t_container.h new file mode 100644 index 0000000..5bdab70 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_container.h @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_CONTAINER_H +#define T_CONTAINER_H + +#include "thrift/parse/t_type.h" + +class t_container : public t_type { +public: + t_container() : cpp_name_(), has_cpp_name_(false) {} + + virtual ~t_container() {} + + void set_cpp_name(std::string cpp_name) { + cpp_name_ = cpp_name; + has_cpp_name_ = true; + } + + bool has_cpp_name() const { return has_cpp_name_; } + + std::string get_cpp_name() const { return cpp_name_; } + + bool is_container() const { return true; } + +private: + std::string cpp_name_; + bool has_cpp_name_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_doc.h b/compiler/cpp/src/thrift/parse/t_doc.h new file mode 100644 index 0000000..7bcb8f5 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_doc.h @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_DOC_H +#define T_DOC_H + +#include "thrift/globals.h" +#include "thrift/logging.h" + +/** + * Documentation stubs + * + */ +class t_doc { + +public: + t_doc() : has_doc_(false) {} + virtual ~t_doc() {} + + void set_doc(const std::string& doc) { + doc_ = doc; + has_doc_ = true; + if ((g_program_doctext_lineno == g_doctext_lineno) + && (g_program_doctext_status == STILL_CANDIDATE)) { + g_program_doctext_status = ALREADY_PROCESSED; + pdebug("%s", "program doctext set to ALREADY_PROCESSED"); + } + } + + const std::string& get_doc() const { return doc_; } + + bool has_doc() { return has_doc_; } + +private: + std::string doc_; + bool has_doc_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_enum.h b/compiler/cpp/src/thrift/parse/t_enum.h new file mode 100644 index 0000000..9e23780 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_enum.h @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_ENUM_H +#define T_ENUM_H + +#include + +#include "thrift/parse/t_enum_value.h" +#include "thrift/parse/t_type.h" + +/** + * An enumerated type. A list of constant objects with a name for the type. + * + */ +class t_enum : public t_type { +public: + t_enum(t_program* program) : t_type(program) {} + + void set_name(const std::string& name) { name_ = name; } + + void append(t_enum_value* constant) { constants_.push_back(constant); } + + const std::vector& get_constants() const { return constants_; } + + t_enum_value* get_constant_by_name(const std::string& name) { + const std::vector& enum_values = get_constants(); + std::vector::const_iterator c_iter; + for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { + if ((*c_iter)->get_name() == name) { + return *c_iter; + } + } + return NULL; + } + + t_enum_value* get_constant_by_value(int64_t value) { + const std::vector& enum_values = get_constants(); + std::vector::const_iterator c_iter; + for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { + if ((*c_iter)->get_value() == value) { + return *c_iter; + } + } + return NULL; + } + + t_enum_value* get_min_value() { + const std::vector& enum_values = get_constants(); + std::vector::const_iterator c_iter; + t_enum_value* min_value; + if (enum_values.size() == 0) { + min_value = NULL; + } else { + int min_value_value; + min_value = enum_values.front(); + min_value_value = min_value->get_value(); + for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { + if ((*c_iter)->get_value() < min_value_value) { + min_value = (*c_iter); + min_value_value = min_value->get_value(); + } + } + } + return min_value; + } + + t_enum_value* get_max_value() { + const std::vector& enum_values = get_constants(); + std::vector::const_iterator c_iter; + t_enum_value* max_value; + if (enum_values.size() == 0) { + max_value = NULL; + } else { + int max_value_value; + max_value = enum_values.back(); + max_value_value = max_value->get_value(); + for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { + if ((*c_iter)->get_value() > max_value_value) { + max_value = (*c_iter); + max_value_value = max_value->get_value(); + } + } + } + return max_value; + } + + bool is_enum() const { return true; } + +private: + std::vector constants_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_enum_value.h b/compiler/cpp/src/thrift/parse/t_enum_value.h new file mode 100644 index 0000000..c0bf3ad --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_enum_value.h @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_ENUM_VALUE_H +#define T_ENUM_VALUE_H + +#include +#include +#include "thrift/parse/t_doc.h" + +/** + * A constant. These are used inside of enum definitions. Constants are just + * symbol identifiers that may or may not have an explicit value associated + * with them. + * + */ +class t_enum_value : public t_doc { +public: + t_enum_value(std::string name, int value) : name_(name), value_(value) {} + + ~t_enum_value() {} + + const std::string& get_name() const { return name_; } + + int get_value() const { return value_; } + + std::map annotations_; + +private: + std::string name_; + int value_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_field.h b/compiler/cpp/src/thrift/parse/t_field.h new file mode 100644 index 0000000..c5f1f80 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_field.h @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_FIELD_H +#define T_FIELD_H + +#include +#include +#include + +#include "thrift/parse/t_doc.h" +#include "thrift/parse/t_type.h" + +// Forward declare for xsd_attrs +class t_struct; + +/** + * Class to represent a field in a thrift structure. A field has a data type, + * a symbolic name, and a numeric identifier. + * + */ +class t_field : public t_doc { +public: + t_field(t_type* type, std::string name) + : type_(type), + name_(name), + key_(0), + value_(NULL), + xsd_optional_(false), + xsd_nillable_(false), + xsd_attrs_(NULL), + reference_(false) {} + + t_field(t_type* type, std::string name, int32_t key) + : type_(type), + name_(name), + key_(key), + req_(T_OPT_IN_REQ_OUT), + value_(NULL), + xsd_optional_(false), + xsd_nillable_(false), + xsd_attrs_(NULL), + reference_(false) {} + + ~t_field() {} + + t_type* get_type() { return type_; } + + const t_type* get_type() const { return type_; } + + const std::string& get_name() const { return name_; } + + int32_t get_key() const { return key_; } + + enum e_req { T_REQUIRED, T_OPTIONAL, T_OPT_IN_REQ_OUT }; + + void set_req(e_req req) { req_ = req; } + + e_req get_req() const { return req_; } + + void set_value(t_const_value* value) { value_ = value; } + + t_const_value* get_value() { return value_; } + + const t_const_value* get_value() const { return value_; } + + void set_xsd_optional(bool xsd_optional) { xsd_optional_ = xsd_optional; } + + bool get_xsd_optional() const { return xsd_optional_; } + + void set_xsd_nillable(bool xsd_nillable) { xsd_nillable_ = xsd_nillable; } + + bool get_xsd_nillable() const { return xsd_nillable_; } + + void set_xsd_attrs(t_struct* xsd_attrs) { xsd_attrs_ = xsd_attrs; } + + t_struct* get_xsd_attrs() { return xsd_attrs_; } + + /** + * Comparator to sort fields in ascending order by key. + * Make this a functor instead of a function to help GCC inline it. + * The arguments are (const) references to const pointers to const t_fields. + */ + struct key_compare { + bool operator()(t_field const* const& a, t_field const* const& b) { + return a->get_key() < b->get_key(); + } + }; + + std::map annotations_; + + bool get_reference() { return reference_; } + + void set_reference(bool reference) { reference_ = reference; } + +private: + t_type* type_; + std::string name_; + int32_t key_; + e_req req_; + t_const_value* value_; + + bool xsd_optional_; + bool xsd_nillable_; + t_struct* xsd_attrs_; + bool reference_; +}; + +/** + * A simple struct for the parser to use to store a field ID, and whether or + * not it was specified by the user or automatically chosen. + */ +struct t_field_id { + int32_t value; + bool auto_assigned; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_function.h b/compiler/cpp/src/thrift/parse/t_function.h new file mode 100644 index 0000000..22d2609 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_function.h @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_FUNCTION_H +#define T_FUNCTION_H + +#include +#include "thrift/parse/t_type.h" +#include "thrift/parse/t_struct.h" +#include "thrift/parse/t_doc.h" + +/** + * Representation of a function. Key parts are return type, function name, + * optional modifiers, and an argument list, which is implemented as a thrift + * struct. + * + */ +class t_function : public t_doc { +public: + t_function(t_type* returntype, std::string name, t_struct* arglist, bool oneway = false) + : returntype_(returntype), + name_(name), + arglist_(arglist), + xceptions_(new t_struct(NULL)), + own_xceptions_(true), + oneway_(oneway) { + if (oneway_ && (!returntype_->is_void())) { + pwarning(1, "Oneway methods should return void.\n"); + } + } + + t_function(t_type* returntype, + std::string name, + t_struct* arglist, + t_struct* xceptions, + bool oneway = false) + : returntype_(returntype), + name_(name), + arglist_(arglist), + xceptions_(xceptions), + own_xceptions_(false), + oneway_(oneway) { + if (oneway_ && !xceptions_->get_members().empty()) { + throw std::string("Oneway methods can't throw exceptions."); + } + if (oneway_ && (!returntype_->is_void())) { + pwarning(1, "Oneway methods should return void.\n"); + } + } + + ~t_function() { + if (own_xceptions_) + delete xceptions_; + } + + t_type* get_returntype() const { return returntype_; } + + const std::string& get_name() const { return name_; } + + t_struct* get_arglist() const { return arglist_; } + + t_struct* get_xceptions() const { return xceptions_; } + + bool is_oneway() const { return oneway_; } + + std::map annotations_; + +private: + t_type* returntype_; + std::string name_; + t_struct* arglist_; + t_struct* xceptions_; + bool own_xceptions_; + bool oneway_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_list.h b/compiler/cpp/src/thrift/parse/t_list.h new file mode 100644 index 0000000..acf6865 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_list.h @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_LIST_H +#define T_LIST_H + +#include "thrift/parse/t_container.h" + +/** + * A list is a lightweight container type that just wraps another data type. + * + */ +class t_list : public t_container { +public: + t_list(t_type* elem_type) : elem_type_(elem_type) {} + + t_type* get_elem_type() const { return elem_type_; } + + bool is_list() const { return true; } + +private: + t_type* elem_type_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_map.h b/compiler/cpp/src/thrift/parse/t_map.h new file mode 100644 index 0000000..dd3f089 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_map.h @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_MAP_H +#define T_MAP_H + +#include "thrift/parse/t_container.h" + +/** + * A map is a lightweight container type that just wraps another two data + * types. + * + */ +class t_map : public t_container { +public: + t_map(t_type* key_type, t_type* val_type) : key_type_(key_type), val_type_(val_type) {} + + t_type* get_key_type() const { return key_type_; } + + t_type* get_val_type() const { return val_type_; } + + bool is_map() const { return true; } + +private: + t_type* key_type_; + t_type* val_type_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_program.h b/compiler/cpp/src/thrift/parse/t_program.h new file mode 100644 index 0000000..43dd45a --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_program.h @@ -0,0 +1,395 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_PROGRAM_H +#define T_PROGRAM_H + +#include +#include +#include + +// For program_name() +#include "thrift/main.h" + +#include "thrift/parse/t_doc.h" +#include "thrift/parse/t_scope.h" +#include "thrift/parse/t_base_type.h" +#include "thrift/parse/t_typedef.h" +#include "thrift/parse/t_enum.h" +#include "thrift/parse/t_const.h" +#include "thrift/parse/t_struct.h" +#include "thrift/parse/t_service.h" +#include "thrift/parse/t_list.h" +#include "thrift/parse/t_map.h" +#include "thrift/parse/t_set.h" +#include "thrift/generate/t_generator_registry.h" +//#include "thrift/parse/t_doc.h" + +/** + * Top level class representing an entire thrift program. A program consists + * fundamentally of the following: + * + * Typedefs + * Enumerations + * Constants + * Structs + * Exceptions + * Services + * + * The program module also contains the definitions of the base types. + * + */ +class t_program : public t_doc { +public: + t_program(std::string path, std::string name) + : path_(path), name_(name), out_path_("./"), out_path_is_absolute_(false), scope_(new t_scope) {} + + t_program(std::string path) : path_(path), out_path_("./"), out_path_is_absolute_(false) { + name_ = program_name(path); + scope_ = new t_scope(); + } + + ~t_program() { + if (scope_) { + delete scope_; + scope_ = NULL; + } + } + + // Path accessor + const std::string& get_path() const { return path_; } + + // Output path accessor + const std::string& get_out_path() const { return out_path_; } + + // Create gen-* dir accessor + bool is_out_path_absolute() const { return out_path_is_absolute_; } + + // Name accessor + const std::string& get_name() const { return name_; } + + // Namespace + const std::string& get_namespace() const { return namespace_; } + + // Include prefix accessor + const std::string& get_include_prefix() const { return include_prefix_; } + + // Accessors for program elements + const std::vector& get_typedefs() const { return typedefs_; } + const std::vector& get_enums() const { return enums_; } + const std::vector& get_consts() const { return consts_; } + const std::vector& get_structs() const { return structs_; } + const std::vector& get_xceptions() const { return xceptions_; } + const std::vector& get_objects() const { return objects_; } + const std::vector& get_services() const { return services_; } + const std::map& get_namespaces() const { return namespaces_; } + + // Program elements + void add_typedef(t_typedef* td) { typedefs_.push_back(td); } + void add_enum(t_enum* te) { enums_.push_back(te); } + void add_const(t_const* tc) { consts_.push_back(tc); } + void add_struct(t_struct* ts) { + objects_.push_back(ts); + structs_.push_back(ts); + } + void add_xception(t_struct* tx) { + objects_.push_back(tx); + xceptions_.push_back(tx); + } + void add_service(t_service* ts) { services_.push_back(ts); } + + // Programs to include + const std::vector& get_includes() const { return includes_; } + + void set_out_path(std::string out_path, bool out_path_is_absolute) { + out_path_ = out_path; + out_path_is_absolute_ = out_path_is_absolute; + // Ensure that it ends with a trailing '/' (or '\' for windows machines) + char c = out_path_.at(out_path_.size() - 1); + if (!(c == '/' || c == '\\')) { + out_path_.push_back('/'); + } + } + + // Typename collision detection + /** + * Search for typename collisions + * @param t the type to test for collisions + * @return true if a certain collision was found, otherwise false + */ + bool is_unique_typename(t_type* t) { + int occurrences = program_typename_count(this, t); + for (std::vector::iterator it = includes_.begin(); it != includes_.end(); ++it) { + occurrences += program_typename_count(*it, t); + } + return 0 == occurrences; + } + + /** + * Search all type collections for duplicate typenames + * @param prog the program to search + * @param t the type to test for collisions + * @return the number of certain typename collisions + */ + int program_typename_count(t_program* prog, t_type* t) { + int occurrences = 0; + occurrences += collection_typename_count(prog, prog->typedefs_, t); + occurrences += collection_typename_count(prog, prog->enums_, t); + occurrences += collection_typename_count(prog, prog->objects_, t); + occurrences += collection_typename_count(prog, prog->services_, t); + return occurrences; + } + + /** + * Search a type collection for duplicate typenames + * @param prog the program to search + * @param type_collection the type collection to search + * @param t the type to test for collisions + * @return the number of certain typename collisions + */ + template + int collection_typename_count(t_program* prog, T type_collection, t_type* t) { + int occurrences = 0; + for (typename T::iterator it = type_collection.begin(); it != type_collection.end(); ++it) + if (t != *it && 0 == t->get_name().compare((*it)->get_name()) && is_common_namespace(prog, t)) + ++occurrences; + return occurrences; + } + + /** + * Determine whether identical typenames will collide based on namespaces. + * + * Because we do not know which languages the user will generate code for, + * collisions within programs (IDL files) having namespace declarations can be + * difficult to determine. Only guaranteed collisions return true (cause an error). + * Possible collisions involving explicit namespace declarations produce a warning. + * Other possible collisions go unreported. + * @param prog the program containing the preexisting typename + * @param t the type containing the typename match + * @return true if a collision within namespaces is found, otherwise false + */ + bool is_common_namespace(t_program* prog, t_type* t) { + // Case 1: Typenames are in the same program [collision] + if (prog == t->get_program()) { + pwarning(1, + "Duplicate typename %s found in %s", + t->get_name().c_str(), + t->get_program()->get_name().c_str()); + return true; + } + + // Case 2: Both programs have identical namespace scope/name declarations [collision] + bool match = true; + for (std::map::iterator it = prog->namespaces_.begin(); + it != prog->namespaces_.end(); + ++it) { + if (0 == it->second.compare(t->get_program()->get_namespace(it->first))) { + pwarning(1, + "Duplicate typename %s found in %s,%s,%s and %s,%s,%s [file,scope,ns]", + t->get_name().c_str(), + t->get_program()->get_name().c_str(), + it->first.c_str(), + it->second.c_str(), + prog->get_name().c_str(), + it->first.c_str(), + it->second.c_str()); + } else { + match = false; + } + } + for (std::map::iterator it = t->get_program()->namespaces_.begin(); + it != t->get_program()->namespaces_.end(); + ++it) { + if (0 == it->second.compare(prog->get_namespace(it->first))) { + pwarning(1, + "Duplicate typename %s found in %s,%s,%s and %s,%s,%s [file,scope,ns]", + t->get_name().c_str(), + t->get_program()->get_name().c_str(), + it->first.c_str(), + it->second.c_str(), + prog->get_name().c_str(), + it->first.c_str(), + it->second.c_str()); + } else { + match = false; + } + } + if (0 == prog->namespaces_.size() && 0 == t->get_program()->namespaces_.size()) { + pwarning(1, + "Duplicate typename %s found in %s and %s", + t->get_name().c_str(), + t->get_program()->get_name().c_str(), + prog->get_name().c_str()); + } + return match; + } + + // Scoping and namespacing + void set_namespace(std::string name) { namespace_ = name; } + + // Scope accessor + t_scope* scope() const { return scope_; } + + // Includes + + void add_include(t_program* program) { + includes_.push_back(program); + } + + void add_include(std::string path, std::string include_site) { + t_program* program = new t_program(path); + + // include prefix for this program is the site at which it was included + // (minus the filename) + std::string include_prefix; + std::string::size_type last_slash = std::string::npos; + if ((last_slash = include_site.rfind("/")) != std::string::npos) { + include_prefix = include_site.substr(0, last_slash); + } + + program->set_include_prefix(include_prefix); + includes_.push_back(program); + } + + std::vector& get_includes() { return includes_; } + + void set_include_prefix(std::string include_prefix) { + include_prefix_ = include_prefix; + + // this is intended to be a directory; add a trailing slash if necessary + std::string::size_type len = include_prefix_.size(); + if (len > 0 && include_prefix_[len - 1] != '/') { + include_prefix_ += '/'; + } + } + + // Language neutral namespace / packaging + void set_namespace(std::string language, std::string name_space) { + if (language != "*") { + size_t sub_index = language.find('.'); + std::string base_language = language.substr(0, sub_index); + std::string sub_namespace; + + if (base_language == "smalltalk") { + pwarning(1, "Namespace 'smalltalk' is deprecated. Use 'st' instead"); + base_language = "st"; + } + + t_generator_registry::gen_map_t my_copy = t_generator_registry::get_generator_map(); + + t_generator_registry::gen_map_t::iterator it; + it = my_copy.find(base_language); + + if (it == my_copy.end()) { + std::string warning = "No generator named '" + base_language + "' could be found!"; + pwarning(1, warning.c_str()); + } else { + if (sub_index != std::string::npos) { + std::string sub_namespace = language.substr(sub_index + 1); + if (!it->second->is_valid_namespace(sub_namespace)) { + std::string warning = base_language + " generator does not accept '" + sub_namespace + + "' as sub-namespace!"; + pwarning(1, warning.c_str()); + } + } + } + } + + namespaces_[language] = name_space; + } + + std::string get_namespace(std::string language) const { + std::map::const_iterator iter; + if ((iter = namespaces_.find(language)) != namespaces_.end() + || (iter = namespaces_.find("*")) != namespaces_.end()) { + return iter->second; + } + return std::string(); + } + + const std::map& get_all_namespaces(){ + return namespaces_; + } + + void set_namespace_annotations(std::string language, std::map annotations) { + namespace_annotations_[language] = annotations; + } + + const std::map& get_namespace_annotations(std::string language) { + return namespace_annotations_[language]; + } + + // Language specific namespace / packaging + + void add_cpp_include(std::string path) { cpp_includes_.push_back(path); } + + const std::vector& get_cpp_includes() { return cpp_includes_; } + + void add_c_include(std::string path) { c_includes_.push_back(path); } + + const std::vector& get_c_includes() { return c_includes_; } + +private: + // File path + std::string path_; + + // Name + std::string name_; + + // Output directory + std::string out_path_; + + // Output directory is absolute location for generated source (no gen-*) + bool out_path_is_absolute_; + + // Namespace + std::string namespace_; + + // Included programs + std::vector includes_; + + // Include prefix for this program, if any + std::string include_prefix_; + + // Identifier lookup scope + t_scope* scope_; + + // Components to generate code for + std::vector typedefs_; + std::vector enums_; + std::vector consts_; + std::vector objects_; + std::vector structs_; + std::vector xceptions_; + std::vector services_; + + // Dynamic namespaces + std::map namespaces_; + + // Annotations for dynamic namespaces + std::map > namespace_annotations_; + + // C++ extra includes + std::vector cpp_includes_; + + // C extra includes + std::vector c_includes_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_scope.h b/compiler/cpp/src/thrift/parse/t_scope.h new file mode 100644 index 0000000..02aa550 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_scope.h @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_SCOPE_H +#define T_SCOPE_H + +#include +#include +#include + +#include "thrift/parse/t_type.h" +#include "thrift/parse/t_service.h" +#include "thrift/parse/t_const.h" +#include "thrift/parse/t_const_value.h" +#include "thrift/parse/t_base_type.h" +#include "thrift/parse/t_map.h" +#include "thrift/parse/t_list.h" +#include "thrift/parse/t_set.h" + +namespace plugin_output { +template +void convert(From*, To&); +} + +/** + * This represents a variable scope used for looking up predefined types and + * services. Typically, a scope is associated with a t_program. Scopes are not + * used to determine code generation, but rather to resolve identifiers at + * parse time. + * + */ +class t_scope { +public: + t_scope() {} + + void add_type(std::string name, t_type* type) { types_[name] = type; } + + t_type* get_type(std::string name) { return types_[name]; } + + void add_service(std::string name, t_service* service) { services_[name] = service; } + + t_service* get_service(std::string name) { return services_[name]; } + + void add_constant(std::string name, t_const* constant) { + if (constants_.find(name) != constants_.end()) { + throw "Enum " + name + " is already defined!"; + } else { + constants_[name] = constant; + } + } + + t_const* get_constant(std::string name) { return constants_[name]; } + + void print() { + std::map::iterator iter; + for (iter = types_.begin(); iter != types_.end(); ++iter) { + printf("%s => %s\n", iter->first.c_str(), iter->second->get_name().c_str()); + } + } + + void resolve_const_value(t_const_value* const_val, t_type* ttype) { + if (ttype->is_map()) { + const std::map& map = const_val->get_map(); + std::map::const_iterator v_iter; + for (v_iter = map.begin(); v_iter != map.end(); ++v_iter) { + resolve_const_value(v_iter->first, ((t_map*)ttype)->get_key_type()); + resolve_const_value(v_iter->second, ((t_map*)ttype)->get_val_type()); + } + } else if (ttype->is_list()) { + const std::vector& val = const_val->get_list(); + std::vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + resolve_const_value((*v_iter), ((t_list*)ttype)->get_elem_type()); + } + } else if (ttype->is_set()) { + const std::vector& val = const_val->get_list(); + std::vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + resolve_const_value((*v_iter), ((t_set*)ttype)->get_elem_type()); + } + } else if (ttype->is_struct()) { + t_struct* tstruct = (t_struct*)ttype; + const std::map& map = const_val->get_map(); + std::map::const_iterator v_iter; + for (v_iter = map.begin(); v_iter != map.end(); ++v_iter) { + t_field* field = tstruct->get_field_by_name(v_iter->first->get_string()); + if (field == NULL) { + throw "No field named \"" + v_iter->first->get_string() + + "\" was found in struct of type \"" + tstruct->get_name() + "\""; + } + resolve_const_value(v_iter->second, field->get_type()); + } + } else if (const_val->get_type() == t_const_value::CV_IDENTIFIER) { + if (ttype->is_enum()) { + const_val->set_enum((t_enum*)ttype); + } else { + t_const* constant = get_constant(const_val->get_identifier()); + if (constant == NULL) { + throw "No enum value or constant found named \"" + const_val->get_identifier() + "\"!"; + } + + // Resolve typedefs to the underlying type + t_type* const_type = constant->get_type()->get_true_type(); + + if (const_type->is_base_type()) { + switch (((t_base_type*)const_type)->get_base()) { + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + case t_base_type::TYPE_BOOL: + case t_base_type::TYPE_I8: + const_val->set_integer(constant->get_value()->get_integer()); + break; + case t_base_type::TYPE_STRING: + const_val->set_string(constant->get_value()->get_string()); + break; + case t_base_type::TYPE_DOUBLE: + const_val->set_double(constant->get_value()->get_double()); + break; + case t_base_type::TYPE_VOID: + throw "Constants cannot be of type VOID"; + } + } else if (const_type->is_map()) { + const std::map& map = constant->get_value()->get_map(); + std::map::const_iterator v_iter; + + const_val->set_map(); + for (v_iter = map.begin(); v_iter != map.end(); ++v_iter) { + const_val->add_map(v_iter->first, v_iter->second); + } + } else if (const_type->is_list()) { + const std::vector& val = constant->get_value()->get_list(); + std::vector::const_iterator v_iter; + + const_val->set_list(); + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + const_val->add_list(*v_iter); + } + } + } + } else if (ttype->is_enum()) { + // enum constant with non-identifier value. set the enum and find the + // value's name. + t_enum* tenum = (t_enum*)ttype; + t_enum_value* enum_value = tenum->get_constant_by_value(const_val->get_integer()); + if (enum_value == NULL) { + std::ostringstream valstm; + valstm << const_val->get_integer(); + throw "Couldn't find a named value in enum " + tenum->get_name() + " for value " + + valstm.str(); + } + const_val->set_identifier(tenum->get_name() + "." + enum_value->get_name()); + const_val->set_enum(tenum); + } + } + +private: + // Map of names to types + std::map types_; + + // Map of names to constants + std::map constants_; + + // Map of names to services + std::map services_; + + // to list map entries + template + friend void plugin_output::convert(From*, To&); +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_service.h b/compiler/cpp/src/thrift/parse/t_service.h new file mode 100644 index 0000000..e2204ca --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_service.h @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_SERVICE_H +#define T_SERVICE_H + +#include "thrift/parse/t_function.h" +#include + +class t_program; + +/** + * A service consists of a set of functions. + * + */ +class t_service : public t_type { +public: + t_service(t_program* program) : t_type(program), extends_(NULL) {} + + bool is_service() const { return true; } + + void set_extends(t_service* extends) { extends_ = extends; } + + void add_function(t_function* func) { + std::vector::const_iterator iter; + for (iter = functions_.begin(); iter != functions_.end(); ++iter) { + if (func->get_name() == (*iter)->get_name()) { + throw "Function " + func->get_name() + " is already defined"; + } + } + functions_.push_back(func); + } + + const std::vector& get_functions() const { return functions_; } + + t_service* get_extends() { return extends_; } + + const t_service* get_extends() const { return extends_; } + +private: + std::vector functions_; + t_service* extends_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_set.h b/compiler/cpp/src/thrift/parse/t_set.h new file mode 100644 index 0000000..f913be4 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_set.h @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_SET_H +#define T_SET_H + +#include "thrift/parse/t_container.h" + +/** + * A set is a lightweight container type that just wraps another data type. + * + */ +class t_set : public t_container { +public: + t_set(t_type* elem_type) : elem_type_(elem_type) {} + + t_type* get_elem_type() const { return elem_type_; } + + bool is_set() const { return true; } + +private: + t_type* elem_type_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_struct.h b/compiler/cpp/src/thrift/parse/t_struct.h new file mode 100644 index 0000000..4102da7 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_struct.h @@ -0,0 +1,171 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_STRUCT_H +#define T_STRUCT_H + +#include +#include +#include +#include + +#include "thrift/parse/t_type.h" +#include "thrift/parse/t_field.h" + +// Forward declare that puppy +class t_program; + +/** + * A struct is a container for a set of member fields that has a name. Structs + * are also used to implement exception types. + * + */ +class t_struct : public t_type { +public: + typedef std::vector members_type; + + t_struct(t_program* program) + : t_type(program), + is_xception_(false), + is_union_(false), + members_validated(false), + members_with_value(0), + xsd_all_(false) {} + + t_struct(t_program* program, const std::string& name) + : t_type(program, name), + is_xception_(false), + is_union_(false), + members_validated(false), + members_with_value(0), + xsd_all_(false) {} + + void set_name(const std::string& name) { + name_ = name; + validate_union_members(); + } + + void set_xception(bool is_xception) { is_xception_ = is_xception; } + + void validate_union_member(t_field* field) { + if (is_union_ && (!name_.empty())) { + + // 1) unions can't have required fields + // 2) union members are implicitly optional, otherwise bugs like THRIFT-3650 wait to happen + if (field->get_req() != t_field::T_OPTIONAL) { + // no warning on default requiredness, but do warn on anything else that is explicitly asked for + if(field->get_req() != t_field::T_OPT_IN_REQ_OUT) { + pwarning(1, + "Union %s field %s: union members must be optional, ignoring specified requiredness.\n", + name_.c_str(), + field->get_name().c_str()); + } + field->set_req(t_field::T_OPTIONAL); + } + + // unions may have up to one member defaulted, but not more + if (field->get_value() != NULL) { + if (1 < ++members_with_value) { + throw "Error: Field " + field->get_name() + " provides another default value for union " + + name_; + } + } + } + } + + void validate_union_members() { + if (is_union_ && (!name_.empty()) && (!members_validated)) { + members_type::const_iterator m_iter; + for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) { + validate_union_member(*m_iter); + } + members_validated = true; + } + } + + void set_union(bool is_union) { + is_union_ = is_union; + validate_union_members(); + } + + void set_xsd_all(bool xsd_all) { xsd_all_ = xsd_all; } + + bool get_xsd_all() const { return xsd_all_; } + + bool append(t_field* elem) { + typedef members_type::iterator iter_type; + std::pair bounds = std::equal_range(members_in_id_order_.begin(), + members_in_id_order_.end(), + elem, + t_field::key_compare()); + if (bounds.first != bounds.second) { + return false; + } + // returns false when there is a conflict of field names + if (get_field_by_name(elem->get_name()) != NULL) { + return false; + } + members_.push_back(elem); + members_in_id_order_.insert(bounds.second, elem); + validate_union_member(elem); + return true; + } + + const members_type& get_members() const { return members_; } + + const members_type& get_sorted_members() { return members_in_id_order_; } + + bool is_struct() const { return !is_xception_; } + + bool is_xception() const { return is_xception_; } + + bool is_union() const { return is_union_; } + + t_field* get_field_by_name(std::string field_name) { + members_type::const_iterator m_iter; + for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) { + if ((*m_iter)->get_name() == field_name) { + return *m_iter; + } + } + return NULL; + } + + const t_field* get_field_by_name(std::string field_name) const { + members_type::const_iterator m_iter; + for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) { + if ((*m_iter)->get_name() == field_name) { + return *m_iter; + } + } + return NULL; + } + +private: + members_type members_; + members_type members_in_id_order_; + bool is_xception_; + bool is_union_; + bool members_validated; + int members_with_value; + + bool xsd_all_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_type.h b/compiler/cpp/src/thrift/parse/t_type.h new file mode 100644 index 0000000..3a6d1e0 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_type.h @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_TYPE_H +#define T_TYPE_H + +#include +#include +#include +#include +#include "thrift/parse/t_doc.h" + +class t_program; + +/** + * Generic representation of a thrift type. These objects are used by the + * parser module to build up a tree of object that are all explicitly typed. + * The generic t_type class exports a variety of useful methods that are + * used by the code generator to branch based upon different handling for the + * various types. + * + */ +class t_type : public t_doc { +public: + virtual ~t_type() {} + + virtual void set_name(const std::string& name) { name_ = name; } + + virtual const std::string& get_name() const { return name_; } + + virtual bool is_void() const { return false; } + virtual bool is_base_type() const { return false; } + virtual bool is_string() const { return false; } + virtual bool is_binary() const { return false; } + virtual bool is_bool() const { return false; } + virtual bool is_typedef() const { return false; } + virtual bool is_enum() const { return false; } + virtual bool is_struct() const { return false; } + virtual bool is_xception() const { return false; } + virtual bool is_container() const { return false; } + virtual bool is_list() const { return false; } + virtual bool is_set() const { return false; } + virtual bool is_map() const { return false; } + virtual bool is_service() const { return false; } + + t_program* get_program() { return program_; } + + const t_program* get_program() const { return program_; } + + t_type* get_true_type(); + const t_type* get_true_type() const; + + // This function will break (maybe badly) unless 0 <= num <= 16. + static char nybble_to_xdigit(int num) { + if (num < 10) { + return '0' + num; + } else { + return 'A' + num - 10; + } + } + + static std::string byte_to_hex(uint8_t byte) { + std::string rv; + rv += nybble_to_xdigit(byte >> 4); + rv += nybble_to_xdigit(byte & 0x0f); + return rv; + } + + std::map annotations_; + +protected: + t_type() : program_(NULL) { ; } + + t_type(t_program* program) : program_(program) { ; } + + t_type(t_program* program, std::string name) : program_(program), name_(name) { ; } + + t_type(std::string name) : program_(NULL), name_(name) { ; } + + t_program* program_; + std::string name_; +}; + +/** + * Placeholder struct for returning the key and value of an annotation + * during parsing. + */ +struct t_annotation { + std::string key; + std::string val; +}; + +#endif diff --git a/compiler/cpp/src/thrift/parse/t_typedef.cc b/compiler/cpp/src/thrift/parse/t_typedef.cc new file mode 100644 index 0000000..99ffdb8 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_typedef.cc @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include + +#include "thrift/parse/t_typedef.h" +#include "thrift/parse/t_program.h" + +t_type* t_typedef::get_type() const { + if (type_ == NULL) { + t_type* type = get_program()->scope()->get_type(symbolic_); + if (type == NULL) { + printf("Type \"%s\" not defined\n", symbolic_.c_str()); + exit(1); + } + return type; + } + return type_; +} diff --git a/compiler/cpp/src/thrift/parse/t_typedef.h b/compiler/cpp/src/thrift/parse/t_typedef.h new file mode 100644 index 0000000..aad3a50 --- /dev/null +++ b/compiler/cpp/src/thrift/parse/t_typedef.h @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_TYPEDEF_H +#define T_TYPEDEF_H + +#include +#include "thrift/parse/t_type.h" + +/** + * A typedef is a mapping from a symbolic name to another type. In dymanically + * typed languages (i.e. php/python) the code generator can actually usually + * ignore typedefs and just use the underlying type directly, though in C++ + * the symbolic naming can be quite useful for code clarity. + * + */ +class t_typedef : public t_type { +public: + t_typedef(t_program* program, t_type* type, const std::string& symbolic) + : t_type(program, symbolic), type_(type), symbolic_(symbolic), forward_(false) {} + + /** + * This constructor is used to refer to a type that is lazily + * resolved at a later time, like for forward declarations or + * recursive types. + */ + t_typedef(t_program* program, const std::string& symbolic, bool forward) + : t_type(program, symbolic), + type_(NULL), + symbolic_(symbolic), + forward_(forward) + {} + + ~t_typedef() {} + + t_type* get_type() const; + + const std::string& get_symbolic() const { return symbolic_; } + + bool is_forward_typedef() const { return forward_; } + + bool is_typedef() const { return true; } + +private: + t_type* type_; + std::string symbolic_; + bool forward_; +}; + +#endif diff --git a/compiler/cpp/src/thrift/platform.h b/compiler/cpp/src/thrift/platform.h new file mode 100644 index 0000000..f49adb9 --- /dev/null +++ b/compiler/cpp/src/thrift/platform.h @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * define for mkdir,since the method signature + * is different for the non-POSIX MinGW + */ + +#ifdef _MSC_VER +#include "thrift/windows/config.h" +#endif + +#ifdef _WIN32 +#include +#include +#else +#include +#include +#endif + +#include + +// ignore EEXIST, throw on any other error +#ifdef _WIN32 +#define MKDIR(x) { int r = _mkdir(x); if (r == -1 && errno != EEXIST) { throw (std::string(x) + ": ") + strerror(errno); } } +#else +#define MKDIR(x) { int r = mkdir(x, S_IRWXU | S_IRWXG | S_IRWXO); if (r == -1 && errno != EEXIST) { throw (std::string(x) + ": ") + strerror(errno); } } +#endif + +#ifdef PATH_MAX +#define THRIFT_PATH_MAX PATH_MAX +#else +#define THRIFT_PATH_MAX MAX_PATH +#endif diff --git a/compiler/cpp/src/thrift/plugin/Makefile.am b/compiler/cpp/src/thrift/plugin/Makefile.am new file mode 100644 index 0000000..e84cdbd --- /dev/null +++ b/compiler/cpp/src/thrift/plugin/Makefile.am @@ -0,0 +1,47 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# +# Contains some contributions under the Thrift Software License. +# Please see doc/old-thrift-license.txt in the Thrift distribution for +# details. + +AUTOMAKE_OPTIONS = subdir-objects + +if WITH_PLUGIN +plugin_gen = plugin_types.h \ + plugin_types.cpp \ + plugin_constants.h \ + plugin_constants.cpp + +BUILT_SOURCES = $(plugin_gen) +gen.stamp: plugin.thrift $(top_builddir)/compiler/cpp/src/thrift/thrift-bootstrap + @$(RM) -f gen.tmp + @touch gen.tmp + $(top_builddir)/compiler/cpp/src/thrift/thrift-bootstrap -gen cpp -out . $< + @mv -f gen.tmp $@ + +$(plugin_gen): gen.stamp + @if test -f $@; then :; else \ + $(RM) -f gen.stamp; \ + $(MAKE) $(AM_MAKEFLAGS) gen.stamp; \ + fi + +clean-local: + $(RM) version.h windows/version.h $(plugin_gen) +endif diff --git a/compiler/cpp/src/thrift/plugin/Makefile.in b/compiler/cpp/src/thrift/plugin/Makefile.in new file mode 100644 index 0000000..f284416 --- /dev/null +++ b/compiler/cpp/src/thrift/plugin/Makefile.in @@ -0,0 +1,652 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# +# Contains some contributions under the Thrift Software License. +# Please see doc/old-thrift-license.txt in the Thrift distribution for +# details. +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = compiler/cpp/src/thrift/plugin +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = subdir-objects +@WITH_PLUGIN_TRUE@plugin_gen = plugin_types.h \ +@WITH_PLUGIN_TRUE@ plugin_types.cpp \ +@WITH_PLUGIN_TRUE@ plugin_constants.h \ +@WITH_PLUGIN_TRUE@ plugin_constants.cpp + +@WITH_PLUGIN_TRUE@BUILT_SOURCES = $(plugin_gen) +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign compiler/cpp/src/thrift/plugin/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign compiler/cpp/src/thrift/plugin/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile +installdirs: +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +@WITH_PLUGIN_FALSE@clean-local: +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: all check install install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + +@WITH_PLUGIN_TRUE@gen.stamp: plugin.thrift $(top_builddir)/compiler/cpp/src/thrift/thrift-bootstrap +@WITH_PLUGIN_TRUE@ @$(RM) -f gen.tmp +@WITH_PLUGIN_TRUE@ @touch gen.tmp +@WITH_PLUGIN_TRUE@ $(top_builddir)/compiler/cpp/src/thrift/thrift-bootstrap -gen cpp -out . $< +@WITH_PLUGIN_TRUE@ @mv -f gen.tmp $@ + +@WITH_PLUGIN_TRUE@$(plugin_gen): gen.stamp +@WITH_PLUGIN_TRUE@ @if test -f $@; then :; else \ +@WITH_PLUGIN_TRUE@ $(RM) -f gen.stamp; \ +@WITH_PLUGIN_TRUE@ $(MAKE) $(AM_MAKEFLAGS) gen.stamp; \ +@WITH_PLUGIN_TRUE@ fi + +@WITH_PLUGIN_TRUE@clean-local: +@WITH_PLUGIN_TRUE@ $(RM) version.h windows/version.h $(plugin_gen) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/compiler/cpp/src/thrift/plugin/plugin.cc b/compiler/cpp/src/thrift/plugin/plugin.cc new file mode 100644 index 0000000..0bac135 --- /dev/null +++ b/compiler/cpp/src/thrift/plugin/plugin.cc @@ -0,0 +1,501 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "thrift/plugin/plugin.h" + +#ifdef _WIN32 +#include +#include +#endif + +#include +#include + +#include +#include + +#include "thrift/generate/t_generator.h" +#include "thrift/plugin/type_util.h" +#include "thrift/protocol/TBinaryProtocol.h" +#include "thrift/transport/TBufferTransports.h" +#include "thrift/transport/TFDTransport.h" +#include "thrift/stdcxx.h" +#include "thrift/plugin/plugin_types.h" + +namespace apache { +namespace thrift { +namespace plugin { + +using apache::thrift::protocol::TBinaryProtocol; +using apache::thrift::transport::TFDTransport; +using apache::thrift::transport::TFramedTransport; + +#define THRIFT_CONVERT_FORWARD(from_type) \ + template <> \ + typename ToType::type* convert_forward(const from_type& from) + +#define THRIFT_CONVERT_COMPLETE_DECL(from_type) \ + template <> \ + void convert(const from_type& from, ToType::type* to) + +#define THRIFT_CONVERT_UNARY_DECL(from_type) \ + template <> \ + typename ToType::type* convert(const from_type& from) + +#define THRIFT_CONVERSION_DECL(from_type) \ + THRIFT_CONVERT_FORWARD(from_type); \ + THRIFT_CONVERT_COMPLETE_DECL(from_type); \ + THRIFT_CONVERT_UNARY_DECL(from_type) + +#define THRIFT_CONVERT_COMPLETE(from_type) \ + THRIFT_CONVERSION_DECL(from_type) { \ + ToType::type* to = convert_forward(from); \ + convert(from, to); \ + return to; \ + } \ + THRIFT_CONVERT_COMPLETE_DECL(from_type) + +#define THRIFT_CONVERSION(from_type, ...) \ + THRIFT_CONVERT_FORWARD(from_type) { \ + (void)from; \ + return new ToType::type(__VA_ARGS__); \ + } \ + THRIFT_CONVERT_COMPLETE(from_type) + +#define THRIFT_ASSIGN_DOC() \ + do { \ + if (from.__isset.doc) \ + to->set_doc(from.doc); \ + } while (0) + +#define THRIFT_ASSIGN_ANNOTATIONS() \ + THRIFT_ASSIGN_DOC(); \ + do { \ + if (from.__isset.annotations) \ + to->annotations_ = from.annotations; \ + } while (0) + +#define THRIFT_ASSIGN_METADATA() \ + do { \ + to->set_name(from.metadata.name); \ + if (from.metadata.__isset.doc) \ + to->set_doc(from.metadata.doc); \ + if (from.metadata.__isset.annotations) \ + to->annotations_ = from.metadata.annotations; \ + } while (0) + +::t_program* g_program = 0; + +template +struct TypeCache { + C* operator[](const int64_t& k) { + typename std::map::iterator it = cache.find(k); + if (it != cache.end()) { + return it->second; + } else { + typename std::map::const_iterator cit = source->find(k); + if (cit == source->end()) { + throw ThriftPluginError("Type not found"); + } + return (cache)[k] = convert_forward(cit->second); + } + } + + void compileAll() { + boost::for_each(*source | boost::adaptors::map_keys, + stdcxx::bind(&TypeCache::compile, this, stdcxx::placeholders::_1)); + } + + std::map const* source; + +protected: + std::map cache; + +private: + void compile(const int64_t& k) { + typename std::map::const_iterator cit = source->find(k); + if (cit == source->end()) { + throw ThriftPluginError("Type not found "); + } + convert(cit->second, (*this)[k]); + } +}; +std::map g_program_cache; +TypeCache< ::t_type, t_type> g_type_cache; +TypeCache< ::t_const, t_const> g_const_cache; +TypeCache< ::t_service, t_service> g_service_cache; + +void set_global_cache(const TypeRegistry& from) { + g_type_cache.source = &from.types; + g_const_cache.source = &from.constants; + g_service_cache.source = &from.services; + + g_type_cache.compileAll(); + g_const_cache.compileAll(); + g_service_cache.compileAll(); +} + +template +T* resolve_type(int64_t name) { + return reinterpret_cast(g_type_cache[name]); +} + +::t_const* resolve_const(int64_t name) { + return g_const_cache[name]; +} + +::t_service* resolve_service(int64_t name) { + return g_service_cache[name]; +} + +THRIFT_CONVERT_FORWARD(t_base_type) { +#define T_BASETYPE_CASE(type) \ + case t_base::TYPE_##type: \ + t = ::t_base_type::TYPE_##type; \ + break + + ::t_base_type::t_base t = ::t_base_type::TYPE_VOID; + bool is_binary = false; + switch (from.value) { + T_BASETYPE_CASE(VOID); + T_BASETYPE_CASE(STRING); + T_BASETYPE_CASE(BOOL); + T_BASETYPE_CASE(I8); + T_BASETYPE_CASE(I16); + T_BASETYPE_CASE(I32); + T_BASETYPE_CASE(I64); + T_BASETYPE_CASE(DOUBLE); + case t_base::TYPE_BINARY: + t = ::t_base_type::TYPE_STRING; + is_binary = true; + break; + } + ::t_base_type* to = new ::t_base_type(from.metadata.name, t); + to->set_binary(is_binary); + return to; +#undef T_BASETYPE_CASE +} +THRIFT_CONVERT_COMPLETE(t_base_type) { + THRIFT_ASSIGN_METADATA(); +} + +THRIFT_CONVERT_FORWARD(t_typedef) { + ::t_typedef* to; + if (from.forward) { + to = new ::t_typedef(g_program_cache[from.metadata.program_id], from.symbolic, true); + } else { + to = new ::t_typedef(g_program_cache[from.metadata.program_id], + resolve_type< ::t_type>(from.type), from.symbolic); + } + return to; +} +THRIFT_CONVERT_COMPLETE(t_typedef) { + THRIFT_ASSIGN_METADATA(); +} +THRIFT_CONVERSION(t_enum_value, from.name, from.value) { + assert(to); + THRIFT_ASSIGN_ANNOTATIONS(); +} +THRIFT_CONVERSION(t_enum, g_program_cache[from.metadata.program_id]) { + assert(to); + THRIFT_ASSIGN_METADATA(); + boost::for_each(from.constants | boost::adaptors::transformed(convert), + stdcxx::bind(&::t_enum::append, to, stdcxx::placeholders::_1)); +} +THRIFT_CONVERSION(t_list, resolve_type< ::t_type>(from.elem_type)) { + assert(to); + THRIFT_ASSIGN_METADATA(); + if (from.__isset.cpp_name) + to->set_cpp_name(from.cpp_name); +} +THRIFT_CONVERSION(t_set, resolve_type< ::t_type>(from.elem_type)) { + assert(to); + THRIFT_ASSIGN_METADATA(); + if (from.__isset.cpp_name) + to->set_cpp_name(from.cpp_name); +} +THRIFT_CONVERSION(t_map, + resolve_type< ::t_type>(from.key_type), + resolve_type< ::t_type>(from.val_type)) { + assert(to); + THRIFT_ASSIGN_METADATA(); + if (from.__isset.cpp_name) + to->set_cpp_name(from.cpp_name); +} +THRIFT_CONVERSION(t_const_value, ) { +#define T_CONST_VALUE_CASE(type) \ + if (from.__isset.type##_val) \ + to->set_##type(from.type##_val) + + assert(to); + if (from.__isset.map_val) { + to->set_map(); + for (std::map::const_iterator it = from.map_val.begin(); + it != from.map_val.end(); it++) { + to->add_map(convert(it->first), convert(it->second)); + } + } else if (from.__isset.list_val) { + to->set_list(); + boost::for_each(from.list_val | boost::adaptors::transformed(&convert), + stdcxx::bind(&::t_const_value::add_list, to, stdcxx::placeholders::_1)); + } else + T_CONST_VALUE_CASE(string); + else T_CONST_VALUE_CASE(integer); + else T_CONST_VALUE_CASE(double); + else { + T_CONST_VALUE_CASE(identifier); + if (from.__isset.enum_val) + to->set_enum(resolve_type< ::t_enum>(from.enum_val)); + } +#undef T_CONST_VALUE_CASE +} +THRIFT_CONVERSION(t_field, resolve_type< ::t_type>(from.type), from.name, from.key) { + assert(to); + THRIFT_ASSIGN_ANNOTATIONS(); + to->set_reference(from.reference); + to->set_req(static_cast< ::t_field::e_req>(from.req)); + if (from.__isset.value) { + to->set_value(convert(from.value)); + } +} +THRIFT_CONVERSION(t_struct, g_program_cache[from.metadata.program_id]) { + assert(to); + THRIFT_ASSIGN_METADATA(); + to->set_union(from.is_union); + to->set_xception(from.is_xception); + boost::for_each(from.members | boost::adaptors::transformed(convert), + stdcxx::bind(&::t_struct::append, to, stdcxx::placeholders::_1)); +} +THRIFT_CONVERSION(t_const, + resolve_type< ::t_type>(from.type), + from.name, + convert(from.value)) { + assert(to); + THRIFT_ASSIGN_DOC(); +} + +THRIFT_CONVERSION(t_function, + resolve_type< ::t_type>(from.returntype), + from.name, + resolve_type< ::t_struct>(from.arglist), + resolve_type< ::t_struct>(from.xceptions), + from.is_oneway) { + assert(to); + THRIFT_ASSIGN_DOC(); +} + +THRIFT_CONVERSION(t_service, g_program_cache[from.metadata.program_id]) { + assert(to); + assert(from.metadata.program_id); + assert(g_program_cache[from.metadata.program_id]); + THRIFT_ASSIGN_METADATA(); + + boost::for_each(from.functions | boost::adaptors::transformed(convert), + stdcxx::bind(&::t_service::add_function, to, stdcxx::placeholders::_1)); + + if (from.__isset.extends_) + to->set_extends(resolve_service(from.extends_)); +} + +THRIFT_CONVERT_FORWARD(t_type) { +#define T_TYPE_CASE_FW_T(case, type) \ + if (from.__isset.case##_val) \ + return convert_forward(from.case##_val) +#define T_TYPE_CASE_FW(case) T_TYPE_CASE_FW_T(case, t_##case) + + T_TYPE_CASE_FW(base_type); + T_TYPE_CASE_FW(typedef); + T_TYPE_CASE_FW(enum); + T_TYPE_CASE_FW(struct); + T_TYPE_CASE_FW_T(xception, t_struct); + T_TYPE_CASE_FW(list); + T_TYPE_CASE_FW(set); + T_TYPE_CASE_FW(map); + T_TYPE_CASE_FW(service); + throw ThriftPluginError("Invalid data: Type union has no value."); +#undef T_TYPE_CASE_FW_T +#undef T_TYPE_CASE_FW +} +THRIFT_CONVERT_COMPLETE(t_type) { +#define T_TYPE_CASE_T(case, type) \ + else if (from.__isset.case##_val) \ + convert(from.case##_val, reinterpret_cast< ::type*>(to)) +#define T_TYPE_CASE(case) T_TYPE_CASE_T(case, t_##case) + + if (false) { + } + T_TYPE_CASE(base_type); + T_TYPE_CASE(typedef); + T_TYPE_CASE(enum); + T_TYPE_CASE(struct); + T_TYPE_CASE_T(xception, t_struct); + T_TYPE_CASE(list); + T_TYPE_CASE(set); + T_TYPE_CASE(map); + T_TYPE_CASE(service); + else { + throw ThriftPluginError("Invalid data: Type union has no value."); + } +#undef T_TYPE_CASE_T +#undef T_TYPE_CASE +} + +THRIFT_CONVERSION(t_scope, ) { + assert(to); +#define T_SCOPE_RESOLVE(type, name, a) \ + for (std::vector::const_iterator it = from.name##s.begin(); it != from.name##s.end(); \ + it++) { \ + ::t_##type* t = resolve_##type a(*it); \ + to->add_##name(t->get_name(), t); \ + } + T_SCOPE_RESOLVE(type, type, < ::t_type>); + T_SCOPE_RESOLVE(const, constant, ); + T_SCOPE_RESOLVE(service, service, ); +#undef T_SCOPE_RESOLVE +} + +THRIFT_CONVERT_FORWARD(t_program) { + ::t_program* to = new ::t_program(from.path, from.name); + for (std::vector::const_iterator it = from.includes.begin(); it != from.includes.end(); + it++) { + to->add_include(convert_forward(*it)); + } + g_program_cache[from.program_id] = to; + return to; +} +THRIFT_CONVERT_COMPLETE(t_program) { + assert(to); + g_program = to; + convert(from.scope, to->scope()); + THRIFT_ASSIGN_DOC(); + + to->set_out_path(from.out_path, from.out_path_is_absolute); + + boost::for_each(from.typedefs | boost::adaptors::transformed(&resolve_type< ::t_typedef>), + stdcxx::bind(&::t_program::add_typedef, to, stdcxx::placeholders::_1)); + boost::for_each(from.enums | boost::adaptors::transformed(&resolve_type< ::t_enum>), + stdcxx::bind(&::t_program::add_enum, to, stdcxx::placeholders::_1)); + for (std::vector::const_iterator it = from.objects.begin(); it != from.objects.end(); + it++) { + ::t_struct* t2 = resolve_type< ::t_struct>(*it); + if (t2->is_xception()) { + to->add_xception(t2); + } else { + to->add_struct(t2); + } + } + boost::for_each(from.consts | boost::adaptors::transformed(&resolve_const), + stdcxx::bind(&::t_program::add_const, to, stdcxx::placeholders::_1)); + boost::for_each(from.services | boost::adaptors::transformed(&resolve_service), + stdcxx::bind(&::t_program::add_service, to, stdcxx::placeholders::_1)); + + for (std::vector::const_iterator it = from.includes.begin(); it != from.includes.end(); + it++) { + convert(*it, g_program_cache[it->program_id]); + } + std::for_each(from.c_includes.begin(), from.c_includes.end(), + stdcxx::bind(&::t_program::add_c_include, to, stdcxx::placeholders::_1)); + std::for_each(from.cpp_includes.begin(), from.cpp_includes.end(), + stdcxx::bind(&::t_program::add_cpp_include, to, stdcxx::placeholders::_1)); + for (std::map::const_iterator it = from.namespaces.begin(); + it != from.namespaces.end(); it++) { + to->set_namespace(it->first, it->second); + } + + to->set_include_prefix(from.include_prefix); + to->set_namespace(from.namespace_); +} + +int GeneratorPlugin::exec(int, char* []) { +#ifdef _WIN32 + _setmode(fileno(stdin), _O_BINARY); +#endif + stdcxx::shared_ptr transport( + new TFramedTransport(stdcxx::make_shared(fileno(stdin)))); + TBinaryProtocol proto(transport); + GeneratorInput input; + try { + input.read(&proto); + } catch (std::exception& err) { + std::cerr << "Error while receiving plugin data: " << err.what() << std::endl; + return -1; + } + initGlobals(); + ::t_program* p = g_program = convert_forward(input.program); + set_global_cache(input.type_registry); + convert(input.program, p); + + int ret = generate(p, input.parsed_options); + clearGlobals(); + + return ret; +} + +::t_const_value::t_const_value_type const_value_case(const t_const_value& v) { + if (v.__isset.map_val) + return ::t_const_value::CV_MAP; + if (v.__isset.list_val) + return ::t_const_value::CV_LIST; + if (v.__isset.string_val) + return ::t_const_value::CV_STRING; + if (v.__isset.integer_val) + return ::t_const_value::CV_INTEGER; + if (v.__isset.double_val) + return ::t_const_value::CV_DOUBLE; + if (v.__isset.identifier_val) + return ::t_const_value::CV_IDENTIFIER; + if (v.__isset.enum_val) + return ::t_const_value::CV_IDENTIFIER; + throw ThriftPluginError("Unknown const value type"); +} + +bool t_const_value::operator<(const t_const_value& that) const { + ::t_const_value::t_const_value_type t1 = const_value_case(*this); + ::t_const_value::t_const_value_type t2 = const_value_case(that); + if (t1 != t2) + return t1 < t2; + switch (t1) { + case ::t_const_value::CV_INTEGER: + return integer_val < that.integer_val; + case ::t_const_value::CV_DOUBLE: + return double_val < that.double_val; + case ::t_const_value::CV_STRING: + return string_val < that.string_val; + case ::t_const_value::CV_MAP: + if (that.map_val.empty()) + return false; + else if (map_val.empty()) + return true; + else + return map_val.begin()->first < that.map_val.begin()->first; + case ::t_const_value::CV_LIST: + if (that.list_val.empty()) + return false; + else if (list_val.empty()) + return true; + else + return list_val.front() < that.list_val.front(); + case ::t_const_value::CV_IDENTIFIER: + return integer_val < that.integer_val; + } + throw ThriftPluginError("Unknown const value type"); +} +} +} +} diff --git a/compiler/cpp/src/thrift/plugin/plugin.h b/compiler/cpp/src/thrift/plugin/plugin.h new file mode 100644 index 0000000..705cd41 --- /dev/null +++ b/compiler/cpp/src/thrift/plugin/plugin.h @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_PLUGIN_PLUGIN_H +#define T_PLUGIN_PLUGIN_H + +#include "thrift/Thrift.h" + +class t_program; + +namespace apache { +namespace thrift { +namespace plugin { + +struct ThriftPluginError : public apache::thrift::TException { + ThriftPluginError(const std::string& msg) : apache::thrift::TException(msg) {} +}; + +class GeneratorPlugin { +public: + int exec(int argc, char* argv[]); + virtual int generate(::t_program*, const std::map&) = 0; +}; +} +} +} + +#endif diff --git a/compiler/cpp/src/thrift/plugin/plugin.thrift b/compiler/cpp/src/thrift/plugin/plugin.thrift new file mode 100644 index 0000000..1e51310 --- /dev/null +++ b/compiler/cpp/src/thrift/plugin/plugin.thrift @@ -0,0 +1,202 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +namespace as3 org.apache.thrift.plugin +namespace cpp apache.thrift.plugin +namespace csharp Thrift.Plugin +namespace d thrift.plugin +namespace delphi Thrift.Plugin +namespace erl thrift.plugin +namespace go thrift +namespace haxe org.apache.thrift.plugin +namespace hs Thrift.Plugin +namespace java org.apache.thrift.plugin +namespace ocaml Thrift +namespace perl Thrift.Plugin +namespace php thrift.plugin +namespace py thrift.plugin +namespace rb Thrift + +typedef i64 t_program_id +typedef i64 t_type_id +typedef i64 t_const_id +typedef i64 t_service_id + +enum t_base { + TYPE_VOID + TYPE_STRING + TYPE_BOOL + TYPE_I8 + TYPE_I16 + TYPE_I32 + TYPE_I64 + TYPE_DOUBLE + TYPE_BINARY +} + +struct TypeMetadata { + 1: required string name + 2: required t_program_id program_id + 99: optional map annotations + 100: optional string doc +} + +struct t_base_type { + 1: required TypeMetadata metadata + 2: required t_base value +} + +struct t_list { + 1: required TypeMetadata metadata + 2: optional string cpp_name + 3: required t_type_id elem_type +} + +struct t_set { + 1: required TypeMetadata metadata + 2: optional string cpp_name + 3: required t_type_id elem_type +} + +struct t_map { + 1: required TypeMetadata metadata + 2: optional string cpp_name + 3: required t_type_id key_type + 4: required t_type_id val_type +} + +struct t_typedef { + 1: required TypeMetadata metadata + 2: required t_type_id type + 3: required string symbolic + 4: required bool forward +} + +struct t_enum_value { + 1: required string name + 2: required i32 value + 99: optional map annotations + 100: optional string doc +} +struct t_enum { + 1: required TypeMetadata metadata + 2: required list constants +} + +enum Requiredness { + T_REQUIRED = 0 + T_OPTIONAL = 1 + T_OPT_IN_REQ_OUT = 2 +} + +union t_const_value { + 1: optional map map_val + 2: optional list list_val + 3: optional string string_val + 4: optional i64 integer_val + 5: optional double double_val + 6: optional string identifier_val + 7: optional t_type_id enum_val +} +struct t_const { + 1: required string name + 2: required t_type_id type + 3: required t_const_value value + 100: optional string doc +} +struct t_field { + 1: required string name + 2: required t_type_id type + 3: required i32 key + 4: required Requiredness req + 5: optional t_const_value value + 10: required bool reference + 99: optional map annotations + 100: optional string doc +} +struct t_struct { + 1: required TypeMetadata metadata + 2: required list members + 3: required bool is_union + 4: required bool is_xception +} +struct t_function { + 1: required string name + 2: required t_type_id returntype + 3: required t_type_id arglist + 4: required t_type_id xceptions + 5: required bool is_oneway + 100: optional string doc +} +struct t_service { + 1: required TypeMetadata metadata + 2: required list functions + 3: optional t_service_id extends_ +} +union t_type { + 1: optional t_base_type base_type_val + 2: optional t_typedef typedef_val + 3: optional t_enum enum_val + 4: optional t_struct struct_val + 5: optional t_struct xception_val + 6: optional t_list list_val + 7: optional t_set set_val + 8: optional t_map map_val + 9: optional t_service service_val +} +struct t_scope { + 1: required list types + 2: required list constants + 3: required list services +} + +struct TypeRegistry { + 1: required map types + 2: required map constants + 3: required map services +} + +struct t_program { + 1: required string name + 2: required t_program_id program_id + 3: required string path + 4: required string namespace_ + 5: required string out_path + 6: required bool out_path_is_absolute + 8: required list includes + 9: required string include_prefix + 10: required t_scope scope + + 11: required list typedefs + 12: required list enums + 13: required list consts + 14: required list objects + 15: required list services + + 16: required map namespaces + 17: required list cpp_includes + 18: required list c_includes + 100: optional string doc +} + +struct GeneratorInput { + 1: required t_program program + 2: required TypeRegistry type_registry + 3: required map parsed_options +} diff --git a/compiler/cpp/src/thrift/plugin/plugin_output.cc b/compiler/cpp/src/thrift/plugin/plugin_output.cc new file mode 100644 index 0000000..75725a1 --- /dev/null +++ b/compiler/cpp/src/thrift/plugin/plugin_output.cc @@ -0,0 +1,412 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifdef _WIN32 +#include +#include +#include +#include +#define THRIFT_POPEN(cmd) _popen(cmd, "wb") +#define THRIFT_PCLOSE _pclose +#else +#define THRIFT_POPEN(cmd) popen(cmd, "w") +#define THRIFT_PCLOSE pclose +#endif + +#include "thrift/plugin/plugin_output.h" + +#include +#include +#include + +#include "thrift/generate/t_generator.h" +#include "thrift/plugin/plugin.h" +#include "thrift/plugin/type_util.h" +#include "thrift/protocol/TBinaryProtocol.h" +#include "thrift/stdcxx.h" +#include "thrift/transport/TBufferTransports.h" +#include "thrift/transport/TFDTransport.h" + +#include "thrift/plugin/plugin_types.h" + +namespace plugin_output { + +template +typename apache::thrift::plugin::ToType::type convert(From* from) { + typename apache::thrift::plugin::ToType::type to; + convert(from, to); + return to; +} + +using apache::thrift::protocol::TBinaryProtocol; +using apache::thrift::stdcxx::make_shared; +using apache::thrift::stdcxx::shared_ptr; +using apache::thrift::transport::TFDTransport; +using apache::thrift::transport::TFramedTransport; + +using namespace apache::thrift; + +#define THRIFT_CONVERSION_N(from_type, to_type) \ + template <> \ + void convert(from_type * from, to_type & to) +#define THRIFT_CONVERSION(type) THRIFT_CONVERSION_N(::type, plugin::type) + +#define THRIFT_ASSIGN_N(from_name, to_name, prefix) \ + do { \ + if (from) \ + to.__set_##to_name(prefix(from->from_name)); \ + } while (0) + +#define THRIFT_ASSIGN(name) THRIFT_ASSIGN_N(get_##name(), name, ) +#define THRIFT_ASSIGN_CONVERT(type, from_name, to_name) \ + do { \ + if (from && from->from_name) { \ + to.__set_##to_name(convert(from->from_name)); \ + } \ + } while (0) + +#define THRIFT_ASSIGN_OPT(name) \ + do { \ + if (from->has_##name()) \ + THRIFT_ASSIGN(name); \ + } while (0) + +#define THRIFT_ASSIGN_LIST_N(type, from_name, to_name) \ + do { \ + if (from && !from->from_name.empty()) { \ + std::transform(from->from_name.begin(), \ + from->from_name.end(), \ + std::back_inserter(to.to_name), \ + convert< ::type>); \ + } \ + } while (0) + +#define THRIFT_ASSIGN_METADATA() convert(reinterpret_cast(from), to.metadata) + +// To avoid multiple instances of same type, t_type, t_const and t_service are stored in one place +// and referenced by ID. +template +struct TypeCache { + typedef typename plugin::ToType::type to_type; + std::map cache; + + template + int64_t store(T2* t) { + intptr_t id = reinterpret_cast(t); + if (id) { + typename std::map::iterator it = cache.find(id); + if (it == cache.end()) { + // HACK: fake resolve for recursive type + cache.insert(std::make_pair(id, to_type())); + // overwrite with true value + cache[id] = convert(t); + } + } + return static_cast(id); + } + + void clear() { cache.clear(); } +}; + +template +int64_t store_type(T* t); + +#define T_STORE(type) \ + TypeCache type##_cache; \ + template <> \ + plugin::t_##type##_id store_type(t_##type * t) { \ + return type##_cache.store(t); \ + } +T_STORE(type) +T_STORE(const) +T_STORE(service) +#undef T_STORE + +#define THRIFT_ASSIGN_ID_N(t, from_name, to_name) \ + do { \ + if (from && from->from_name) \ + to.__set_##to_name(store_type(from->from_name)); \ + } while (0) + +#define THRIFT_ASSIGN_ID(name) THRIFT_ASSIGN_ID_N(t_type, get_##name(), name) + +#define THRIFT_ASSIGN_LIST_ID(t, name) \ + do { \ + if (from && !from->get_##name##s().empty()) { \ + std::transform(from->get_##name##s().begin(), \ + from->get_##name##s().end(), \ + std::back_inserter(to.name##s), \ + &store_type); \ + } \ + } while (0) + +THRIFT_CONVERSION_N(::t_type, plugin::TypeMetadata) { + to.program_id = reinterpret_cast(from->get_program()); + THRIFT_ASSIGN_N(annotations_, annotations, ); + if (from->has_doc()) { + to.__set_doc(from->get_doc()); + } + THRIFT_ASSIGN(name); +} + +THRIFT_CONVERSION(t_typedef) { + THRIFT_ASSIGN_METADATA(); + THRIFT_ASSIGN_ID(type); + THRIFT_ASSIGN(symbolic); + THRIFT_ASSIGN_N(is_forward_typedef(), forward, ); +} + +THRIFT_CONVERSION(t_enum_value) { + THRIFT_ASSIGN_OPT(doc); + THRIFT_ASSIGN(name); + THRIFT_ASSIGN(value); +} + +THRIFT_CONVERSION(t_enum) { + THRIFT_ASSIGN_METADATA(); + THRIFT_ASSIGN_LIST_N(t_enum_value, get_constants(), constants); +} + +THRIFT_CONVERSION(t_const_value) { + switch (from->get_type()) { + case t_const_value::CV_INTEGER: + THRIFT_ASSIGN_N(get_integer(), integer_val, ); + break; + case t_const_value::CV_DOUBLE: + THRIFT_ASSIGN_N(get_double(), double_val, ); + break; + case t_const_value::CV_STRING: + THRIFT_ASSIGN_N(get_string(), string_val, ); + break; + case t_const_value::CV_IDENTIFIER: + THRIFT_ASSIGN_ID_N(t_type, enum_, enum_val); + THRIFT_ASSIGN_N(get_identifier(), identifier_val, ); + break; + case t_const_value::CV_MAP: + to.__isset.map_val = true; + if (from && !from->get_map().empty()) { + for (std::map< ::t_const_value*, ::t_const_value*>::const_iterator it + = from->get_map().begin(); + it != from->get_map().end(); + it++) { + to.map_val.insert(std::make_pair(convert(it->first), convert(it->second))); + } + } + break; + case t_const_value::CV_LIST: + to.__isset.list_val = true; + THRIFT_ASSIGN_LIST_N(t_const_value, get_list(), list_val); + break; + default: + throw plugin::ThriftPluginError("const value has no value"); + } +} +THRIFT_CONVERSION(t_const) { + THRIFT_ASSIGN_OPT(doc); + THRIFT_ASSIGN(name); + THRIFT_ASSIGN_ID(type); + THRIFT_ASSIGN_CONVERT(t_const_value, get_value(), value); +} +THRIFT_CONVERSION(t_field) { + THRIFT_ASSIGN_OPT(doc); + THRIFT_ASSIGN(name); + THRIFT_ASSIGN(key); + THRIFT_ASSIGN_N(get_req(), req, (plugin::Requiredness::type)); + THRIFT_ASSIGN(reference); + THRIFT_ASSIGN_ID(type); + THRIFT_ASSIGN_CONVERT(t_const_value, get_value(), value); +} +THRIFT_CONVERSION(t_struct) { + THRIFT_ASSIGN_METADATA(); + THRIFT_ASSIGN_LIST_N(t_field, get_members(), members); + THRIFT_ASSIGN_N(is_union(), is_union, ); + THRIFT_ASSIGN_N(is_xception(), is_xception, ); +} +THRIFT_CONVERSION(t_function) { + THRIFT_ASSIGN_OPT(doc); + THRIFT_ASSIGN(name); + THRIFT_ASSIGN_ID(returntype); + THRIFT_ASSIGN_N(is_oneway(), is_oneway, ); + THRIFT_ASSIGN_ID(arglist); + THRIFT_ASSIGN_ID(xceptions); +} + +THRIFT_CONVERSION(t_list) { + THRIFT_ASSIGN_METADATA(); + THRIFT_ASSIGN_OPT(cpp_name); + THRIFT_ASSIGN_ID(elem_type); +} +THRIFT_CONVERSION(t_set) { + THRIFT_ASSIGN_METADATA(); + THRIFT_ASSIGN_OPT(cpp_name); + THRIFT_ASSIGN_ID(elem_type); +} +THRIFT_CONVERSION(t_map) { + THRIFT_ASSIGN_METADATA(); + THRIFT_ASSIGN_OPT(cpp_name); + THRIFT_ASSIGN_ID(key_type); + THRIFT_ASSIGN_ID(val_type); +} + +THRIFT_CONVERSION(t_service) { + THRIFT_ASSIGN_METADATA(); + THRIFT_ASSIGN_LIST_N(t_function, get_functions(), functions); + THRIFT_ASSIGN_ID_N(t_service, get_extends(), extends_); +} + +THRIFT_CONVERSION(t_base_type) { + THRIFT_ASSIGN_METADATA(); + if (from->is_binary()) { + to.value = plugin::t_base::TYPE_BINARY; + } else { + switch (from->get_base()) { +#define T_BASETYPE_CASE(name) \ + case t_base_type::TYPE_##name: \ + to.value = plugin::t_base::TYPE_##name; \ + break + T_BASETYPE_CASE(VOID); + T_BASETYPE_CASE(STRING); + T_BASETYPE_CASE(BOOL); + T_BASETYPE_CASE(I8); + T_BASETYPE_CASE(I16); + T_BASETYPE_CASE(I32); + T_BASETYPE_CASE(I64); + T_BASETYPE_CASE(DOUBLE); + default: + throw plugin::ThriftPluginError("Base type union has no value"); + break; +#undef T_BASETYPE_CASE + } + } +} +THRIFT_CONVERSION(t_type) { +#define T_CONVERT_UNION_N(name, type) \ + else if (from->is_##name()) { \ + to.__isset.name##_val = true; \ + convert(reinterpret_cast< ::type*>(from), to.name##_val); \ + } +#define T_CONVERT_UNION(name) T_CONVERT_UNION_N(name, t_##name) + if (false) { + } + T_CONVERT_UNION(base_type) + T_CONVERT_UNION(typedef) + T_CONVERT_UNION(enum) + T_CONVERT_UNION(struct) + T_CONVERT_UNION_N(xception, t_struct) + T_CONVERT_UNION(list) + T_CONVERT_UNION(set) + T_CONVERT_UNION(map) + T_CONVERT_UNION(service) + else { + throw plugin::ThriftPluginError("Type union has no value"); + } +#undef T_CONVERT_UNION_N +#undef T_CONVERT_UNION +} + +THRIFT_CONVERSION(t_scope) { +#define T_SCOPE_ASSIGN(name, type) \ + boost::copy(from->name##s_ | boost::adaptors::map_values \ + | boost::adaptors::transformed(&store_type), \ + std::back_inserter(to.name##s)) + T_SCOPE_ASSIGN(type, t_type); + T_SCOPE_ASSIGN(constant, t_const); + T_SCOPE_ASSIGN(service, t_service); +#undef T_SCOPE_ASSIGN +} + +void get_global_cache(plugin::TypeRegistry& reg) { + reg.types = type_cache.cache; + reg.constants = const_cache.cache; + reg.services = service_cache.cache; +} + +void clear_global_cache() { + type_cache.clear(); + const_cache.clear(); + service_cache.clear(); +} + +THRIFT_CONVERSION(t_program) { + THRIFT_ASSIGN_CONVERT(t_scope, scope(), scope); + THRIFT_ASSIGN(path); + THRIFT_ASSIGN(out_path); + THRIFT_ASSIGN(name); + THRIFT_ASSIGN(include_prefix); + THRIFT_ASSIGN(cpp_includes); + THRIFT_ASSIGN(c_includes); + THRIFT_ASSIGN(namespaces); + THRIFT_ASSIGN_N(is_out_path_absolute(), out_path_is_absolute, ); + THRIFT_ASSIGN_N(get_namespace(), namespace_, ); + THRIFT_ASSIGN_LIST_ID(t_type, typedef); + THRIFT_ASSIGN_LIST_ID(t_type, enum); + THRIFT_ASSIGN_LIST_ID(t_type, object); + THRIFT_ASSIGN_LIST_ID(t_const, const); + THRIFT_ASSIGN_LIST_ID(t_service, service); + THRIFT_ASSIGN_LIST_N(t_program, get_includes(), includes); + to.program_id = reinterpret_cast(from); +} + +PluginDelegateResult delegateToPlugin(t_program* program, const std::string& options) { + std::string language; + std::map parsed_options; + t_generator::parse_options(options, language, parsed_options); + std::string cmd = "thrift-gen-"; + if (language.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-0123456789") + != std::string::npos) { + std::cerr << "Invalid language name" << std::endl; + return PLUGIN_FAILURE; + } + cmd.append(language); + FILE* fd = THRIFT_POPEN(cmd.c_str()); + if (fd) { +#ifdef _WIN32 + _setmode(fileno(fd), _O_BINARY); +#endif + shared_ptr transport( + new TFramedTransport(make_shared(fileno(fd)))); + TBinaryProtocol proto(transport); + + plugin::GeneratorInput input; + input.__set_parsed_options(parsed_options); + clear_global_cache(); + convert(program, input.program); + get_global_cache(input.type_registry); + try { + input.write(&proto); + transport->flush(); + } catch (std::exception& err) { + std::cerr << "Error while sending data to plugin: " << err.what() << std::endl; + THRIFT_PCLOSE(fd); + return PLUGIN_FAILURE; + } + + // TODO: be prepared for hang or crash of child process + int ret = THRIFT_PCLOSE(fd); + if (!ret) { + return PLUGIN_SUCCEESS; + } else { + std::cerr << "plugin process returned non zero exit code: " << ret << std::endl; + return PLUGIN_FAILURE; + } + } + clear_global_cache(); + return PLUGIN_NOT_FOUND; +} +} diff --git a/compiler/cpp/src/thrift/plugin/plugin_output.h b/compiler/cpp/src/thrift/plugin/plugin_output.h new file mode 100644 index 0000000..eab2d1b --- /dev/null +++ b/compiler/cpp/src/thrift/plugin/plugin_output.h @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_PLUGIN_PLUGIN_OUTPUT_H +#define T_PLUGIN_PLUGIN_OUTPUT_H + +#include + +class t_program; + +namespace plugin_output { + +enum PluginDelegateResult { + PLUGIN_NOT_FOUND, + PLUGIN_FAILURE, + PLUGIN_SUCCEESS, +}; + +PluginDelegateResult delegateToPlugin(t_program* program, const std::string& options); +} + +#endif diff --git a/compiler/cpp/src/thrift/plugin/type_util.h b/compiler/cpp/src/thrift/plugin/type_util.h new file mode 100644 index 0000000..508b741 --- /dev/null +++ b/compiler/cpp/src/thrift/plugin/type_util.h @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_PLUGIN_TYPE_UTIL_H +#define T_PLUGIN_TYPE_UTIL_H + +namespace apache { +namespace thrift { +namespace plugin { + +template +struct ToType {}; + +template +typename ToType::type* convert_forward(const From&); + +template +void convert(const From&, To*); + +template +typename ToType::type* convert(const From& from); + +class TypeRegistry; +void set_global_cache(const TypeRegistry&); +} +} +} + +// conversion from raw compiler types to plugin wire type +namespace plugin_output { + +template +void convert(From* from, To& to); + +template +typename apache::thrift::plugin::ToType::type convert(From* from); + +void get_global_cache(apache::thrift::plugin::TypeRegistry&); +void clear_global_cache(); +} + +#define THRIFT_TYPE_MAPPING(TYPE) \ + class TYPE; \ + namespace apache { \ + namespace thrift { \ + namespace plugin { \ + class TYPE; \ + template <> \ + struct ToType< ::TYPE> { \ + typedef TYPE type; \ + }; \ + template <> \ + struct ToType { \ + typedef ::TYPE type; \ + }; \ + } \ + } \ + } +THRIFT_TYPE_MAPPING(t_base_type) +THRIFT_TYPE_MAPPING(t_const) +THRIFT_TYPE_MAPPING(t_const_value) +THRIFT_TYPE_MAPPING(t_container) +THRIFT_TYPE_MAPPING(t_doc) +THRIFT_TYPE_MAPPING(t_enum) +THRIFT_TYPE_MAPPING(t_enum_value) +THRIFT_TYPE_MAPPING(t_field) +THRIFT_TYPE_MAPPING(t_function) +THRIFT_TYPE_MAPPING(t_list) +THRIFT_TYPE_MAPPING(t_map) +THRIFT_TYPE_MAPPING(t_program) +THRIFT_TYPE_MAPPING(t_scope) +THRIFT_TYPE_MAPPING(t_service) +THRIFT_TYPE_MAPPING(t_set) +THRIFT_TYPE_MAPPING(t_struct) +THRIFT_TYPE_MAPPING(t_type) +THRIFT_TYPE_MAPPING(t_typedef) +#undef THRIFT_TYPE_MAPPING +#endif diff --git a/compiler/cpp/src/thrift/thriftl.cc b/compiler/cpp/src/thrift/thriftl.cc new file mode 100644 index 0000000..799efcf --- /dev/null +++ b/compiler/cpp/src/thrift/thriftl.cc @@ -0,0 +1,3496 @@ + +#line 3 "thrift/thriftl.cc" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 0 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern yy_size_t yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE yylex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + #define YY_LINENO_REWIND_TO(dst) \ + do {\ + const char *p;\ + for ( p = yy_cp-1; p >= (dst); --p)\ + if ( *p == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +yy_size_t yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart (FILE *input_file ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); +void yy_delete_buffer (YY_BUFFER_STATE b ); +void yy_flush_buffer (YY_BUFFER_STATE b ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state (void ); + +static void yyensure_buffer_stack (void ); +static void yy_load_buffer_state (void ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ); + +void *yyalloc (yy_size_t ); +void *yyrealloc (void *,yy_size_t ); +void yyfree (void * ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap() (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +typedef int yy_state_type; + +#define YY_FLEX_LEX_COMPAT +extern int yylineno; + +int yylineno = 1; + +extern char yytext[]; + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +#if defined(__GNUC__) && __GNUC__ >= 3 +__attribute__((__noreturn__)) +#endif +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + if ( yyleng >= YYLMAX ) \ + YY_FATAL_ERROR( "token too large, exceeds YYLMAX" ); \ + yy_flex_strncpy( yytext, (yytext_ptr), yyleng + 1 ); \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 169 +#define YY_END_OF_BUFFER 170 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[768] = + { 0, + 1, 1, 170, 168, 1, 1, 167, 6, 59, 7, + 8, 166, 168, 168, 163, 163, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 1, 6, 0, 163, 163, 0, 166, 4, + 5, 0, 0, 165, 165, 0, 165, 165, 165, 165, + 165, 165, 165, 73, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 87, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 34, 111, 165, 114, 118, 165, 165, 165, 165, + + 165, 165, 165, 165, 165, 165, 165, 126, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 166, 3, + 5, 164, 165, 61, 165, 165, 165, 165, 165, 165, + 165, 165, 71, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 83, 85, 165, 165, 165, 165, 93, 165, 165, 165, + 165, 165, 165, 165, 165, 105, 165, 165, 165, 165, + 35, 36, 37, 165, 165, 165, 165, 165, 165, 165, + + 165, 43, 165, 165, 165, 122, 165, 124, 125, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 45, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 149, 165, 165, 165, 165, 165, 165, + 154, 155, 165, 165, 165, 165, 165, 165, 161, 165, + 165, 0, 2, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 72, 165, 165, 165, 165, 32, 165, + 33, 77, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 89, 90, 165, 165, + + 165, 165, 165, 165, 165, 54, 165, 102, 165, 165, + 165, 165, 165, 107, 165, 165, 110, 165, 165, 165, + 165, 165, 165, 165, 165, 44, 165, 165, 165, 123, + 165, 165, 165, 128, 165, 165, 165, 165, 165, 165, + 165, 165, 134, 165, 165, 165, 165, 165, 165, 139, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 145, 146, 165, 165, 10, 165, 165, 165, 165, + 165, 165, 165, 31, 165, 158, 165, 160, 165, 165, + 60, 165, 165, 165, 165, 165, 165, 165, 165, 70, + 165, 58, 75, 165, 76, 78, 79, 80, 165, 55, + + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 92, 165, 165, 97, 165, 165, 165, 165, + 165, 9, 165, 104, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 130, 165, 165, 165, 165, 133, 165, + 165, 165, 136, 165, 165, 42, 165, 165, 41, 165, + 165, 165, 165, 142, 165, 165, 147, 165, 165, 150, + 49, 165, 165, 153, 165, 165, 159, 165, 165, 165, + 162, 165, 165, 165, 165, 165, 165, 165, 165, 74, + 40, 165, 165, 165, 165, 165, 165, 165, 165, 86, + + 165, 38, 165, 91, 165, 95, 165, 165, 100, 101, + 165, 165, 165, 165, 109, 165, 113, 165, 115, 165, + 165, 165, 119, 120, 165, 121, 46, 165, 165, 165, + 165, 165, 165, 129, 165, 165, 165, 135, 138, 165, + 165, 140, 165, 141, 39, 48, 143, 165, 52, 165, + 165, 151, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 63, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 82, 84, 165, 88, 165, 165, + 165, 165, 165, 51, 103, 106, 165, 165, 30, 165, + 165, 165, 165, 165, 127, 165, 165, 131, 165, 165, + + 165, 165, 165, 53, 165, 165, 165, 47, 165, 156, + 165, 25, 165, 165, 165, 165, 165, 64, 165, 66, + 165, 165, 69, 165, 81, 165, 165, 14, 165, 165, + 165, 165, 165, 99, 165, 108, 165, 165, 165, 165, + 165, 57, 165, 165, 165, 165, 137, 56, 165, 165, + 165, 165, 152, 157, 165, 165, 165, 165, 62, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 98, + 50, 165, 165, 117, 165, 11, 165, 165, 132, 20, + 165, 165, 165, 148, 29, 165, 165, 165, 165, 67, + 165, 165, 165, 165, 165, 165, 94, 96, 112, 116, + + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 13, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 65, 165, 16, 165, + 165, 165, 15, 21, 165, 165, 165, 165, 144, 165, + 27, 26, 68, 12, 165, 165, 19, 165, 165, 165, + 28, 165, 165, 22, 165, 165, 165, 165, 165, 165, + 17, 18, 165, 24, 165, 23, 0 + } ; + +static yyconst YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 4, 5, 1, 1, 6, 4, 7, + 7, 8, 9, 7, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 17, 19, 17, 7, 7, 7, + 7, 7, 1, 1, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 29, 30, 31, 32, 33, 34, + 29, 35, 36, 37, 38, 29, 29, 29, 29, 29, + 7, 1, 7, 1, 39, 1, 40, 41, 42, 43, + + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 7, 1, 7, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst YY_CHAR yy_meta[66] = + { 0, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, + 1, 4, 4, 4, 4, 4, 4, 4, 4, 5, + 5, 5, 5, 4, 5, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, + 5, 5, 5, 4, 5, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6 + } ; + +static yyconst flex_uint16_t yy_base[774] = + { 0, + 0, 0, 1609, 1610, 64, 66, 1610, 0, 1610, 1610, + 1610, 60, 61, 74, 71, 1545, 1597, 73, 126, 61, + 96, 102, 117, 116, 172, 152, 77, 186, 76, 81, + 78, 154, 110, 173, 167, 204, 185, 120, 205, 104, + 164, 100, 87, 0, 257, 0, 1543, 268, 69, 1597, + 0, 0, 1594, 1593, 82, 276, 245, 84, 287, 166, + 107, 183, 115, 241, 123, 187, 206, 218, 219, 248, + 290, 269, 247, 200, 291, 255, 251, 293, 303, 306, + 304, 311, 313, 314, 315, 317, 318, 316, 91, 88, + 89, 1592, 1591, 319, 335, 1590, 321, 169, 209, 324, + + 310, 328, 322, 325, 329, 337, 330, 1589, 348, 339, + 342, 344, 327, 352, 347, 356, 363, 350, 346, 368, + 373, 390, 395, 398, 400, 407, 408, 410, 411, 412, + 409, 414, 425, 413, 415, 418, 417, 419, 424, 111, + 0, 0, 416, 1588, 93, 421, 457, 424, 226, 467, + 422, 448, 1587, 435, 468, 469, 470, 473, 472, 474, + 476, 480, 479, 481, 482, 484, 486, 487, 488, 489, + 490, 492, 491, 493, 496, 498, 505, 494, 497, 499, + 495, 507, 500, 515, 517, 521, 509, 524, 519, 542, + 1586, 1585, 1584, 546, 552, 554, 549, 560, 558, 564, + + 559, 1583, 561, 562, 563, 1582, 565, 1581, 1580, 566, + 567, 569, 568, 571, 570, 572, 573, 576, 577, 578, + 580, 575, 579, 574, 581, 582, 585, 583, 584, 1579, + 591, 589, 597, 600, 602, 607, 604, 610, 603, 621, + 627, 630, 632, 1578, 634, 643, 639, 644, 647, 648, + 1577, 1576, 645, 651, 650, 654, 655, 656, 1575, 658, + 657, 235, 1610, 659, 660, 663, 662, 667, 679, 664, + 674, 661, 665, 1574, 672, 675, 690, 676, 1573, 692, + 1572, 1571, 699, 700, 703, 704, 702, 705, 706, 709, + 710, 711, 714, 715, 712, 716, 1570, 721, 722, 720, + + 718, 725, 717, 727, 724, 1569, 728, 1568, 729, 731, + 726, 730, 738, 1567, 735, 745, 1566, 742, 739, 741, + 746, 747, 750, 766, 770, 1565, 774, 778, 780, 1564, + 781, 783, 782, 1563, 785, 787, 788, 790, 794, 796, + 792, 798, 1562, 793, 800, 799, 801, 804, 806, 1561, + 802, 805, 808, 807, 809, 810, 816, 813, 817, 821, + 823, 1560, 1559, 818, 819, 1558, 824, 833, 822, 825, + 839, 840, 829, 1557, 842, 1556, 846, 1555, 854, 861, + 1554, 862, 847, 858, 866, 863, 869, 871, 874, 1553, + 882, 1552, 1551, 883, 1550, 1549, 1548, 1547, 887, 1546, + + 889, 890, 892, 893, 895, 896, 900, 901, 906, 902, + 907, 899, 1545, 910, 903, 1544, 908, 911, 905, 909, + 915, 1543, 912, 1542, 919, 914, 913, 917, 918, 923, + 921, 920, 925, 924, 927, 928, 926, 930, 929, 938, + 961, 965, 966, 1541, 968, 970, 972, 973, 1540, 974, + 975, 977, 1539, 976, 978, 1538, 980, 979, 1537, 982, + 984, 988, 985, 1536, 989, 986, 987, 990, 991, 1535, + 1534, 992, 993, 1533, 999, 994, 1532, 998, 1000, 1001, + 1531, 1015, 1008, 1013, 1018, 1020, 1027, 1043, 1044, 1530, + 1529, 1003, 1005, 1051, 1052, 1009, 1053, 1056, 1057, 1528, + + 1058, 1527, 1059, 1526, 1060, 1061, 1062, 1063, 1525, 1064, + 1065, 1066, 1068, 1070, 1524, 1073, 1523, 1074, 1522, 1067, + 1079, 1080, 1521, 1520, 1085, 1519, 1518, 1086, 1078, 1088, + 1075, 1089, 1072, 1517, 1077, 1092, 1096, 1516, 1515, 1098, + 1097, 1514, 1103, 1513, 1512, 1511, 1510, 1081, 1509, 1100, + 1084, 1508, 1122, 1124, 1129, 1132, 1093, 1135, 1137, 1136, + 1138, 1507, 1139, 1140, 1143, 101, 1145, 1141, 1144, 1146, + 1147, 1148, 1149, 1150, 1506, 1505, 1151, 1504, 1154, 1157, + 1160, 1152, 1153, 1503, 1502, 1501, 1155, 1159, 1500, 1161, + 1164, 1171, 1174, 1163, 1499, 1175, 1166, 1498, 1176, 1179, + + 1162, 1181, 1189, 1497, 1199, 1201, 1205, 1496, 1208, 1495, + 1211, 1494, 1212, 1213, 1215, 1216, 1217, 1493, 1219, 1486, + 1221, 1218, 1474, 1223, 1471, 1222, 1225, 1470, 1230, 1232, + 1224, 1226, 1227, 1469, 1233, 1468, 1229, 1235, 1234, 1237, + 1236, 1466, 1243, 1238, 1249, 1251, 1465, 1464, 1253, 1252, + 1255, 1239, 1462, 1461, 1261, 1263, 1265, 1266, 1460, 1267, + 1269, 995, 1280, 1274, 1275, 1281, 1284, 1290, 1291, 1459, + 1458, 1294, 1296, 1457, 1297, 1456, 1299, 1300, 1455, 1454, + 1301, 1303, 1302, 1453, 1452, 1305, 1304, 1308, 1312, 1451, + 1316, 1306, 1313, 1318, 1319, 1321, 1450, 1449, 1446, 1445, + + 1322, 1325, 1333, 1314, 1334, 1336, 1337, 1339, 1338, 1317, + 1340, 1343, 1444, 1352, 1354, 1356, 1360, 1364, 1365, 1362, + 1371, 1372, 1373, 1375, 1374, 1376, 1443, 1381, 1442, 1377, + 1378, 1382, 1440, 1438, 1386, 1383, 1385, 1387, 1436, 1388, + 1435, 1430, 1428, 1071, 1395, 1399, 506, 1390, 1403, 1391, + 501, 1400, 1409, 423, 1412, 1393, 1405, 1413, 1389, 1414, + 349, 333, 1416, 231, 1418, 224, 1610, 1482, 1486, 1488, + 92, 1494, 1497 + } ; + +static yyconst flex_int16_t yy_def[774] = + { 0, + 767, 1, 767, 767, 767, 767, 767, 768, 767, 767, + 767, 769, 767, 767, 769, 15, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 767, 768, 767, 15, 15, 767, 771, 767, + 772, 773, 770, 770, 770, 767, 25, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 767, 767, + 772, 773, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 767, 767, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 770, 770, 770, 0, 767, 767, 767, + 767, 767, 767 + } ; + +static yyconst flex_uint16_t yy_nxt[1676] = + { 0, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 16, 16, 16, 16, 16, 16, 17, + 18, 17, 17, 19, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 20, 21, + 22, 23, 24, 25, 26, 27, 17, 28, 29, 17, + 30, 31, 32, 33, 34, 17, 35, 36, 37, 38, + 39, 40, 41, 42, 17, 43, 43, 43, 43, 45, + 53, 46, 49, 49, 49, 49, 49, 49, 49, 49, + 45, 50, 53, 48, 51, 53, 53, 53, 43, 43, + 53, 53, 48, 53, 48, 49, 55, 53, 53, 59, + + 53, 192, 53, 48, 193, 53, 144, 143, 191, 53, + 53, 53, 48, 53, 48, 97, 53, 100, 262, 53, + 98, 263, 265, 621, 53, 53, 53, 87, 99, 53, + 88, 101, 53, 52, 56, 53, 60, 57, 57, 57, + 57, 57, 57, 57, 57, 65, 61, 138, 62, 66, + 134, 135, 63, 64, 152, 67, 70, 58, 68, 75, + 154, 53, 106, 53, 107, 69, 108, 71, 157, 76, + 72, 73, 129, 53, 74, 53, 53, 130, 53, 77, + 56, 53, 53, 57, 57, 57, 57, 57, 57, 57, + 57, 81, 53, 102, 53, 53, 53, 103, 89, 82, + + 90, 104, 83, 91, 92, 84, 115, 105, 85, 53, + 116, 86, 109, 53, 53, 53, 110, 136, 53, 111, + 200, 137, 78, 151, 79, 153, 117, 53, 53, 112, + 93, 126, 113, 53, 80, 53, 114, 94, 95, 158, + 53, 127, 262, 96, 131, 263, 169, 118, 128, 270, + 53, 119, 132, 767, 120, 121, 53, 53, 133, 159, + 53, 160, 122, 123, 53, 124, 201, 125, 49, 49, + 49, 49, 49, 49, 49, 49, 56, 161, 53, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 54, 53, 54, 155, 53, + + 53, 168, 53, 174, 156, 162, 163, 54, 145, 146, + 166, 147, 53, 53, 173, 53, 148, 149, 150, 53, + 53, 167, 53, 53, 53, 53, 53, 53, 53, 164, + 53, 53, 170, 53, 53, 171, 53, 53, 53, 53, + 175, 172, 53, 165, 53, 177, 53, 180, 53, 181, + 176, 53, 203, 53, 183, 53, 53, 53, 53, 53, + 178, 53, 179, 184, 182, 53, 185, 218, 187, 188, + 186, 189, 53, 194, 190, 208, 195, 53, 202, 204, + 210, 199, 53, 206, 207, 196, 205, 209, 211, 212, + 219, 216, 197, 198, 220, 214, 215, 217, 221, 53, + + 227, 222, 228, 226, 53, 213, 229, 53, 230, 53, + 231, 223, 233, 224, 225, 232, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 234, + 53, 53, 53, 53, 53, 139, 139, 139, 139, 139, + 139, 139, 139, 264, 53, 237, 235, 242, 266, 236, + 239, 269, 238, 246, 240, 251, 256, 53, 247, 260, + 257, 248, 261, 241, 245, 252, 53, 243, 249, 250, + 253, 244, 254, 258, 259, 255, 53, 53, 53, 53, + 272, 53, 53, 53, 267, 53, 271, 273, 53, 53, + 53, 53, 274, 53, 268, 53, 53, 53, 53, 53, + + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 275, 278, 280, 53, 53, 53, 277, 53, 281, + 283, 276, 279, 282, 53, 289, 53, 290, 53, 292, + 53, 295, 296, 53, 285, 293, 308, 286, 284, 291, + 297, 298, 307, 287, 288, 299, 294, 300, 306, 301, + 309, 53, 302, 305, 311, 53, 312, 310, 53, 316, + 314, 53, 303, 53, 313, 315, 304, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 317, 318, 324, 53, 319, + + 53, 321, 320, 323, 325, 328, 53, 322, 336, 53, + 329, 53, 53, 53, 332, 346, 53, 326, 333, 53, + 327, 335, 344, 330, 337, 334, 340, 331, 341, 350, + 53, 339, 338, 343, 353, 342, 53, 347, 345, 53, + 348, 53, 351, 53, 352, 349, 354, 355, 53, 357, + 359, 361, 53, 53, 53, 362, 53, 53, 356, 53, + 53, 358, 360, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 366, 53, 367, 363, 382, + 364, 53, 365, 53, 53, 53, 368, 370, 53, 375, + 381, 384, 369, 374, 371, 372, 379, 383, 385, 53, + + 387, 53, 378, 373, 388, 377, 376, 380, 53, 53, + 386, 53, 53, 53, 53, 53, 392, 389, 53, 53, + 53, 53, 390, 53, 53, 53, 53, 53, 391, 53, + 53, 53, 394, 53, 53, 53, 53, 53, 53, 53, + 53, 395, 393, 399, 53, 396, 398, 53, 53, 406, + 53, 53, 401, 402, 53, 53, 53, 397, 403, 53, + 400, 409, 410, 414, 404, 405, 413, 411, 412, 416, + 407, 415, 408, 418, 422, 53, 423, 425, 417, 53, + 419, 421, 420, 53, 427, 428, 432, 53, 424, 53, + 53, 53, 53, 426, 53, 429, 53, 53, 431, 53, + + 430, 53, 53, 53, 434, 53, 433, 53, 53, 53, + 53, 53, 435, 53, 53, 53, 53, 53, 53, 53, + 439, 441, 53, 442, 436, 53, 53, 53, 53, 445, + 53, 53, 53, 53, 53, 437, 440, 446, 53, 443, + 438, 449, 53, 447, 455, 448, 444, 451, 53, 53, + 450, 53, 457, 456, 463, 53, 53, 461, 452, 460, + 454, 458, 465, 53, 453, 459, 469, 53, 462, 466, + 53, 53, 53, 464, 471, 53, 468, 470, 53, 467, + 53, 484, 472, 53, 473, 483, 486, 485, 475, 477, + 474, 53, 53, 478, 488, 487, 53, 482, 53, 53, + + 476, 53, 53, 481, 53, 53, 479, 480, 53, 53, + 53, 53, 53, 489, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 492, 53, 53, 53, 53, + 53, 495, 53, 53, 53, 53, 53, 53, 53, 53, + 490, 493, 494, 504, 500, 502, 491, 53, 509, 497, + 499, 505, 498, 501, 503, 507, 496, 511, 508, 506, + 513, 514, 512, 515, 519, 518, 523, 510, 516, 521, + 53, 524, 520, 526, 53, 53, 517, 53, 522, 53, + 525, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 528, 53, 527, 53, 53, 53, 53, 53, 53, 53, + + 53, 53, 53, 53, 53, 531, 529, 53, 53, 53, + 53, 533, 53, 534, 53, 535, 691, 53, 53, 530, + 538, 541, 53, 542, 53, 544, 532, 53, 539, 53, + 540, 537, 536, 545, 551, 547, 53, 550, 554, 558, + 543, 555, 548, 546, 549, 553, 562, 559, 556, 552, + 561, 563, 53, 53, 564, 560, 557, 569, 565, 566, + 53, 53, 53, 573, 570, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 567, 53, + 53, 53, 53, 53, 53, 568, 53, 53, 53, 53, + 53, 574, 571, 53, 53, 53, 577, 53, 53, 575, + + 578, 53, 53, 572, 580, 53, 53, 53, 590, 53, + 579, 583, 53, 582, 586, 576, 588, 589, 591, 592, + 581, 595, 584, 587, 593, 594, 597, 596, 608, 585, + 599, 53, 598, 53, 606, 601, 600, 603, 53, 602, + 604, 53, 605, 607, 53, 53, 53, 53, 53, 53, + 53, 613, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 609, 53, 619, 53, 53, + 53, 53, 53, 53, 610, 53, 617, 618, 622, 611, + 53, 620, 612, 53, 53, 53, 614, 615, 53, 625, + 53, 627, 628, 631, 616, 634, 632, 626, 53, 623, + + 624, 633, 629, 630, 638, 639, 635, 636, 53, 644, + 53, 637, 640, 642, 53, 641, 643, 53, 647, 645, + 53, 53, 53, 648, 53, 53, 53, 53, 53, 646, + 53, 53, 53, 53, 53, 53, 53, 662, 53, 53, + 649, 53, 53, 53, 53, 53, 53, 53, 53, 650, + 653, 660, 53, 651, 654, 659, 656, 652, 53, 661, + 53, 53, 53, 658, 53, 657, 663, 669, 655, 666, + 53, 667, 53, 670, 53, 53, 53, 674, 53, 676, + 668, 664, 665, 53, 53, 671, 675, 672, 673, 53, + 53, 679, 677, 53, 680, 678, 681, 684, 689, 53, + + 53, 682, 683, 53, 687, 53, 53, 690, 53, 53, + 53, 53, 53, 53, 53, 53, 693, 53, 685, 688, + 686, 53, 53, 53, 692, 53, 53, 53, 53, 694, + 53, 53, 695, 697, 53, 696, 701, 698, 702, 711, + 700, 705, 53, 53, 708, 53, 53, 53, 53, 53, + 710, 699, 53, 712, 703, 727, 713, 714, 704, 707, + 709, 53, 715, 53, 716, 53, 706, 717, 720, 53, + 718, 53, 719, 53, 53, 721, 724, 726, 728, 723, + 53, 53, 53, 53, 53, 53, 53, 53, 722, 725, + 53, 53, 53, 730, 53, 53, 53, 53, 53, 53, + + 53, 736, 53, 733, 53, 729, 735, 734, 53, 53, + 737, 731, 53, 732, 53, 739, 740, 741, 53, 743, + 744, 53, 53, 53, 748, 53, 742, 53, 738, 747, + 750, 751, 745, 754, 752, 756, 746, 53, 753, 53, + 760, 757, 763, 749, 53, 53, 755, 53, 761, 53, + 758, 53, 53, 53, 53, 53, 762, 759, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 765, 53, 53, 53, 764, 53, 53, 53, + 53, 766, 44, 53, 44, 44, 44, 44, 47, 47, + 54, 54, 54, 54, 141, 53, 141, 141, 141, 141, + + 142, 142, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + + 53, 53, 53, 767, 140, 767, 53, 767, 767, 3, + 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, + 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, + 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, + 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, + 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, + 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, + 767, 767, 767, 767, 767 + } ; + +static yyconst flex_int16_t yy_chk[1676] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5, 5, 6, 6, 12, + 20, 12, 13, 13, 13, 13, 13, 13, 13, 13, + 15, 14, 18, 12, 14, 29, 27, 31, 43, 43, + 30, 55, 49, 58, 15, 771, 18, 90, 91, 20, + + 89, 90, 145, 12, 91, 21, 58, 55, 89, 42, + 566, 22, 49, 40, 15, 29, 61, 31, 140, 33, + 30, 140, 145, 566, 63, 24, 23, 27, 30, 38, + 27, 31, 65, 15, 19, 19, 21, 19, 19, 19, + 19, 19, 19, 19, 19, 22, 21, 42, 21, 22, + 40, 40, 21, 21, 61, 22, 23, 19, 22, 24, + 63, 26, 33, 32, 33, 22, 33, 23, 65, 24, + 23, 23, 38, 41, 23, 60, 35, 38, 98, 24, + 25, 25, 34, 25, 25, 25, 25, 25, 25, 25, + 25, 26, 62, 32, 37, 28, 66, 32, 28, 26, + + 28, 32, 26, 28, 28, 26, 35, 32, 26, 74, + 35, 26, 34, 36, 39, 67, 34, 41, 99, 34, + 98, 41, 25, 60, 25, 62, 35, 68, 69, 34, + 28, 37, 34, 766, 25, 149, 34, 28, 28, 66, + 764, 37, 262, 28, 39, 262, 74, 36, 37, 149, + 64, 36, 39, 57, 36, 36, 73, 70, 39, 67, + 77, 68, 36, 36, 76, 36, 99, 36, 45, 45, + 45, 45, 45, 45, 45, 45, 48, 69, 72, 48, + 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, + 56, 56, 56, 56, 56, 57, 59, 57, 64, 71, + + 75, 73, 78, 77, 64, 70, 70, 57, 59, 59, + 72, 59, 79, 81, 76, 80, 59, 59, 59, 101, + 82, 72, 83, 84, 85, 88, 86, 87, 94, 71, + 97, 103, 75, 100, 104, 75, 113, 102, 105, 107, + 78, 75, 762, 71, 95, 79, 106, 80, 110, 80, + 78, 111, 101, 112, 81, 119, 115, 109, 761, 118, + 79, 114, 79, 82, 80, 116, 83, 113, 85, 86, + 84, 87, 117, 94, 88, 104, 95, 120, 100, 102, + 106, 97, 121, 103, 103, 95, 102, 105, 107, 109, + 114, 112, 95, 95, 115, 110, 111, 112, 116, 122, + + 118, 116, 118, 117, 123, 109, 118, 124, 118, 125, + 119, 116, 121, 116, 116, 120, 126, 127, 131, 128, + 129, 130, 134, 132, 135, 143, 137, 136, 138, 122, + 146, 151, 754, 148, 133, 139, 139, 139, 139, 139, + 139, 139, 139, 143, 154, 124, 122, 127, 146, 123, + 126, 148, 125, 129, 126, 130, 134, 152, 129, 137, + 134, 129, 138, 126, 128, 131, 147, 127, 129, 129, + 132, 127, 133, 135, 136, 133, 150, 155, 156, 157, + 151, 159, 158, 160, 147, 161, 150, 152, 163, 162, + 164, 165, 154, 166, 147, 167, 168, 169, 170, 171, + + 173, 172, 174, 178, 181, 175, 179, 176, 180, 183, + 751, 155, 158, 160, 177, 747, 182, 157, 187, 161, + 163, 156, 159, 162, 184, 168, 185, 169, 189, 171, + 186, 173, 174, 188, 165, 172, 181, 166, 164, 170, + 175, 176, 180, 167, 167, 176, 172, 177, 179, 177, + 182, 190, 177, 178, 184, 194, 185, 183, 197, 189, + 187, 195, 177, 196, 186, 188, 177, 199, 201, 198, + 203, 204, 205, 200, 207, 210, 211, 213, 212, 215, + 214, 216, 217, 224, 222, 218, 219, 220, 223, 221, + 225, 226, 228, 229, 227, 190, 194, 199, 232, 194, + + 231, 196, 195, 198, 200, 204, 233, 197, 215, 234, + 205, 235, 239, 237, 211, 224, 236, 201, 212, 238, + 203, 214, 222, 207, 216, 213, 218, 210, 219, 227, + 240, 217, 216, 221, 231, 220, 241, 225, 223, 242, + 225, 243, 228, 245, 229, 226, 232, 233, 247, 235, + 236, 238, 246, 248, 253, 239, 249, 250, 234, 255, + 254, 235, 237, 256, 257, 258, 261, 260, 264, 265, + 272, 267, 266, 270, 273, 243, 268, 245, 240, 265, + 241, 275, 242, 271, 276, 278, 246, 248, 269, 255, + 264, 267, 247, 254, 249, 250, 260, 266, 268, 277, + + 270, 280, 258, 253, 271, 257, 256, 261, 283, 284, + 269, 287, 285, 286, 288, 289, 276, 272, 290, 291, + 292, 295, 273, 293, 294, 296, 303, 301, 275, 300, + 298, 299, 278, 305, 302, 311, 304, 307, 309, 312, + 310, 280, 277, 286, 315, 283, 285, 313, 319, 291, + 320, 318, 288, 289, 316, 321, 322, 284, 289, 323, + 287, 294, 295, 300, 289, 290, 299, 296, 298, 302, + 292, 301, 293, 304, 310, 324, 311, 313, 303, 325, + 305, 309, 307, 327, 316, 318, 322, 328, 312, 329, + 331, 333, 332, 315, 335, 319, 336, 337, 321, 338, + + 320, 341, 344, 339, 324, 340, 323, 342, 346, 345, + 347, 351, 325, 348, 352, 349, 354, 353, 355, 356, + 331, 333, 358, 335, 327, 357, 359, 364, 365, 338, + 360, 369, 361, 367, 370, 328, 332, 339, 373, 336, + 329, 342, 368, 340, 349, 341, 337, 345, 371, 372, + 344, 375, 352, 351, 358, 377, 383, 356, 346, 355, + 348, 353, 360, 379, 347, 354, 367, 384, 357, 361, + 380, 382, 386, 359, 369, 385, 365, 368, 387, 364, + 388, 384, 370, 389, 371, 383, 386, 385, 373, 377, + 372, 391, 394, 379, 388, 387, 399, 382, 401, 402, + + 375, 403, 404, 380, 405, 406, 379, 379, 412, 407, + 408, 410, 415, 389, 419, 409, 411, 417, 420, 414, + 418, 423, 427, 426, 421, 399, 428, 429, 425, 432, + 431, 403, 430, 434, 433, 437, 435, 436, 439, 438, + 391, 401, 402, 412, 408, 410, 394, 440, 419, 405, + 407, 414, 406, 409, 411, 417, 404, 421, 418, 415, + 425, 426, 423, 427, 431, 430, 435, 420, 428, 433, + 441, 436, 432, 438, 442, 443, 429, 445, 434, 446, + 437, 447, 448, 450, 451, 454, 452, 455, 458, 457, + 440, 460, 439, 461, 463, 466, 467, 462, 465, 468, + + 469, 472, 473, 476, 662, 443, 441, 478, 475, 479, + 480, 446, 492, 447, 493, 448, 662, 483, 496, 442, + 452, 457, 484, 458, 482, 461, 445, 485, 454, 486, + 455, 451, 450, 462, 469, 465, 487, 468, 475, 479, + 460, 476, 466, 463, 467, 473, 483, 479, 478, 472, + 482, 484, 488, 489, 485, 480, 478, 492, 486, 487, + 494, 495, 497, 496, 493, 498, 499, 501, 503, 505, + 506, 507, 508, 510, 511, 512, 520, 513, 488, 514, + 744, 533, 516, 518, 531, 489, 535, 529, 521, 522, + 548, 497, 494, 551, 525, 528, 501, 530, 532, 498, + + 503, 536, 557, 495, 506, 537, 541, 540, 520, 550, + 505, 510, 543, 508, 513, 499, 516, 518, 521, 522, + 507, 529, 511, 514, 525, 528, 531, 530, 551, 512, + 533, 553, 532, 554, 548, 536, 535, 540, 555, 537, + 541, 556, 543, 550, 558, 560, 559, 561, 563, 564, + 568, 557, 565, 569, 567, 570, 571, 572, 573, 574, + 577, 582, 583, 579, 587, 553, 580, 564, 588, 581, + 590, 601, 594, 591, 554, 597, 561, 563, 567, 555, + 592, 565, 556, 593, 596, 599, 558, 559, 600, 570, + 602, 572, 573, 579, 560, 582, 580, 571, 603, 568, + + 569, 581, 574, 577, 590, 591, 583, 587, 605, 597, + 606, 588, 592, 594, 607, 593, 596, 609, 601, 599, + 611, 613, 614, 602, 615, 616, 617, 622, 619, 600, + 621, 626, 624, 631, 627, 632, 633, 622, 637, 629, + 603, 630, 635, 639, 638, 641, 640, 644, 652, 605, + 609, 619, 643, 606, 611, 617, 614, 607, 645, 621, + 646, 650, 649, 616, 651, 615, 624, 632, 613, 629, + 655, 630, 656, 633, 657, 658, 660, 639, 661, 641, + 631, 626, 627, 664, 665, 635, 640, 637, 638, 663, + 666, 645, 643, 667, 646, 644, 649, 652, 660, 668, + + 669, 650, 651, 672, 657, 673, 675, 661, 677, 678, + 681, 683, 682, 687, 686, 692, 664, 688, 655, 658, + 656, 689, 693, 704, 663, 691, 710, 694, 695, 665, + 696, 701, 666, 668, 702, 667, 675, 669, 677, 691, + 673, 682, 703, 705, 687, 706, 707, 709, 708, 711, + 689, 672, 712, 692, 678, 710, 693, 694, 681, 686, + 688, 714, 695, 715, 696, 716, 683, 701, 704, 717, + 702, 720, 703, 718, 719, 705, 707, 709, 711, 706, + 721, 722, 723, 725, 724, 726, 730, 731, 705, 708, + 728, 732, 736, 714, 737, 735, 738, 740, 759, 748, + + 750, 720, 756, 717, 745, 712, 719, 718, 746, 752, + 721, 715, 749, 716, 757, 723, 724, 725, 753, 728, + 730, 755, 758, 760, 736, 763, 726, 765, 722, 735, + 738, 740, 731, 748, 745, 750, 732, 743, 746, 742, + 756, 752, 759, 737, 741, 739, 749, 734, 757, 733, + 753, 729, 727, 713, 700, 699, 758, 755, 698, 697, + 690, 685, 684, 680, 679, 676, 674, 671, 670, 659, + 654, 653, 763, 648, 647, 642, 760, 636, 634, 628, + 625, 765, 768, 623, 768, 768, 768, 768, 769, 769, + 770, 770, 770, 770, 772, 620, 772, 772, 772, 772, + + 773, 773, 618, 612, 610, 608, 604, 598, 595, 589, + 586, 585, 584, 578, 576, 575, 562, 552, 549, 547, + 546, 545, 544, 542, 539, 538, 534, 527, 526, 524, + 523, 519, 517, 515, 509, 504, 502, 500, 491, 490, + 481, 477, 474, 471, 470, 464, 459, 456, 453, 449, + 444, 424, 422, 416, 413, 400, 398, 397, 396, 395, + 393, 392, 390, 381, 378, 376, 374, 366, 363, 362, + 350, 343, 334, 330, 326, 317, 314, 308, 306, 297, + 282, 281, 279, 274, 259, 252, 251, 244, 230, 209, + 208, 206, 202, 193, 192, 191, 153, 144, 108, 96, + + 93, 92, 54, 53, 50, 47, 17, 16, 3, 767, + 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, + 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, + 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, + 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, + 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, + 767, 767, 767, 767, 767, 767, 767, 767, 767, 767, + 767, 767, 767, 767, 767 + } ; + +/* Table of booleans, true if rule could match eol. */ +static yyconst flex_int32_t yy_rule_can_match_eol[170] = + { 0, +1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#ifndef YYLMAX +#define YYLMAX 8192 +#endif + +char yytext[YYLMAX]; +char *yytext_ptr; +#line 1 "thrift/thriftl.ll" +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +/** + * Thrift scanner. + * + * Tokenizes a thrift definition file. + */ +#line 27 "thrift/thriftl.ll" + +/* This is redundant with some of the flags in Makefile.am, but it works + * when people override CXXFLAGS without being careful. The pragmas are + * the 'right' way to do it, but don't work on old-enough GCC (in particular + * the GCC that ship on Mac OS X 10.6.5, *counter* to what the GNU docs say) + * + * We should revert the Makefile.am changes once Apple ships a reasonable + * GCC. + */ +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-label" +#endif + +#ifdef _MSC_VER +#pragma warning( push ) + +// warning C4102: 'find_rule' : unreferenced label +#pragma warning( disable : 4102 ) + +// warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data +#pragma warning( disable : 4267 ) + +// avoid isatty redefinition +#define YY_NEVER_INTERACTIVE 1 + +#define YY_NO_UNISTD_H 1 +#endif + +#include +#include +#include +#include + +#ifdef _MSC_VER +#include "thrift/windows/config.h" +#endif +#include "thrift/main.h" +#include "thrift/common.h" +#include "thrift/globals.h" +#include "thrift/parse/t_program.h" + +/** + * Must be included AFTER parse/t_program.h, but I can't remember why anymore + * because I wrote this a while ago. + */ +#if defined(BISON_USE_PARSER_H_EXTENSION) +#include "thrift/thrifty.h" +#else +#include "thrift/thrifty.hh" +#endif + +void thrift_reserved_keyword(char* keyword) { + yyerror("Cannot use reserved language keyword: \"%s\"\n", keyword); + exit(1); +} + +void integer_overflow(char* text) { + yyerror("This integer is too big: \"%s\"\n", text); + exit(1); +} + +void unexpected_token(char* text) { + yyerror("Unexpected token in input: \"%s\"\n", text); + exit(1); +} + +/** + * Provides the yylineno global, useful for debugging output + */ +/** + * Our inputs are all single files, so no need for yywrap + */ +/** + * We don't use it, and it fires up warnings at -Wall + */ +/** + * Helper definitions, comments, constants, and whatnot + */ +#line 1231 "thrift/thriftl.cc" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (void ); + +int yyget_debug (void ); + +void yyset_debug (int debug_flag ); + +YY_EXTRA_TYPE yyget_extra (void ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in (void ); + +void yyset_in (FILE * _in_str ); + +FILE *yyget_out (void ); + +void yyset_out (FILE * _out_str ); + +yy_size_t yyget_leng (void ); + +char *yyget_text (void ); + +int yyget_lineno (void ); + +void yyset_lineno (int _line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (void ); +#else +extern int yywrap (void ); +#endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + { +#line 128 "thrift/thriftl.ll" + + +#line 1450 "thrift/thriftl.cc" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 768 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 1610 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + yy_size_t yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + yylineno++; +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +/* rule 1 can match eol */ +YY_RULE_SETUP +#line 130 "thrift/thriftl.ll" +{ /* do nothing */ } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 131 "thrift/thriftl.ll" +{ /* do nothing */ } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 133 "thrift/thriftl.ll" +{ + std::string parsed("/**"); + int state = 0; // 0 = normal, 1 = "*" seen, "*/" seen + while(state < 2) + { + int ch = yyinput(); + parsed.push_back(ch); + switch (ch) { + case EOF: + yyerror("Unexpected end of file in doc-comment at %d\n", yylineno); + exit(1); + case '*': + state = 1; + break; + case '/': + state = (state == 1) ? 2 : 0; + break; + default: + state = 0; + break; + } + } + pdebug("doctext = \"%s\"\n",parsed.c_str()); + + /* This does not show up in the parse tree. */ + /* Rather, the parser will grab it out of the global. */ + if (g_parse_mode == PROGRAM) { + clear_doctext(); + g_doctext = strdup(parsed.c_str() + 3); + assert(strlen(g_doctext) >= 2); + g_doctext[strlen(g_doctext) - 2] = ' '; + g_doctext[strlen(g_doctext) - 1] = '\0'; + g_doctext = clean_up_doctext(g_doctext); + g_doctext_lineno = yylineno; + if( (g_program_doctext_candidate == NULL) && (g_program_doctext_status == INVALID)){ + g_program_doctext_candidate = strdup(g_doctext); + g_program_doctext_lineno = g_doctext_lineno; + g_program_doctext_status = STILL_CANDIDATE; + pdebug("%s","program doctext set to STILL_CANDIDATE"); + } + } +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 176 "thrift/thriftl.ll" +{ /* parsed, but thrown away */ + std::string parsed("/*"); + int state = 0; // 0 = normal, 1 = "*" seen, "*/" seen + while(state < 2) + { + int ch = yyinput(); + parsed.push_back(ch); + switch (ch) { + case EOF: + yyerror("Unexpected end of file in multiline comment at %d\n", yylineno); + exit(1); + case '*': + state = 1; + break; + case '/': + state = (state == 1) ? 2 : 0; + break; + default: + state = 0; + break; + } + } + pdebug("multi_comm = \"%s\"\n",parsed.c_str()); +} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 201 "thrift/thriftl.ll" +{ /* do nothing */ } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 202 "thrift/thriftl.ll" +{ /* do nothing */ } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 204 "thrift/thriftl.ll" +{ return yytext[0]; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 205 "thrift/thriftl.ll" +{ return yytext[0]; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 207 "thrift/thriftl.ll" +{ yylval.iconst=0; return tok_int_constant; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 208 "thrift/thriftl.ll" +{ yylval.iconst=1; return tok_int_constant; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 210 "thrift/thriftl.ll" +{ return tok_namespace; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 211 "thrift/thriftl.ll" +{ error_unsupported_namespace_decl("cpp"); /* do nothing */ } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 212 "thrift/thriftl.ll" +{ return tok_cpp_include; } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 213 "thrift/thriftl.ll" +{ return tok_cpp_type; } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 214 "thrift/thriftl.ll" +{ error_unsupported_namespace_decl("java_package", "java"); /* do nothing */ } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 215 "thrift/thriftl.ll" +{ error_unsupported_namespace_decl("cocoa_prefix", "cocoa"); /* do nothing */ } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 216 "thrift/thriftl.ll" +{ error_unsupported_namespace_decl("csharp"); /* do nothing */ } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 217 "thrift/thriftl.ll" +{ error_unsupported_namespace_decl("delphi"); /* do nothing */ } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 218 "thrift/thriftl.ll" +{ error_unsupported_namespace_decl("php"); /* do nothing */ } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 219 "thrift/thriftl.ll" +{ error_unsupported_namespace_decl("py_module", "py"); /* do nothing */ } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 220 "thrift/thriftl.ll" +{ error_unsupported_namespace_decl("perl_package", "perl"); /* do nothing */ } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 221 "thrift/thriftl.ll" +{ error_unsupported_namespace_decl("ruby"); /* do nothing */ } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 222 "thrift/thriftl.ll" +{ error_unsupported_namespace_decl("smalltalk_category", "smalltalk.category"); /* do nothing */ } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 223 "thrift/thriftl.ll" +{ error_unsupported_namespace_decl("smalltalk_category", "smalltalk.category"); /* do nothing */ } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 224 "thrift/thriftl.ll" +{ return tok_xsd_all; } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 225 "thrift/thriftl.ll" +{ return tok_xsd_optional; } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 226 "thrift/thriftl.ll" +{ return tok_xsd_nillable; } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 227 "thrift/thriftl.ll" +{ error_unsupported_namespace_decl("xsd"); /* do nothing */ } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 228 "thrift/thriftl.ll" +{ return tok_xsd_attrs; } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 229 "thrift/thriftl.ll" +{ return tok_include; } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 230 "thrift/thriftl.ll" +{ return tok_void; } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 231 "thrift/thriftl.ll" +{ return tok_bool; } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 232 "thrift/thriftl.ll" +{ + emit_byte_type_warning(); + return tok_i8; +} + YY_BREAK +case 34: +YY_RULE_SETUP +#line 236 "thrift/thriftl.ll" +{ return tok_i8; } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 237 "thrift/thriftl.ll" +{ return tok_i16; } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 238 "thrift/thriftl.ll" +{ return tok_i32; } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 239 "thrift/thriftl.ll" +{ return tok_i64; } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 240 "thrift/thriftl.ll" +{ return tok_double; } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 241 "thrift/thriftl.ll" +{ return tok_string; } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 242 "thrift/thriftl.ll" +{ return tok_binary; } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 243 "thrift/thriftl.ll" +{ + pwarning(0, "\"slist\" is deprecated and will be removed in a future compiler version. This type should be replaced with \"string\".\n"); + return tok_slist; +} + YY_BREAK +case 42: +YY_RULE_SETUP +#line 247 "thrift/thriftl.ll" +{ + pwarning(0, "\"senum\" is deprecated and will be removed in a future compiler version. This type should be replaced with \"string\".\n"); + return tok_senum; +} + YY_BREAK +case 43: +YY_RULE_SETUP +#line 251 "thrift/thriftl.ll" +{ return tok_map; } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 252 "thrift/thriftl.ll" +{ return tok_list; } + YY_BREAK +case 45: +YY_RULE_SETUP +#line 253 "thrift/thriftl.ll" +{ return tok_set; } + YY_BREAK +case 46: +YY_RULE_SETUP +#line 254 "thrift/thriftl.ll" +{ return tok_oneway; } + YY_BREAK +case 47: +YY_RULE_SETUP +#line 255 "thrift/thriftl.ll" +{ return tok_typedef; } + YY_BREAK +case 48: +YY_RULE_SETUP +#line 256 "thrift/thriftl.ll" +{ return tok_struct; } + YY_BREAK +case 49: +YY_RULE_SETUP +#line 257 "thrift/thriftl.ll" +{ return tok_union; } + YY_BREAK +case 50: +YY_RULE_SETUP +#line 258 "thrift/thriftl.ll" +{ return tok_xception; } + YY_BREAK +case 51: +YY_RULE_SETUP +#line 259 "thrift/thriftl.ll" +{ return tok_extends; } + YY_BREAK +case 52: +YY_RULE_SETUP +#line 260 "thrift/thriftl.ll" +{ return tok_throws; } + YY_BREAK +case 53: +YY_RULE_SETUP +#line 261 "thrift/thriftl.ll" +{ return tok_service; } + YY_BREAK +case 54: +YY_RULE_SETUP +#line 262 "thrift/thriftl.ll" +{ return tok_enum; } + YY_BREAK +case 55: +YY_RULE_SETUP +#line 263 "thrift/thriftl.ll" +{ return tok_const; } + YY_BREAK +case 56: +YY_RULE_SETUP +#line 264 "thrift/thriftl.ll" +{ return tok_required; } + YY_BREAK +case 57: +YY_RULE_SETUP +#line 265 "thrift/thriftl.ll" +{ return tok_optional; } + YY_BREAK +case 58: +YY_RULE_SETUP +#line 266 "thrift/thriftl.ll" +{ + pwarning(0, "\"async\" is deprecated. It is called \"oneway\" now.\n"); + return tok_oneway; +} + YY_BREAK +case 59: +YY_RULE_SETUP +#line 270 "thrift/thriftl.ll" +{ return tok_reference; } + YY_BREAK +case 60: +YY_RULE_SETUP +#line 273 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 61: +YY_RULE_SETUP +#line 274 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 62: +YY_RULE_SETUP +#line 275 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 63: +YY_RULE_SETUP +#line 276 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 64: +YY_RULE_SETUP +#line 277 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 65: +YY_RULE_SETUP +#line 278 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 66: +YY_RULE_SETUP +#line 279 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 67: +YY_RULE_SETUP +#line 280 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 68: +YY_RULE_SETUP +#line 281 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 69: +YY_RULE_SETUP +#line 282 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 70: +YY_RULE_SETUP +#line 283 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 71: +YY_RULE_SETUP +#line 284 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 72: +YY_RULE_SETUP +#line 285 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 73: +YY_RULE_SETUP +#line 286 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 74: +YY_RULE_SETUP +#line 287 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 75: +YY_RULE_SETUP +#line 288 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 76: +YY_RULE_SETUP +#line 289 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 77: +YY_RULE_SETUP +#line 290 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 78: +YY_RULE_SETUP +#line 291 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 79: +YY_RULE_SETUP +#line 292 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 80: +YY_RULE_SETUP +#line 293 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 81: +YY_RULE_SETUP +#line 294 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 82: +YY_RULE_SETUP +#line 295 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 83: +YY_RULE_SETUP +#line 296 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 84: +YY_RULE_SETUP +#line 297 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 85: +YY_RULE_SETUP +#line 298 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 86: +YY_RULE_SETUP +#line 299 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 87: +YY_RULE_SETUP +#line 300 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 88: +YY_RULE_SETUP +#line 301 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 89: +YY_RULE_SETUP +#line 302 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 90: +YY_RULE_SETUP +#line 303 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 91: +YY_RULE_SETUP +#line 304 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 92: +YY_RULE_SETUP +#line 305 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 93: +YY_RULE_SETUP +#line 306 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 94: +YY_RULE_SETUP +#line 307 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 95: +YY_RULE_SETUP +#line 308 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 96: +YY_RULE_SETUP +#line 309 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 97: +YY_RULE_SETUP +#line 310 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 98: +YY_RULE_SETUP +#line 311 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 99: +YY_RULE_SETUP +#line 312 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 100: +YY_RULE_SETUP +#line 313 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 101: +YY_RULE_SETUP +#line 314 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 102: +YY_RULE_SETUP +#line 315 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 103: +YY_RULE_SETUP +#line 316 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 104: +YY_RULE_SETUP +#line 317 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 105: +YY_RULE_SETUP +#line 318 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 106: +YY_RULE_SETUP +#line 319 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 107: +YY_RULE_SETUP +#line 320 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 108: +YY_RULE_SETUP +#line 321 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 109: +YY_RULE_SETUP +#line 322 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 110: +YY_RULE_SETUP +#line 323 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 111: +YY_RULE_SETUP +#line 324 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 112: +YY_RULE_SETUP +#line 325 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 113: +YY_RULE_SETUP +#line 326 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 114: +YY_RULE_SETUP +#line 327 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 115: +YY_RULE_SETUP +#line 328 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 116: +YY_RULE_SETUP +#line 329 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 117: +YY_RULE_SETUP +#line 330 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 118: +YY_RULE_SETUP +#line 331 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 119: +YY_RULE_SETUP +#line 332 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 120: +YY_RULE_SETUP +#line 333 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 121: +YY_RULE_SETUP +#line 334 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 122: +YY_RULE_SETUP +#line 335 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 123: +YY_RULE_SETUP +#line 336 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 124: +YY_RULE_SETUP +#line 337 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 125: +YY_RULE_SETUP +#line 338 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 126: +YY_RULE_SETUP +#line 339 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 127: +YY_RULE_SETUP +#line 340 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 128: +YY_RULE_SETUP +#line 341 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 129: +YY_RULE_SETUP +#line 342 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 130: +YY_RULE_SETUP +#line 343 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 131: +YY_RULE_SETUP +#line 344 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 132: +YY_RULE_SETUP +#line 345 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 133: +YY_RULE_SETUP +#line 346 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 134: +YY_RULE_SETUP +#line 347 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 135: +YY_RULE_SETUP +#line 348 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 136: +YY_RULE_SETUP +#line 349 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 137: +YY_RULE_SETUP +#line 350 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 138: +YY_RULE_SETUP +#line 351 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 139: +YY_RULE_SETUP +#line 352 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 140: +YY_RULE_SETUP +#line 353 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 141: +YY_RULE_SETUP +#line 354 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 142: +YY_RULE_SETUP +#line 355 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 143: +YY_RULE_SETUP +#line 356 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 144: +YY_RULE_SETUP +#line 357 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 145: +YY_RULE_SETUP +#line 358 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 146: +YY_RULE_SETUP +#line 359 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 147: +YY_RULE_SETUP +#line 360 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 148: +YY_RULE_SETUP +#line 361 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 149: +YY_RULE_SETUP +#line 362 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 150: +YY_RULE_SETUP +#line 363 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 151: +YY_RULE_SETUP +#line 364 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 152: +YY_RULE_SETUP +#line 365 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 153: +YY_RULE_SETUP +#line 366 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 154: +YY_RULE_SETUP +#line 367 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 155: +YY_RULE_SETUP +#line 368 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 156: +YY_RULE_SETUP +#line 369 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 157: +YY_RULE_SETUP +#line 370 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 158: +YY_RULE_SETUP +#line 371 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 159: +YY_RULE_SETUP +#line 372 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 160: +YY_RULE_SETUP +#line 373 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 161: +YY_RULE_SETUP +#line 374 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 162: +YY_RULE_SETUP +#line 375 "thrift/thriftl.ll" +{ thrift_reserved_keyword(yytext); } + YY_BREAK +case 163: +YY_RULE_SETUP +#line 377 "thrift/thriftl.ll" +{ + errno = 0; + yylval.iconst = strtoll(yytext, NULL, 10); + if (errno == ERANGE) { + integer_overflow(yytext); + } + return tok_int_constant; +} + YY_BREAK +case 164: +YY_RULE_SETUP +#line 386 "thrift/thriftl.ll" +{ + errno = 0; + char sign = yytext[0]; + int shift = sign == '0' ? 2 : 3; + yylval.iconst = strtoll(yytext+shift, NULL, 16); + if (sign == '-') { + yylval.iconst = -yylval.iconst; + } + if (errno == ERANGE) { + integer_overflow(yytext); + } + return tok_int_constant; +} + YY_BREAK +case 165: +YY_RULE_SETUP +#line 400 "thrift/thriftl.ll" +{ + yylval.id = strdup(yytext); + return tok_identifier; +} + YY_BREAK +case 166: +YY_RULE_SETUP +#line 405 "thrift/thriftl.ll" +{ + /* Deliberately placed after identifier, since "e10" is NOT a double literal (THRIFT-3477) */ + yylval.dconst = atof(yytext); + return tok_dub_constant; +} + YY_BREAK +case 167: +YY_RULE_SETUP +#line 411 "thrift/thriftl.ll" +{ + char mark = yytext[0]; + std::string result; + for(;;) + { + int ch = yyinput(); + switch (ch) { + case EOF: + yyerror("End of file while read string at %d\n", yylineno); + exit(1); + case '\n': + yyerror("End of line while read string at %d\n", yylineno - 1); + exit(1); + case '\\': + ch = yyinput(); + switch (ch) { + case 'r': + result.push_back('\r'); + continue; + case 'n': + result.push_back('\n'); + continue; + case 't': + result.push_back('\t'); + continue; + case '"': + result.push_back('"'); + continue; + case '\'': + result.push_back('\''); + continue; + case '\\': + result.push_back('\\'); + continue; + default: + yyerror("Bad escape character\n"); + return -1; + } + break; + default: + if (ch == mark) { + yylval.id = strdup(result.c_str()); + return tok_literal; + } else { + result.push_back(ch); + } + } + } +} + YY_BREAK +case 168: +YY_RULE_SETUP +#line 462 "thrift/thriftl.ll" +{ + unexpected_token(yytext); +} + YY_BREAK +case 169: +YY_RULE_SETUP +#line 466 "thrift/thriftl.ll" +ECHO; + YY_BREAK +#line 2515 "thrift/thriftl.cc" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = (yytext_ptr); + yy_size_t number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + yy_size_t num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + yy_size_t new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + yy_state_type yy_current_state; + char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 768 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + int yy_is_jam; + char *yy_cp = (yy_c_buf_p); + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 768 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 767); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + if ( c == '\n' ) + + yylineno++; +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = (yy_size_t)size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ); + + yyfree((void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + yy_size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + yy_size_t i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +yy_size_t yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param _line_number line number + * + */ +void yyset_lineno (int _line_number ) +{ + + yylineno = _line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str ) +{ + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str ) +{ + yyout = _out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int _bdebug ) +{ + yy_flex_debug = _bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + /* We do not touch yylineno unless the option is enabled. */ + yylineno = 1; + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 466 "thrift/thriftl.ll" + + + +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + +/* vim: filetype=lex +*/ + diff --git a/compiler/cpp/src/thrift/thriftl.ll b/compiler/cpp/src/thrift/thriftl.ll new file mode 100644 index 0000000..30669a4 --- /dev/null +++ b/compiler/cpp/src/thrift/thriftl.ll @@ -0,0 +1,473 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Thrift scanner. + * + * Tokenizes a thrift definition file. + */ + +%{ + +/* This is redundant with some of the flags in Makefile.am, but it works + * when people override CXXFLAGS without being careful. The pragmas are + * the 'right' way to do it, but don't work on old-enough GCC (in particular + * the GCC that ship on Mac OS X 10.6.5, *counter* to what the GNU docs say) + * + * We should revert the Makefile.am changes once Apple ships a reasonable + * GCC. + */ +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-label" +#endif + +#ifdef _MSC_VER +#pragma warning( push ) + +// warning C4102: 'find_rule' : unreferenced label +#pragma warning( disable : 4102 ) + +// warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data +#pragma warning( disable : 4267 ) + +// avoid isatty redefinition +#define YY_NEVER_INTERACTIVE 1 + +#define YY_NO_UNISTD_H 1 +#endif + +#include +#include +#include +#include + +#ifdef _MSC_VER +#include "thrift/windows/config.h" +#endif +#include "thrift/main.h" +#include "thrift/common.h" +#include "thrift/globals.h" +#include "thrift/parse/t_program.h" + +/** + * Must be included AFTER parse/t_program.h, but I can't remember why anymore + * because I wrote this a while ago. + */ +#if defined(BISON_USE_PARSER_H_EXTENSION) +#include "thrift/thrifty.h" +#else +#include "thrift/thrifty.hh" +#endif + +void thrift_reserved_keyword(char* keyword) { + yyerror("Cannot use reserved language keyword: \"%s\"\n", keyword); + exit(1); +} + +void integer_overflow(char* text) { + yyerror("This integer is too big: \"%s\"\n", text); + exit(1); +} + +void unexpected_token(char* text) { + yyerror("Unexpected token in input: \"%s\"\n", text); + exit(1); +} + +%} + +/** + * Provides the yylineno global, useful for debugging output + */ +%option lex-compat + +/** + * Our inputs are all single files, so no need for yywrap + */ +%option noyywrap + +/** + * We don't use it, and it fires up warnings at -Wall + */ +%option nounput + +/** + * Helper definitions, comments, constants, and whatnot + */ + +intconstant ([+-]?[0-9]+) +hexconstant ([+-]?"0x"[0-9A-Fa-f]+) +dubconstant ([+-]?[0-9]*(\.[0-9]+)?([eE][+-]?[0-9]+)?) +identifier ([a-zA-Z_](\.[a-zA-Z_0-9]|[a-zA-Z_0-9])*) +whitespace ([ \t\r\n]*) +sillycomm ("/*""*"*"*/") +multicm_begin ("/*") +doctext_begin ("/**") +comment ("//"[^\n]*) +unixcomment ("#"[^\n]*) +symbol ([:;\,\{\}\(\)\=<>\[\]]) +literal_begin (['\"]) + +%% + +{whitespace} { /* do nothing */ } +{sillycomm} { /* do nothing */ } + +{doctext_begin} { + std::string parsed("/**"); + int state = 0; // 0 = normal, 1 = "*" seen, "*/" seen + while(state < 2) + { + int ch = yyinput(); + parsed.push_back(ch); + switch (ch) { + case EOF: + yyerror("Unexpected end of file in doc-comment at %d\n", yylineno); + exit(1); + case '*': + state = 1; + break; + case '/': + state = (state == 1) ? 2 : 0; + break; + default: + state = 0; + break; + } + } + pdebug("doctext = \"%s\"\n",parsed.c_str()); + + /* This does not show up in the parse tree. */ + /* Rather, the parser will grab it out of the global. */ + if (g_parse_mode == PROGRAM) { + clear_doctext(); + g_doctext = strdup(parsed.c_str() + 3); + assert(strlen(g_doctext) >= 2); + g_doctext[strlen(g_doctext) - 2] = ' '; + g_doctext[strlen(g_doctext) - 1] = '\0'; + g_doctext = clean_up_doctext(g_doctext); + g_doctext_lineno = yylineno; + if( (g_program_doctext_candidate == NULL) && (g_program_doctext_status == INVALID)){ + g_program_doctext_candidate = strdup(g_doctext); + g_program_doctext_lineno = g_doctext_lineno; + g_program_doctext_status = STILL_CANDIDATE; + pdebug("%s","program doctext set to STILL_CANDIDATE"); + } + } +} + +{multicm_begin} { /* parsed, but thrown away */ + std::string parsed("/*"); + int state = 0; // 0 = normal, 1 = "*" seen, "*/" seen + while(state < 2) + { + int ch = yyinput(); + parsed.push_back(ch); + switch (ch) { + case EOF: + yyerror("Unexpected end of file in multiline comment at %d\n", yylineno); + exit(1); + case '*': + state = 1; + break; + case '/': + state = (state == 1) ? 2 : 0; + break; + default: + state = 0; + break; + } + } + pdebug("multi_comm = \"%s\"\n",parsed.c_str()); +} + +{comment} { /* do nothing */ } +{unixcomment} { /* do nothing */ } + +{symbol} { return yytext[0]; } +"*" { return yytext[0]; } + +"false" { yylval.iconst=0; return tok_int_constant; } +"true" { yylval.iconst=1; return tok_int_constant; } + +"namespace" { return tok_namespace; } +"cpp_namespace" { error_unsupported_namespace_decl("cpp"); /* do nothing */ } +"cpp_include" { return tok_cpp_include; } +"cpp_type" { return tok_cpp_type; } +"java_package" { error_unsupported_namespace_decl("java_package", "java"); /* do nothing */ } +"cocoa_prefix" { error_unsupported_namespace_decl("cocoa_prefix", "cocoa"); /* do nothing */ } +"csharp_namespace" { error_unsupported_namespace_decl("csharp"); /* do nothing */ } +"delphi_namespace" { error_unsupported_namespace_decl("delphi"); /* do nothing */ } +"php_namespace" { error_unsupported_namespace_decl("php"); /* do nothing */ } +"py_module" { error_unsupported_namespace_decl("py_module", "py"); /* do nothing */ } +"perl_package" { error_unsupported_namespace_decl("perl_package", "perl"); /* do nothing */ } +"ruby_namespace" { error_unsupported_namespace_decl("ruby"); /* do nothing */ } +"smalltalk_category" { error_unsupported_namespace_decl("smalltalk_category", "smalltalk.category"); /* do nothing */ } +"smalltalk_prefix" { error_unsupported_namespace_decl("smalltalk_category", "smalltalk.category"); /* do nothing */ } +"xsd_all" { return tok_xsd_all; } +"xsd_optional" { return tok_xsd_optional; } +"xsd_nillable" { return tok_xsd_nillable; } +"xsd_namespace" { error_unsupported_namespace_decl("xsd"); /* do nothing */ } +"xsd_attrs" { return tok_xsd_attrs; } +"include" { return tok_include; } +"void" { return tok_void; } +"bool" { return tok_bool; } +"byte" { + emit_byte_type_warning(); + return tok_i8; +} +"i8" { return tok_i8; } +"i16" { return tok_i16; } +"i32" { return tok_i32; } +"i64" { return tok_i64; } +"double" { return tok_double; } +"string" { return tok_string; } +"binary" { return tok_binary; } +"slist" { + pwarning(0, "\"slist\" is deprecated and will be removed in a future compiler version. This type should be replaced with \"string\".\n"); + return tok_slist; +} +"senum" { + pwarning(0, "\"senum\" is deprecated and will be removed in a future compiler version. This type should be replaced with \"string\".\n"); + return tok_senum; +} +"map" { return tok_map; } +"list" { return tok_list; } +"set" { return tok_set; } +"oneway" { return tok_oneway; } +"typedef" { return tok_typedef; } +"struct" { return tok_struct; } +"union" { return tok_union; } +"exception" { return tok_xception; } +"extends" { return tok_extends; } +"throws" { return tok_throws; } +"service" { return tok_service; } +"enum" { return tok_enum; } +"const" { return tok_const; } +"required" { return tok_required; } +"optional" { return tok_optional; } +"async" { + pwarning(0, "\"async\" is deprecated. It is called \"oneway\" now.\n"); + return tok_oneway; +} +"&" { return tok_reference; } + + +"BEGIN" { thrift_reserved_keyword(yytext); } +"END" { thrift_reserved_keyword(yytext); } +"__CLASS__" { thrift_reserved_keyword(yytext); } +"__DIR__" { thrift_reserved_keyword(yytext); } +"__FILE__" { thrift_reserved_keyword(yytext); } +"__FUNCTION__" { thrift_reserved_keyword(yytext); } +"__LINE__" { thrift_reserved_keyword(yytext); } +"__METHOD__" { thrift_reserved_keyword(yytext); } +"__NAMESPACE__" { thrift_reserved_keyword(yytext); } +"abstract" { thrift_reserved_keyword(yytext); } +"alias" { thrift_reserved_keyword(yytext); } +"and" { thrift_reserved_keyword(yytext); } +"args" { thrift_reserved_keyword(yytext); } +"as" { thrift_reserved_keyword(yytext); } +"assert" { thrift_reserved_keyword(yytext); } +"begin" { thrift_reserved_keyword(yytext); } +"break" { thrift_reserved_keyword(yytext); } +"case" { thrift_reserved_keyword(yytext); } +"catch" { thrift_reserved_keyword(yytext); } +"class" { thrift_reserved_keyword(yytext); } +"clone" { thrift_reserved_keyword(yytext); } +"continue" { thrift_reserved_keyword(yytext); } +"declare" { thrift_reserved_keyword(yytext); } +"def" { thrift_reserved_keyword(yytext); } +"default" { thrift_reserved_keyword(yytext); } +"del" { thrift_reserved_keyword(yytext); } +"delete" { thrift_reserved_keyword(yytext); } +"do" { thrift_reserved_keyword(yytext); } +"dynamic" { thrift_reserved_keyword(yytext); } +"elif" { thrift_reserved_keyword(yytext); } +"else" { thrift_reserved_keyword(yytext); } +"elseif" { thrift_reserved_keyword(yytext); } +"elsif" { thrift_reserved_keyword(yytext); } +"end" { thrift_reserved_keyword(yytext); } +"enddeclare" { thrift_reserved_keyword(yytext); } +"endfor" { thrift_reserved_keyword(yytext); } +"endforeach" { thrift_reserved_keyword(yytext); } +"endif" { thrift_reserved_keyword(yytext); } +"endswitch" { thrift_reserved_keyword(yytext); } +"endwhile" { thrift_reserved_keyword(yytext); } +"ensure" { thrift_reserved_keyword(yytext); } +"except" { thrift_reserved_keyword(yytext); } +"exec" { thrift_reserved_keyword(yytext); } +"finally" { thrift_reserved_keyword(yytext); } +"float" { thrift_reserved_keyword(yytext); } +"for" { thrift_reserved_keyword(yytext); } +"foreach" { thrift_reserved_keyword(yytext); } +"from" { thrift_reserved_keyword(yytext); } +"function" { thrift_reserved_keyword(yytext); } +"global" { thrift_reserved_keyword(yytext); } +"goto" { thrift_reserved_keyword(yytext); } +"if" { thrift_reserved_keyword(yytext); } +"implements" { thrift_reserved_keyword(yytext); } +"import" { thrift_reserved_keyword(yytext); } +"in" { thrift_reserved_keyword(yytext); } +"inline" { thrift_reserved_keyword(yytext); } +"instanceof" { thrift_reserved_keyword(yytext); } +"interface" { thrift_reserved_keyword(yytext); } +"is" { thrift_reserved_keyword(yytext); } +"lambda" { thrift_reserved_keyword(yytext); } +"module" { thrift_reserved_keyword(yytext); } +"native" { thrift_reserved_keyword(yytext); } +"new" { thrift_reserved_keyword(yytext); } +"next" { thrift_reserved_keyword(yytext); } +"nil" { thrift_reserved_keyword(yytext); } +"not" { thrift_reserved_keyword(yytext); } +"or" { thrift_reserved_keyword(yytext); } +"package" { thrift_reserved_keyword(yytext); } +"pass" { thrift_reserved_keyword(yytext); } +"public" { thrift_reserved_keyword(yytext); } +"print" { thrift_reserved_keyword(yytext); } +"private" { thrift_reserved_keyword(yytext); } +"protected" { thrift_reserved_keyword(yytext); } +"raise" { thrift_reserved_keyword(yytext); } +"redo" { thrift_reserved_keyword(yytext); } +"rescue" { thrift_reserved_keyword(yytext); } +"retry" { thrift_reserved_keyword(yytext); } +"register" { thrift_reserved_keyword(yytext); } +"return" { thrift_reserved_keyword(yytext); } +"self" { thrift_reserved_keyword(yytext); } +"sizeof" { thrift_reserved_keyword(yytext); } +"static" { thrift_reserved_keyword(yytext); } +"super" { thrift_reserved_keyword(yytext); } +"switch" { thrift_reserved_keyword(yytext); } +"synchronized" { thrift_reserved_keyword(yytext); } +"then" { thrift_reserved_keyword(yytext); } +"this" { thrift_reserved_keyword(yytext); } +"throw" { thrift_reserved_keyword(yytext); } +"transient" { thrift_reserved_keyword(yytext); } +"try" { thrift_reserved_keyword(yytext); } +"undef" { thrift_reserved_keyword(yytext); } +"unless" { thrift_reserved_keyword(yytext); } +"unsigned" { thrift_reserved_keyword(yytext); } +"until" { thrift_reserved_keyword(yytext); } +"use" { thrift_reserved_keyword(yytext); } +"var" { thrift_reserved_keyword(yytext); } +"virtual" { thrift_reserved_keyword(yytext); } +"volatile" { thrift_reserved_keyword(yytext); } +"when" { thrift_reserved_keyword(yytext); } +"while" { thrift_reserved_keyword(yytext); } +"with" { thrift_reserved_keyword(yytext); } +"xor" { thrift_reserved_keyword(yytext); } +"yield" { thrift_reserved_keyword(yytext); } + +{intconstant} { + errno = 0; + yylval.iconst = strtoll(yytext, NULL, 10); + if (errno == ERANGE) { + integer_overflow(yytext); + } + return tok_int_constant; +} + +{hexconstant} { + errno = 0; + char sign = yytext[0]; + int shift = sign == '0' ? 2 : 3; + yylval.iconst = strtoll(yytext+shift, NULL, 16); + if (sign == '-') { + yylval.iconst = -yylval.iconst; + } + if (errno == ERANGE) { + integer_overflow(yytext); + } + return tok_int_constant; +} + +{identifier} { + yylval.id = strdup(yytext); + return tok_identifier; +} + +{dubconstant} { + /* Deliberately placed after identifier, since "e10" is NOT a double literal (THRIFT-3477) */ + yylval.dconst = atof(yytext); + return tok_dub_constant; +} + +{literal_begin} { + char mark = yytext[0]; + std::string result; + for(;;) + { + int ch = yyinput(); + switch (ch) { + case EOF: + yyerror("End of file while read string at %d\n", yylineno); + exit(1); + case '\n': + yyerror("End of line while read string at %d\n", yylineno - 1); + exit(1); + case '\\': + ch = yyinput(); + switch (ch) { + case 'r': + result.push_back('\r'); + continue; + case 'n': + result.push_back('\n'); + continue; + case 't': + result.push_back('\t'); + continue; + case '"': + result.push_back('"'); + continue; + case '\'': + result.push_back('\''); + continue; + case '\\': + result.push_back('\\'); + continue; + default: + yyerror("Bad escape character\n"); + return -1; + } + break; + default: + if (ch == mark) { + yylval.id = strdup(result.c_str()); + return tok_literal; + } else { + result.push_back(ch); + } + } + } +} + + +. { + unexpected_token(yytext); +} + +%% + +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + +/* vim: filetype=lex +*/ diff --git a/compiler/cpp/src/thrift/thrifty.cc b/compiler/cpp/src/thrift/thrifty.cc new file mode 100644 index 0000000..ed8c8c9 --- /dev/null +++ b/compiler/cpp/src/thrift/thrifty.cc @@ -0,0 +1,3057 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + + + +/* Copy the first part of user declarations. */ +#line 4 "thrift/thrifty.yy" /* yacc.c:339 */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Thrift parser. + * + * This parser is used on a thrift definition file. + * + */ + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif +#include +#ifndef _MSC_VER +#include +#else +#include +#endif +#include +#ifdef _MSC_VER +#include "thrift/windows/config.h" +#endif +#include "thrift/main.h" +#include "thrift/common.h" +#include "thrift/globals.h" +#include "thrift/parse/t_program.h" +#include "thrift/parse/t_scope.h" + +#ifdef _MSC_VER +//warning C4065: switch statement contains 'default' but no 'case' labels +#pragma warning(disable:4065) +#endif + +/** + * This global variable is used for automatic numbering of field indices etc. + * when parsing the members of a struct. Field values are automatically + * assigned starting from -1 and working their way down. + */ +int y_field_val = -1; +/** + * This global variable is used for automatic numbering of enum values. + * y_enum_val is the last value assigned; the next auto-assigned value will be + * y_enum_val+1, and then it continues working upwards. Explicitly specified + * enum values reset y_enum_val to that value. + */ +int32_t y_enum_val = -1; +int g_arglist = 0; +const int struct_is_struct = 0; +const int struct_is_union = 1; + + +#line 139 "thrift/thrifty.cc" /* yacc.c:339 */ + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "y.tab.h". */ +#ifndef YY_YY_THRIFT_THRIFTY_HH_INCLUDED +# define YY_YY_THRIFT_THRIFTY_HH_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif +/* "%code requires" blocks. */ +#line 1 "thrift/thrifty.yy" /* yacc.c:355 */ + +#include "thrift/parse/t_program.h" + +#line 173 "thrift/thrifty.cc" /* yacc.c:355 */ + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + tok_identifier = 258, + tok_literal = 259, + tok_doctext = 260, + tok_int_constant = 261, + tok_dub_constant = 262, + tok_include = 263, + tok_namespace = 264, + tok_cpp_include = 265, + tok_cpp_type = 266, + tok_xsd_all = 267, + tok_xsd_optional = 268, + tok_xsd_nillable = 269, + tok_xsd_attrs = 270, + tok_void = 271, + tok_bool = 272, + tok_string = 273, + tok_binary = 274, + tok_slist = 275, + tok_senum = 276, + tok_i8 = 277, + tok_i16 = 278, + tok_i32 = 279, + tok_i64 = 280, + tok_double = 281, + tok_map = 282, + tok_list = 283, + tok_set = 284, + tok_oneway = 285, + tok_typedef = 286, + tok_struct = 287, + tok_xception = 288, + tok_throws = 289, + tok_extends = 290, + tok_service = 291, + tok_enum = 292, + tok_const = 293, + tok_required = 294, + tok_optional = 295, + tok_union = 296, + tok_reference = 297 + }; +#endif +/* Tokens. */ +#define tok_identifier 258 +#define tok_literal 259 +#define tok_doctext 260 +#define tok_int_constant 261 +#define tok_dub_constant 262 +#define tok_include 263 +#define tok_namespace 264 +#define tok_cpp_include 265 +#define tok_cpp_type 266 +#define tok_xsd_all 267 +#define tok_xsd_optional 268 +#define tok_xsd_nillable 269 +#define tok_xsd_attrs 270 +#define tok_void 271 +#define tok_bool 272 +#define tok_string 273 +#define tok_binary 274 +#define tok_slist 275 +#define tok_senum 276 +#define tok_i8 277 +#define tok_i16 278 +#define tok_i32 279 +#define tok_i64 280 +#define tok_double 281 +#define tok_map 282 +#define tok_list 283 +#define tok_set 284 +#define tok_oneway 285 +#define tok_typedef 286 +#define tok_struct 287 +#define tok_xception 288 +#define tok_throws 289 +#define tok_extends 290 +#define tok_service 291 +#define tok_enum 292 +#define tok_const 293 +#define tok_required 294 +#define tok_optional 295 +#define tok_union 296 +#define tok_reference 297 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 81 "thrift/thrifty.yy" /* yacc.c:355 */ + + char* id; + int64_t iconst; + double dconst; + bool tbool; + t_doc* tdoc; + t_type* ttype; + t_base_type* tbase; + t_typedef* ttypedef; + t_enum* tenum; + t_enum_value* tenumv; + t_const* tconst; + t_const_value* tconstv; + t_struct* tstruct; + t_service* tservice; + t_function* tfunction; + t_field* tfield; + char* dtext; + t_field::e_req ereq; + t_annotation* tannot; + t_field_id tfieldid; + +#line 292 "thrift/thrifty.cc" /* yacc.c:355 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + +extern YYSTYPE yylval; + +int yyparse (void); + +#endif /* !YY_YY_THRIFT_THRIFTY_HH_INCLUDED */ + +/* Copy the second part of user declarations. */ + +#line 309 "thrift/thrifty.cc" /* yacc.c:358 */ + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 3 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 173 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 56 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 60 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 115 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 200 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 297 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 52, 53, 43, 2, 44, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 51, 45, + 54, 48, 55, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 49, 2, 50, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 46, 2, 47, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 249, 249, 261, 272, 281, 286, 291, 295, 307, + 315, 325, 338, 346, 351, 359, 374, 392, 399, 406, + 413, 420, 429, 431, 434, 437, 450, 478, 485, 492, + 506, 521, 533, 545, 552, 559, 566, 585, 594, 600, + 605, 611, 616, 623, 630, 637, 644, 651, 658, 665, + 669, 675, 690, 695, 700, 705, 710, 715, 720, 725, + 730, 744, 758, 763, 768, 781, 786, 793, 799, 814, + 819, 824, 834, 839, 849, 856, 890, 930, 940, 945, + 950, 954, 966, 971, 980, 985, 990, 997, 1016, 1021, + 1027, 1040, 1045, 1050, 1055, 1060, 1065, 1070, 1075, 1080, + 1086, 1097, 1102, 1107, 1114, 1124, 1134, 1145, 1150, 1155, + 1161, 1166, 1174, 1180, 1189, 1195 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "tok_identifier", "tok_literal", + "tok_doctext", "tok_int_constant", "tok_dub_constant", "tok_include", + "tok_namespace", "tok_cpp_include", "tok_cpp_type", "tok_xsd_all", + "tok_xsd_optional", "tok_xsd_nillable", "tok_xsd_attrs", "tok_void", + "tok_bool", "tok_string", "tok_binary", "tok_slist", "tok_senum", + "tok_i8", "tok_i16", "tok_i32", "tok_i64", "tok_double", "tok_map", + "tok_list", "tok_set", "tok_oneway", "tok_typedef", "tok_struct", + "tok_xception", "tok_throws", "tok_extends", "tok_service", "tok_enum", + "tok_const", "tok_required", "tok_optional", "tok_union", + "tok_reference", "'*'", "','", "';'", "'{'", "'}'", "'='", "'['", "']'", + "':'", "'('", "')'", "'<'", "'>'", "$accept", "Program", + "CaptureDocText", "DestroyDocText", "HeaderList", "Header", "Include", + "DefinitionList", "Definition", "TypeDefinition", + "CommaOrSemicolonOptional", "Typedef", "Enum", "EnumDefList", "EnumDef", + "EnumValue", "Senum", "SenumDefList", "SenumDef", "Const", "ConstValue", + "ConstList", "ConstListContents", "ConstMap", "ConstMapContents", + "StructHead", "Struct", "XsdAll", "XsdOptional", "XsdNillable", + "XsdAttributes", "Xception", "Service", "FlagArgs", "UnflagArgs", + "Extends", "FunctionList", "Function", "Oneway", "Throws", "FieldList", + "Field", "FieldIdentifier", "FieldReference", "FieldRequiredness", + "FieldValue", "FunctionType", "FieldType", "BaseType", "SimpleBaseType", + "ContainerType", "SimpleContainerType", "MapType", "SetType", "ListType", + "CppType", "TypeAnnotations", "TypeAnnotationList", "TypeAnnotation", + "TypeAnnotationValue", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 42, 44, 59, 123, 125, 61, 91, + 93, 58, 40, 41, 60, 62 +}; +# endif + +#define YYPACT_NINF -124 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-124))) + +#define YYTABLE_NINF -64 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + -124, 15, 9, -124, 26, 33, 35, 13, 36, -124, + -124, 132, -124, 39, 40, -124, 41, 123, -124, 42, + 45, 46, 123, -124, -124, -124, -124, -124, -124, -124, + 61, -124, -124, -124, 16, -124, 19, -124, -124, -124, + -124, -124, -124, -124, -124, -124, -124, 56, 18, 56, + 70, -124, 16, -124, 16, -124, -124, -124, 29, 43, + 30, 74, 68, -124, -124, -124, 77, 28, 123, 34, + 16, -124, -124, -124, 80, 38, -124, 44, -124, 48, + 7, 3, -124, 123, 32, 123, -23, 49, -124, -124, + 50, 25, -124, 47, -124, -124, -23, 16, -124, 55, + 56, 65, -124, -124, -124, 16, 84, -124, -124, 16, + 98, -124, -124, -124, -124, -124, -124, -124, -23, -124, + -124, 75, 117, -23, -124, -124, 123, -124, -124, -124, + 51, -2, 76, -124, 79, 16, 5, 20, -124, 16, + -124, -124, 78, -124, -124, -124, 123, 95, 82, -124, + 124, -23, -124, 81, -124, -23, -124, -124, 89, -124, + 90, 16, -124, -124, 25, -124, -124, 131, -124, 133, + -124, -124, -23, 87, 92, -124, 25, 141, -124, -124, + -124, 142, 102, -124, 143, 125, 111, 16, 108, 16, + -124, -23, -124, -23, 114, -124, 109, -124, -124, -124 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 6, 0, 13, 1, 0, 3, 0, 0, 0, 5, + 7, 0, 11, 0, 0, 10, 0, 0, 49, 0, + 0, 0, 0, 50, 12, 15, 17, 18, 19, 14, + 0, 20, 21, 16, 110, 9, 0, 87, 94, 91, + 92, 93, 95, 96, 97, 98, 99, 108, 0, 108, + 0, 88, 110, 89, 110, 101, 102, 103, 0, 65, + 0, 0, 53, 112, 8, 34, 0, 0, 0, 0, + 110, 90, 100, 74, 0, 0, 28, 0, 52, 0, + 0, 0, 107, 0, 0, 0, 24, 3, 64, 62, + 3, 0, 74, 115, 109, 111, 24, 110, 33, 0, + 108, 0, 22, 23, 25, 110, 77, 73, 67, 110, + 0, 27, 40, 39, 37, 38, 48, 45, 24, 41, + 42, 3, 0, 24, 35, 32, 0, 106, 105, 60, + 0, 82, 3, 26, 31, 110, 0, 0, 36, 110, + 114, 113, 0, 76, 80, 81, 0, 70, 0, 66, + 0, 24, 46, 0, 43, 24, 51, 104, 79, 69, + 0, 110, 30, 29, 0, 44, 78, 0, 86, 0, + 85, 61, 24, 84, 0, 47, 0, 55, 74, 83, + 54, 57, 3, 56, 59, 72, 0, 110, 0, 110, + 74, 24, 74, 24, 3, 75, 3, 68, 58, 71 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -124, -124, -4, -124, -124, -124, -124, -124, -124, -124, + -93, -124, -124, -124, -124, -124, -124, -124, -124, -124, + -123, -124, -124, -124, -124, -124, -124, -124, -124, -124, + -124, -124, -124, -124, -124, -124, -124, -124, -124, -124, + -87, -124, -124, -124, -124, -124, -124, -22, -124, -124, + -124, -124, -124, -124, -124, -43, -50, -124, -124, -124 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 1, 106, 4, 2, 9, 10, 5, 24, 25, + 104, 26, 27, 90, 111, 135, 28, 81, 98, 29, + 118, 119, 137, 120, 136, 30, 31, 79, 181, 184, + 187, 32, 33, 108, 148, 75, 132, 149, 160, 189, + 87, 107, 131, 167, 146, 177, 169, 50, 51, 52, + 53, 54, 55, 56, 57, 67, 64, 80, 95, 123 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int16 yytable[] = +{ + 61, 11, 71, 124, 72, 121, 69, 96, 112, 113, + 93, 114, 115, 153, 155, 3, 13, -4, -4, -4, + 86, 102, 103, 112, 113, 138, 114, 115, 112, 113, + 141, 114, 115, -2, 6, 7, 8, 144, 145, 12, + 15, 172, 34, 35, 36, 58, 84, 125, 59, 60, + 97, 116, 152, 179, 117, 129, 14, 127, 163, 133, + 94, 99, 165, 101, 62, 65, 116, 66, 63, 117, + 154, 116, 68, 70, 117, 73, 76, 77, 74, 175, + 78, 82, 83, 88, 89, 151, 110, 100, 85, 156, + 130, 182, 91, 37, 92, 122, 105, 109, 195, 126, + 197, 134, 143, 194, 142, 196, 168, 38, 39, 40, + 41, 171, 42, 43, 44, 45, 46, 47, 48, 49, + 128, 140, 139, -63, 158, 159, 37, 150, 147, 161, + 162, 166, 164, 157, 173, 176, 174, 191, 170, 193, + 38, 39, 40, 41, 178, 42, 43, 44, 45, 46, + 47, 48, 49, 16, 180, 185, 183, 190, 186, 188, + 192, 198, 199, 17, 18, 19, 0, 0, 20, 21, + 22, 0, 0, 23 +}; + +static const yytype_int16 yycheck[] = +{ + 22, 5, 52, 96, 54, 92, 49, 4, 3, 4, + 3, 6, 7, 136, 137, 0, 3, 8, 9, 10, + 70, 44, 45, 3, 4, 118, 6, 7, 3, 4, + 123, 6, 7, 0, 8, 9, 10, 39, 40, 4, + 4, 164, 3, 3, 3, 3, 68, 97, 3, 3, + 47, 46, 47, 176, 49, 105, 43, 100, 151, 109, + 53, 83, 155, 85, 3, 46, 46, 11, 52, 49, + 50, 46, 54, 3, 49, 46, 46, 3, 35, 172, + 12, 4, 54, 3, 46, 135, 90, 55, 54, 139, + 6, 178, 48, 3, 46, 48, 47, 47, 191, 44, + 193, 3, 51, 190, 126, 192, 16, 17, 18, 19, + 20, 161, 22, 23, 24, 25, 26, 27, 28, 29, + 55, 4, 47, 47, 146, 30, 3, 48, 132, 47, + 6, 42, 51, 55, 3, 48, 3, 187, 160, 189, + 17, 18, 19, 20, 52, 22, 23, 24, 25, 26, + 27, 28, 29, 21, 13, 53, 14, 46, 15, 34, + 52, 47, 53, 31, 32, 33, -1, -1, 36, 37, + 38, -1, -1, 41 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 57, 60, 0, 59, 63, 8, 9, 10, 61, + 62, 58, 4, 3, 43, 4, 21, 31, 32, 33, + 36, 37, 38, 41, 64, 65, 67, 68, 72, 75, + 81, 82, 87, 88, 3, 3, 3, 3, 17, 18, + 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, + 103, 104, 105, 106, 107, 108, 109, 110, 3, 3, + 3, 103, 3, 52, 112, 46, 11, 111, 54, 111, + 3, 112, 112, 46, 35, 91, 46, 3, 12, 83, + 113, 73, 4, 54, 103, 54, 112, 96, 3, 46, + 69, 48, 46, 3, 53, 114, 4, 47, 74, 103, + 55, 103, 44, 45, 66, 47, 58, 97, 89, 47, + 58, 70, 3, 4, 6, 7, 46, 49, 76, 77, + 79, 96, 48, 115, 66, 112, 44, 111, 55, 112, + 6, 98, 92, 112, 3, 71, 80, 78, 66, 47, + 4, 66, 103, 51, 39, 40, 100, 58, 90, 93, + 48, 112, 47, 76, 50, 76, 112, 55, 103, 30, + 94, 47, 6, 66, 51, 66, 42, 99, 16, 102, + 103, 112, 76, 3, 3, 66, 48, 101, 52, 76, + 13, 84, 96, 14, 85, 53, 15, 86, 34, 95, + 46, 112, 52, 112, 96, 66, 96, 66, 47, 53 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 56, 57, 58, 59, 60, 60, 61, 61, 61, + 61, 62, 63, 63, 64, 64, 64, 65, 65, 65, + 65, 65, 66, 66, 66, 67, 68, 69, 69, 70, + 71, 71, 72, 73, 73, 74, 75, 76, 76, 76, + 76, 76, 76, 77, 78, 78, 79, 80, 80, 81, + 81, 82, 83, 83, 84, 84, 85, 85, 86, 86, + 87, 88, 89, 90, 91, 91, 92, 92, 93, 94, + 94, 95, 95, 96, 96, 97, 98, 98, 99, 99, + 100, 100, 100, 101, 101, 102, 102, 103, 103, 103, + 104, 105, 105, 105, 105, 105, 105, 105, 105, 105, + 106, 107, 107, 107, 108, 109, 110, 111, 111, 112, + 112, 113, 113, 114, 115, 115 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 0, 0, 3, 0, 1, 4, 3, + 2, 2, 3, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 5, 6, 2, 0, 4, + 3, 1, 6, 2, 0, 2, 6, 1, 1, 1, + 1, 1, 1, 3, 3, 0, 3, 5, 0, 1, + 1, 7, 1, 0, 1, 0, 1, 0, 4, 0, + 6, 9, 0, 0, 2, 0, 2, 0, 10, 1, + 0, 4, 0, 2, 0, 12, 2, 0, 1, 0, + 1, 1, 0, 2, 0, 1, 1, 1, 1, 1, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 1, 1, 1, 7, 5, 5, 2, 0, 3, + 0, 2, 0, 3, 2, 0 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +{ + YYUSE (yyvaluep); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; +/* Number of syntax errors so far. */ +int yynerrs; + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (void) +{ + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 250 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Program -> Headers DefinitionList"); + if((g_program_doctext_candidate != NULL) && (g_program_doctext_status != ALREADY_PROCESSED)) + { + g_program->set_doc(g_program_doctext_candidate); + g_program_doctext_status = ALREADY_PROCESSED; + } + clear_doctext(); + } +#line 1547 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 3: +#line 261 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + if (g_parse_mode == PROGRAM) { + (yyval.dtext) = g_doctext; + g_doctext = NULL; + } else { + (yyval.dtext) = NULL; + } + } +#line 1560 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 4: +#line 272 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + if (g_parse_mode == PROGRAM) { + clear_doctext(); + } + } +#line 1570 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 5: +#line 282 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("HeaderList -> HeaderList Header"); + } +#line 1578 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 6: +#line 286 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("HeaderList -> "); + } +#line 1586 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 7: +#line 292 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Header -> Include"); + } +#line 1594 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 8: +#line 296 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Header -> tok_namespace tok_identifier tok_identifier"); + declare_valid_program_doctext(); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace((yyvsp[-2].id), (yyvsp[-1].id)); + } + if ((yyvsp[0].ttype) != NULL) { + g_program->set_namespace_annotations((yyvsp[-2].id), (yyvsp[0].ttype)->annotations_); + delete (yyvsp[0].ttype); + } + } +#line 1610 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 9: +#line 308 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Header -> tok_namespace * tok_identifier"); + declare_valid_program_doctext(); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace("*", (yyvsp[0].id)); + } + } +#line 1622 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 10: +#line 316 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Header -> tok_cpp_include tok_literal"); + declare_valid_program_doctext(); + if (g_parse_mode == PROGRAM) { + g_program->add_cpp_include((yyvsp[0].id)); + } + } +#line 1634 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 11: +#line 326 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Include -> tok_include tok_literal"); + declare_valid_program_doctext(); + if (g_parse_mode == INCLUDES) { + std::string path = include_file(std::string((yyvsp[0].id))); + if (!path.empty()) { + g_program->add_include(path, std::string((yyvsp[0].id))); + } + } + } +#line 1649 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 12: +#line 339 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("DefinitionList -> DefinitionList Definition"); + if ((yyvsp[-1].dtext) != NULL && (yyvsp[0].tdoc) != NULL) { + (yyvsp[0].tdoc)->set_doc((yyvsp[-1].dtext)); + } + } +#line 1660 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 13: +#line 346 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("DefinitionList -> "); + } +#line 1668 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 14: +#line 352 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Definition -> Const"); + if (g_parse_mode == PROGRAM) { + g_program->add_const((yyvsp[0].tconst)); + } + (yyval.tdoc) = (yyvsp[0].tconst); + } +#line 1680 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 15: +#line 360 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Definition -> TypeDefinition"); + if (g_parse_mode == PROGRAM) { + g_scope->add_type((yyvsp[0].ttype)->get_name(), (yyvsp[0].ttype)); + if (g_parent_scope != NULL) { + g_parent_scope->add_type(g_parent_prefix + (yyvsp[0].ttype)->get_name(), (yyvsp[0].ttype)); + } + if (! g_program->is_unique_typename((yyvsp[0].ttype))) { + yyerror("Type \"%s\" is already defined.", (yyvsp[0].ttype)->get_name().c_str()); + exit(1); + } + } + (yyval.tdoc) = (yyvsp[0].ttype); + } +#line 1699 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 16: +#line 375 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Definition -> Service"); + if (g_parse_mode == PROGRAM) { + g_scope->add_service((yyvsp[0].tservice)->get_name(), (yyvsp[0].tservice)); + if (g_parent_scope != NULL) { + g_parent_scope->add_service(g_parent_prefix + (yyvsp[0].tservice)->get_name(), (yyvsp[0].tservice)); + } + g_program->add_service((yyvsp[0].tservice)); + if (! g_program->is_unique_typename((yyvsp[0].tservice))) { + yyerror("Type \"%s\" is already defined.", (yyvsp[0].tservice)->get_name().c_str()); + exit(1); + } + } + (yyval.tdoc) = (yyvsp[0].tservice); + } +#line 1719 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 17: +#line 393 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("TypeDefinition -> Typedef"); + if (g_parse_mode == PROGRAM) { + g_program->add_typedef((yyvsp[0].ttypedef)); + } + } +#line 1730 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 18: +#line 400 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("TypeDefinition -> Enum"); + if (g_parse_mode == PROGRAM) { + g_program->add_enum((yyvsp[0].tenum)); + } + } +#line 1741 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 19: +#line 407 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("TypeDefinition -> Senum"); + if (g_parse_mode == PROGRAM) { + g_program->add_typedef((yyvsp[0].ttypedef)); + } + } +#line 1752 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 20: +#line 414 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("TypeDefinition -> Struct"); + if (g_parse_mode == PROGRAM) { + g_program->add_struct((yyvsp[0].tstruct)); + } + } +#line 1763 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 21: +#line 421 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("TypeDefinition -> Xception"); + if (g_parse_mode == PROGRAM) { + g_program->add_xception((yyvsp[0].tstruct)); + } + } +#line 1774 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 22: +#line 430 "thrift/thrifty.yy" /* yacc.c:1646 */ + {} +#line 1780 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 23: +#line 432 "thrift/thrifty.yy" /* yacc.c:1646 */ + {} +#line 1786 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 24: +#line 434 "thrift/thrifty.yy" /* yacc.c:1646 */ + {} +#line 1792 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 25: +#line 438 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("TypeDef -> tok_typedef FieldType tok_identifier"); + validate_simple_identifier( (yyvsp[-2].id)); + t_typedef *td = new t_typedef(g_program, (yyvsp[-3].ttype), (yyvsp[-2].id)); + (yyval.ttypedef) = td; + if ((yyvsp[-1].ttype) != NULL) { + (yyval.ttypedef)->annotations_ = (yyvsp[-1].ttype)->annotations_; + delete (yyvsp[-1].ttype); + } + } +#line 1807 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 26: +#line 451 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Enum -> tok_enum tok_identifier { EnumDefList }"); + (yyval.tenum) = (yyvsp[-2].tenum); + validate_simple_identifier( (yyvsp[-4].id)); + (yyval.tenum)->set_name((yyvsp[-4].id)); + if ((yyvsp[0].ttype) != NULL) { + (yyval.tenum)->annotations_ = (yyvsp[0].ttype)->annotations_; + delete (yyvsp[0].ttype); + } + + // make constants for all the enum values + if (g_parse_mode == PROGRAM) { + const std::vector& enum_values = (yyval.tenum)->get_constants(); + std::vector::const_iterator c_iter; + for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { + std::string const_name = (yyval.tenum)->get_name() + "." + (*c_iter)->get_name(); + t_const_value* const_val = new t_const_value((*c_iter)->get_value()); + const_val->set_enum((yyval.tenum)); + g_scope->add_constant(const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val)); + if (g_parent_scope != NULL) { + g_parent_scope->add_constant(g_parent_prefix + const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val)); + } + } + } + } +#line 1837 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 27: +#line 479 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("EnumDefList -> EnumDefList EnumDef"); + (yyval.tenum) = (yyvsp[-1].tenum); + (yyval.tenum)->append((yyvsp[0].tenumv)); + } +#line 1847 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 28: +#line 485 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("EnumDefList -> "); + (yyval.tenum) = new t_enum(g_program); + y_enum_val = -1; + } +#line 1857 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 29: +#line 493 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("EnumDef -> EnumValue"); + (yyval.tenumv) = (yyvsp[-2].tenumv); + if ((yyvsp[-3].dtext) != NULL) { + (yyval.tenumv)->set_doc((yyvsp[-3].dtext)); + } + if ((yyvsp[-1].ttype) != NULL) { + (yyval.tenumv)->annotations_ = (yyvsp[-1].ttype)->annotations_; + delete (yyvsp[-1].ttype); + } + } +#line 1873 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 30: +#line 507 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("EnumValue -> tok_identifier = tok_int_constant"); + if ((yyvsp[0].iconst) < INT32_MIN || (yyvsp[0].iconst) > INT32_MAX) { + // Note: this used to be just a warning. However, since thrift always + // treats enums as i32 values, I'm changing it to a fatal error. + // I doubt this will affect many people, but users who run into this + // will have to update their thrift files to manually specify the + // truncated i32 value that thrift has always been using anyway. + failure("64-bit value supplied for enum %s will be truncated.", (yyvsp[-2].id)); + } + y_enum_val = static_cast((yyvsp[0].iconst)); + (yyval.tenumv) = new t_enum_value((yyvsp[-2].id), y_enum_val); + } +#line 1891 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 31: +#line 522 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("EnumValue -> tok_identifier"); + validate_simple_identifier( (yyvsp[0].id)); + if (y_enum_val == INT32_MAX) { + failure("enum value overflow at enum %s", (yyvsp[0].id)); + } + ++y_enum_val; + (yyval.tenumv) = new t_enum_value((yyvsp[0].id), y_enum_val); + } +#line 1905 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 32: +#line 534 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Senum -> tok_senum tok_identifier { SenumDefList }"); + validate_simple_identifier( (yyvsp[-4].id)); + (yyval.ttypedef) = new t_typedef(g_program, (yyvsp[-2].tbase), (yyvsp[-4].id)); + if ((yyvsp[0].ttype) != NULL) { + (yyval.ttypedef)->annotations_ = (yyvsp[0].ttype)->annotations_; + delete (yyvsp[0].ttype); + } + } +#line 1919 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 33: +#line 546 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("SenumDefList -> SenumDefList SenumDef"); + (yyval.tbase) = (yyvsp[-1].tbase); + (yyval.tbase)->add_string_enum_val((yyvsp[0].id)); + } +#line 1929 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 34: +#line 552 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("SenumDefList -> "); + (yyval.tbase) = new t_base_type("string", t_base_type::TYPE_STRING); + (yyval.tbase)->set_string_enum(true); + } +#line 1939 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 35: +#line 560 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("SenumDef -> tok_literal"); + (yyval.id) = (yyvsp[-1].id); + } +#line 1948 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 36: +#line 567 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Const -> tok_const FieldType tok_identifier = ConstValue"); + if (g_parse_mode == PROGRAM) { + validate_simple_identifier( (yyvsp[-3].id)); + g_scope->resolve_const_value((yyvsp[-1].tconstv), (yyvsp[-4].ttype)); + (yyval.tconst) = new t_const((yyvsp[-4].ttype), (yyvsp[-3].id), (yyvsp[-1].tconstv)); + validate_const_type((yyval.tconst)); + + g_scope->add_constant((yyvsp[-3].id), (yyval.tconst)); + if (g_parent_scope != NULL) { + g_parent_scope->add_constant(g_parent_prefix + (yyvsp[-3].id), (yyval.tconst)); + } + } else { + (yyval.tconst) = NULL; + } + } +#line 1969 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 37: +#line 586 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ConstValue => tok_int_constant"); + (yyval.tconstv) = new t_const_value(); + (yyval.tconstv)->set_integer((yyvsp[0].iconst)); + if (!g_allow_64bit_consts && ((yyvsp[0].iconst) < INT32_MIN || (yyvsp[0].iconst) > INT32_MAX)) { + pwarning(1, "64-bit constant \"%" PRIi64"\" may not work in all languages.\n", (yyvsp[0].iconst)); + } + } +#line 1982 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 38: +#line 595 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ConstValue => tok_dub_constant"); + (yyval.tconstv) = new t_const_value(); + (yyval.tconstv)->set_double((yyvsp[0].dconst)); + } +#line 1992 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 39: +#line 601 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ConstValue => tok_literal"); + (yyval.tconstv) = new t_const_value((yyvsp[0].id)); + } +#line 2001 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 40: +#line 606 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ConstValue => tok_identifier"); + (yyval.tconstv) = new t_const_value(); + (yyval.tconstv)->set_identifier((yyvsp[0].id)); + } +#line 2011 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 41: +#line 612 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ConstValue => ConstList"); + (yyval.tconstv) = (yyvsp[0].tconstv); + } +#line 2020 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 42: +#line 617 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ConstValue => ConstMap"); + (yyval.tconstv) = (yyvsp[0].tconstv); + } +#line 2029 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 43: +#line 624 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ConstList => [ ConstListContents ]"); + (yyval.tconstv) = (yyvsp[-1].tconstv); + } +#line 2038 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 44: +#line 631 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ConstListContents => ConstListContents ConstValue CommaOrSemicolonOptional"); + (yyval.tconstv) = (yyvsp[-2].tconstv); + (yyval.tconstv)->add_list((yyvsp[-1].tconstv)); + } +#line 2048 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 45: +#line 637 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ConstListContents =>"); + (yyval.tconstv) = new t_const_value(); + (yyval.tconstv)->set_list(); + } +#line 2058 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 46: +#line 645 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ConstMap => { ConstMapContents }"); + (yyval.tconstv) = (yyvsp[-1].tconstv); + } +#line 2067 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 47: +#line 652 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ConstMapContents => ConstMapContents ConstValue CommaOrSemicolonOptional"); + (yyval.tconstv) = (yyvsp[-4].tconstv); + (yyval.tconstv)->add_map((yyvsp[-3].tconstv), (yyvsp[-1].tconstv)); + } +#line 2077 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 48: +#line 658 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ConstMapContents =>"); + (yyval.tconstv) = new t_const_value(); + (yyval.tconstv)->set_map(); + } +#line 2087 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 49: +#line 666 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.iconst) = struct_is_struct; + } +#line 2095 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 50: +#line 670 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.iconst) = struct_is_union; + } +#line 2103 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 51: +#line 676 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Struct -> tok_struct tok_identifier { FieldList }"); + validate_simple_identifier( (yyvsp[-5].id)); + (yyvsp[-2].tstruct)->set_xsd_all((yyvsp[-4].tbool)); + (yyvsp[-2].tstruct)->set_union((yyvsp[-6].iconst) == struct_is_union); + (yyval.tstruct) = (yyvsp[-2].tstruct); + (yyval.tstruct)->set_name((yyvsp[-5].id)); + if ((yyvsp[0].ttype) != NULL) { + (yyval.tstruct)->annotations_ = (yyvsp[0].ttype)->annotations_; + delete (yyvsp[0].ttype); + } + } +#line 2120 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 52: +#line 691 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tbool) = true; + } +#line 2128 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 53: +#line 695 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tbool) = false; + } +#line 2136 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 54: +#line 701 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tbool) = true; + } +#line 2144 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 55: +#line 705 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tbool) = false; + } +#line 2152 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 56: +#line 711 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tbool) = true; + } +#line 2160 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 57: +#line 715 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tbool) = false; + } +#line 2168 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 58: +#line 721 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tstruct) = (yyvsp[-1].tstruct); + } +#line 2176 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 59: +#line 725 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tstruct) = NULL; + } +#line 2184 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 60: +#line 731 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Xception -> tok_xception tok_identifier { FieldList }"); + validate_simple_identifier( (yyvsp[-4].id)); + (yyvsp[-2].tstruct)->set_name((yyvsp[-4].id)); + (yyvsp[-2].tstruct)->set_xception(true); + (yyval.tstruct) = (yyvsp[-2].tstruct); + if ((yyvsp[0].ttype) != NULL) { + (yyval.tstruct)->annotations_ = (yyvsp[0].ttype)->annotations_; + delete (yyvsp[0].ttype); + } + } +#line 2200 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 61: +#line 745 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Service -> tok_service tok_identifier { FunctionList }"); + validate_simple_identifier( (yyvsp[-7].id)); + (yyval.tservice) = (yyvsp[-3].tservice); + (yyval.tservice)->set_name((yyvsp[-7].id)); + (yyval.tservice)->set_extends((yyvsp[-6].tservice)); + if ((yyvsp[0].ttype) != NULL) { + (yyval.tservice)->annotations_ = (yyvsp[0].ttype)->annotations_; + delete (yyvsp[0].ttype); + } + } +#line 2216 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 62: +#line 758 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + g_arglist = 1; + } +#line 2224 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 63: +#line 763 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + g_arglist = 0; + } +#line 2232 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 64: +#line 769 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Extends -> tok_extends tok_identifier"); + (yyval.tservice) = NULL; + if (g_parse_mode == PROGRAM) { + (yyval.tservice) = g_scope->get_service((yyvsp[0].id)); + if ((yyval.tservice) == NULL) { + yyerror("Service \"%s\" has not been defined.", (yyvsp[0].id)); + exit(1); + } + } + } +#line 2248 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 65: +#line 781 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tservice) = NULL; + } +#line 2256 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 66: +#line 787 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("FunctionList -> FunctionList Function"); + (yyval.tservice) = (yyvsp[-1].tservice); + (yyvsp[-1].tservice)->add_function((yyvsp[0].tfunction)); + } +#line 2266 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 67: +#line 793 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("FunctionList -> "); + (yyval.tservice) = new t_service(g_program); + } +#line 2275 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 68: +#line 800 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + validate_simple_identifier( (yyvsp[-6].id)); + (yyvsp[-4].tstruct)->set_name(std::string((yyvsp[-6].id)) + "_args"); + (yyval.tfunction) = new t_function((yyvsp[-7].ttype), (yyvsp[-6].id), (yyvsp[-4].tstruct), (yyvsp[-2].tstruct), (yyvsp[-8].tbool)); + if ((yyvsp[-9].dtext) != NULL) { + (yyval.tfunction)->set_doc((yyvsp[-9].dtext)); + } + if ((yyvsp[-1].ttype) != NULL) { + (yyval.tfunction)->annotations_ = (yyvsp[-1].ttype)->annotations_; + delete (yyvsp[-1].ttype); + } + } +#line 2292 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 69: +#line 815 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tbool) = true; + } +#line 2300 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 70: +#line 819 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tbool) = false; + } +#line 2308 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 71: +#line 825 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("Throws -> tok_throws ( FieldList )"); + (yyval.tstruct) = (yyvsp[-1].tstruct); + if (g_parse_mode == PROGRAM && !validate_throws((yyval.tstruct))) { + yyerror("Throws clause may not contain non-exception types"); + exit(1); + } + } +#line 2321 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 72: +#line 834 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tstruct) = new t_struct(g_program); + } +#line 2329 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 73: +#line 840 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("FieldList -> FieldList , Field"); + (yyval.tstruct) = (yyvsp[-1].tstruct); + if (!((yyval.tstruct)->append((yyvsp[0].tfield)))) { + yyerror("\"%d: %s\" - field identifier/name has already been used", (yyvsp[0].tfield)->get_key(), (yyvsp[0].tfield)->get_name().c_str()); + exit(1); + } + } +#line 2342 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 74: +#line 849 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("FieldList -> "); + y_field_val = -1; + (yyval.tstruct) = new t_struct(g_program); + } +#line 2352 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 75: +#line 857 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("tok_int_constant : Field -> FieldType tok_identifier"); + if ((yyvsp[-10].tfieldid).auto_assigned) { + pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", (yyvsp[-6].id)); + if (g_strict >= 192) { + yyerror("Implicit field keys are deprecated and not allowed with -strict"); + exit(1); + } + } + validate_simple_identifier((yyvsp[-6].id)); + (yyval.tfield) = new t_field((yyvsp[-8].ttype), (yyvsp[-6].id), (yyvsp[-10].tfieldid).value); + (yyval.tfield)->set_reference((yyvsp[-7].tbool)); + (yyval.tfield)->set_req((yyvsp[-9].ereq)); + if ((yyvsp[-5].tconstv) != NULL) { + g_scope->resolve_const_value((yyvsp[-5].tconstv), (yyvsp[-8].ttype)); + validate_field_value((yyval.tfield), (yyvsp[-5].tconstv)); + (yyval.tfield)->set_value((yyvsp[-5].tconstv)); + } + (yyval.tfield)->set_xsd_optional((yyvsp[-4].tbool)); + (yyval.tfield)->set_xsd_nillable((yyvsp[-3].tbool)); + if ((yyvsp[-11].dtext) != NULL) { + (yyval.tfield)->set_doc((yyvsp[-11].dtext)); + } + if ((yyvsp[-2].tstruct) != NULL) { + (yyval.tfield)->set_xsd_attrs((yyvsp[-2].tstruct)); + } + if ((yyvsp[-1].ttype) != NULL) { + (yyval.tfield)->annotations_ = (yyvsp[-1].ttype)->annotations_; + delete (yyvsp[-1].ttype); + } + } +#line 2388 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 76: +#line 891 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + if ((yyvsp[-1].iconst) <= 0) { + if (g_allow_neg_field_keys) { + /* + * g_allow_neg_field_keys exists to allow users to add explicitly + * specified key values to old .thrift files without breaking + * protocol compatibility. + */ + if ((yyvsp[-1].iconst) != y_field_val) { + /* + * warn if the user-specified negative value isn't what + * thrift would have auto-assigned. + */ + pwarning(1, "Nonpositive field key (%" PRIi64") differs from what would be " + "auto-assigned by thrift (%d).\n", (yyvsp[-1].iconst), y_field_val); + } + /* + * Leave $1 as-is, and update y_field_val to be one less than $1. + * The FieldList parsing will catch any duplicate key values. + */ + y_field_val = static_cast((yyvsp[-1].iconst) - 1); + (yyval.tfieldid).value = static_cast((yyvsp[-1].iconst)); + (yyval.tfieldid).auto_assigned = false; + } else { + pwarning(1, "Nonpositive value (%d) not allowed as a field key.\n", + (yyvsp[-1].iconst)); + (yyval.tfieldid).value = y_field_val--; + (yyval.tfieldid).auto_assigned = true; + } + } else { + (yyval.tfieldid).value = static_cast((yyvsp[-1].iconst)); + (yyval.tfieldid).auto_assigned = false; + } + if( (SHRT_MIN > (yyval.tfieldid).value) || ((yyval.tfieldid).value > SHRT_MAX)) { + pwarning(1, "Field key (%d) exceeds allowed range (%d..%d).\n", + (yyval.tfieldid).value, SHRT_MIN, SHRT_MAX); + } + } +#line 2431 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 77: +#line 930 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tfieldid).value = y_field_val--; + (yyval.tfieldid).auto_assigned = true; + if( (SHRT_MIN > (yyval.tfieldid).value) || ((yyval.tfieldid).value > SHRT_MAX)) { + pwarning(1, "Field key (%d) exceeds allowed range (%d..%d).\n", + (yyval.tfieldid).value, SHRT_MIN, SHRT_MAX); + } + } +#line 2444 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 78: +#line 941 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tbool) = true; + } +#line 2452 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 79: +#line 945 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tbool) = false; + } +#line 2460 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 80: +#line 951 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.ereq) = t_field::T_REQUIRED; + } +#line 2468 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 81: +#line 955 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + if (g_arglist) { + if (g_parse_mode == PROGRAM) { + pwarning(1, "optional keyword is ignored in argument lists.\n"); + } + (yyval.ereq) = t_field::T_OPT_IN_REQ_OUT; + } else { + (yyval.ereq) = t_field::T_OPTIONAL; + } + } +#line 2483 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 82: +#line 966 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.ereq) = t_field::T_OPT_IN_REQ_OUT; + } +#line 2491 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 83: +#line 972 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + if (g_parse_mode == PROGRAM) { + (yyval.tconstv) = (yyvsp[0].tconstv); + } else { + (yyval.tconstv) = NULL; + } + } +#line 2503 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 84: +#line 980 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.tconstv) = NULL; + } +#line 2511 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 85: +#line 986 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("FunctionType -> FieldType"); + (yyval.ttype) = (yyvsp[0].ttype); + } +#line 2520 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 86: +#line 991 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("FunctionType -> tok_void"); + (yyval.ttype) = g_type_void; + } +#line 2529 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 87: +#line 998 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("FieldType -> tok_identifier"); + if (g_parse_mode == INCLUDES) { + // Ignore identifiers in include mode + (yyval.ttype) = NULL; + } else { + // Lookup the identifier in the current scope + (yyval.ttype) = g_scope->get_type((yyvsp[0].id)); + if ((yyval.ttype) == NULL) { + /* + * Either this type isn't yet declared, or it's never + declared. Either way allow it and we'll figure it out + during generation. + */ + (yyval.ttype) = new t_typedef(g_program, (yyvsp[0].id), true); + } + } + } +#line 2552 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 88: +#line 1017 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("FieldType -> BaseType"); + (yyval.ttype) = (yyvsp[0].ttype); + } +#line 2561 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 89: +#line 1022 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("FieldType -> ContainerType"); + (yyval.ttype) = (yyvsp[0].ttype); + } +#line 2570 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 90: +#line 1028 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("BaseType -> SimpleBaseType TypeAnnotations"); + if ((yyvsp[0].ttype) != NULL) { + (yyval.ttype) = new t_base_type(*static_cast((yyvsp[-1].ttype))); + (yyval.ttype)->annotations_ = (yyvsp[0].ttype)->annotations_; + delete (yyvsp[0].ttype); + } else { + (yyval.ttype) = (yyvsp[-1].ttype); + } + } +#line 2585 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 91: +#line 1041 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("BaseType -> tok_string"); + (yyval.ttype) = g_type_string; + } +#line 2594 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 92: +#line 1046 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("BaseType -> tok_binary"); + (yyval.ttype) = g_type_binary; + } +#line 2603 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 93: +#line 1051 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("BaseType -> tok_slist"); + (yyval.ttype) = g_type_slist; + } +#line 2612 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 94: +#line 1056 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("BaseType -> tok_bool"); + (yyval.ttype) = g_type_bool; + } +#line 2621 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 95: +#line 1061 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("BaseType -> tok_i8"); + (yyval.ttype) = g_type_i8; + } +#line 2630 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 96: +#line 1066 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("BaseType -> tok_i16"); + (yyval.ttype) = g_type_i16; + } +#line 2639 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 97: +#line 1071 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("BaseType -> tok_i32"); + (yyval.ttype) = g_type_i32; + } +#line 2648 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 98: +#line 1076 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("BaseType -> tok_i64"); + (yyval.ttype) = g_type_i64; + } +#line 2657 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 99: +#line 1081 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("BaseType -> tok_double"); + (yyval.ttype) = g_type_double; + } +#line 2666 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 100: +#line 1087 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ContainerType -> SimpleContainerType TypeAnnotations"); + (yyval.ttype) = (yyvsp[-1].ttype); + if ((yyvsp[0].ttype) != NULL) { + (yyval.ttype)->annotations_ = (yyvsp[0].ttype)->annotations_; + delete (yyvsp[0].ttype); + } + } +#line 2679 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 101: +#line 1098 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("SimpleContainerType -> MapType"); + (yyval.ttype) = (yyvsp[0].ttype); + } +#line 2688 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 102: +#line 1103 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("SimpleContainerType -> SetType"); + (yyval.ttype) = (yyvsp[0].ttype); + } +#line 2697 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 103: +#line 1108 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("SimpleContainerType -> ListType"); + (yyval.ttype) = (yyvsp[0].ttype); + } +#line 2706 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 104: +#line 1115 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("MapType -> tok_map "); + (yyval.ttype) = new t_map((yyvsp[-3].ttype), (yyvsp[-1].ttype)); + if ((yyvsp[-5].id) != NULL) { + ((t_container*)(yyval.ttype))->set_cpp_name(std::string((yyvsp[-5].id))); + } + } +#line 2718 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 105: +#line 1125 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("SetType -> tok_set"); + (yyval.ttype) = new t_set((yyvsp[-1].ttype)); + if ((yyvsp[-3].id) != NULL) { + ((t_container*)(yyval.ttype))->set_cpp_name(std::string((yyvsp[-3].id))); + } + } +#line 2730 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 106: +#line 1135 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("ListType -> tok_list"); + check_for_list_of_bytes((yyvsp[-2].ttype)); + (yyval.ttype) = new t_list((yyvsp[-2].ttype)); + if ((yyvsp[0].id) != NULL) { + ((t_container*)(yyval.ttype))->set_cpp_name(std::string((yyvsp[0].id))); + } + } +#line 2743 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 107: +#line 1146 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.id) = (yyvsp[0].id); + } +#line 2751 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 108: +#line 1150 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.id) = NULL; + } +#line 2759 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 109: +#line 1156 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("TypeAnnotations -> ( TypeAnnotationList )"); + (yyval.ttype) = (yyvsp[-1].ttype); + } +#line 2768 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 110: +#line 1161 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + (yyval.ttype) = NULL; + } +#line 2776 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 111: +#line 1167 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation"); + (yyval.ttype) = (yyvsp[-1].ttype); + (yyval.ttype)->annotations_[(yyvsp[0].tannot)->key] = (yyvsp[0].tannot)->val; + delete (yyvsp[0].tannot); + } +#line 2787 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 112: +#line 1174 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + /* Just use a dummy structure to hold the annotations. */ + (yyval.ttype) = new t_struct(g_program); + } +#line 2796 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 113: +#line 1181 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("TypeAnnotation -> TypeAnnotationValue"); + (yyval.tannot) = new t_annotation; + (yyval.tannot)->key = (yyvsp[-2].id); + (yyval.tannot)->val = (yyvsp[-1].id); + } +#line 2807 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 114: +#line 1190 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("TypeAnnotationValue -> = tok_literal"); + (yyval.id) = (yyvsp[0].id); + } +#line 2816 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + case 115: +#line 1195 "thrift/thrifty.yy" /* yacc.c:1646 */ + { + pdebug("TypeAnnotationValue ->"); + (yyval.id) = strdup("1"); + } +#line 2825 "thrift/thrifty.cc" /* yacc.c:1646 */ + break; + + +#line 2829 "thrift/thrifty.cc" /* yacc.c:1646 */ + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} +#line 1200 "thrift/thrifty.yy" /* yacc.c:1906 */ + diff --git a/compiler/cpp/src/thrift/thrifty.hh b/compiler/cpp/src/thrift/thrifty.hh new file mode 100644 index 0000000..49ef7c1 --- /dev/null +++ b/compiler/cpp/src/thrift/thrifty.hh @@ -0,0 +1,179 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_YY_THRIFT_THRIFTY_HH_INCLUDED +# define YY_YY_THRIFT_THRIFTY_HH_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif +/* "%code requires" blocks. */ +#line 1 "thrift/thrifty.yy" /* yacc.c:1909 */ + +#include "thrift/parse/t_program.h" + +#line 48 "thrift/thrifty.hh" /* yacc.c:1909 */ + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + tok_identifier = 258, + tok_literal = 259, + tok_doctext = 260, + tok_int_constant = 261, + tok_dub_constant = 262, + tok_include = 263, + tok_namespace = 264, + tok_cpp_include = 265, + tok_cpp_type = 266, + tok_xsd_all = 267, + tok_xsd_optional = 268, + tok_xsd_nillable = 269, + tok_xsd_attrs = 270, + tok_void = 271, + tok_bool = 272, + tok_string = 273, + tok_binary = 274, + tok_slist = 275, + tok_senum = 276, + tok_i8 = 277, + tok_i16 = 278, + tok_i32 = 279, + tok_i64 = 280, + tok_double = 281, + tok_map = 282, + tok_list = 283, + tok_set = 284, + tok_oneway = 285, + tok_typedef = 286, + tok_struct = 287, + tok_xception = 288, + tok_throws = 289, + tok_extends = 290, + tok_service = 291, + tok_enum = 292, + tok_const = 293, + tok_required = 294, + tok_optional = 295, + tok_union = 296, + tok_reference = 297 + }; +#endif +/* Tokens. */ +#define tok_identifier 258 +#define tok_literal 259 +#define tok_doctext 260 +#define tok_int_constant 261 +#define tok_dub_constant 262 +#define tok_include 263 +#define tok_namespace 264 +#define tok_cpp_include 265 +#define tok_cpp_type 266 +#define tok_xsd_all 267 +#define tok_xsd_optional 268 +#define tok_xsd_nillable 269 +#define tok_xsd_attrs 270 +#define tok_void 271 +#define tok_bool 272 +#define tok_string 273 +#define tok_binary 274 +#define tok_slist 275 +#define tok_senum 276 +#define tok_i8 277 +#define tok_i16 278 +#define tok_i32 279 +#define tok_i64 280 +#define tok_double 281 +#define tok_map 282 +#define tok_list 283 +#define tok_set 284 +#define tok_oneway 285 +#define tok_typedef 286 +#define tok_struct 287 +#define tok_xception 288 +#define tok_throws 289 +#define tok_extends 290 +#define tok_service 291 +#define tok_enum 292 +#define tok_const 293 +#define tok_required 294 +#define tok_optional 295 +#define tok_union 296 +#define tok_reference 297 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 81 "thrift/thrifty.yy" /* yacc.c:1909 */ + + char* id; + int64_t iconst; + double dconst; + bool tbool; + t_doc* tdoc; + t_type* ttype; + t_base_type* tbase; + t_typedef* ttypedef; + t_enum* tenum; + t_enum_value* tenumv; + t_const* tconst; + t_const_value* tconstv; + t_struct* tstruct; + t_service* tservice; + t_function* tfunction; + t_field* tfield; + char* dtext; + t_field::e_req ereq; + t_annotation* tannot; + t_field_id tfieldid; + +#line 167 "thrift/thrifty.hh" /* yacc.c:1909 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + +extern YYSTYPE yylval; + +int yyparse (void); + +#endif /* !YY_YY_THRIFT_THRIFTY_HH_INCLUDED */ diff --git a/compiler/cpp/src/thrift/thrifty.yy b/compiler/cpp/src/thrift/thrifty.yy new file mode 100644 index 0000000..e4cae0c --- /dev/null +++ b/compiler/cpp/src/thrift/thrifty.yy @@ -0,0 +1,1200 @@ +%code requires { +#include "thrift/parse/t_program.h" +} +%{ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Thrift parser. + * + * This parser is used on a thrift definition file. + * + */ + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif +#include +#ifndef _MSC_VER +#include +#else +#include +#endif +#include +#ifdef _MSC_VER +#include "thrift/windows/config.h" +#endif +#include "thrift/main.h" +#include "thrift/common.h" +#include "thrift/globals.h" +#include "thrift/parse/t_program.h" +#include "thrift/parse/t_scope.h" + +#ifdef _MSC_VER +//warning C4065: switch statement contains 'default' but no 'case' labels +#pragma warning(disable:4065) +#endif + +/** + * This global variable is used for automatic numbering of field indices etc. + * when parsing the members of a struct. Field values are automatically + * assigned starting from -1 and working their way down. + */ +int y_field_val = -1; +/** + * This global variable is used for automatic numbering of enum values. + * y_enum_val is the last value assigned; the next auto-assigned value will be + * y_enum_val+1, and then it continues working upwards. Explicitly specified + * enum values reset y_enum_val to that value. + */ +int32_t y_enum_val = -1; +int g_arglist = 0; +const int struct_is_struct = 0; +const int struct_is_union = 1; + +%} + +/** + * This structure is used by the parser to hold the data types associated with + * various parse nodes. + */ +%union { + char* id; + int64_t iconst; + double dconst; + bool tbool; + t_doc* tdoc; + t_type* ttype; + t_base_type* tbase; + t_typedef* ttypedef; + t_enum* tenum; + t_enum_value* tenumv; + t_const* tconst; + t_const_value* tconstv; + t_struct* tstruct; + t_service* tservice; + t_function* tfunction; + t_field* tfield; + char* dtext; + t_field::e_req ereq; + t_annotation* tannot; + t_field_id tfieldid; +} + +/** + * Strings identifier + */ +%token tok_identifier +%token tok_literal +%token tok_doctext + +/** + * Constant values + */ +%token tok_int_constant +%token tok_dub_constant + +/** + * Header keywords + */ +%token tok_include +%token tok_namespace +%token tok_cpp_include +%token tok_cpp_type +%token tok_xsd_all +%token tok_xsd_optional +%token tok_xsd_nillable +%token tok_xsd_attrs + +/** + * Base datatype keywords + */ +%token tok_void +%token tok_bool +%token tok_string +%token tok_binary +%token tok_slist +%token tok_senum +%token tok_i8 +%token tok_i16 +%token tok_i32 +%token tok_i64 +%token tok_double + +/** + * Complex type keywords + */ +%token tok_map +%token tok_list +%token tok_set + +/** + * Function modifiers + */ +%token tok_oneway + +/** + * Thrift language keywords + */ +%token tok_typedef +%token tok_struct +%token tok_xception +%token tok_throws +%token tok_extends +%token tok_service +%token tok_enum +%token tok_const +%token tok_required +%token tok_optional +%token tok_union +%token tok_reference + +/** + * Grammar nodes + */ + +%type BaseType +%type SimpleBaseType +%type ContainerType +%type SimpleContainerType +%type MapType +%type SetType +%type ListType + +%type Definition +%type TypeDefinition + +%type Typedef + +%type TypeAnnotations +%type TypeAnnotationList +%type TypeAnnotation +%type TypeAnnotationValue + +%type Field +%type FieldIdentifier +%type FieldRequiredness +%type FieldType +%type FieldValue +%type FieldList +%type FieldReference + +%type Enum +%type EnumDefList +%type EnumDef +%type EnumValue + +%type Senum +%type SenumDefList +%type SenumDef + +%type Const +%type ConstValue +%type ConstList +%type ConstListContents +%type ConstMap +%type ConstMapContents + +%type StructHead +%type Struct +%type Xception +%type Service + +%type Function +%type FunctionType +%type FunctionList + +%type Throws +%type Extends +%type Oneway +%type XsdAll +%type XsdOptional +%type XsdNillable +%type XsdAttributes +%type CppType + +%type CaptureDocText + +%% + +/** + * Thrift Grammar Implementation. + * + * For the most part this source file works its way top down from what you + * might expect to find in a typical .thrift file, i.e. type definitions and + * namespaces up top followed by service definitions using those types. + */ + +Program: + HeaderList DefinitionList + { + pdebug("Program -> Headers DefinitionList"); + if((g_program_doctext_candidate != NULL) && (g_program_doctext_status != ALREADY_PROCESSED)) + { + g_program->set_doc(g_program_doctext_candidate); + g_program_doctext_status = ALREADY_PROCESSED; + } + clear_doctext(); + } + +CaptureDocText: + { + if (g_parse_mode == PROGRAM) { + $$ = g_doctext; + g_doctext = NULL; + } else { + $$ = NULL; + } + } + +/* TODO(dreiss): Try to DestroyDocText in all sorts or random places. */ +DestroyDocText: + { + if (g_parse_mode == PROGRAM) { + clear_doctext(); + } + } + +/* We have to DestroyDocText here, otherwise it catches the doctext + on the first real element. */ +HeaderList: + HeaderList DestroyDocText Header + { + pdebug("HeaderList -> HeaderList Header"); + } +| + { + pdebug("HeaderList -> "); + } + +Header: + Include + { + pdebug("Header -> Include"); + } +| tok_namespace tok_identifier tok_identifier TypeAnnotations + { + pdebug("Header -> tok_namespace tok_identifier tok_identifier"); + declare_valid_program_doctext(); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace($2, $3); + } + if ($4 != NULL) { + g_program->set_namespace_annotations($2, $4->annotations_); + delete $4; + } + } +| tok_namespace '*' tok_identifier + { + pdebug("Header -> tok_namespace * tok_identifier"); + declare_valid_program_doctext(); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace("*", $3); + } + } +| tok_cpp_include tok_literal + { + pdebug("Header -> tok_cpp_include tok_literal"); + declare_valid_program_doctext(); + if (g_parse_mode == PROGRAM) { + g_program->add_cpp_include($2); + } + } + +Include: + tok_include tok_literal + { + pdebug("Include -> tok_include tok_literal"); + declare_valid_program_doctext(); + if (g_parse_mode == INCLUDES) { + std::string path = include_file(std::string($2)); + if (!path.empty()) { + g_program->add_include(path, std::string($2)); + } + } + } + +DefinitionList: + DefinitionList CaptureDocText Definition + { + pdebug("DefinitionList -> DefinitionList Definition"); + if ($2 != NULL && $3 != NULL) { + $3->set_doc($2); + } + } +| + { + pdebug("DefinitionList -> "); + } + +Definition: + Const + { + pdebug("Definition -> Const"); + if (g_parse_mode == PROGRAM) { + g_program->add_const($1); + } + $$ = $1; + } +| TypeDefinition + { + pdebug("Definition -> TypeDefinition"); + if (g_parse_mode == PROGRAM) { + g_scope->add_type($1->get_name(), $1); + if (g_parent_scope != NULL) { + g_parent_scope->add_type(g_parent_prefix + $1->get_name(), $1); + } + if (! g_program->is_unique_typename($1)) { + yyerror("Type \"%s\" is already defined.", $1->get_name().c_str()); + exit(1); + } + } + $$ = $1; + } +| Service + { + pdebug("Definition -> Service"); + if (g_parse_mode == PROGRAM) { + g_scope->add_service($1->get_name(), $1); + if (g_parent_scope != NULL) { + g_parent_scope->add_service(g_parent_prefix + $1->get_name(), $1); + } + g_program->add_service($1); + if (! g_program->is_unique_typename($1)) { + yyerror("Type \"%s\" is already defined.", $1->get_name().c_str()); + exit(1); + } + } + $$ = $1; + } + +TypeDefinition: + Typedef + { + pdebug("TypeDefinition -> Typedef"); + if (g_parse_mode == PROGRAM) { + g_program->add_typedef($1); + } + } +| Enum + { + pdebug("TypeDefinition -> Enum"); + if (g_parse_mode == PROGRAM) { + g_program->add_enum($1); + } + } +| Senum + { + pdebug("TypeDefinition -> Senum"); + if (g_parse_mode == PROGRAM) { + g_program->add_typedef($1); + } + } +| Struct + { + pdebug("TypeDefinition -> Struct"); + if (g_parse_mode == PROGRAM) { + g_program->add_struct($1); + } + } +| Xception + { + pdebug("TypeDefinition -> Xception"); + if (g_parse_mode == PROGRAM) { + g_program->add_xception($1); + } + } + +CommaOrSemicolonOptional: + ',' + {} +| ';' + {} +| + {} + +Typedef: + tok_typedef FieldType tok_identifier TypeAnnotations CommaOrSemicolonOptional + { + pdebug("TypeDef -> tok_typedef FieldType tok_identifier"); + validate_simple_identifier( $3); + t_typedef *td = new t_typedef(g_program, $2, $3); + $$ = td; + if ($4 != NULL) { + $$->annotations_ = $4->annotations_; + delete $4; + } + } + +Enum: + tok_enum tok_identifier '{' EnumDefList '}' TypeAnnotations + { + pdebug("Enum -> tok_enum tok_identifier { EnumDefList }"); + $$ = $4; + validate_simple_identifier( $2); + $$->set_name($2); + if ($6 != NULL) { + $$->annotations_ = $6->annotations_; + delete $6; + } + + // make constants for all the enum values + if (g_parse_mode == PROGRAM) { + const std::vector& enum_values = $$->get_constants(); + std::vector::const_iterator c_iter; + for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { + std::string const_name = $$->get_name() + "." + (*c_iter)->get_name(); + t_const_value* const_val = new t_const_value((*c_iter)->get_value()); + const_val->set_enum($$); + g_scope->add_constant(const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val)); + if (g_parent_scope != NULL) { + g_parent_scope->add_constant(g_parent_prefix + const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val)); + } + } + } + } + +EnumDefList: + EnumDefList EnumDef + { + pdebug("EnumDefList -> EnumDefList EnumDef"); + $$ = $1; + $$->append($2); + } +| + { + pdebug("EnumDefList -> "); + $$ = new t_enum(g_program); + y_enum_val = -1; + } + +EnumDef: + CaptureDocText EnumValue TypeAnnotations CommaOrSemicolonOptional + { + pdebug("EnumDef -> EnumValue"); + $$ = $2; + if ($1 != NULL) { + $$->set_doc($1); + } + if ($3 != NULL) { + $$->annotations_ = $3->annotations_; + delete $3; + } + } + +EnumValue: + tok_identifier '=' tok_int_constant + { + pdebug("EnumValue -> tok_identifier = tok_int_constant"); + if ($3 < INT32_MIN || $3 > INT32_MAX) { + // Note: this used to be just a warning. However, since thrift always + // treats enums as i32 values, I'm changing it to a fatal error. + // I doubt this will affect many people, but users who run into this + // will have to update their thrift files to manually specify the + // truncated i32 value that thrift has always been using anyway. + failure("64-bit value supplied for enum %s will be truncated.", $1); + } + y_enum_val = static_cast($3); + $$ = new t_enum_value($1, y_enum_val); + } + | + tok_identifier + { + pdebug("EnumValue -> tok_identifier"); + validate_simple_identifier( $1); + if (y_enum_val == INT32_MAX) { + failure("enum value overflow at enum %s", $1); + } + ++y_enum_val; + $$ = new t_enum_value($1, y_enum_val); + } + +Senum: + tok_senum tok_identifier '{' SenumDefList '}' TypeAnnotations + { + pdebug("Senum -> tok_senum tok_identifier { SenumDefList }"); + validate_simple_identifier( $2); + $$ = new t_typedef(g_program, $4, $2); + if ($6 != NULL) { + $$->annotations_ = $6->annotations_; + delete $6; + } + } + +SenumDefList: + SenumDefList SenumDef + { + pdebug("SenumDefList -> SenumDefList SenumDef"); + $$ = $1; + $$->add_string_enum_val($2); + } +| + { + pdebug("SenumDefList -> "); + $$ = new t_base_type("string", t_base_type::TYPE_STRING); + $$->set_string_enum(true); + } + +SenumDef: + tok_literal CommaOrSemicolonOptional + { + pdebug("SenumDef -> tok_literal"); + $$ = $1; + } + +Const: + tok_const FieldType tok_identifier '=' ConstValue CommaOrSemicolonOptional + { + pdebug("Const -> tok_const FieldType tok_identifier = ConstValue"); + if (g_parse_mode == PROGRAM) { + validate_simple_identifier( $3); + g_scope->resolve_const_value($5, $2); + $$ = new t_const($2, $3, $5); + validate_const_type($$); + + g_scope->add_constant($3, $$); + if (g_parent_scope != NULL) { + g_parent_scope->add_constant(g_parent_prefix + $3, $$); + } + } else { + $$ = NULL; + } + } + +ConstValue: + tok_int_constant + { + pdebug("ConstValue => tok_int_constant"); + $$ = new t_const_value(); + $$->set_integer($1); + if (!g_allow_64bit_consts && ($1 < INT32_MIN || $1 > INT32_MAX)) { + pwarning(1, "64-bit constant \"%" PRIi64"\" may not work in all languages.\n", $1); + } + } +| tok_dub_constant + { + pdebug("ConstValue => tok_dub_constant"); + $$ = new t_const_value(); + $$->set_double($1); + } +| tok_literal + { + pdebug("ConstValue => tok_literal"); + $$ = new t_const_value($1); + } +| tok_identifier + { + pdebug("ConstValue => tok_identifier"); + $$ = new t_const_value(); + $$->set_identifier($1); + } +| ConstList + { + pdebug("ConstValue => ConstList"); + $$ = $1; + } +| ConstMap + { + pdebug("ConstValue => ConstMap"); + $$ = $1; + } + +ConstList: + '[' ConstListContents ']' + { + pdebug("ConstList => [ ConstListContents ]"); + $$ = $2; + } + +ConstListContents: + ConstListContents ConstValue CommaOrSemicolonOptional + { + pdebug("ConstListContents => ConstListContents ConstValue CommaOrSemicolonOptional"); + $$ = $1; + $$->add_list($2); + } +| + { + pdebug("ConstListContents =>"); + $$ = new t_const_value(); + $$->set_list(); + } + +ConstMap: + '{' ConstMapContents '}' + { + pdebug("ConstMap => { ConstMapContents }"); + $$ = $2; + } + +ConstMapContents: + ConstMapContents ConstValue ':' ConstValue CommaOrSemicolonOptional + { + pdebug("ConstMapContents => ConstMapContents ConstValue CommaOrSemicolonOptional"); + $$ = $1; + $$->add_map($2, $4); + } +| + { + pdebug("ConstMapContents =>"); + $$ = new t_const_value(); + $$->set_map(); + } + +StructHead: + tok_struct + { + $$ = struct_is_struct; + } +| tok_union + { + $$ = struct_is_union; + } + +Struct: + StructHead tok_identifier XsdAll '{' FieldList '}' TypeAnnotations + { + pdebug("Struct -> tok_struct tok_identifier { FieldList }"); + validate_simple_identifier( $2); + $5->set_xsd_all($3); + $5->set_union($1 == struct_is_union); + $$ = $5; + $$->set_name($2); + if ($7 != NULL) { + $$->annotations_ = $7->annotations_; + delete $7; + } + } + +XsdAll: + tok_xsd_all + { + $$ = true; + } +| + { + $$ = false; + } + +XsdOptional: + tok_xsd_optional + { + $$ = true; + } +| + { + $$ = false; + } + +XsdNillable: + tok_xsd_nillable + { + $$ = true; + } +| + { + $$ = false; + } + +XsdAttributes: + tok_xsd_attrs '{' FieldList '}' + { + $$ = $3; + } +| + { + $$ = NULL; + } + +Xception: + tok_xception tok_identifier '{' FieldList '}' TypeAnnotations + { + pdebug("Xception -> tok_xception tok_identifier { FieldList }"); + validate_simple_identifier( $2); + $4->set_name($2); + $4->set_xception(true); + $$ = $4; + if ($6 != NULL) { + $$->annotations_ = $6->annotations_; + delete $6; + } + } + +Service: + tok_service tok_identifier Extends '{' FlagArgs FunctionList UnflagArgs '}' TypeAnnotations + { + pdebug("Service -> tok_service tok_identifier { FunctionList }"); + validate_simple_identifier( $2); + $$ = $6; + $$->set_name($2); + $$->set_extends($3); + if ($9 != NULL) { + $$->annotations_ = $9->annotations_; + delete $9; + } + } + +FlagArgs: + { + g_arglist = 1; + } + +UnflagArgs: + { + g_arglist = 0; + } + +Extends: + tok_extends tok_identifier + { + pdebug("Extends -> tok_extends tok_identifier"); + $$ = NULL; + if (g_parse_mode == PROGRAM) { + $$ = g_scope->get_service($2); + if ($$ == NULL) { + yyerror("Service \"%s\" has not been defined.", $2); + exit(1); + } + } + } +| + { + $$ = NULL; + } + +FunctionList: + FunctionList Function + { + pdebug("FunctionList -> FunctionList Function"); + $$ = $1; + $1->add_function($2); + } +| + { + pdebug("FunctionList -> "); + $$ = new t_service(g_program); + } + +Function: + CaptureDocText Oneway FunctionType tok_identifier '(' FieldList ')' Throws TypeAnnotations CommaOrSemicolonOptional + { + validate_simple_identifier( $4); + $6->set_name(std::string($4) + "_args"); + $$ = new t_function($3, $4, $6, $8, $2); + if ($1 != NULL) { + $$->set_doc($1); + } + if ($9 != NULL) { + $$->annotations_ = $9->annotations_; + delete $9; + } + } + +Oneway: + tok_oneway + { + $$ = true; + } +| + { + $$ = false; + } + +Throws: + tok_throws '(' FieldList ')' + { + pdebug("Throws -> tok_throws ( FieldList )"); + $$ = $3; + if (g_parse_mode == PROGRAM && !validate_throws($$)) { + yyerror("Throws clause may not contain non-exception types"); + exit(1); + } + } +| + { + $$ = new t_struct(g_program); + } + +FieldList: + FieldList Field + { + pdebug("FieldList -> FieldList , Field"); + $$ = $1; + if (!($$->append($2))) { + yyerror("\"%d: %s\" - field identifier/name has already been used", $2->get_key(), $2->get_name().c_str()); + exit(1); + } + } +| + { + pdebug("FieldList -> "); + y_field_val = -1; + $$ = new t_struct(g_program); + } + +Field: + CaptureDocText FieldIdentifier FieldRequiredness FieldType FieldReference tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes TypeAnnotations CommaOrSemicolonOptional + { + pdebug("tok_int_constant : Field -> FieldType tok_identifier"); + if ($2.auto_assigned) { + pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $6); + if (g_strict >= 192) { + yyerror("Implicit field keys are deprecated and not allowed with -strict"); + exit(1); + } + } + validate_simple_identifier($6); + $$ = new t_field($4, $6, $2.value); + $$->set_reference($5); + $$->set_req($3); + if ($7 != NULL) { + g_scope->resolve_const_value($7, $4); + validate_field_value($$, $7); + $$->set_value($7); + } + $$->set_xsd_optional($8); + $$->set_xsd_nillable($9); + if ($1 != NULL) { + $$->set_doc($1); + } + if ($10 != NULL) { + $$->set_xsd_attrs($10); + } + if ($11 != NULL) { + $$->annotations_ = $11->annotations_; + delete $11; + } + } + +FieldIdentifier: + tok_int_constant ':' + { + if ($1 <= 0) { + if (g_allow_neg_field_keys) { + /* + * g_allow_neg_field_keys exists to allow users to add explicitly + * specified key values to old .thrift files without breaking + * protocol compatibility. + */ + if ($1 != y_field_val) { + /* + * warn if the user-specified negative value isn't what + * thrift would have auto-assigned. + */ + pwarning(1, "Nonpositive field key (%" PRIi64") differs from what would be " + "auto-assigned by thrift (%d).\n", $1, y_field_val); + } + /* + * Leave $1 as-is, and update y_field_val to be one less than $1. + * The FieldList parsing will catch any duplicate key values. + */ + y_field_val = static_cast($1 - 1); + $$.value = static_cast($1); + $$.auto_assigned = false; + } else { + pwarning(1, "Nonpositive value (%d) not allowed as a field key.\n", + $1); + $$.value = y_field_val--; + $$.auto_assigned = true; + } + } else { + $$.value = static_cast($1); + $$.auto_assigned = false; + } + if( (SHRT_MIN > $$.value) || ($$.value > SHRT_MAX)) { + pwarning(1, "Field key (%d) exceeds allowed range (%d..%d).\n", + $$.value, SHRT_MIN, SHRT_MAX); + } + } +| + { + $$.value = y_field_val--; + $$.auto_assigned = true; + if( (SHRT_MIN > $$.value) || ($$.value > SHRT_MAX)) { + pwarning(1, "Field key (%d) exceeds allowed range (%d..%d).\n", + $$.value, SHRT_MIN, SHRT_MAX); + } + } + +FieldReference: + tok_reference + { + $$ = true; + } +| + { + $$ = false; + } + +FieldRequiredness: + tok_required + { + $$ = t_field::T_REQUIRED; + } +| tok_optional + { + if (g_arglist) { + if (g_parse_mode == PROGRAM) { + pwarning(1, "optional keyword is ignored in argument lists.\n"); + } + $$ = t_field::T_OPT_IN_REQ_OUT; + } else { + $$ = t_field::T_OPTIONAL; + } + } +| + { + $$ = t_field::T_OPT_IN_REQ_OUT; + } + +FieldValue: + '=' ConstValue + { + if (g_parse_mode == PROGRAM) { + $$ = $2; + } else { + $$ = NULL; + } + } +| + { + $$ = NULL; + } + +FunctionType: + FieldType + { + pdebug("FunctionType -> FieldType"); + $$ = $1; + } +| tok_void + { + pdebug("FunctionType -> tok_void"); + $$ = g_type_void; + } + +FieldType: + tok_identifier + { + pdebug("FieldType -> tok_identifier"); + if (g_parse_mode == INCLUDES) { + // Ignore identifiers in include mode + $$ = NULL; + } else { + // Lookup the identifier in the current scope + $$ = g_scope->get_type($1); + if ($$ == NULL) { + /* + * Either this type isn't yet declared, or it's never + declared. Either way allow it and we'll figure it out + during generation. + */ + $$ = new t_typedef(g_program, $1, true); + } + } + } +| BaseType + { + pdebug("FieldType -> BaseType"); + $$ = $1; + } +| ContainerType + { + pdebug("FieldType -> ContainerType"); + $$ = $1; + } + +BaseType: SimpleBaseType TypeAnnotations + { + pdebug("BaseType -> SimpleBaseType TypeAnnotations"); + if ($2 != NULL) { + $$ = new t_base_type(*static_cast($1)); + $$->annotations_ = $2->annotations_; + delete $2; + } else { + $$ = $1; + } + } + +SimpleBaseType: + tok_string + { + pdebug("BaseType -> tok_string"); + $$ = g_type_string; + } +| tok_binary + { + pdebug("BaseType -> tok_binary"); + $$ = g_type_binary; + } +| tok_slist + { + pdebug("BaseType -> tok_slist"); + $$ = g_type_slist; + } +| tok_bool + { + pdebug("BaseType -> tok_bool"); + $$ = g_type_bool; + } +| tok_i8 + { + pdebug("BaseType -> tok_i8"); + $$ = g_type_i8; + } +| tok_i16 + { + pdebug("BaseType -> tok_i16"); + $$ = g_type_i16; + } +| tok_i32 + { + pdebug("BaseType -> tok_i32"); + $$ = g_type_i32; + } +| tok_i64 + { + pdebug("BaseType -> tok_i64"); + $$ = g_type_i64; + } +| tok_double + { + pdebug("BaseType -> tok_double"); + $$ = g_type_double; + } + +ContainerType: SimpleContainerType TypeAnnotations + { + pdebug("ContainerType -> SimpleContainerType TypeAnnotations"); + $$ = $1; + if ($2 != NULL) { + $$->annotations_ = $2->annotations_; + delete $2; + } + } + +SimpleContainerType: + MapType + { + pdebug("SimpleContainerType -> MapType"); + $$ = $1; + } +| SetType + { + pdebug("SimpleContainerType -> SetType"); + $$ = $1; + } +| ListType + { + pdebug("SimpleContainerType -> ListType"); + $$ = $1; + } + +MapType: + tok_map CppType '<' FieldType ',' FieldType '>' + { + pdebug("MapType -> tok_map "); + $$ = new t_map($4, $6); + if ($2 != NULL) { + ((t_container*)$$)->set_cpp_name(std::string($2)); + } + } + +SetType: + tok_set CppType '<' FieldType '>' + { + pdebug("SetType -> tok_set"); + $$ = new t_set($4); + if ($2 != NULL) { + ((t_container*)$$)->set_cpp_name(std::string($2)); + } + } + +ListType: + tok_list '<' FieldType '>' CppType + { + pdebug("ListType -> tok_list"); + check_for_list_of_bytes($3); + $$ = new t_list($3); + if ($5 != NULL) { + ((t_container*)$$)->set_cpp_name(std::string($5)); + } + } + +CppType: + tok_cpp_type tok_literal + { + $$ = $2; + } +| + { + $$ = NULL; + } + +TypeAnnotations: + '(' TypeAnnotationList ')' + { + pdebug("TypeAnnotations -> ( TypeAnnotationList )"); + $$ = $2; + } +| + { + $$ = NULL; + } + +TypeAnnotationList: + TypeAnnotationList TypeAnnotation + { + pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation"); + $$ = $1; + $$->annotations_[$2->key] = $2->val; + delete $2; + } +| + { + /* Just use a dummy structure to hold the annotations. */ + $$ = new t_struct(g_program); + } + +TypeAnnotation: + tok_identifier TypeAnnotationValue CommaOrSemicolonOptional + { + pdebug("TypeAnnotation -> TypeAnnotationValue"); + $$ = new t_annotation; + $$->key = $1; + $$->val = $2; + } + +TypeAnnotationValue: + '=' tok_literal + { + pdebug("TypeAnnotationValue -> = tok_literal"); + $$ = $2; + } +| + { + pdebug("TypeAnnotationValue ->"); + $$ = strdup("1"); + } + +%% diff --git a/compiler/cpp/src/thrift/version.h b/compiler/cpp/src/thrift/version.h new file mode 100644 index 0000000..85a126c --- /dev/null +++ b/compiler/cpp/src/thrift/version.h @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_VERSION_H_ +#define _THRIFT_VERSION_H_ 1 + +#if defined(_MSC_VER) && (_MSC_VER > 1200) +#pragma once +#endif // _MSC_VER + +#define THRIFT_VERSION "0.11.0" + +#endif // _THRIFT_VERSION_H_ diff --git a/compiler/cpp/src/thrift/version.h.in b/compiler/cpp/src/thrift/version.h.in new file mode 100644 index 0000000..aef076f --- /dev/null +++ b/compiler/cpp/src/thrift/version.h.in @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_VERSION_H_ +#define _THRIFT_VERSION_H_ 1 + +#if defined(_MSC_VER) && (_MSC_VER > 1200) +#pragma once +#endif // _MSC_VER + +#define THRIFT_VERSION "@PACKAGE_VERSION@" + +#endif // _THRIFT_VERSION_H_ diff --git a/compiler/cpp/src/thrift/windows/config.h b/compiler/cpp/src/thrift/windows/config.h new file mode 100644 index 0000000..d2269cf --- /dev/null +++ b/compiler/cpp/src/thrift/windows/config.h @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_WINDOWS_CONFIG_H_ +#define _THRIFT_WINDOWS_CONFIG_H_ 1 + +#if defined(_MSC_VER) && (_MSC_VER > 1200) +#pragma once +#endif // _MSC_VER + +#ifndef _WIN32 +#error "This is a Windows header only" +#endif + +#include +#include +#include + +#define strtoll(begin_ptr, end_ptr, length) _strtoi64(begin_ptr, end_ptr, length) + +#ifndef PRIu64 +#define PRIu64 "I64u" +#endif + +#ifndef PRIi64 +#define PRIi64 "I64i" +#endif +// squelch deprecation warnings +#pragma warning(disable : 4996) +// squelch bool conversion performance warning +#pragma warning(disable : 4800) + +// MSVC10 (2010) or later has stdint.h +#if _MSC_VER >= 1600 +#define HAVE_STDINT_H 1 +#endif + +// Must be using VS2010 or later, or boost, so that C99 types are defined in the global namespace +#ifdef HAVE_STDINT_H +#include +#else +#include + +typedef boost::int64_t int64_t; +typedef boost::uint64_t uint64_t; +typedef boost::int32_t int32_t; +typedef boost::uint32_t uint32_t; +typedef boost::int16_t int16_t; +typedef boost::uint16_t uint16_t; +typedef boost::int8_t int8_t; +typedef boost::uint8_t uint8_t; +#endif + +#endif // _THRIFT_WINDOWS_CONFIG_H_ diff --git a/compiler/cpp/test/CMakeLists.txt b/compiler/cpp/test/CMakeLists.txt new file mode 100644 index 0000000..c1fe914 --- /dev/null +++ b/compiler/cpp/test/CMakeLists.txt @@ -0,0 +1,77 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +if(${WITH_PLUGIN}) + include_directories(SYSTEM "${Boost_INCLUDE_DIRS}") + + # Make sure gen-cpp files can be included + include_directories("${CMAKE_CURRENT_BINARY_DIR}") + + set(plugintest_SOURCES + plugin/conversion_test.cc + ) + add_executable(plugintest ${plugintest_SOURCES}) + if(WITH_SHARED_LIB AND NOT MSVC) + target_link_libraries(plugintest + thriftc + ${Boost_LIBRARIES} + ) + else() + target_link_libraries(plugintest + thriftc_static + thrift_static + ${Boost_LIBRARIES} + ) + endif() + add_test(NAME PluginUnitTest COMMAND plugintest) + + set(thrift-gen-mycpp_SOURCES + ../src/thrift/generate/t_cpp_generator.cc + plugin/cpp_plugin.cc + ) + add_executable(thrift-gen-mycpp ${thrift-gen-mycpp_SOURCES}) + if(WITH_SHARED_LIB AND NOT MSVC) + target_link_libraries(thrift-gen-mycpp thriftc) + else() + target_link_libraries(thrift-gen-mycpp thriftc_static thrift_static) + endif() + + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(BUILDTYPE "Debug") + else() + # RelWithDebInfo generates binaries in "Release" directory too + set(BUILDTYPE "Release") + endif() + + set_directory_properties(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES gen-cpp + ADDITIONAL_MAKE_CLEAN_FILES gen-mycpp) + + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/gen-mycpp) + add_test(NAME PluginIntegrationTest + COMMAND ${CMAKE_COMMAND} + -DTHRIFT_COMPILER=${THRIFT_COMPILER} + -DBINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + -DBUILDTYPE=${BUILDTYPE} + -DCURDIR=${CMAKE_CURRENT_BINARY_DIR} + -DSRCDIR=${CMAKE_CURRENT_SOURCE_DIR} + -P ${CMAKE_CURRENT_SOURCE_DIR}/cpp_plugin_test.cmake) +endif() diff --git a/compiler/cpp/test/Makefile b/compiler/cpp/test/Makefile new file mode 100644 index 0000000..a49e22d --- /dev/null +++ b/compiler/cpp/test/Makefile @@ -0,0 +1,984 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# compiler/cpp/test/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# +# Contains some contributions under the Thrift Software License. +# Please see doc/old-thrift-license.txt in the Thrift distribution for +# details. + + +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/thrift +pkgincludedir = $(includedir)/thrift +pkglibdir = $(libdir)/thrift +pkglibexecdir = $(libexecdir)/thrift +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-pc-linux-gnu +host_triplet = x86_64-pc-linux-gnu +#check_PROGRAMS = plugintest$(EXEEXT) +#noinst_PROGRAMS = thrift-gen-mycpp$(EXEEXT) +#am__append_1 = -I$(top_srcdir)/lib/cpp/src -I$(top_builddir)/lib/cpp/src +subdir = compiler/cpp/test +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +PROGRAMS = $(noinst_PROGRAMS) +am__plugintest_SOURCES_DIST = plugin/conversion_test.cc +am__dirstamp = $(am__leading_dot)dirstamp +#am_plugintest_OBJECTS = \ +# plugin/conversion_test.$(OBJEXT) +plugintest_OBJECTS = $(am_plugintest_OBJECTS) +#plugintest_DEPENDENCIES = \ +# $(top_builddir)/compiler/cpp/libthriftc.la +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am__v_lt_1 = +am__thrift_gen_mycpp_SOURCES_DIST = plugin/cpp_plugin.cc \ + plugin/t_cpp_generator.cc +#am_thrift_gen_mycpp_OBJECTS = plugin/thrift_gen_mycpp-cpp_plugin.$(OBJEXT) \ +# plugin/thrift_gen_mycpp-t_cpp_generator.$(OBJEXT) +thrift_gen_mycpp_OBJECTS = $(am_thrift_gen_mycpp_OBJECTS) +#thrift_gen_mycpp_DEPENDENCIES = \ +# $(top_builddir)/compiler/cpp/libthriftc.la +AM_V_P = $(am__v_P_$(V)) +am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I. -I$(top_builddir) -I$(top_builddir)/lib/cpp/src/thrift -I$(top_builddir)/lib/c_glib/src/thrift +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_$(V)) +am__v_CXX_ = $(am__v_CXX_$(AM_DEFAULT_VERBOSITY)) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_$(V)) +am__v_CXXLD_ = $(am__v_CXXLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(plugintest_SOURCES) $(thrift_gen_mycpp_SOURCES) +DIST_SOURCES = $(am__plugintest_SOURCES_DIST) \ + $(am__thrift_gen_mycpp_SOURCES_DIST) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red=''; \ + grn=''; \ + lgn=''; \ + blu=''; \ + mgn=''; \ + brg=''; \ + std=''; \ + fi; \ +} +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15 +ALLOCA = +AMTAR = $${TAR-tar} +AM_DEFAULT_VERBOSITY = 1 +ANT = /usr/bin/ant +ANT_FLAGS = +AR = ar +AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf +AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader +AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15 +AWK = gawk +BISON = bison +BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a +BOOST_CPPFLAGS = -I/usr/include +BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a +BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu +BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu +BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a +BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a +BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a +BUNDLER = /usr/bin/bundle +CABAL = /usr/bin/cabal +CABAL_CONFIGURE_FLAGS = +CARGO = /usr/bin/cargo +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 +CLASSPATH = +CPP = gcc -E +CPPFLAGS = +CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \; +CXX = g++ -std=c++11 +CXXCPP = g++ -E -std=c++11 +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -g -O2 +CYGPATH_W = echo +DART = /usr/lib/dart/bin/dart +DARTPUB = /usr/lib/dart/bin/pub +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +DLLTOOL = false +DMD = dmd +DMD_LIBEVENT_FLAGS = +DMD_OF_DIRSEP = / +DMD_OPENSSL_FLAGS = +DOTNETCORE = /usr/bin/dotnet +DOTNETCORE_VERSION = 2.0.3 +DSYMUTIL = +DUMPBIN = +D_EVENT_LIB_NAME = libthriftd-event.a +D_IMPORT_PREFIX = ${prefix}/include/d2 +D_LIB_NAME = libthriftd.a +D_SSL_LIB_NAME = libthriftd-ssl.a +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +ENABLE_COVERAGE = 2 +ERL = /usr/bin/erl +ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib +ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0 +ERLANG_LIB_DIR = /usr/lib/erlang/lib +ERLC = /usr/bin/erlc +ERLCFLAGS = +EXEEXT = +FGREP = /bin/grep -F +GCOV_CFLAGS = +GCOV_CXXFLAGS = +GCOV_LDFLAGS = +GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GLIB_LIBS = -lglib-2.0 +GO = /usr/bin/go +GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0 +GREP = /bin/grep +HAVE_CXX11 = 1 +HAXE = /usr/bin/haxe +HAXE_VERSION = 3.2.1 +INSTALL = /usr/bin/install -c +INSTALLDIRS = vendor +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +JAVA_PREFIX = /usr/local/lib +LD = /usr/bin/ld -m elf_x86_64 +LDFLAGS = +LEX = flex +LEXLIB = -lfl +LEX_OUTPUT_ROOT = lex.yy +LIBEVENT_CPPFLAGS = +LIBEVENT_LDFLAGS = +LIBEVENT_LIBS = -levent +LIBOBJS = +LIBS = -lrt -lpthread +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LIPO = +LN_S = ln -s +LTLIBOBJS = +LT_SYS_LIBRARY_PATH = +LUA = /usr/bin/lua5.3 +LUA_EXEC_PREFIX = ${exec_prefix} +LUA_INCLUDE = -I/usr/include/lua5.3 +LUA_LIB = -llua5.3 -ldl +LUA_PLATFORM = unknown +LUA_PREFIX = ${prefix} +LUA_SHORT_VERSION = 53 +LUA_VERSION = 5.3 +MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo +MANIFEST_TOOL = : +MAYBE_CPP = cpp +MAYBE_CSHARP = csharp +MAYBE_C_GLIB = c_glib +MAYBE_D = +MAYBE_DART = dart +MAYBE_DOTNETCORE = netcore +MAYBE_ERLANG = erl +MAYBE_GO = go +MAYBE_HASKELL = hs +MAYBE_JAVA = java +MAYBE_LUA = lua +MAYBE_NODEJS = nodejs +MAYBE_PERL = perl +MAYBE_PHP = php +MAYBE_PY3 = py3 +MAYBE_PYTHON = py +MAYBE_RS = rs +MAYBE_RUBY = rb +MCS = /usr/bin/mcs +MKDIR_P = /bin/mkdir -p +MONO_CFLAGS = +MONO_LIBS = +NM = /usr/bin/nm -B +NMEDIT = +NODEJS = /usr/bin/nodejs +NPM = /usr/bin/npm +OBJDUMP = objdump +OBJEXT = o +OPENSSL_INCLUDES = +OPENSSL_LDFLAGS = +OPENSSL_LIBS = -lssl -lcrypto +OTOOL = +OTOOL64 = +PACKAGE = thrift +PACKAGE_BUGREPORT = +PACKAGE_NAME = thrift +PACKAGE_STRING = thrift 0.11.0 +PACKAGE_TARNAME = thrift +PACKAGE_URL = +PACKAGE_VERSION = 0.11.0 +PATH_SEPARATOR = : +PERL = /usr/bin/perl +PERL_PREFIX = /usr/local +PHP = /usr/bin/php +PHPUNIT = /usr/bin/phpunit +PHP_CONFIG = /usr/bin/php-config +PHP_CONFIG_PREFIX = /etc/php.d +PHP_PREFIX = /usr/lib/php +PKG_CONFIG = /usr/bin/pkg-config +PKG_CONFIG_LIBDIR = +PKG_CONFIG_PATH = +PYTHON = /usr/bin/python +PYTHON3 = /usr/bin/python3 +PYTHON_EXEC_PREFIX = ${exec_prefix} +PYTHON_PLATFORM = linux2 +PYTHON_PREFIX = ${prefix} +PYTHON_VERSION = 2.7 +PY_PREFIX = /usr +QT5_CFLAGS = +QT5_LIBS = +QT5_MOC = +QT_CFLAGS = +QT_LIBS = +QT_MOC = +RANLIB = ranlib +REBAR = /usr/bin/rebar +RUBY = /usr/bin/ruby +RUBY_PREFIX = +RUNHASKELL = /usr/bin/runhaskell +RUSTC = /usr/bin/rustc +SED = /bin/sed +SET_MAKE = +SHELL = /bin/bash +STRIP = strip +THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift +TRIAL = /usr/bin/trial +VERSION = 0.11.0 +YACC = bison -y +YFLAGS = +ZLIB_CPPFLAGS = +ZLIB_LDFLAGS = +ZLIB_LIBS = -lz +abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/test +abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/test +abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift +abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift +ac_ct_AR = ar +ac_ct_CC = gcc +ac_ct_CXX = g++ +ac_ct_DUMPBIN = +am__include = include +am__leading_dot = . +am__quote = +am__tar = tar --format=ustar -chf - "$$tardir" +am__untar = tar -xf - +bindir = ${exec_prefix}/bin +build = x86_64-pc-linux-gnu +build_alias = +build_cpu = x86_64 +build_os = linux-gnu +build_vendor = pc +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +golang_version = 1.6.2 +have_prog_bison = yes +host = x86_64-pc-linux-gnu +host_alias = +host_cpu = x86_64 +host_os = linux-gnu +host_vendor = pc +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +luadir = ${prefix}/share/lua/5.3 +luaexecdir = ${exec_prefix}/lib/lua/5.3 +mandir = ${datarootdir}/man +mkdir_p = $(MKDIR_P) +oldincludedir = /usr/include +pdfdir = ${docdir} +pkgluadir = ${luadir}/thrift +pkgluaexecdir = ${luaexecdir}/thrift +pkgpyexecdir = ${pyexecdir}/thrift +pkgpythondir = ${pythondir}/thrift +prefix = /usr/local +program_transform_name = s,x,x, +psdir = ${docdir} +pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages +pythondir = ${prefix}/lib/python2.7/dist-packages +runstatedir = ${localstatedir}/run +rustc_version = rustc 1.17.0 +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +subdirs = lib/php/src/ext/thrift_protocol +sysconfdir = ${prefix}/etc +target_alias = +top_build_prefix = ../../../ +top_builddir = ../../.. +top_srcdir = ../../.. +AUTOMAKE_OPTIONS = subdir-objects serial-tests +AM_CPPFLAGS = $(BOOST_CPPFLAGS) -I$(top_srcdir)/compiler/cpp/src \ + $(am__append_1) +AM_LDFLAGS = $(BOOST_LDFLAGS) +AM_CXXFLAGS = -Wall -Wextra -pedantic +#plugintest_SOURCES = plugin/conversion_test.cc +#plugintest_LDADD = $(top_builddir)/compiler/cpp/libthriftc.la +#thrift_gen_mycpp_SOURCES = plugin/cpp_plugin.cc \ +# plugin/t_cpp_generator.cc + +#thrift_gen_mycpp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/compiler/cpp -I$(top_srcdir)/compiler/cpp/src/generate +#thrift_gen_mycpp_LDADD = $(top_builddir)/compiler/cpp/libthriftc.la +#TESTS = $(check_PROGRAMS) cpp_plugin_test.sh +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign compiler/cpp/test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign compiler/cpp/test/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +plugin/$(am__dirstamp): + @$(MKDIR_P) plugin + @: > plugin/$(am__dirstamp) +plugin/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) plugin/$(DEPDIR) + @: > plugin/$(DEPDIR)/$(am__dirstamp) +plugin/conversion_test.$(OBJEXT): plugin/$(am__dirstamp) \ + plugin/$(DEPDIR)/$(am__dirstamp) + +plugintest$(EXEEXT): $(plugintest_OBJECTS) $(plugintest_DEPENDENCIES) $(EXTRA_plugintest_DEPENDENCIES) + @rm -f plugintest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(plugintest_OBJECTS) $(plugintest_LDADD) $(LIBS) +plugin/thrift_gen_mycpp-cpp_plugin.$(OBJEXT): plugin/$(am__dirstamp) \ + plugin/$(DEPDIR)/$(am__dirstamp) +plugin/thrift_gen_mycpp-t_cpp_generator.$(OBJEXT): \ + plugin/$(am__dirstamp) plugin/$(DEPDIR)/$(am__dirstamp) + +thrift-gen-mycpp$(EXEEXT): $(thrift_gen_mycpp_OBJECTS) $(thrift_gen_mycpp_DEPENDENCIES) $(EXTRA_thrift_gen_mycpp_DEPENDENCIES) + @rm -f thrift-gen-mycpp$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(thrift_gen_mycpp_OBJECTS) $(thrift_gen_mycpp_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f plugin/*.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +include plugin/$(DEPDIR)/conversion_test.Po +include plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Po +include plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Po + +.cc.o: + $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ + $(am__mv) $$depbase.Tpo $$depbase.Po +# $(AM_V_CXX)source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ +# $(AM_V_CXX_no)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: + $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ + $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ + $(am__mv) $$depbase.Tpo $$depbase.Po +# $(AM_V_CXX)source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ +# $(AM_V_CXX_no)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: + $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ + $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ + $(am__mv) $$depbase.Tpo $$depbase.Plo +# $(AM_V_CXX)source='$<' object='$@' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ +# $(AM_V_CXX_no)$(LTCXXCOMPILE) -c -o $@ $< + +plugin/thrift_gen_mycpp-cpp_plugin.o: plugin/cpp_plugin.cc + $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT plugin/thrift_gen_mycpp-cpp_plugin.o -MD -MP -MF plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Tpo -c -o plugin/thrift_gen_mycpp-cpp_plugin.o `test -f 'plugin/cpp_plugin.cc' || echo '$(srcdir)/'`plugin/cpp_plugin.cc + $(AM_V_at)$(am__mv) plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Tpo plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Po +# $(AM_V_CXX)source='plugin/cpp_plugin.cc' object='plugin/thrift_gen_mycpp-cpp_plugin.o' libtool=no \ +# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ +# $(AM_V_CXX_no)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o plugin/thrift_gen_mycpp-cpp_plugin.o `test -f 'plugin/cpp_plugin.cc' || echo '$(srcdir)/'`plugin/cpp_plugin.cc + +plugin/thrift_gen_mycpp-cpp_plugin.obj: plugin/cpp_plugin.cc + $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT plugin/thrift_gen_mycpp-cpp_plugin.obj -MD -MP -MF plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Tpo -c -o plugin/thrift_gen_mycpp-cpp_plugin.obj `if test -f 'plugin/cpp_plugin.cc'; then $(CYGPATH_W) 'plugin/cpp_plugin.cc'; else $(CYGPATH_W) '$(srcdir)/plugin/cpp_plugin.cc'; fi` + $(AM_V_at)$(am__mv) plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Tpo plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Po +# $(AM_V_CXX)source='plugin/cpp_plugin.cc' object='plugin/thrift_gen_mycpp-cpp_plugin.obj' libtool=no \ +# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ +# $(AM_V_CXX_no)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o plugin/thrift_gen_mycpp-cpp_plugin.obj `if test -f 'plugin/cpp_plugin.cc'; then $(CYGPATH_W) 'plugin/cpp_plugin.cc'; else $(CYGPATH_W) '$(srcdir)/plugin/cpp_plugin.cc'; fi` + +plugin/thrift_gen_mycpp-t_cpp_generator.o: plugin/t_cpp_generator.cc + $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT plugin/thrift_gen_mycpp-t_cpp_generator.o -MD -MP -MF plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Tpo -c -o plugin/thrift_gen_mycpp-t_cpp_generator.o `test -f 'plugin/t_cpp_generator.cc' || echo '$(srcdir)/'`plugin/t_cpp_generator.cc + $(AM_V_at)$(am__mv) plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Tpo plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Po +# $(AM_V_CXX)source='plugin/t_cpp_generator.cc' object='plugin/thrift_gen_mycpp-t_cpp_generator.o' libtool=no \ +# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ +# $(AM_V_CXX_no)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o plugin/thrift_gen_mycpp-t_cpp_generator.o `test -f 'plugin/t_cpp_generator.cc' || echo '$(srcdir)/'`plugin/t_cpp_generator.cc + +plugin/thrift_gen_mycpp-t_cpp_generator.obj: plugin/t_cpp_generator.cc + $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT plugin/thrift_gen_mycpp-t_cpp_generator.obj -MD -MP -MF plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Tpo -c -o plugin/thrift_gen_mycpp-t_cpp_generator.obj `if test -f 'plugin/t_cpp_generator.cc'; then $(CYGPATH_W) 'plugin/t_cpp_generator.cc'; else $(CYGPATH_W) '$(srcdir)/plugin/t_cpp_generator.cc'; fi` + $(AM_V_at)$(am__mv) plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Tpo plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Po +# $(AM_V_CXX)source='plugin/t_cpp_generator.cc' object='plugin/thrift_gen_mycpp-t_cpp_generator.obj' libtool=no \ +# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ +# $(AM_V_CXX_no)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o plugin/thrift_gen_mycpp-t_cpp_generator.obj `if test -f 'plugin/t_cpp_generator.cc'; then $(CYGPATH_W) 'plugin/t_cpp_generator.cc'; else $(CYGPATH_W) '$(srcdir)/plugin/t_cpp_generator.cc'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f plugin/$(DEPDIR)/$(am__dirstamp) + -rm -f plugin/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean-local: +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool clean-local \ + clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf plugin/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf plugin/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool clean-local \ + clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am style-am style-local tags tags-am \ + uninstall uninstall-am + +.PRECIOUS: Makefile + + +#cpp_plugin_test.sh: thrift-gen-mycpp + +#clean-local: +# $(RM) -rf gen-cpp gen-mycpp + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/compiler/cpp/test/Makefile.am b/compiler/cpp/test/Makefile.am new file mode 100644 index 0000000..5a23202 --- /dev/null +++ b/compiler/cpp/test/Makefile.am @@ -0,0 +1,51 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# +# Contains some contributions under the Thrift Software License. +# Please see doc/old-thrift-license.txt in the Thrift distribution for +# details. + +AUTOMAKE_OPTIONS = subdir-objects serial-tests + +AM_CPPFLAGS = $(BOOST_CPPFLAGS) -I$(top_srcdir)/compiler/cpp/src +AM_LDFLAGS = $(BOOST_LDFLAGS) +AM_CXXFLAGS = -Wall -Wextra -pedantic + +if WITH_PLUGIN +check_PROGRAMS = plugintest + +noinst_PROGRAMS = thrift-gen-mycpp + +AM_CPPFLAGS += -I$(top_srcdir)/lib/cpp/src -I$(top_builddir)/lib/cpp/src + +plugintest_SOURCES = plugin/conversion_test.cc +plugintest_LDADD = $(top_builddir)/compiler/cpp/libthriftc.la + +thrift_gen_mycpp_SOURCES = plugin/cpp_plugin.cc \ + plugin/t_cpp_generator.cc +thrift_gen_mycpp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/compiler/cpp -I$(top_srcdir)/compiler/cpp/src/generate +thrift_gen_mycpp_LDADD = $(top_builddir)/compiler/cpp/libthriftc.la + +cpp_plugin_test.sh: thrift-gen-mycpp +TESTS = $(check_PROGRAMS) cpp_plugin_test.sh + +clean-local: + $(RM) -rf gen-cpp gen-mycpp + +endif diff --git a/compiler/cpp/test/Makefile.in b/compiler/cpp/test/Makefile.in new file mode 100644 index 0000000..52676a8 --- /dev/null +++ b/compiler/cpp/test/Makefile.in @@ -0,0 +1,984 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# +# Contains some contributions under the Thrift Software License. +# Please see doc/old-thrift-license.txt in the Thrift distribution for +# details. + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@WITH_PLUGIN_TRUE@check_PROGRAMS = plugintest$(EXEEXT) +@WITH_PLUGIN_TRUE@noinst_PROGRAMS = thrift-gen-mycpp$(EXEEXT) +@WITH_PLUGIN_TRUE@am__append_1 = -I$(top_srcdir)/lib/cpp/src -I$(top_builddir)/lib/cpp/src +subdir = compiler/cpp/test +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +PROGRAMS = $(noinst_PROGRAMS) +am__plugintest_SOURCES_DIST = plugin/conversion_test.cc +am__dirstamp = $(am__leading_dot)dirstamp +@WITH_PLUGIN_TRUE@am_plugintest_OBJECTS = \ +@WITH_PLUGIN_TRUE@ plugin/conversion_test.$(OBJEXT) +plugintest_OBJECTS = $(am_plugintest_OBJECTS) +@WITH_PLUGIN_TRUE@plugintest_DEPENDENCIES = \ +@WITH_PLUGIN_TRUE@ $(top_builddir)/compiler/cpp/libthriftc.la +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +am__thrift_gen_mycpp_SOURCES_DIST = plugin/cpp_plugin.cc \ + plugin/t_cpp_generator.cc +@WITH_PLUGIN_TRUE@am_thrift_gen_mycpp_OBJECTS = plugin/thrift_gen_mycpp-cpp_plugin.$(OBJEXT) \ +@WITH_PLUGIN_TRUE@ plugin/thrift_gen_mycpp-t_cpp_generator.$(OBJEXT) +thrift_gen_mycpp_OBJECTS = $(am_thrift_gen_mycpp_OBJECTS) +@WITH_PLUGIN_TRUE@thrift_gen_mycpp_DEPENDENCIES = \ +@WITH_PLUGIN_TRUE@ $(top_builddir)/compiler/cpp/libthriftc.la +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/lib/cpp/src/thrift -I$(top_builddir)/lib/c_glib/src/thrift +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(plugintest_SOURCES) $(thrift_gen_mycpp_SOURCES) +DIST_SOURCES = $(am__plugintest_SOURCES_DIST) \ + $(am__thrift_gen_mycpp_SOURCES_DIST) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red=''; \ + grn=''; \ + lgn=''; \ + blu=''; \ + mgn=''; \ + brg=''; \ + std=''; \ + fi; \ +} +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = subdir-objects serial-tests +AM_CPPFLAGS = $(BOOST_CPPFLAGS) -I$(top_srcdir)/compiler/cpp/src \ + $(am__append_1) +AM_LDFLAGS = $(BOOST_LDFLAGS) +AM_CXXFLAGS = -Wall -Wextra -pedantic +@WITH_PLUGIN_TRUE@plugintest_SOURCES = plugin/conversion_test.cc +@WITH_PLUGIN_TRUE@plugintest_LDADD = $(top_builddir)/compiler/cpp/libthriftc.la +@WITH_PLUGIN_TRUE@thrift_gen_mycpp_SOURCES = plugin/cpp_plugin.cc \ +@WITH_PLUGIN_TRUE@ plugin/t_cpp_generator.cc + +@WITH_PLUGIN_TRUE@thrift_gen_mycpp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/compiler/cpp -I$(top_srcdir)/compiler/cpp/src/generate +@WITH_PLUGIN_TRUE@thrift_gen_mycpp_LDADD = $(top_builddir)/compiler/cpp/libthriftc.la +@WITH_PLUGIN_TRUE@TESTS = $(check_PROGRAMS) cpp_plugin_test.sh +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign compiler/cpp/test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign compiler/cpp/test/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +plugin/$(am__dirstamp): + @$(MKDIR_P) plugin + @: > plugin/$(am__dirstamp) +plugin/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) plugin/$(DEPDIR) + @: > plugin/$(DEPDIR)/$(am__dirstamp) +plugin/conversion_test.$(OBJEXT): plugin/$(am__dirstamp) \ + plugin/$(DEPDIR)/$(am__dirstamp) + +plugintest$(EXEEXT): $(plugintest_OBJECTS) $(plugintest_DEPENDENCIES) $(EXTRA_plugintest_DEPENDENCIES) + @rm -f plugintest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(plugintest_OBJECTS) $(plugintest_LDADD) $(LIBS) +plugin/thrift_gen_mycpp-cpp_plugin.$(OBJEXT): plugin/$(am__dirstamp) \ + plugin/$(DEPDIR)/$(am__dirstamp) +plugin/thrift_gen_mycpp-t_cpp_generator.$(OBJEXT): \ + plugin/$(am__dirstamp) plugin/$(DEPDIR)/$(am__dirstamp) + +thrift-gen-mycpp$(EXEEXT): $(thrift_gen_mycpp_OBJECTS) $(thrift_gen_mycpp_DEPENDENCIES) $(EXTRA_thrift_gen_mycpp_DEPENDENCIES) + @rm -f thrift-gen-mycpp$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(thrift_gen_mycpp_OBJECTS) $(thrift_gen_mycpp_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f plugin/*.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@plugin/$(DEPDIR)/conversion_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +plugin/thrift_gen_mycpp-cpp_plugin.o: plugin/cpp_plugin.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT plugin/thrift_gen_mycpp-cpp_plugin.o -MD -MP -MF plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Tpo -c -o plugin/thrift_gen_mycpp-cpp_plugin.o `test -f 'plugin/cpp_plugin.cc' || echo '$(srcdir)/'`plugin/cpp_plugin.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Tpo plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='plugin/cpp_plugin.cc' object='plugin/thrift_gen_mycpp-cpp_plugin.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o plugin/thrift_gen_mycpp-cpp_plugin.o `test -f 'plugin/cpp_plugin.cc' || echo '$(srcdir)/'`plugin/cpp_plugin.cc + +plugin/thrift_gen_mycpp-cpp_plugin.obj: plugin/cpp_plugin.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT plugin/thrift_gen_mycpp-cpp_plugin.obj -MD -MP -MF plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Tpo -c -o plugin/thrift_gen_mycpp-cpp_plugin.obj `if test -f 'plugin/cpp_plugin.cc'; then $(CYGPATH_W) 'plugin/cpp_plugin.cc'; else $(CYGPATH_W) '$(srcdir)/plugin/cpp_plugin.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Tpo plugin/$(DEPDIR)/thrift_gen_mycpp-cpp_plugin.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='plugin/cpp_plugin.cc' object='plugin/thrift_gen_mycpp-cpp_plugin.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o plugin/thrift_gen_mycpp-cpp_plugin.obj `if test -f 'plugin/cpp_plugin.cc'; then $(CYGPATH_W) 'plugin/cpp_plugin.cc'; else $(CYGPATH_W) '$(srcdir)/plugin/cpp_plugin.cc'; fi` + +plugin/thrift_gen_mycpp-t_cpp_generator.o: plugin/t_cpp_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT plugin/thrift_gen_mycpp-t_cpp_generator.o -MD -MP -MF plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Tpo -c -o plugin/thrift_gen_mycpp-t_cpp_generator.o `test -f 'plugin/t_cpp_generator.cc' || echo '$(srcdir)/'`plugin/t_cpp_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Tpo plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='plugin/t_cpp_generator.cc' object='plugin/thrift_gen_mycpp-t_cpp_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o plugin/thrift_gen_mycpp-t_cpp_generator.o `test -f 'plugin/t_cpp_generator.cc' || echo '$(srcdir)/'`plugin/t_cpp_generator.cc + +plugin/thrift_gen_mycpp-t_cpp_generator.obj: plugin/t_cpp_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT plugin/thrift_gen_mycpp-t_cpp_generator.obj -MD -MP -MF plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Tpo -c -o plugin/thrift_gen_mycpp-t_cpp_generator.obj `if test -f 'plugin/t_cpp_generator.cc'; then $(CYGPATH_W) 'plugin/t_cpp_generator.cc'; else $(CYGPATH_W) '$(srcdir)/plugin/t_cpp_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Tpo plugin/$(DEPDIR)/thrift_gen_mycpp-t_cpp_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='plugin/t_cpp_generator.cc' object='plugin/thrift_gen_mycpp-t_cpp_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(thrift_gen_mycpp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o plugin/thrift_gen_mycpp-t_cpp_generator.obj `if test -f 'plugin/t_cpp_generator.cc'; then $(CYGPATH_W) 'plugin/t_cpp_generator.cc'; else $(CYGPATH_W) '$(srcdir)/plugin/t_cpp_generator.cc'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f plugin/$(DEPDIR)/$(am__dirstamp) + -rm -f plugin/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +@WITH_PLUGIN_FALSE@clean-local: +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool clean-local \ + clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf plugin/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf plugin/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool clean-local \ + clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am style-am style-local tags tags-am \ + uninstall uninstall-am + +.PRECIOUS: Makefile + + +@WITH_PLUGIN_TRUE@cpp_plugin_test.sh: thrift-gen-mycpp + +@WITH_PLUGIN_TRUE@clean-local: +@WITH_PLUGIN_TRUE@ $(RM) -rf gen-cpp gen-mycpp + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/compiler/cpp/test/cpp_plugin_test.cmake b/compiler/cpp/test/cpp_plugin_test.cmake new file mode 100644 index 0000000..fd18281 --- /dev/null +++ b/compiler/cpp/test/cpp_plugin_test.cmake @@ -0,0 +1,45 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +file(MAKE_DIRECTORY ${CURDIR}/gen-cpp) +execute_process(COMMAND ${THRIFT_COMPILER} -r -out ${CURDIR}/gen-cpp -gen cpp ${SRCDIR}/../../../test/Include.thrift) +if(EXITCODE) + message(FATAL_ERROR "FAILED: \"${ARGV}\": \"${EXITCODE}\"") +endif() +if(WIN32) + set(ENV{PATH} "${BINDIR}/${BUILDTYPE};${BINDIR};$ENV{PATH}") +else() + set(ENV{PATH} "${BINDIR}:$ENV{PATH}") +endif() + +file(MAKE_DIRECTORY ${CURDIR}/gen-mycpp) +execute_process(COMMAND ${THRIFT_COMPILER} -r -out ${CURDIR}/gen-mycpp -gen mycpp ${SRCDIR}/../../../test/Include.thrift RESULT_VARIABLE EXITCODE) +if(EXITCODE) + message(FATAL_ERROR "FAILED: \"${EXITCODE}\"") +endif() + +find_program(DIFF diff) +if(DIFF) + execute_process(COMMAND ${DIFF} -urN gen-cpp gen-mycpp RESULT_VARIABLE EXITCODE) + if(EXITCODE) + message(FATAL_ERROR "FAILED: \"${EXITCODE}\"") + endif() +else() + message(WARNING "diff executable is not available. Not validating plugin-generated code.") +endif() diff --git a/compiler/cpp/test/cpp_plugin_test.sh b/compiler/cpp/test/cpp_plugin_test.sh new file mode 100755 index 0000000..ddb2e0a --- /dev/null +++ b/compiler/cpp/test/cpp_plugin_test.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# this file is intended to be invoked by make. +set -e +mkdir -p gen-cpp gen-mycpp +PATH=.:"$PATH" ../thrift -r -out gen-cpp -gen cpp ../../../test/Include.thrift +PATH=.:"$PATH" ../thrift -r -out gen-mycpp -gen mycpp ../../../test/Include.thrift +diff -urN gen-cpp gen-mycpp diff --git a/compiler/cpp/test/plugin/conversion_test.cc b/compiler/cpp/test/plugin/conversion_test.cc new file mode 100644 index 0000000..5159ba4 --- /dev/null +++ b/compiler/cpp/test/plugin/conversion_test.cc @@ -0,0 +1,496 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "thrift/parse/t_program.h" +#include "thrift/plugin/type_util.h" +#include "thrift/plugin/plugin_types.h" + +#include +#include + +#include +#include +#include + +using namespace apache::thrift; +using namespace boost::unit_test; + +namespace test_data { +#define T_TEST_TYPES \ + BOOST_PP_TUPLE_TO_LIST(14, \ + (program, \ + base_type, \ + enum_value, \ + enum, \ + const_value, \ + const, \ + list, \ + set, \ + map, \ + field, \ + struct, \ + typedef, \ + function, \ + service)) +#define T_DELETE_TESTDATA(r, d, elem) \ + for (std::vector::reverse_iterator it = elem##s.rbegin(); it != elem##s.rend(); it++) \ + delete *it; +#define T_DECL_TESTDATA(r, d, elem) static std::vector< ::t_##elem*> elem##s; +BOOST_PP_LIST_FOR_EACH(T_DECL_TESTDATA, _, T_TEST_TYPES) +#undef T_DECL_TESTDATA + +bool has_data = false; +void cleanup() { + if (has_data) { + has_data = false; + BOOST_PP_LIST_FOR_EACH(T_DELETE_TESTDATA, _, T_TEST_TYPES) + } +} + +void init_programs() { + programs.push_back(new t_program("prog path", "prog_name")); +} + +void init_base_types() { + base_types.push_back(new ::t_base_type("name0", ::t_base_type::TYPE_VOID)); + base_types.push_back(new ::t_base_type("name1", ::t_base_type::TYPE_STRING)); + base_types.push_back(new ::t_base_type("name2", ::t_base_type::TYPE_BOOL)); + base_types.push_back(new ::t_base_type("name3", ::t_base_type::TYPE_I8)); + base_types.push_back(new ::t_base_type("name4", ::t_base_type::TYPE_I16)); + base_types.push_back(new ::t_base_type("name5", ::t_base_type::TYPE_I32)); + base_types.push_back(new ::t_base_type("name6", ::t_base_type::TYPE_I64)); + base_types.push_back(new ::t_base_type("name7", ::t_base_type::TYPE_DOUBLE)); +} + +void init_const_values() { + const_values.push_back(new t_const_value(42)); + const_values.push_back(new t_const_value("foo")); + { + t_const_value* x = new t_const_value; + x->set_double(3.1415); + const_values.push_back(x); + } + { + t_const_value* x = new t_const_value; + x->set_identifier("bar"); + x->set_enum(enums[0]); + const_values.push_back(x); + } + { + t_const_value* x = new t_const_value; + x->set_map(); + x->add_map(const_values[0], const_values[1]); + x->add_map(const_values[1], const_values[0]); + const_values.push_back(x); + } + { + t_const_value* x = new t_const_value; + x->set_list(); + x->add_list(const_values[0]); + x->add_list(const_values[1]); + const_values.push_back(x); + } +} + +void init_consts() { + // base_type/enum indexes for this and other tests are arbitrary + consts.push_back(new t_const(base_types[2], "aaa", const_values[0])); + consts.back()->set_doc("soem doc"); + consts.push_back(new t_const(base_types[3], "bbb", const_values[1])); +} + +void init_enum_values() { + enum_values.push_back(new t_enum_value("VAL1", 11)); + enum_values.back()->set_doc("enum doc 1"); + enum_values.back()->annotations_.insert(std::make_pair("anno1", "val1")); + + enum_values.push_back(new t_enum_value("VAL2", 22)); +} + +void init_enums() { + enums.push_back(new t_enum(programs[0])); + enums.back()->set_doc("enum doc 1"); + enums.back()->annotations_.insert(std::make_pair("anno1", "val1")); + enums.back()->set_name("fooo"); + enums.back()->append(enum_values[0]); + enums.back()->append(enum_values[1]); +} + +void init_lists() { + lists.push_back(new t_list(enums[0])); + lists.push_back(new t_list(base_types[5])); + lists.back()->set_cpp_name("list_cpp_name_1"); +} +void init_sets() { + sets.push_back(new t_set(base_types[4])); + sets.push_back(new t_set(enums[0])); + sets.back()->set_cpp_name("set_cpp_name_1"); +} +void init_maps() { + maps.push_back(new t_map(base_types[4], base_types[1])); + maps.push_back(new t_map(base_types[5], enums[0])); + maps.back()->set_cpp_name("map_cpp_name_1"); +} + +void init_typedefs() { + typedefs.push_back(new t_typedef(programs[0], base_types[3], "VAL1")); +} +void init_fields() { + fields.push_back(new t_field(base_types[1], "f1")); + fields.back()->set_reference(false); + fields.back()->set_req(t_field::T_OPTIONAL); + fields.push_back(new t_field(base_types[2], "f2", 9)); + fields.back()->set_reference(true); + fields.push_back(new t_field(base_types[3], "f3", 11)); + fields.back()->set_req(t_field::T_REQUIRED); + fields.back()->set_value(const_values[0]); +} +void init_structs() { + structs.push_back(new t_struct(programs[0], "struct1")); + structs.back()->append(fields[0]); + structs.back()->append(fields[1]); + structs.push_back(new t_struct(programs[0], "union1")); + structs.back()->append(fields[0]); + structs.back()->append(fields[1]); + structs.back()->set_union(true); + structs.push_back(new t_struct(programs[0], "xcept1")); + structs.back()->set_xception(true); +} +void init_functions() { + structs.push_back(new t_struct(programs[0], "errs1")); + t_struct* errors = structs.back(); + structs.push_back(new t_struct(programs[0], "args1")); + t_struct* arglist = structs.back(); + functions.push_back(new t_function(base_types[0], "func1", errors, arglist, false)); + functions.push_back(new t_function(base_types[0], "func2", errors, arglist, true)); +} +void init_services() { + services.push_back(new t_service(programs[0])); + services.back()->set_doc("srv1 doc"); + services.back()->set_name("srv1"); + services.back()->add_function(functions[0]); + services.back()->add_function(functions[1]); + + services.push_back(new t_service(programs[0])); + services.back()->set_name("srv2"); + services.back()->set_extends(services[0]); +} + +std::vector types; +void init_types() { +#define T_COPY_TYPES(type) std::copy(type##s.begin(), type##s.end(), std::back_inserter(types)) + T_COPY_TYPES(base_type); + T_COPY_TYPES(enum); + T_COPY_TYPES(typedef); + T_COPY_TYPES(struct); + T_COPY_TYPES(list); + T_COPY_TYPES(set); + T_COPY_TYPES(map); +// T_COPY_TYPES(service); +#undef T_COPY_TYPES +} + +void init() { + if (!has_data) { + has_data = true; +#define T_INIT_TESTDATA(r, d, elem) init_##elem##s(); + BOOST_PP_LIST_FOR_EACH(T_INIT_TESTDATA, _, T_TEST_TYPES) + init_types(); +#undef T_INIT_TESTDATA + } +} +} +struct GlobalFixture { + ~GlobalFixture() { test_data::cleanup(); } +}; +#if (BOOST_VERSION >= 105900) +BOOST_GLOBAL_FIXTURE(GlobalFixture); +#else +BOOST_GLOBAL_FIXTURE(GlobalFixture) +#endif + +void migrate_global_cache() { + plugin::TypeRegistry reg; + plugin_output::get_global_cache(reg); + plugin::set_global_cache(reg); + plugin_output::clear_global_cache(); +} +template +T* round_trip(T* t) { + typename plugin::ToType::type p; + plugin_output::convert(t, p); + migrate_global_cache(); + return plugin::convert(p); +} + +void test_base_type(::t_base_type* sut) { + plugin::t_base_type p; + plugin_output::convert(sut, p); + boost::scoped_ptr< ::t_base_type> sut2(plugin::convert(p)); + +#define THRIFT_CHECK(r, data, elem) BOOST_PP_EXPAND(BOOST_CHECK_EQUAL(data elem, sut2->elem)); + BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, + sut->, + BOOST_PP_TUPLE_TO_LIST(7, + (is_void(), + is_string(), + is_bool(), + is_string_list(), + is_binary(), + is_string_enum(), + is_base_type()))) +} + +void test_const_value(t_const_value* sut) { + boost::scoped_ptr sut2(round_trip(sut)); + + BOOST_CHECK_EQUAL(sut->get_type(), sut2->get_type()); + switch (sut->get_type()) { +#define T_CONST_VALUE_CASE(type, name) \ + case t_const_value::type: \ + BOOST_CHECK_EQUAL(sut->get_##name(), sut2->get_##name()); \ + break + T_CONST_VALUE_CASE(CV_INTEGER, integer); + T_CONST_VALUE_CASE(CV_DOUBLE, double); + T_CONST_VALUE_CASE(CV_STRING, string); + T_CONST_VALUE_CASE(CV_IDENTIFIER, identifier); +#undef T_CONST_VALUE_CASE + case t_const_value::CV_MAP: + BOOST_CHECK_EQUAL(sut->get_map().size(), sut2->get_map().size()); + { + std::map sut_values; + for (std::map::const_iterator it = sut->get_map().begin(); + it != sut->get_map().end(); it++) { + sut_values[it->first->get_type()] = it->second->get_type(); + } + std::map sut2_values; + for (std::map::const_iterator it = sut2->get_map().begin(); + it != sut2->get_map().end(); it++) { + sut2_values[it->first->get_type()] = it->second->get_type(); + } + BOOST_CHECK_EQUAL(sut_values.begin()->first, sut2_values.begin()->first); + BOOST_CHECK_EQUAL(sut_values.begin()->second, sut2_values.begin()->second); + } + break; + case t_const_value::CV_LIST: + BOOST_CHECK_EQUAL(sut->get_list().size(), sut2->get_list().size()); + BOOST_CHECK_EQUAL(sut->get_list().front()->get_type(), sut2->get_list().front()->get_type()); + break; + default: + BOOST_ASSERT(false); + break; + } +} + +void test_const(t_const* sut) { + boost::scoped_ptr< ::t_const> sut2(round_trip(sut)); + + BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, + sut->, + BOOST_PP_TUPLE_TO_LIST(4, + (get_type()->get_name(), + get_name(), + get_value()->get_type(), + get_doc()))) +} + +void test_enum_value(t_enum_value* sut) { + boost::scoped_ptr sut2(round_trip(sut)); + + BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, + sut->, + BOOST_PP_TUPLE_TO_LIST(3, (get_name(), get_value(), get_doc()))) +} + +void test_enum(t_enum* sut) { + boost::scoped_ptr< ::t_enum> sut2(round_trip(sut)); + + BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, + sut->, + BOOST_PP_TUPLE_TO_LIST(6, + (get_name(), + get_min_value()->get_value(), + get_max_value()->get_value(), + get_constant_by_value(11)->get_value(), + get_constant_by_name("VAL1")->get_value(), + get_doc()))) +} + +void test_list(t_list* sut) { + boost::scoped_ptr sut2(round_trip(sut)); + + BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, + sut->, + BOOST_PP_TUPLE_TO_LIST(4, + (get_elem_type()->get_name(), + has_cpp_name(), + get_doc(), + get_name()))) + if (sut->has_cpp_name()) + BOOST_CHECK_EQUAL(sut->get_cpp_name(), sut2->get_cpp_name()); +} +void test_set(t_set* sut) { + boost::scoped_ptr sut2(round_trip(sut)); + + BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, + sut->, + BOOST_PP_TUPLE_TO_LIST(4, + (get_elem_type()->get_name(), + has_cpp_name(), + get_doc(), + get_name()))) + if (sut->has_cpp_name()) + BOOST_CHECK_EQUAL(sut->get_cpp_name(), sut2->get_cpp_name()); +} +void test_map(t_map* sut) { + boost::scoped_ptr sut2(round_trip(sut)); + + BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, + sut->, + BOOST_PP_TUPLE_TO_LIST(5, + (get_key_type()->get_name(), + get_val_type()->get_name(), + has_cpp_name(), + get_doc(), + get_name()))) + if (sut->has_cpp_name()) + BOOST_CHECK_EQUAL(sut->get_cpp_name(), sut2->get_cpp_name()); +} + +void test_typedef(t_typedef* sut) { + boost::scoped_ptr sut2(round_trip(sut)); + + BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, + sut->, + BOOST_PP_TUPLE_TO_LIST(4, + (get_doc(), + get_name(), + get_symbolic(), + is_forward_typedef()))) +} + +void test_type(t_type* sut) { + boost::scoped_ptr sut2(round_trip(sut)); + + BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, + sut->, + BOOST_PP_TUPLE_TO_LIST(15, + (is_void(), + is_base_type(), + is_string(), + is_bool(), + is_typedef(), + is_enum(), + is_struct(), + is_xception(), + is_container(), + is_list(), + is_set(), + is_map(), + is_service(), + get_doc(), + get_name()))) +} + +void test_field(t_field* sut) { + boost::scoped_ptr sut2(round_trip(sut)); + + BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, + sut->, + BOOST_PP_TUPLE_TO_LIST(5, + (get_req(), + get_reference(), + get_key(), + get_doc(), + get_name()))) + if (sut->get_value()) { + THRIFT_CHECK(, sut->, get_value()->get_type()); + } else { + BOOST_CHECK(!sut2->get_value()); + } + if (sut->get_type()) { + THRIFT_CHECK(, sut->, get_type()->get_name()); + } else { + BOOST_CHECK(!sut2->get_type()); + } +} +void test_struct(t_struct* sut) { + boost::scoped_ptr sut2(round_trip(sut)); + + BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, + sut->, + BOOST_PP_TUPLE_TO_LIST(5, + (is_union(), + is_xception(), + is_struct(), + get_doc(), + get_name()))) +} + +void test_function(t_function* sut) { + boost::scoped_ptr sut2(round_trip(sut)); + + BOOST_PP_LIST_FOR_EACH( + THRIFT_CHECK, + sut->, + BOOST_PP_TUPLE_TO_LIST(4, (get_doc(), get_name(), get_returntype()->get_name(), is_oneway()))) +} +void test_service(t_service* sut) { + boost::scoped_ptr sut2(round_trip(sut)); + + BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, + sut->, + BOOST_PP_TUPLE_TO_LIST(3, (get_doc(), get_name(), get_functions().size()))) + if (sut->get_extends()) { + THRIFT_CHECK(, sut->, get_extends()->get_name()); + } else { + BOOST_CHECK(!sut2->get_extends()); + } +} + +void test_program(t_program* sut) { + boost::scoped_ptr sut2(round_trip(sut)); + + BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, sut->, BOOST_PP_TUPLE_TO_LIST(2, (get_doc(), get_name()))) +} +boost::unit_test::test_suite* do_init_unit_test_suite() { + test_data::init(); + test_suite* ts = BOOST_TEST_SUITE("PluginConversionTest"); + +#define T_TEST_CASE(r, d, type) \ + ts->add(BOOST_PARAM_TEST_CASE(test_##type, test_data::type##s.begin(), test_data::type##s.end())); + BOOST_PP_LIST_FOR_EACH(T_TEST_CASE, _, T_TEST_TYPES) + T_TEST_CASE(_, _, type) +#undef T_TEST_CASE + return ts; +} + +#ifdef BOOST_TEST_DYN_LINK +bool init_unit_test_suite() { + framework::master_test_suite().add(do_init_unit_test_suite()); + return true; +} +int main(int argc, char* argv[]) { + return ::boost::unit_test::unit_test_main(&init_unit_test_suite, argc, argv); +} +#else +boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) { + return do_init_unit_test_suite(); +} +#endif diff --git a/compiler/cpp/test/plugin/cpp_plugin.cc b/compiler/cpp/test/plugin/cpp_plugin.cc new file mode 100644 index 0000000..6cc19f2 --- /dev/null +++ b/compiler/cpp/test/plugin/cpp_plugin.cc @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "thrift/plugin/plugin.h" +#include "thrift/generate/t_generator.h" + +namespace apache { +namespace thrift { +namespace plugin { + +class MyCppGenerator : public GeneratorPlugin { + virtual int generate(::t_program* program, + const std::map& parsed_options) { + t_generator* gen = t_generator_registry::get_generator(program, "cpp", parsed_options, ""); + gen->generate_program(); + delete gen; + return 0; + } +}; +} +} +} + +int main(int argc, char* argv[]) { + apache::thrift::plugin::MyCppGenerator p; + return p.exec(argc, argv); +} diff --git a/compiler/cpp/test/plugin/t_cpp_generator.cc b/compiler/cpp/test/plugin/t_cpp_generator.cc new file mode 100644 index 0000000..1c93957 --- /dev/null +++ b/compiler/cpp/test/plugin/t_cpp_generator.cc @@ -0,0 +1,4486 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include "thrift/platform.h" +#include "thrift/generate/t_oop_generator.h" + +using std::map; +using std::ofstream; +using std::ostream; +using std::string; +using std::vector; + +static const string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * C++ code generator. This is legitimacy incarnate. + * + */ +class t_cpp_generator : public t_oop_generator { +public: + t_cpp_generator(t_program* program, + const std::map& parsed_options, + const std::string& option_string) + : t_oop_generator(program) { + (void)option_string; + std::map::const_iterator iter; + + + gen_pure_enums_ = false; + use_include_prefix_ = false; + gen_cob_style_ = false; + gen_no_client_completion_ = false; + gen_no_default_operators_ = false; + gen_templates_ = false; + gen_templates_only_ = false; + gen_moveable_ = false; + gen_no_ostream_operators_ = false; + gen_no_skeleton_ = false; + + for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { + if( iter->first.compare("pure_enums") == 0) { + gen_pure_enums_ = true; + } else if( iter->first.compare("include_prefix") == 0) { + use_include_prefix_ = true; + } else if( iter->first.compare("cob_style") == 0) { + gen_cob_style_ = true; + } else if( iter->first.compare("no_client_completion") == 0) { + gen_no_client_completion_ = true; + } else if( iter->first.compare("no_default_operators") == 0) { + gen_no_default_operators_ = true; + } else if( iter->first.compare("templates") == 0) { + gen_templates_ = true; + gen_templates_only_ = (iter->second == "only"); + } else if( iter->first.compare("moveable_types") == 0) { + gen_moveable_ = true; + } else if ( iter->first.compare("no_ostream_operators") == 0) { + gen_no_ostream_operators_ = true; + } else if ( iter->first.compare("no_skeleton") == 0) { + gen_no_skeleton_ = true; + } else { + throw "unknown option cpp:" + iter->first; + } + } + + out_dir_base_ = "gen-cpp"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + void generate_consts(std::vector consts); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_enum_ostream_operator_decl(std::ofstream& out, t_enum* tenum); + void generate_enum_ostream_operator(std::ofstream& out, t_enum* tenum); + void generate_forward_declaration(t_struct* tstruct); + void generate_struct(t_struct* tstruct) { generate_cpp_struct(tstruct, false); } + void generate_xception(t_struct* txception) { generate_cpp_struct(txception, true); } + void generate_cpp_struct(t_struct* tstruct, bool is_exception); + + void generate_service(t_service* tservice); + + void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value); + std::string render_const_value(std::ofstream& out, + std::string name, + t_type* type, + t_const_value* value); + + void generate_struct_declaration(std::ofstream& out, + t_struct* tstruct, + bool is_exception = false, + bool pointers = false, + bool read = true, + bool write = true, + bool swap = false, + bool is_user_struct = false); + void generate_struct_definition(std::ofstream& out, + std::ofstream& force_cpp_out, + t_struct* tstruct, + bool setters = true, + bool is_user_struct = false); + void generate_copy_constructor(std::ofstream& out, t_struct* tstruct, bool is_exception); + void generate_move_constructor(std::ofstream& out, t_struct* tstruct, bool is_exception); + void generate_constructor_helper(std::ofstream& out, + t_struct* tstruct, + bool is_excpetion, + bool is_move); + void generate_assignment_operator(std::ofstream& out, t_struct* tstruct); + void generate_move_assignment_operator(std::ofstream& out, t_struct* tstruct); + void generate_assignment_helper(std::ofstream& out, t_struct* tstruct, bool is_move); + void generate_struct_reader(std::ofstream& out, t_struct* tstruct, bool pointers = false); + void generate_struct_writer(std::ofstream& out, t_struct* tstruct, bool pointers = false); + void generate_struct_result_writer(std::ofstream& out, t_struct* tstruct, bool pointers = false); + void generate_struct_swap(std::ofstream& out, t_struct* tstruct); + void generate_struct_print_method(std::ofstream& out, t_struct* tstruct); + void generate_exception_what_method(std::ofstream& out, t_struct* tstruct); + + /** + * Service-level generation functions + */ + + void generate_service_interface(t_service* tservice, string style); + void generate_service_interface_factory(t_service* tservice, string style); + void generate_service_null(t_service* tservice, string style); + void generate_service_multiface(t_service* tservice); + void generate_service_helpers(t_service* tservice); + void generate_service_client(t_service* tservice, string style); + void generate_service_processor(t_service* tservice, string style); + void generate_service_skeleton(t_service* tservice); + void generate_process_function(t_service* tservice, + t_function* tfunction, + string style, + bool specialized = false); + void generate_function_helpers(t_service* tservice, t_function* tfunction); + void generate_service_async_skeleton(t_service* tservice); + + /** + * Serialization constructs + */ + + void generate_deserialize_field(std::ofstream& out, + t_field* tfield, + std::string prefix = "", + std::string suffix = ""); + + void generate_deserialize_struct(std::ofstream& out, + t_struct* tstruct, + std::string prefix = "", + bool pointer = false); + + void generate_deserialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_deserialize_set_element(std::ofstream& out, t_set* tset, std::string prefix = ""); + + void generate_deserialize_map_element(std::ofstream& out, t_map* tmap, std::string prefix = ""); + + void generate_deserialize_list_element(std::ofstream& out, + t_list* tlist, + std::string prefix, + bool push_back, + std::string index); + + void generate_serialize_field(std::ofstream& out, + t_field* tfield, + std::string prefix = "", + std::string suffix = ""); + + void generate_serialize_struct(std::ofstream& out, + t_struct* tstruct, + std::string prefix = "", + bool pointer = false); + + void generate_serialize_container(std::ofstream& out, t_type* ttype, std::string prefix = ""); + + void generate_serialize_map_element(std::ofstream& out, t_map* tmap, std::string iter); + + void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter); + + void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter); + + void generate_function_call(ostream& out, + t_function* tfunction, + string target, + string iface, + string arg_prefix); + /* + * Helper rendering functions + */ + + std::string namespace_prefix(std::string ns); + std::string namespace_open(std::string ns); + std::string namespace_close(std::string ns); + std::string type_name(t_type* ttype, bool in_typedef = false, bool arg = false); + std::string base_type_name(t_base_type::t_base tbase); + std::string declare_field(t_field* tfield, + bool init = false, + bool pointer = false, + bool constant = false, + bool reference = false); + std::string function_signature(t_function* tfunction, + std::string style, + std::string prefix = "", + bool name_params = true); + std::string cob_function_signature(t_function* tfunction, + std::string prefix = "", + bool name_params = true); + std::string argument_list(t_struct* tstruct, bool name_params = true, bool start_comma = false); + std::string type_to_enum(t_type* ttype); + + void generate_enum_constant_list(std::ofstream& f, + const vector& constants, + const char* prefix, + const char* suffix, + bool include_values); + + void generate_struct_ostream_operator_decl(std::ofstream& f, t_struct* tstruct); + void generate_struct_ostream_operator(std::ofstream& f, t_struct* tstruct); + void generate_struct_print_method_decl(std::ofstream& f, t_struct* tstruct); + void generate_exception_what_method_decl(std::ofstream& f, + t_struct* tstruct, + bool external = false); + + bool is_reference(t_field* tfield) { return tfield->get_reference(); } + + bool is_complex_type(t_type* ttype) { + ttype = get_true_type(ttype); + + return ttype->is_container() || ttype->is_struct() || ttype->is_xception() + || (ttype->is_base_type() + && (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING)); + } + + void set_use_include_prefix(bool use_include_prefix) { use_include_prefix_ = use_include_prefix; } + + /** + * The compiler option "no_thrift_ostream_impl" can be used to prevent + * the compiler from emitting implementations for operator <<. In this + * case the consuming application must provide any needed to build. + * + * To disable this on a per structure bases, one can alternatively set + * the annotation "cpp.customostream" to prevent thrift from emitting an + * operator << (std::ostream&). + * + * See AnnotationTest for validation of this annotation feature. + */ + bool has_custom_ostream(t_type* ttype) const { + return (gen_no_ostream_operators_) || + (ttype->annotations_.find("cpp.customostream") != ttype->annotations_.end()); + } + +private: + /** + * Returns the include prefix to use for a file generated by program, or the + * empty string if no include prefix should be used. + */ + std::string get_include_prefix(const t_program& program) const; + + /** + * True if we should generate pure enums for Thrift enums, instead of wrapper classes. + */ + bool gen_pure_enums_; + + /** + * True if we should generate templatized reader/writer methods. + */ + bool gen_templates_; + + /** + * True iff we should generate process function pointers for only templatized + * reader/writer methods. + */ + bool gen_templates_only_; + + /** + * True if we should generate move constructors & assignment operators. + */ + bool gen_moveable_; + + /** + * True if we should generate ostream definitions + */ + bool gen_no_ostream_operators_; + + /** + * True iff we should use a path prefix in our #include statements for other + * thrift-generated header files. + */ + bool use_include_prefix_; + + /** + * True if we should generate "Continuation OBject"-style classes as well. + */ + bool gen_cob_style_; + + /** + * True if we should omit calls to completion__() in CobClient class. + */ + bool gen_no_client_completion_; + + /** + * True if we should omit generating the default opeartors ==, != and <. + */ + bool gen_no_default_operators_; + + /** + * True if we should generate skeleton. + */ + bool gen_no_skeleton_; + + /** + * Strings for namespace, computed once up front then used directly + */ + + std::string ns_open_; + std::string ns_close_; + + /** + * File streams, stored here to avoid passing them as parameters to every + * function. + */ + + std::ofstream f_types_; + std::ofstream f_types_impl_; + std::ofstream f_types_tcc_; + std::ofstream f_header_; + std::ofstream f_service_; + std::ofstream f_service_tcc_; + + // The ProcessorGenerator is used to generate parts of the code, + // so it needs access to many of our protected members and methods. + // + // TODO: The code really should be cleaned up so that helper methods for + // writing to the output files are separate from the generator classes + // themselves. + friend class ProcessorGenerator; +}; + +/** + * Prepares for file generation by opening up the necessary file output + * streams. + */ +void t_cpp_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + + // Make output file + string f_types_name = get_out_dir() + program_name_ + "_types.h"; + f_types_.open(f_types_name.c_str()); + + string f_types_impl_name = get_out_dir() + program_name_ + "_types.cpp"; + f_types_impl_.open(f_types_impl_name.c_str()); + + if (gen_templates_) { + // If we don't open the stream, it appears to just discard data, + // which is fine. + string f_types_tcc_name = get_out_dir() + program_name_ + "_types.tcc"; + f_types_tcc_.open(f_types_tcc_name.c_str()); + } + + // Print header + f_types_ << autogen_comment(); + f_types_impl_ << autogen_comment(); + f_types_tcc_ << autogen_comment(); + + // Start ifndef + f_types_ << "#ifndef " << program_name_ << "_TYPES_H" << endl << "#define " << program_name_ + << "_TYPES_H" << endl << endl; + f_types_tcc_ << "#ifndef " << program_name_ << "_TYPES_TCC" << endl << "#define " << program_name_ + << "_TYPES_TCC" << endl << endl; + + // Include base types + f_types_ << "#include " << endl + << endl + << "#include " << endl + << "#include " << endl + << "#include " << endl + << "#include " << endl + << "#include " << endl + << endl; + // Include C++xx compatibility header + f_types_ << "#include " << endl; + + // Include other Thrift includes + const vector& includes = program_->get_includes(); + for (size_t i = 0; i < includes.size(); ++i) { + f_types_ << "#include \"" << get_include_prefix(*(includes[i])) << includes[i]->get_name() + << "_types.h\"" << endl; + + // XXX(simpkins): If gen_templates_ is enabled, we currently assume all + // included files were also generated with templates enabled. + f_types_tcc_ << "#include \"" << get_include_prefix(*(includes[i])) << includes[i]->get_name() + << "_types.tcc\"" << endl; + } + f_types_ << endl; + + // Include custom headers + const vector& cpp_includes = program_->get_cpp_includes(); + for (size_t i = 0; i < cpp_includes.size(); ++i) { + if (cpp_includes[i][0] == '<') { + f_types_ << "#include " << cpp_includes[i] << endl; + } else { + f_types_ << "#include \"" << cpp_includes[i] << "\"" << endl; + } + } + f_types_ << endl; + + // Include the types file + f_types_impl_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ + << "_types.h\"" << endl << endl; + f_types_tcc_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ + << "_types.h\"" << endl << endl; + + // The swap() code needs for std::swap() + f_types_impl_ << "#include " << endl; + // for operator<< + f_types_impl_ << "#include " << endl << endl; + f_types_impl_ << "#include " << endl << endl; + + // Open namespace + ns_open_ = namespace_open(program_->get_namespace("cpp")); + ns_close_ = namespace_close(program_->get_namespace("cpp")); + + f_types_ << ns_open_ << endl << endl; + + f_types_impl_ << ns_open_ << endl << endl; + + f_types_tcc_ << ns_open_ << endl << endl; +} + +/** + * Closes the output files. + */ +void t_cpp_generator::close_generator() { + // Close namespace + f_types_ << ns_close_ << endl << endl; + f_types_impl_ << ns_close_ << endl; + f_types_tcc_ << ns_close_ << endl << endl; + + // Include the types.tcc file from the types header file, + // so clients don't have to explicitly include the tcc file. + // TODO(simpkins): Make this a separate option. + if (gen_templates_) { + f_types_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ + << "_types.tcc\"" << endl << endl; + } + + // Close ifndef + f_types_ << "#endif" << endl; + f_types_tcc_ << "#endif" << endl; + + // Close output file + f_types_.close(); + f_types_impl_.close(); + f_types_tcc_.close(); +} + +/** + * Generates a typedef. This is just a simple 1-liner in C++ + * + * @param ttypedef The type definition + */ +void t_cpp_generator::generate_typedef(t_typedef* ttypedef) { + f_types_ << indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " + << ttypedef->get_symbolic() << ";" << endl << endl; +} + +void t_cpp_generator::generate_enum_constant_list(std::ofstream& f, + const vector& constants, + const char* prefix, + const char* suffix, + bool include_values) { + f << " {" << endl; + indent_up(); + + vector::const_iterator c_iter; + bool first = true; + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + if (first) { + first = false; + } else { + f << "," << endl; + } + indent(f) << prefix << (*c_iter)->get_name() << suffix; + if (include_values) { + f << " = " << (*c_iter)->get_value(); + } + } + + f << endl; + indent_down(); + indent(f) << "};" << endl; +} + +/** + * Generates code for an enumerated type. In C++, this is essentially the same + * as the thrift definition itself, using the enum keyword in C++. + * + * @param tenum The enumeration + */ +void t_cpp_generator::generate_enum(t_enum* tenum) { + vector constants = tenum->get_constants(); + + std::string enum_name = tenum->get_name(); + if (!gen_pure_enums_) { + enum_name = "type"; + f_types_ << indent() << "struct " << tenum->get_name() << " {" << endl; + indent_up(); + } + f_types_ << indent() << "enum " << enum_name; + + generate_enum_constant_list(f_types_, constants, "", "", true); + + if (!gen_pure_enums_) { + indent_down(); + f_types_ << "};" << endl; + } + + f_types_ << endl; + + /** + Generate a character array of enum names for debugging purposes. + */ + std::string prefix = ""; + if (!gen_pure_enums_) { + prefix = tenum->get_name() + "::"; + } + + f_types_impl_ << indent() << "int _k" << tenum->get_name() << "Values[] ="; + generate_enum_constant_list(f_types_impl_, constants, prefix.c_str(), "", false); + + f_types_impl_ << indent() << "const char* _k" << tenum->get_name() << "Names[] ="; + generate_enum_constant_list(f_types_impl_, constants, "\"", "\"", false); + + f_types_ << indent() << "extern const std::map _" << tenum->get_name() + << "_VALUES_TO_NAMES;" << endl << endl; + + f_types_impl_ << indent() << "const std::map _" << tenum->get_name() + << "_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(" << constants.size() << ", _k" + << tenum->get_name() << "Values" + << ", _k" << tenum->get_name() << "Names), " + << "::apache::thrift::TEnumIterator(-1, NULL, NULL));" << endl << endl; + + generate_enum_ostream_operator_decl(f_types_, tenum); + generate_enum_ostream_operator(f_types_impl_, tenum); +} + +void t_cpp_generator::generate_enum_ostream_operator_decl(std::ofstream& out, t_enum* tenum) { + + out << "std::ostream& operator<<(std::ostream& out, const "; + if (gen_pure_enums_) { + out << tenum->get_name(); + } else { + out << tenum->get_name() << "::type&"; + } + out << " val);" << endl; + out << endl; +} + +void t_cpp_generator::generate_enum_ostream_operator(std::ofstream& out, t_enum* tenum) { + + // If we've been told the consuming application will provide an ostream + // operator definition then we only make a declaration: + + if (!has_custom_ostream(tenum)) { + out << "std::ostream& operator<<(std::ostream& out, const "; + if (gen_pure_enums_) { + out << tenum->get_name(); + } else { + out << tenum->get_name() << "::type&"; + } + out << " val) "; + scope_up(out); + + out << indent() << "std::map::const_iterator it = _" + << tenum->get_name() << "_VALUES_TO_NAMES.find(val);" << endl; + out << indent() << "if (it != _" << tenum->get_name() << "_VALUES_TO_NAMES.end()) {" << endl; + indent_up(); + out << indent() << "out << it->second;" << endl; + indent_down(); + out << indent() << "} else {" << endl; + indent_up(); + out << indent() << "out << static_cast(val);" << endl; + indent_down(); + out << indent() << "}" << endl; + + out << indent() << "return out;" << endl; + scope_down(out); + out << endl; + } +} + +/** + * Generates a class that holds all the constants. + */ +void t_cpp_generator::generate_consts(std::vector consts) { + string f_consts_name = get_out_dir() + program_name_ + "_constants.h"; + ofstream f_consts; + f_consts.open(f_consts_name.c_str()); + + string f_consts_impl_name = get_out_dir() + program_name_ + "_constants.cpp"; + ofstream f_consts_impl; + f_consts_impl.open(f_consts_impl_name.c_str()); + + // Print header + f_consts << autogen_comment(); + f_consts_impl << autogen_comment(); + + // Start ifndef + f_consts << "#ifndef " << program_name_ << "_CONSTANTS_H" << endl << "#define " << program_name_ + << "_CONSTANTS_H" << endl << endl << "#include \"" << get_include_prefix(*get_program()) + << program_name_ << "_types.h\"" << endl << endl << ns_open_ << endl << endl; + + f_consts_impl << "#include \"" << get_include_prefix(*get_program()) << program_name_ + << "_constants.h\"" << endl << endl << ns_open_ << endl << endl; + + f_consts << "class " << program_name_ << "Constants {" << endl << " public:" << endl << " " + << program_name_ << "Constants();" << endl << endl; + indent_up(); + vector::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + string name = (*c_iter)->get_name(); + t_type* type = (*c_iter)->get_type(); + f_consts << indent() << type_name(type) << " " << name << ";" << endl; + } + indent_down(); + f_consts << "};" << endl; + + f_consts_impl << "const " << program_name_ << "Constants g_" << program_name_ << "_constants;" + << endl << endl << program_name_ << "Constants::" << program_name_ + << "Constants() {" << endl; + indent_up(); + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + print_const_value(f_consts_impl, + (*c_iter)->get_name(), + (*c_iter)->get_type(), + (*c_iter)->get_value()); + } + indent_down(); + indent(f_consts_impl) << "}" << endl; + + f_consts << endl << "extern const " << program_name_ << "Constants g_" << program_name_ + << "_constants;" << endl << endl << ns_close_ << endl << endl << "#endif" << endl; + f_consts.close(); + + f_consts_impl << endl << ns_close_ << endl << endl; +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +void t_cpp_generator::print_const_value(ofstream& out, + string name, + t_type* type, + t_const_value* value) { + type = get_true_type(type); + if (type->is_base_type()) { + string v2 = render_const_value(out, name, type, value); + indent(out) << name << " = " << v2 << ";" << endl << endl; + } else if (type->is_enum()) { + indent(out) << name << " = (" << type_name(type) << ")" << value->get_integer() << ";" << endl + << endl; + } else if (type->is_struct() || type->is_xception()) { + const vector& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::const_iterator v_iter; + bool is_nonrequired_field = false; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + is_nonrequired_field = false; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + is_nonrequired_field = (*f_iter)->get_req() != t_field::T_REQUIRED; + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + string val = render_const_value(out, name, field_type, v_iter->second); + indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl; + if (is_nonrequired_field) { + indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl; + } + } + out << endl; + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + const map& val = value->get_map(); + map::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string key = render_const_value(out, name, ktype, v_iter->first); + string val = render_const_value(out, name, vtype, v_iter->second); + indent(out) << name << ".insert(std::make_pair(" << key << ", " << val << "));" << endl; + } + out << endl; + } else if (type->is_list()) { + t_type* etype = ((t_list*)type)->get_elem_type(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(out, name, etype, *v_iter); + indent(out) << name << ".push_back(" << val << ");" << endl; + } + out << endl; + } else if (type->is_set()) { + t_type* etype = ((t_set*)type)->get_elem_type(); + const vector& val = value->get_list(); + vector::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + string val = render_const_value(out, name, etype, *v_iter); + indent(out) << name << ".insert(" << val << ");" << endl; + } + out << endl; + } else { + throw "INVALID TYPE IN print_const_value: " + type->get_name(); + } +} + +/** + * + */ +string t_cpp_generator::render_const_value(ofstream& out, + string name, + t_type* type, + t_const_value* value) { + (void)name; + std::ostringstream render; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + render << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + render << ((value->get_integer() > 0) ? "true" : "false"); + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + render << value->get_integer(); + break; + case t_base_type::TYPE_I64: + render << value->get_integer() << "LL"; + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + render << value->get_integer(); + } else { + render << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + render << "(" << type_name(type) << ")" << value->get_integer(); + } else { + string t = tmp("tmp"); + indent(out) << type_name(type) << " " << t << ";" << endl; + print_const_value(out, t, type, value); + render << t; + } + + return render.str(); +} + +void t_cpp_generator::generate_forward_declaration(t_struct* tstruct) { + // Forward declare struct def + f_types_ << indent() << "class " << tstruct->get_name() << ";" << endl << endl; +} + +/** + * Generates a struct definition for a thrift data type. This is a class + * with data members and a read/write() function, plus a mirroring isset + * inner class. + * + * @param tstruct The struct definition + */ +void t_cpp_generator::generate_cpp_struct(t_struct* tstruct, bool is_exception) { + generate_struct_declaration(f_types_, tstruct, is_exception, false, true, true, true, true); + generate_struct_definition(f_types_impl_, f_types_impl_, tstruct, true, true); + + std::ofstream& out = (gen_templates_ ? f_types_tcc_ : f_types_impl_); + generate_struct_reader(out, tstruct); + generate_struct_writer(out, tstruct); + generate_struct_swap(f_types_impl_, tstruct); + generate_copy_constructor(f_types_impl_, tstruct, is_exception); + if (gen_moveable_) { + generate_move_constructor(f_types_impl_, tstruct, is_exception); + } + generate_assignment_operator(f_types_impl_, tstruct); + if (gen_moveable_) { + generate_move_assignment_operator(f_types_impl_, tstruct); + } + + if (!has_custom_ostream(tstruct)) { + generate_struct_print_method(f_types_impl_, tstruct); + } + + if (is_exception) { + generate_exception_what_method(f_types_impl_, tstruct); + } +} + +void t_cpp_generator::generate_copy_constructor(ofstream& out, + t_struct* tstruct, + bool is_exception) { + generate_constructor_helper(out, tstruct, is_exception, /*is_move=*/false); +} + +void t_cpp_generator::generate_move_constructor(ofstream& out, + t_struct* tstruct, + bool is_exception) { + generate_constructor_helper(out, tstruct, is_exception, /*is_move=*/true); +} + +namespace { +// Helper to convert a variable to rvalue, if move is enabled +std::string maybeMove(std::string const& other, bool move) { + if (move) { + return "std::move(" + other + ")"; + } + return other; +} +} + +void t_cpp_generator::generate_constructor_helper(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool is_move) { + + std::string tmp_name = tmp("other"); + + indent(out) << tstruct->get_name() << "::" << tstruct->get_name(); + + if (is_move) { + out << "( " << tstruct->get_name() << "&& "; + } else { + out << "(const " << tstruct->get_name() << "& "; + } + out << tmp_name << ") "; + if (is_exception) + out << ": TException() "; + out << "{" << endl; + indent_up(); + + const vector& members = tstruct->get_members(); + + // eliminate compiler unused warning + if (members.empty()) + indent(out) << "(void) " << tmp_name << ";" << endl; + + vector::const_iterator f_iter; + bool has_nonrequired_fields = false; + for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) { + if ((*f_iter)->get_req() != t_field::T_REQUIRED) + has_nonrequired_fields = true; + indent(out) << (*f_iter)->get_name() << " = " + << maybeMove(tmp_name + "." + (*f_iter)->get_name(), is_move) << ";" << endl; + } + + if (has_nonrequired_fields) { + indent(out) << "__isset = " << maybeMove(tmp_name + ".__isset", is_move) << ";" << endl; + } + + indent_down(); + indent(out) << "}" << endl; +} + +void t_cpp_generator::generate_assignment_operator(ofstream& out, t_struct* tstruct) { + generate_assignment_helper(out, tstruct, /*is_move=*/false); +} + +void t_cpp_generator::generate_move_assignment_operator(ofstream& out, t_struct* tstruct) { + generate_assignment_helper(out, tstruct, /*is_move=*/true); +} + +void t_cpp_generator::generate_assignment_helper(ofstream& out, t_struct* tstruct, bool is_move) { + std::string tmp_name = tmp("other"); + + indent(out) << tstruct->get_name() << "& " << tstruct->get_name() << "::operator=("; + + if (is_move) { + out << tstruct->get_name() << "&& "; + } else { + out << "const " << tstruct->get_name() << "& "; + } + out << tmp_name << ") {" << endl; + + indent_up(); + + const vector& members = tstruct->get_members(); + + // eliminate compiler unused warning + if (members.empty()) + indent(out) << "(void) " << tmp_name << ";" << endl; + + vector::const_iterator f_iter; + bool has_nonrequired_fields = false; + for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) { + if ((*f_iter)->get_req() != t_field::T_REQUIRED) + has_nonrequired_fields = true; + indent(out) << (*f_iter)->get_name() << " = " + << maybeMove(tmp_name + "." + (*f_iter)->get_name(), is_move) << ";" << endl; + } + if (has_nonrequired_fields) { + indent(out) << "__isset = " << maybeMove(tmp_name + ".__isset", is_move) << ";" << endl; + } + + indent(out) << "return *this;" << endl; + indent_down(); + indent(out) << "}" << endl; +} + +/** + * Writes the struct declaration into the header file + * + * @param out Output stream + * @param tstruct The struct + */ +void t_cpp_generator::generate_struct_declaration(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool pointers, + bool read, + bool write, + bool swap, + bool is_user_struct) { + string extends = ""; + if (is_exception) { + extends = " : public ::apache::thrift::TException"; + } else { + if (is_user_struct && !gen_templates_) { + extends = " : public virtual ::apache::thrift::TBase"; + } + } + + // Get members + vector::const_iterator m_iter; + const vector& members = tstruct->get_members(); + + // Write the isset structure declaration outside the class. This makes + // the generated code amenable to processing by SWIG. + // We only declare the struct if it gets used in the class. + + // Isset struct has boolean fields, but only for non-required fields. + bool has_nonrequired_fields = false; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() != t_field::T_REQUIRED) + has_nonrequired_fields = true; + } + + if (has_nonrequired_fields && (!pointers || read)) { + + out << indent() << "typedef struct _" << tstruct->get_name() << "__isset {" << endl; + indent_up(); + + indent(out) << "_" << tstruct->get_name() << "__isset() "; + bool first = true; + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() == t_field::T_REQUIRED) { + continue; + } + string isSet = ((*m_iter)->get_value() != NULL) ? "true" : "false"; + if (first) { + first = false; + out << ": " << (*m_iter)->get_name() << "(" << isSet << ")"; + } else { + out << ", " << (*m_iter)->get_name() << "(" << isSet << ")"; + } + } + out << " {}" << endl; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if ((*m_iter)->get_req() != t_field::T_REQUIRED) { + indent(out) << "bool " << (*m_iter)->get_name() << " :1;" << endl; + } + } + + indent_down(); + indent(out) << "} _" << tstruct->get_name() << "__isset;" << endl; + } + + out << endl; + + // Open struct def + out << indent() << "class " << tstruct->get_name() << extends << " {" << endl << indent() + << " public:" << endl << endl; + indent_up(); + + if (!pointers) { + // Copy constructor + indent(out) << tstruct->get_name() << "(const " << tstruct->get_name() << "&);" << endl; + + // Move constructor + if (gen_moveable_) { + indent(out) << tstruct->get_name() << "(" << tstruct->get_name() << "&&);" << endl; + } + + // Assignment Operator + indent(out) << tstruct->get_name() << "& operator=(const " << tstruct->get_name() << "&);" + << endl; + + // Move assignment operator + if (gen_moveable_) { + indent(out) << tstruct->get_name() << "& operator=(" << tstruct->get_name() << "&&);" << endl; + } + + // Default constructor + indent(out) << tstruct->get_name() << "()"; + + bool init_ctor = false; + + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + if (t->is_base_type() || t->is_enum() || is_reference(*m_iter)) { + string dval; + if (t->is_enum()) { + dval += "(" + type_name(t) + ")"; + } + dval += (t->is_string() || is_reference(*m_iter)) ? "" : "0"; + t_const_value* cv = (*m_iter)->get_value(); + if (cv != NULL) { + dval = render_const_value(out, (*m_iter)->get_name(), t, cv); + } + if (!init_ctor) { + init_ctor = true; + out << " : "; + out << (*m_iter)->get_name() << "(" << dval << ")"; + } else { + out << ", " << (*m_iter)->get_name() << "(" << dval << ")"; + } + } + } + out << " {" << endl; + indent_up(); + // TODO(dreiss): When everything else in Thrift is perfect, + // do more of these in the initializer list. + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); + + if (!t->is_base_type()) { + t_const_value* cv = (*m_iter)->get_value(); + if (cv != NULL) { + print_const_value(out, (*m_iter)->get_name(), t, cv); + } + } + } + scope_down(out); + } + + if (tstruct->annotations_.find("final") == tstruct->annotations_.end()) { + out << endl << indent() << "virtual ~" << tstruct->get_name() << "() throw();" << endl; + } + + // Declare all fields + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << declare_field(*m_iter, + false, + (pointers && !(*m_iter)->get_type()->is_xception()), + !read) << endl; + } + + // Add the __isset data member if we need it, using the definition from above + if (has_nonrequired_fields && (!pointers || read)) { + out << endl << indent() << "_" << tstruct->get_name() << "__isset __isset;" << endl; + } + + // Create a setter function for each field + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (pointers) { + continue; + } + if (is_reference((*m_iter))) { + out << endl << indent() << "void __set_" << (*m_iter)->get_name() << "(::apache::thrift::stdcxx::shared_ptr<" + << type_name((*m_iter)->get_type(), false, false) << ">"; + out << " val);" << endl; + } else { + out << endl << indent() << "void __set_" << (*m_iter)->get_name() << "(" + << type_name((*m_iter)->get_type(), false, true); + out << " val);" << endl; + } + } + out << endl; + + if (!pointers) { + // Should we generate default operators? + if (!gen_no_default_operators_) { + // Generate an equality testing operator. Make it inline since the compiler + // will do a better job than we would when deciding whether to inline it. + out << indent() << "bool operator == (const " << tstruct->get_name() << " & " + << (members.size() > 0 ? "rhs" : "/* rhs */") << ") const" << endl; + scope_up(out); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + // Most existing Thrift code does not use isset or optional/required, + // so we treat "default" fields as required. + if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { + out << indent() << "if (!(" << (*m_iter)->get_name() << " == rhs." + << (*m_iter)->get_name() << "))" << endl << indent() << " return false;" << endl; + } else { + out << indent() << "if (__isset." << (*m_iter)->get_name() << " != rhs.__isset." + << (*m_iter)->get_name() << ")" << endl << indent() << " return false;" << endl + << indent() << "else if (__isset." << (*m_iter)->get_name() << " && !(" + << (*m_iter)->get_name() << " == rhs." << (*m_iter)->get_name() << "))" << endl + << indent() << " return false;" << endl; + } + } + indent(out) << "return true;" << endl; + scope_down(out); + out << indent() << "bool operator != (const " << tstruct->get_name() << " &rhs) const {" + << endl << indent() << " return !(*this == rhs);" << endl << indent() << "}" << endl + << endl; + + // Generate the declaration of a less-than operator. This must be + // implemented by the application developer if they wish to use it. (They + // will get a link error if they try to use it without an implementation.) + out << indent() << "bool operator < (const " << tstruct->get_name() << " & ) const;" << endl + << endl; + } + } + + if (read) { + if (gen_templates_) { + out << indent() << "template " << endl << indent() + << "uint32_t read(Protocol_* iprot);" << endl; + } else { + out << indent() << "uint32_t read(" + << "::apache::thrift::protocol::TProtocol* iprot);" << endl; + } + } + if (write) { + if (gen_templates_) { + out << indent() << "template " << endl << indent() + << "uint32_t write(Protocol_* oprot) const;" << endl; + } else { + out << indent() << "uint32_t write(" + << "::apache::thrift::protocol::TProtocol* oprot) const;" << endl; + } + } + out << endl; + + if (is_user_struct && !has_custom_ostream(tstruct)) { + out << indent() << "virtual "; + generate_struct_print_method_decl(out, NULL); + out << ";" << endl; + } + + // std::exception::what() + if (is_exception) { + out << indent() << "mutable std::string thriftTExceptionMessageHolder_;" << endl; + out << indent(); + generate_exception_what_method_decl(out, tstruct, false); + out << ";" << endl; + } + + indent_down(); + indent(out) << "};" << endl << endl; + + if (swap) { + // Generate a namespace-scope swap() function + out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name() + << " &b);" << endl << endl; + } + + if (is_user_struct) { + generate_struct_ostream_operator_decl(out, tstruct); + } +} + +void t_cpp_generator::generate_struct_definition(ofstream& out, + ofstream& force_cpp_out, + t_struct* tstruct, + bool setters, + bool is_user_struct) { + // Get members + vector::const_iterator m_iter; + const vector& members = tstruct->get_members(); + + // Destructor + if (tstruct->annotations_.find("final") == tstruct->annotations_.end()) { + force_cpp_out << endl << indent() << tstruct->get_name() << "::~" << tstruct->get_name() + << "() throw() {" << endl; + indent_up(); + + indent_down(); + force_cpp_out << indent() << "}" << endl << endl; + } + + // Create a setter function for each field + if (setters) { + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + if (is_reference((*m_iter))) { + std::string type = type_name((*m_iter)->get_type()); + out << endl << indent() << "void " << tstruct->get_name() << "::__set_" + << (*m_iter)->get_name() << "(::apache::thrift::stdcxx::shared_ptr<" + << type_name((*m_iter)->get_type(), false, false) << ">"; + out << " val) {" << endl; + } else { + out << endl << indent() << "void " << tstruct->get_name() << "::__set_" + << (*m_iter)->get_name() << "(" << type_name((*m_iter)->get_type(), false, true); + out << " val) {" << endl; + } + indent_up(); + out << indent() << "this->" << (*m_iter)->get_name() << " = val;" << endl; + indent_down(); + + // assume all fields are required except optional fields. + // for optional fields change __isset.name to true + bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL; + if (is_optional) { + out << indent() << indent() << "__isset." << (*m_iter)->get_name() << " = true;" << endl; + } + out << indent() << "}" << endl; + } + } + if (is_user_struct) { + generate_struct_ostream_operator(out, tstruct); + } + out << endl; +} + +/** + * Makes a helper function to gen a struct reader. + * + * @param out Stream to write to + * @param tstruct The struct + */ +void t_cpp_generator::generate_struct_reader(ofstream& out, t_struct* tstruct, bool pointers) { + if (gen_templates_) { + out << indent() << "template " << endl << indent() << "uint32_t " + << tstruct->get_name() << "::read(Protocol_* iprot) {" << endl; + } else { + indent(out) << "uint32_t " << tstruct->get_name() + << "::read(::apache::thrift::protocol::TProtocol* iprot) {" << endl; + } + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Declare stack tmp variables + out << endl + << indent() << "::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot);" << endl + << indent() << "uint32_t xfer = 0;" << endl + << indent() << "std::string fname;" << endl + << indent() << "::apache::thrift::protocol::TType ftype;" << endl + << indent() << "int16_t fid;" << endl + << endl + << indent() << "xfer += iprot->readStructBegin(fname);" << endl + << endl + << indent() << "using ::apache::thrift::protocol::TProtocolException;" << endl + << endl; + + // Required variables aren't in __isset, so we need tmp vars to check them. + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) + indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl; + } + out << endl; + + // Loop over reading in fields + indent(out) << "while (true)" << endl; + scope_up(out); + + // Read beginning field marker + indent(out) << "xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl; + + // Check for field STOP marker + out << indent() << "if (ftype == ::apache::thrift::protocol::T_STOP) {" << endl << indent() + << " break;" << endl << indent() << "}" << endl; + + if (fields.empty()) { + out << indent() << "xfer += iprot->skip(ftype);" << endl; + } else { + // Switch statement on the field we are reading + indent(out) << "switch (fid)" << endl; + + scope_up(out); + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << "case " << (*f_iter)->get_key() << ":" << endl; + indent_up(); + indent(out) << "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; + indent_up(); + + const char* isset_prefix = ((*f_iter)->get_req() != t_field::T_REQUIRED) ? "this->__isset." + : "isset_"; + +#if 0 + // This code throws an exception if the same field is encountered twice. + // We've decided to leave it out for performance reasons. + // TODO(dreiss): Generate this code and "if" it out to make it easier + // for people recompiling thrift to include it. + out << + indent() << "if (" << isset_prefix << (*f_iter)->get_name() << ")" << endl << + indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl; +#endif + + if (pointers && !(*f_iter)->get_type()->is_xception()) { + generate_deserialize_field(out, *f_iter, "(*(this->", "))"); + } else { + generate_deserialize_field(out, *f_iter, "this->"); + } + out << indent() << isset_prefix << (*f_iter)->get_name() << " = true;" << endl; + indent_down(); + out << indent() << "} else {" << endl << indent() << " xfer += iprot->skip(ftype);" << endl + << + // TODO(dreiss): Make this an option when thrift structs + // have a common base class. + // indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl << + indent() << "}" << endl << indent() << "break;" << endl; + indent_down(); + } + + // In the default case we skip the field + out << indent() << "default:" << endl << indent() << " xfer += iprot->skip(ftype);" << endl + << indent() << " break;" << endl; + + scope_down(out); + } //!fields.empty() + // Read field end marker + indent(out) << "xfer += iprot->readFieldEnd();" << endl; + + scope_down(out); + + out << endl << indent() << "xfer += iprot->readStructEnd();" << endl; + + // Throw if any required fields are missing. + // We do this after reading the struct end so that + // there might possibly be a chance of continuing. + out << endl; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_req() == t_field::T_REQUIRED) + out << indent() << "if (!isset_" << (*f_iter)->get_name() << ')' << endl << indent() + << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl; + } + + indent(out) << "return xfer;" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates the write function. + * + * @param out Stream to write to + * @param tstruct The struct + */ +void t_cpp_generator::generate_struct_writer(ofstream& out, t_struct* tstruct, bool pointers) { + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + if (gen_templates_) { + out << indent() << "template " << endl << indent() << "uint32_t " + << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl; + } else { + indent(out) << "uint32_t " << tstruct->get_name() + << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl; + } + indent_up(); + + out << indent() << "uint32_t xfer = 0;" << endl; + + indent(out) << "::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot);" << endl; + indent(out) << "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + bool check_if_set = (*f_iter)->get_req() == t_field::T_OPTIONAL + || (*f_iter)->get_type()->is_xception(); + if (check_if_set) { + out << endl << indent() << "if (this->__isset." << (*f_iter)->get_name() << ") {" << endl; + indent_up(); + } else { + out << endl; + } + + // Write field header + out << indent() << "xfer += oprot->writeFieldBegin(" + << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", " + << (*f_iter)->get_key() << ");" << endl; + // Write field contents + if (pointers && !(*f_iter)->get_type()->is_xception()) { + generate_serialize_field(out, *f_iter, "(*(this->", "))"); + } else { + generate_serialize_field(out, *f_iter, "this->"); + } + // Write field closer + indent(out) << "xfer += oprot->writeFieldEnd();" << endl; + if (check_if_set) { + indent_down(); + indent(out) << '}'; + } + } + + out << endl; + + // Write the struct map + out << indent() << "xfer += oprot->writeFieldStop();" << endl << indent() + << "xfer += oprot->writeStructEnd();" << endl << indent() + << "return xfer;" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Struct writer for result of a function, which can have only one of its + * fields set and does a conditional if else look up into the __isset field + * of the struct. + * + * @param out Output stream + * @param tstruct The result struct + */ +void t_cpp_generator::generate_struct_result_writer(ofstream& out, + t_struct* tstruct, + bool pointers) { + string name = tstruct->get_name(); + const vector& fields = tstruct->get_sorted_members(); + vector::const_iterator f_iter; + + if (gen_templates_) { + out << indent() << "template " << endl << indent() << "uint32_t " + << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl; + } else { + indent(out) << "uint32_t " << tstruct->get_name() + << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl; + } + indent_up(); + + out << endl << indent() << "uint32_t xfer = 0;" << endl << endl; + + indent(out) << "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl; + + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + out << endl << indent() << "if "; + } else { + out << " else if "; + } + + out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl; + + indent_up(); + + // Write field header + out << indent() << "xfer += oprot->writeFieldBegin(" + << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", " + << (*f_iter)->get_key() << ");" << endl; + // Write field contents + if (pointers) { + generate_serialize_field(out, *f_iter, "(*(this->", "))"); + } else { + generate_serialize_field(out, *f_iter, "this->"); + } + // Write field closer + indent(out) << "xfer += oprot->writeFieldEnd();" << endl; + + indent_down(); + indent(out) << "}"; + } + + // Write the struct map + out << endl << indent() << "xfer += oprot->writeFieldStop();" << endl << indent() + << "xfer += oprot->writeStructEnd();" << endl << indent() << "return xfer;" << endl; + + indent_down(); + indent(out) << "}" << endl << endl; +} + +/** + * Generates the swap function. + * + * @param out Stream to write to + * @param tstruct The struct + */ +void t_cpp_generator::generate_struct_swap(ofstream& out, t_struct* tstruct) { + out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name() + << " &b) {" << endl; + indent_up(); + + // Let argument-dependent name lookup find the correct swap() function to + // use based on the argument types. If none is found in the arguments' + // namespaces, fall back to ::std::swap(). + out << indent() << "using ::std::swap;" << endl; + + bool has_nonrequired_fields = false; + const vector& fields = tstruct->get_members(); + for (vector::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + t_field* tfield = *f_iter; + + if (tfield->get_req() != t_field::T_REQUIRED) { + has_nonrequired_fields = true; + } + + out << indent() << "swap(a." << tfield->get_name() << ", b." << tfield->get_name() << ");" + << endl; + } + + if (has_nonrequired_fields) { + out << indent() << "swap(a.__isset, b.__isset);" << endl; + } + + // handle empty structs + if (fields.size() == 0) { + out << indent() << "(void) a;" << endl; + out << indent() << "(void) b;" << endl; + } + + scope_down(out); + out << endl; +} + +void t_cpp_generator::generate_struct_ostream_operator_decl(std::ofstream& out, t_struct* tstruct) { + out << "std::ostream& operator<<(std::ostream& out, const " + << tstruct->get_name() + << "& obj);" << endl; + out << endl; +} + +void t_cpp_generator::generate_struct_ostream_operator(std::ofstream& out, t_struct* tstruct) { + if (!has_custom_ostream(tstruct)) { + // thrift defines this behavior + out << "std::ostream& operator<<(std::ostream& out, const " + << tstruct->get_name() + << "& obj)" << endl; + scope_up(out); + out << indent() << "obj.printTo(out);" << endl + << indent() << "return out;" << endl; + scope_down(out); + out << endl; + } +} + +void t_cpp_generator::generate_struct_print_method_decl(std::ofstream& out, t_struct* tstruct) { + out << "void "; + if (tstruct) { + out << tstruct->get_name() << "::"; + } + out << "printTo(std::ostream& out) const"; +} + +void t_cpp_generator::generate_exception_what_method_decl(std::ofstream& out, + t_struct* tstruct, + bool external) { + out << "const char* "; + if (external) { + out << tstruct->get_name() << "::"; + } + out << "what() const throw()"; +} + +namespace struct_ostream_operator_generator { +void generate_required_field_value(std::ofstream& out, const t_field* field) { + out << " << to_string(" << field->get_name() << ")"; +} + +void generate_optional_field_value(std::ofstream& out, const t_field* field) { + out << "; (__isset." << field->get_name() << " ? (out"; + generate_required_field_value(out, field); + out << ") : (out << \"\"))"; +} + +void generate_field_value(std::ofstream& out, const t_field* field) { + if (field->get_req() == t_field::T_OPTIONAL) + generate_optional_field_value(out, field); + else + generate_required_field_value(out, field); +} + +void generate_field_name(std::ofstream& out, const t_field* field) { + out << "\"" << field->get_name() << "=\""; +} + +void generate_field(std::ofstream& out, const t_field* field) { + generate_field_name(out, field); + generate_field_value(out, field); +} + +void generate_fields(std::ofstream& out, + const vector& fields, + const std::string& indent) { + const vector::const_iterator beg = fields.begin(); + const vector::const_iterator end = fields.end(); + + for (vector::const_iterator it = beg; it != end; ++it) { + out << indent << "out << "; + + if (it != beg) { + out << "\", \" << "; + } + + generate_field(out, *it); + out << ";" << endl; + } +} +} + +/** + * Generates operator<< + */ +void t_cpp_generator::generate_struct_print_method(std::ofstream& out, t_struct* tstruct) { + out << indent(); + generate_struct_print_method_decl(out, tstruct); + out << " {" << endl; + + indent_up(); + + out << indent() << "using ::apache::thrift::to_string;" << endl; + out << indent() << "out << \"" << tstruct->get_name() << "(\";" << endl; + struct_ostream_operator_generator::generate_fields(out, tstruct->get_members(), indent()); + out << indent() << "out << \")\";" << endl; + + indent_down(); + out << "}" << endl << endl; +} + +/** + * Generates what() method for exceptions + */ +void t_cpp_generator::generate_exception_what_method(std::ofstream& out, t_struct* tstruct) { + out << indent(); + generate_exception_what_method_decl(out, tstruct, true); + out << " {" << endl; + + indent_up(); + out << indent() << "try {" << endl; + + indent_up(); + out << indent() << "std::stringstream ss;" << endl; + out << indent() << "ss << \"TException - service has thrown: \" << *this;" << endl; + out << indent() << "this->thriftTExceptionMessageHolder_ = ss.str();" << endl; + out << indent() << "return this->thriftTExceptionMessageHolder_.c_str();" << endl; + indent_down(); + + out << indent() << "} catch (const std::exception&) {" << endl; + + indent_up(); + out << indent() << "return \"TException - service has thrown: " << tstruct->get_name() << "\";" + << endl; + indent_down(); + + out << indent() << "}" << endl; + + indent_down(); + out << "}" << endl << endl; +} + +/** + * Generates a thrift service. In C++, this comprises an entirely separate + * header and source file. The header file defines the methods and includes + * the data types defined in the main header file, and the implementation + * file contains implementations of the basic printer and default interfaces. + * + * @param tservice The service definition + */ +void t_cpp_generator::generate_service(t_service* tservice) { + string svcname = tservice->get_name(); + + // Make output files + string f_header_name = get_out_dir() + svcname + ".h"; + f_header_.open(f_header_name.c_str()); + + // Print header file includes + f_header_ << autogen_comment(); + f_header_ << "#ifndef " << svcname << "_H" << endl << "#define " << svcname << "_H" << endl + << endl; + if (gen_cob_style_) { + f_header_ << "#include " << endl << // TMemoryBuffer + "#include " << endl + << "namespace apache { namespace thrift { namespace async {" << endl + << "class TAsyncChannel;" << endl << "}}}" << endl; + } + f_header_ << "#include " << endl; + if (gen_cob_style_) { + f_header_ << "#include " << endl; + } + f_header_ << "#include " << endl; + f_header_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ << "_types.h\"" + << endl; + + t_service* extends_service = tservice->get_extends(); + if (extends_service != NULL) { + f_header_ << "#include \"" << get_include_prefix(*(extends_service->get_program())) + << extends_service->get_name() << ".h\"" << endl; + } + + f_header_ << endl << ns_open_ << endl << endl; + + f_header_ << "#ifdef _MSC_VER\n" + " #pragma warning( push )\n" + " #pragma warning (disable : 4250 ) //inheriting methods via dominance \n" + "#endif\n\n"; + + // Service implementation file includes + string f_service_name = get_out_dir() + svcname + ".cpp"; + f_service_.open(f_service_name.c_str()); + f_service_ << autogen_comment(); + f_service_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl; + if (gen_cob_style_) { + f_service_ << "#include \"thrift/async/TAsyncChannel.h\"" << endl; + } + if (gen_templates_) { + f_service_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".tcc\"" + << endl; + + string f_service_tcc_name = get_out_dir() + svcname + ".tcc"; + f_service_tcc_.open(f_service_tcc_name.c_str()); + f_service_tcc_ << autogen_comment(); + f_service_tcc_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" + << endl; + + f_service_tcc_ << "#ifndef " << svcname << "_TCC" << endl << "#define " << svcname << "_TCC" + << endl << endl; + + if (gen_cob_style_) { + f_service_tcc_ << "#include \"thrift/async/TAsyncChannel.h\"" << endl; + } + } + + f_service_ << endl << ns_open_ << endl << endl; + f_service_tcc_ << endl << ns_open_ << endl << endl; + + // Generate all the components + generate_service_interface(tservice, ""); + generate_service_interface_factory(tservice, ""); + generate_service_null(tservice, ""); + generate_service_helpers(tservice); + generate_service_client(tservice, ""); + generate_service_processor(tservice, ""); + generate_service_multiface(tservice); + generate_service_client(tservice, "Concurrent"); + + // Generate skeleton + if (!gen_no_skeleton_) { + generate_service_skeleton(tservice); + } + + // Generate all the cob components + if (gen_cob_style_) { + generate_service_interface(tservice, "CobCl"); + generate_service_interface(tservice, "CobSv"); + generate_service_interface_factory(tservice, "CobSv"); + generate_service_null(tservice, "CobSv"); + generate_service_client(tservice, "Cob"); + generate_service_processor(tservice, "Cob"); + + if (!gen_no_skeleton_) { + generate_service_async_skeleton(tservice); + } + + } + + f_header_ << "#ifdef _MSC_VER\n" + " #pragma warning( pop )\n" + "#endif\n\n"; + + // Close the namespace + f_service_ << ns_close_ << endl << endl; + f_service_tcc_ << ns_close_ << endl << endl; + f_header_ << ns_close_ << endl << endl; + + // TODO(simpkins): Make this a separate option + if (gen_templates_) { + f_header_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".tcc\"" << endl + << "#include \"" << get_include_prefix(*get_program()) << program_name_ + << "_types.tcc\"" << endl << endl; + } + + f_header_ << "#endif" << endl; + f_service_tcc_ << "#endif" << endl; + + // Close the files + f_service_tcc_.close(); + f_service_.close(); + f_header_.close(); +} + +/** + * Generates helper functions for a service. Basically, this generates types + * for all the arguments and results to functions. + * + * @param tservice The service to generate a header definition for + */ +void t_cpp_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_); + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + string name_orig = ts->get_name(); + + // TODO(dreiss): Why is this stuff not in generate_function_helpers? + ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_args"); + generate_struct_declaration(f_header_, ts, false); + generate_struct_definition(out, f_service_, ts, false); + generate_struct_reader(out, ts); + generate_struct_writer(out, ts); + ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs"); + generate_struct_declaration(f_header_, ts, false, true, false, true); + generate_struct_definition(out, f_service_, ts, false); + generate_struct_writer(out, ts, true); + ts->set_name(name_orig); + + generate_function_helpers(tservice, *f_iter); + } +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_cpp_generator::generate_service_interface(t_service* tservice, string style) { + + string service_if_name = service_name_ + style + "If"; + if (style == "CobCl") { + // Forward declare the client. + string client_name = service_name_ + "CobClient"; + if (gen_templates_) { + client_name += "T"; + service_if_name += "T"; + indent(f_header_) << "template " << endl; + } + indent(f_header_) << "class " << client_name << ";" << endl << endl; + } + + string extends = ""; + if (tservice->get_extends() != NULL) { + extends = " : virtual public " + type_name(tservice->get_extends()) + style + "If"; + if (style == "CobCl" && gen_templates_) { + // TODO(simpkins): If gen_templates_ is enabled, we currently assume all + // parent services were also generated with templates enabled. + extends += "T"; + } + } + + if (style == "CobCl" && gen_templates_) { + f_header_ << "template " << endl; + } + f_header_ << "class " << service_if_name << extends << " {" << endl << " public:" << endl; + indent_up(); + f_header_ << indent() << "virtual ~" << service_if_name << "() {}" << endl; + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + if ((*f_iter)->has_doc()) + f_header_ << endl; + generate_java_doc(f_header_, *f_iter); + f_header_ << indent() << "virtual " << function_signature(*f_iter, style) << " = 0;" << endl; + } + indent_down(); + f_header_ << "};" << endl << endl; + + if (style == "CobCl" && gen_templates_) { + // generate a backwards-compatible typedef for clients that do not + // know about the new template-style code + f_header_ << "typedef " << service_if_name << "< ::apache::thrift::protocol::TProtocol> " + << service_name_ << style << "If;" << endl << endl; + } +} + +/** + * Generates a service interface factory. + * + * @param tservice The service to generate an interface factory for. + */ +void t_cpp_generator::generate_service_interface_factory(t_service* tservice, string style) { + string service_if_name = service_name_ + style + "If"; + + // Figure out the name of the upper-most parent class. + // Getting everything to work out properly with inheritance is annoying. + // Here's what we're doing for now: + // + // - All handlers implement getHandler(), but subclasses use covariant return + // types to return their specific service interface class type. We have to + // use raw pointers because of this; shared_ptr<> can't be used for + // covariant return types. + // + // - Since we're not using shared_ptr<>, we also provide a releaseHandler() + // function that must be called to release a pointer to a handler obtained + // via getHandler(). + // + // releaseHandler() always accepts a pointer to the upper-most parent class + // type. This is necessary since the parent versions of releaseHandler() + // may accept any of the parent types, not just the most specific subclass + // type. Implementations can use dynamic_cast to cast the pointer to the + // subclass type if desired. + t_service* base_service = tservice; + while (base_service->get_extends() != NULL) { + base_service = base_service->get_extends(); + } + string base_if_name = type_name(base_service) + style + "If"; + + // Generate the abstract factory class + string factory_name = service_if_name + "Factory"; + string extends; + if (tservice->get_extends() != NULL) { + extends = " : virtual public " + type_name(tservice->get_extends()) + style + "IfFactory"; + } + + f_header_ << "class " << factory_name << extends << " {" << endl << " public:" << endl; + indent_up(); + f_header_ << indent() << "typedef " << service_if_name << " Handler;" << endl << endl << indent() + << "virtual ~" << factory_name << "() {}" << endl << endl << indent() << "virtual " + << service_if_name << "* getHandler(" + << "const ::apache::thrift::TConnectionInfo& connInfo) = 0;" << endl << indent() + << "virtual void releaseHandler(" << base_if_name << "* /* handler */) = 0;" << endl; + + indent_down(); + f_header_ << "};" << endl << endl; + + // Generate the singleton factory class + string singleton_factory_name = service_if_name + "SingletonFactory"; + f_header_ << "class " << singleton_factory_name << " : virtual public " << factory_name << " {" + << endl << " public:" << endl; + indent_up(); + f_header_ << indent() << singleton_factory_name << "(const ::apache::thrift::stdcxx::shared_ptr<" << service_if_name + << ">& iface) : iface_(iface) {}" << endl << indent() << "virtual ~" + << singleton_factory_name << "() {}" << endl << endl << indent() << "virtual " + << service_if_name << "* getHandler(" + << "const ::apache::thrift::TConnectionInfo&) {" << endl << indent() + << " return iface_.get();" << endl << indent() << "}" << endl << indent() + << "virtual void releaseHandler(" << base_if_name << "* /* handler */) {}" << endl; + + f_header_ << endl << " protected:" << endl << indent() << "::apache::thrift::stdcxx::shared_ptr<" << service_if_name + << "> iface_;" << endl; + + indent_down(); + f_header_ << "};" << endl << endl; +} + +/** + * Generates a null implementation of the service. + * + * @param tservice The service to generate a header definition for + */ +void t_cpp_generator::generate_service_null(t_service* tservice, string style) { + string extends = ""; + if (tservice->get_extends() != NULL) { + extends = " , virtual public " + type_name(tservice->get_extends()) + style + "Null"; + } + f_header_ << "class " << service_name_ << style << "Null : virtual public " << service_name_ + << style << "If" << extends << " {" << endl << " public:" << endl; + indent_up(); + f_header_ << indent() << "virtual ~" << service_name_ << style << "Null() {}" << endl; + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_header_ << indent() << function_signature(*f_iter, style, "", false) << " {" << endl; + indent_up(); + + t_type* returntype = (*f_iter)->get_returntype(); + t_field returnfield(returntype, "_return"); + + if (style == "") { + if (returntype->is_void() || is_complex_type(returntype)) { + f_header_ << indent() << "return;" << endl; + } else { + f_header_ << indent() << declare_field(&returnfield, true) << endl << indent() + << "return _return;" << endl; + } + } else if (style == "CobSv") { + if (returntype->is_void()) { + f_header_ << indent() << "return cob();" << endl; + } else { + t_field returnfield(returntype, "_return"); + f_header_ << indent() << declare_field(&returnfield, true) << endl << indent() + << "return cob(_return);" << endl; + } + + } else { + throw "UNKNOWN STYLE"; + } + + indent_down(); + f_header_ << indent() << "}" << endl; + } + indent_down(); + f_header_ << "};" << endl << endl; +} + +void t_cpp_generator::generate_function_call(ostream& out, + t_function* tfunction, + string target, + string iface, + string arg_prefix) { + bool first = true; + t_type* ret_type = get_true_type(tfunction->get_returntype()); + out << indent(); + if (!tfunction->is_oneway() && !ret_type->is_void()) { + if (is_complex_type(ret_type)) { + first = false; + out << iface << "->" << tfunction->get_name() << "(" << target; + } else { + out << target << " = " << iface << "->" << tfunction->get_name() << "("; + } + } else { + out << iface << "->" << tfunction->get_name() << "("; + } + const std::vector& fields = tfunction->get_arglist()->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + out << ", "; + } + out << arg_prefix << (*f_iter)->get_name(); + } + out << ");" << endl; +} + +void t_cpp_generator::generate_service_async_skeleton(t_service* tservice) { + string svcname = tservice->get_name(); + + // Service implementation file includes + string f_skeleton_name = get_out_dir() + svcname + "_async_server.skeleton.cpp"; + + string ns = namespace_prefix(tservice->get_program()->get_namespace("cpp")); + + ofstream f_skeleton; + f_skeleton.open(f_skeleton_name.c_str()); + f_skeleton << "// This autogenerated skeleton file illustrates one way to adapt a synchronous" + << endl << "// interface into an asynchronous interface. You should copy it to another" + << endl + << "// filename to avoid overwriting it and rewrite as asynchronous any functions" + << endl << "// that would otherwise introduce unwanted latency." << endl << endl + << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl + << "#include " << endl << endl + << "using namespace ::apache::thrift;" << endl + << "using namespace ::apache::thrift::protocol;" << endl + << "using namespace ::apache::thrift::transport;" << endl + << "using namespace ::apache::thrift::async;" << endl << endl; + + // the following code would not compile: + // using namespace ; + // using namespace ::; + if ((!ns.empty()) && (ns.compare(" ::") != 0)) { + f_skeleton << "using namespace " << string(ns, 0, ns.size() - 2) << ";" << endl << endl; + } + + f_skeleton << "class " << svcname << "AsyncHandler : " + << "public " << svcname << "CobSvIf {" << endl << " public:" << endl; + indent_up(); + f_skeleton << indent() << svcname << "AsyncHandler() {" << endl << indent() + << " syncHandler_ = std::auto_ptr<" << svcname << "Handler>(new " << svcname + << "Handler);" << endl << indent() << " // Your initialization goes here" << endl + << indent() << "}" << endl; + f_skeleton << indent() << "virtual ~" << service_name_ << "AsyncHandler();" << endl; + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_skeleton << endl << indent() << function_signature(*f_iter, "CobSv", "", true) << " {" + << endl; + indent_up(); + + t_type* returntype = (*f_iter)->get_returntype(); + t_field returnfield(returntype, "_return"); + + string target = returntype->is_void() ? "" : "_return"; + if (!returntype->is_void()) { + f_skeleton << indent() << declare_field(&returnfield, true) << endl; + } + generate_function_call(f_skeleton, *f_iter, target, "syncHandler_", ""); + f_skeleton << indent() << "return cob(" << target << ");" << endl; + + scope_down(f_skeleton); + } + f_skeleton << endl << " protected:" << endl << indent() << "std::auto_ptr<" << svcname + << "Handler> syncHandler_;" << endl; + indent_down(); + f_skeleton << "};" << endl << endl; +} + +/** + * Generates a multiface, which is a single server that just takes a set + * of objects implementing the interface and calls them all, returning the + * value of the last one to be called. + * + * @param tservice The service to generate a multiserver for. + */ +void t_cpp_generator::generate_service_multiface(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + string extends = ""; + string extends_multiface = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_multiface = ", public " + extends + "Multiface"; + } + + string list_type = string("std::vector >"; + + // Generate the header portion + f_header_ << "class " << service_name_ << "Multiface : " + << "virtual public " << service_name_ << "If" << extends_multiface << " {" << endl + << " public:" << endl; + indent_up(); + f_header_ << indent() << service_name_ << "Multiface(" << list_type + << "& ifaces) : ifaces_(ifaces) {" << endl; + if (!extends.empty()) { + f_header_ << indent() + << " std::vector >::iterator iter;" + << endl << indent() << " for (iter = ifaces.begin(); iter != ifaces.end(); ++iter) {" + << endl << indent() << " " << extends << "Multiface::add(*iter);" << endl + << indent() << " }" << endl; + } + f_header_ << indent() << "}" << endl << indent() << "virtual ~" << service_name_ + << "Multiface() {}" << endl; + indent_down(); + + // Protected data members + f_header_ << " protected:" << endl; + indent_up(); + f_header_ << indent() << list_type << " ifaces_;" << endl << indent() << service_name_ + << "Multiface() {}" << endl << indent() << "void add(::apache::thrift::stdcxx::shared_ptr<" + << service_name_ << "If> iface) {" << endl; + if (!extends.empty()) { + f_header_ << indent() << " " << extends << "Multiface::add(iface);" << endl; + } + f_header_ << indent() << " ifaces_.push_back(iface);" << endl << indent() << "}" << endl; + indent_down(); + + f_header_ << indent() << " public:" << endl; + indent_up(); + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* arglist = (*f_iter)->get_arglist(); + const vector& args = arglist->get_members(); + vector::const_iterator a_iter; + + string call = string("ifaces_[i]->") + (*f_iter)->get_name() + "("; + bool first = true; + if (is_complex_type((*f_iter)->get_returntype())) { + call += "_return"; + first = false; + } + for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) { + if (first) { + first = false; + } else { + call += ", "; + } + call += (*a_iter)->get_name(); + } + call += ")"; + + f_header_ << indent() << function_signature(*f_iter, "") << " {" << endl; + indent_up(); + f_header_ << indent() << "size_t sz = ifaces_.size();" << endl << indent() << "size_t i = 0;" + << endl << indent() << "for (; i < (sz - 1); ++i) {" << endl; + indent_up(); + f_header_ << indent() << call << ";" << endl; + indent_down(); + f_header_ << indent() << "}" << endl; + + if (!(*f_iter)->get_returntype()->is_void()) { + if (is_complex_type((*f_iter)->get_returntype())) { + f_header_ << indent() << call << ";" << endl << indent() << "return;" << endl; + } else { + f_header_ << indent() << "return " << call << ";" << endl; + } + } else { + f_header_ << indent() << call << ";" << endl; + } + + indent_down(); + f_header_ << indent() << "}" << endl << endl; + } + + indent_down(); + f_header_ << indent() << "};" << endl << endl; +} + +/** + * Generates a service client definition. + * + * @param tservice The service to generate a server for. + */ +void t_cpp_generator::generate_service_client(t_service* tservice, string style) { + string ifstyle; + if (style == "Cob") { + ifstyle = "CobCl"; + } + + std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_); + string template_header, template_suffix, short_suffix, protocol_type, _this; + string const prot_factory_type = "::apache::thrift::protocol::TProtocolFactory"; + if (gen_templates_) { + template_header = "template \n"; + short_suffix = "T"; + template_suffix = "T"; + protocol_type = "Protocol_"; + _this = "this->"; + } else { + protocol_type = "::apache::thrift::protocol::TProtocol"; + } + string prot_ptr = "apache::thrift::stdcxx::shared_ptr< " + protocol_type + ">"; + string client_suffix = "Client" + template_suffix; + string if_suffix = "If"; + if (style == "Cob") { + if_suffix += template_suffix; + } + + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() != NULL) { + // TODO(simpkins): If gen_templates_ is enabled, we currently assume all + // parent services were also generated with templates enabled. + extends = type_name(tservice->get_extends()); + extends_client = ", public " + extends + style + client_suffix; + } + + // Generate the header portion + if (style == "Concurrent") { + f_header_ << "// The \'concurrent\' client is a thread safe client that correctly handles\n" + "// out of order responses. It is slower than the regular client, so should\n" + "// only be used when you need to share a connection among multiple threads\n"; + } + f_header_ << template_header << "class " << service_name_ << style << "Client" << short_suffix + << " : " + << "virtual public " << service_name_ << ifstyle << if_suffix << extends_client << " {" + << endl << " public:" << endl; + + indent_up(); + if (style != "Cob") { + f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" << prot_ptr + << " prot) "; + + if (extends.empty()) { + f_header_ << "{" << endl; + f_header_ << indent() << " setProtocol" << short_suffix << "(prot);" << endl << indent() + << "}" << endl; + } else { + f_header_ << ":" << endl; + f_header_ << indent() << " " << extends << style << client_suffix << "(prot, prot) {}" + << endl; + } + + f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" << prot_ptr + << " iprot, " << prot_ptr << " oprot) "; + if (extends.empty()) { + f_header_ << "{" << endl; + f_header_ << indent() << " setProtocol" << short_suffix << "(iprot,oprot);" << endl + << indent() << "}" << endl; + } else { + f_header_ << ":" << indent() << " " << extends << style << client_suffix + << "(iprot, oprot) {}" << endl; + } + + // create the setProtocol methods + if (extends.empty()) { + f_header_ << " private:" << endl; + // 1: one parameter + f_header_ << indent() << "void setProtocol" << short_suffix << "(" << prot_ptr << " prot) {" + << endl; + f_header_ << indent() << "setProtocol" << short_suffix << "(prot,prot);" << endl; + f_header_ << indent() << "}" << endl; + // 2: two parameter + f_header_ << indent() << "void setProtocol" << short_suffix << "(" << prot_ptr << " iprot, " + << prot_ptr << " oprot) {" << endl; + + f_header_ << indent() << " piprot_=iprot;" << endl << indent() << " poprot_=oprot;" << endl + << indent() << " iprot_ = iprot.get();" << endl << indent() + << " oprot_ = oprot.get();" << endl; + + f_header_ << indent() << "}" << endl; + f_header_ << " public:" << endl; + } + + // Generate getters for the protocols. + // Note that these are not currently templated for simplicity. + // TODO(simpkins): should they be templated? + f_header_ << indent() + << "apache::thrift::stdcxx::shared_ptr< ::apache::thrift::protocol::TProtocol> getInputProtocol() {" + << endl << indent() << " return " << _this << "piprot_;" << endl << indent() << "}" + << endl; + + f_header_ << indent() + << "apache::thrift::stdcxx::shared_ptr< ::apache::thrift::protocol::TProtocol> getOutputProtocol() {" + << endl << indent() << " return " << _this << "poprot_;" << endl << indent() << "}" + << endl; + + } else /* if (style == "Cob") */ { + f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" + << "apache::thrift::stdcxx::shared_ptr< ::apache::thrift::async::TAsyncChannel> channel, " + << "::apache::thrift::protocol::TProtocolFactory* protocolFactory) :" << endl; + if (extends.empty()) { + f_header_ << indent() << " channel_(channel)," << endl << indent() + << " itrans_(new ::apache::thrift::transport::TMemoryBuffer())," << endl + << indent() << " otrans_(new ::apache::thrift::transport::TMemoryBuffer())," + << endl; + if (gen_templates_) { + // TProtocolFactory classes return generic TProtocol pointers. + // We have to dynamic cast to the Protocol_ type we are expecting. + f_header_ << indent() << " piprot_(::apache::thrift::stdcxx::dynamic_pointer_cast(" + << "protocolFactory->getProtocol(itrans_)))," << endl << indent() + << " poprot_(::apache::thrift::stdcxx::dynamic_pointer_cast(" + << "protocolFactory->getProtocol(otrans_))) {" << endl; + // Throw a TException if either dynamic cast failed. + f_header_ << indent() << " if (!piprot_ || !poprot_) {" << endl << indent() + << " throw ::apache::thrift::TException(\"" + << "TProtocolFactory returned unexpected protocol type in " << service_name_ + << style << "Client" << short_suffix << " constructor\");" << endl << indent() + << " }" << endl; + } else { + f_header_ << indent() << " piprot_(protocolFactory->getProtocol(itrans_))," << endl + << indent() << " poprot_(protocolFactory->getProtocol(otrans_)) {" << endl; + } + f_header_ << indent() << " iprot_ = piprot_.get();" << endl << indent() + << " oprot_ = poprot_.get();" << endl << indent() << "}" << endl; + } else { + f_header_ << indent() << " " << extends << style << client_suffix + << "(channel, protocolFactory) {}" << endl; + } + } + + if (style == "Cob") { + f_header_ << indent() + << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::async::TAsyncChannel> getChannel() {" << endl + << indent() << " return " << _this << "channel_;" << endl << indent() << "}" << endl; + if (!gen_no_client_completion_) { + f_header_ << indent() << "virtual void completed__(bool /* success */) {}" << endl; + } + } + + vector functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + indent(f_header_) << function_signature(*f_iter, ifstyle) << ";" << endl; + // TODO(dreiss): Use private inheritance to avoid generating thise in cob-style. + if (style == "Concurrent" && !(*f_iter)->is_oneway()) { + // concurrent clients need to move the seqid from the send function to the + // recv function. Oneway methods don't have a recv function, so we don't need to + // move the seqid for them. Attempting to do so would result in a seqid leak. + t_function send_function(g_type_i32, /*returning seqid*/ + string("send_") + (*f_iter)->get_name(), + (*f_iter)->get_arglist()); + indent(f_header_) << function_signature(&send_function, "") << ";" << endl; + } else { + t_function send_function(g_type_void, + string("send_") + (*f_iter)->get_name(), + (*f_iter)->get_arglist()); + indent(f_header_) << function_signature(&send_function, "") << ";" << endl; + } + if (!(*f_iter)->is_oneway()) { + if (style == "Concurrent") { + t_field seqIdArg(g_type_i32, "seqid"); + t_struct seqIdArgStruct(program_); + seqIdArgStruct.append(&seqIdArg); + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + &seqIdArgStruct); + indent(f_header_) << function_signature(&recv_function, "") << ";" << endl; + } else { + t_struct noargs(program_); + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + &noargs); + indent(f_header_) << function_signature(&recv_function, "") << ";" << endl; + } + } + } + indent_down(); + + if (extends.empty()) { + f_header_ << " protected:" << endl; + indent_up(); + + if (style == "Cob") { + f_header_ << indent() + << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::async::TAsyncChannel> channel_;" << endl + << indent() + << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::transport::TMemoryBuffer> itrans_;" << endl + << indent() + << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::transport::TMemoryBuffer> otrans_;" + << endl; + } + f_header_ << + indent() << prot_ptr << " piprot_;" << endl << + indent() << prot_ptr << " poprot_;" << endl << + indent() << protocol_type << "* iprot_;" << endl << + indent() << protocol_type << "* oprot_;" << endl; + + if (style == "Concurrent") { + f_header_ << + indent() << "::apache::thrift::async::TConcurrentClientSyncInfo sync_;"< " << service_name_ << style + << "Client;" << endl << endl; + } + + string scope = service_name_ + style + client_suffix + "::"; + + // Generate client method implementations + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string seqIdCapture; + string seqIdUse; + string seqIdCommaUse; + if (style == "Concurrent" && !(*f_iter)->is_oneway()) { + seqIdCapture = "int32_t seqid = "; + seqIdUse = "seqid"; + seqIdCommaUse = ", seqid"; + } + + string funname = (*f_iter)->get_name(); + + // Open function + if (gen_templates_) { + indent(out) << template_header; + } + indent(out) << function_signature(*f_iter, ifstyle, scope) << endl; + scope_up(out); + indent(out) << seqIdCapture << "send_" << funname << "("; + + // Get the struct of function call params + t_struct* arg_struct = (*f_iter)->get_arglist(); + + // Declare the function arguments + const vector& fields = arg_struct->get_members(); + vector::const_iterator fld_iter; + bool first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + if (first) { + first = false; + } else { + out << ", "; + } + out << (*fld_iter)->get_name(); + } + out << ");" << endl; + + if (style != "Cob") { + if (!(*f_iter)->is_oneway()) { + out << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + if (is_complex_type((*f_iter)->get_returntype())) { + out << "recv_" << funname << "(_return" << seqIdCommaUse << ");" << endl; + } else { + out << "return recv_" << funname << "(" << seqIdUse << ");" << endl; + } + } else { + out << "recv_" << funname << "(" << seqIdUse << ");" << endl; + } + } + } else { + if (!(*f_iter)->is_oneway()) { + out << indent() << _this << "channel_->sendAndRecvMessage(" + << "::apache::thrift::stdcxx::bind(cob, this), " << _this << "otrans_.get(), " << _this << "itrans_.get());" + << endl; + } else { + out << indent() << _this << "channel_->sendMessage(" + << "::apache::thrift::stdcxx::bind(cob, this), " << _this << "otrans_.get());" << endl; + } + } + scope_down(out); + out << endl; + + // if (style != "Cob") // TODO(dreiss): Libify the client and don't generate this for cob-style + if (true) { + t_type* send_func_return_type = g_type_void; + if (style == "Concurrent" && !(*f_iter)->is_oneway()) { + send_func_return_type = g_type_i32; + } + // Function for sending + t_function send_function(send_func_return_type, + string("send_") + (*f_iter)->get_name(), + (*f_iter)->get_arglist()); + + // Open the send function + if (gen_templates_) { + indent(out) << template_header; + } + indent(out) << function_signature(&send_function, "", scope) << endl; + scope_up(out); + + // Function arguments and results + string argsname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs"; + string resultname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_presult"; + + string cseqidVal = "0"; + if (style == "Concurrent") { + if (!(*f_iter)->is_oneway()) { + cseqidVal = "this->sync_.generateSeqId()"; + } + } + // Serialize the request + out << + indent() << "int32_t cseqid = " << cseqidVal << ";" << endl; + if(style == "Concurrent") { + out << + indent() << "::apache::thrift::async::TConcurrentSendSentry sentry(&this->sync_);" << endl; + } + if (style == "Cob") { + out << + indent() << _this << "otrans_->resetBuffer();" << endl; + } + out << + indent() << _this << "oprot_->writeMessageBegin(\"" << + (*f_iter)->get_name() << + "\", ::apache::thrift::protocol::" << ((*f_iter)->is_oneway() ? "T_ONEWAY" : "T_CALL") << + ", cseqid);" << endl << endl << + indent() << argsname << " args;" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + out << indent() << "args." << (*fld_iter)->get_name() << " = &" << (*fld_iter)->get_name() + << ";" << endl; + } + + out << indent() << "args.write(" << _this << "oprot_);" << endl << endl << indent() << _this + << "oprot_->writeMessageEnd();" << endl << indent() << _this + << "oprot_->getTransport()->writeEnd();" << endl << indent() << _this + << "oprot_->getTransport()->flush();" << endl; + + if (style == "Concurrent") { + out << endl << indent() << "sentry.commit();" << endl; + + if (!(*f_iter)->is_oneway()) { + out << indent() << "return cseqid;" << endl; + } + } + scope_down(out); + out << endl; + + // Generate recv function only if not an oneway function + if (!(*f_iter)->is_oneway()) { + t_struct noargs(program_); + + t_field seqIdArg(g_type_i32, "seqid"); + t_struct seqIdArgStruct(program_); + seqIdArgStruct.append(&seqIdArg); + + t_struct* recv_function_args = &noargs; + if (style == "Concurrent") { + recv_function_args = &seqIdArgStruct; + } + + t_function recv_function((*f_iter)->get_returntype(), + string("recv_") + (*f_iter)->get_name(), + recv_function_args); + // Open the recv function + if (gen_templates_) { + indent(out) << template_header; + } + indent(out) << function_signature(&recv_function, "", scope) << endl; + scope_up(out); + + out << endl << + indent() << "int32_t rseqid = 0;" << endl << + indent() << "std::string fname;" << endl << + indent() << "::apache::thrift::protocol::TMessageType mtype;" << endl; + if(style == "Concurrent") { + out << + endl << + indent() << "// the read mutex gets dropped and reacquired as part of waitForWork()" << endl << + indent() << "// The destructor of this sentry wakes up other clients" << endl << + indent() << "::apache::thrift::async::TConcurrentRecvSentry sentry(&this->sync_, seqid);" << endl; + } + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << "bool completed = false;" << endl << endl << indent() << "try {"; + indent_up(); + } + out << endl; + if (style == "Concurrent") { + out << + indent() << "while(true) {" << endl << + indent() << " if(!this->sync_.getPending(fname, mtype, rseqid)) {" << endl; + indent_up(); + indent_up(); + } + out << + indent() << _this << "iprot_->readMessageBegin(fname, mtype, rseqid);" << endl; + if (style == "Concurrent") { + scope_down(out); + out << indent() << "if(seqid == rseqid) {" << endl; + indent_up(); + } + out << + indent() << "if (mtype == ::apache::thrift::protocol::T_EXCEPTION) {" << endl << + indent() << " ::apache::thrift::TApplicationException x;" << endl << + indent() << " x.read(" << _this << "iprot_);" << endl << + indent() << " " << _this << "iprot_->readMessageEnd();" << endl << + indent() << " " << _this << "iprot_->getTransport()->readEnd();" << endl; + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << " completed = true;" << endl << indent() << " completed__(true);" + << endl; + } + if (style == "Concurrent") { + out << indent() << " sentry.commit();" << endl; + } + out << + indent() << " throw x;" << endl << + indent() << "}" << endl << + indent() << "if (mtype != ::apache::thrift::protocol::T_REPLY) {" << endl << + indent() << " " << _this << "iprot_->skip(" << "::apache::thrift::protocol::T_STRUCT);" << endl << + indent() << " " << _this << "iprot_->readMessageEnd();" << endl << + indent() << " " << _this << "iprot_->getTransport()->readEnd();" << endl; + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << " completed = true;" << endl << indent() << " completed__(false);" + << endl; + } + out << + indent() << "}" << endl << + indent() << "if (fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl << + indent() << " " << _this << "iprot_->skip(" << "::apache::thrift::protocol::T_STRUCT);" << endl << + indent() << " " << _this << "iprot_->readMessageEnd();" << endl << + indent() << " " << _this << "iprot_->getTransport()->readEnd();" << endl; + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << " completed = true;" << endl << indent() << " completed__(false);" + << endl; + } + if (style == "Concurrent") { + out << endl << + indent() << " // in a bad state, don't commit" << endl << + indent() << " using ::apache::thrift::protocol::TProtocolException;" << endl << + indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl; + } + out << indent() << "}" << endl; + + if (!(*f_iter)->get_returntype()->is_void() + && !is_complex_type((*f_iter)->get_returntype())) { + t_field returnfield((*f_iter)->get_returntype(), "_return"); + out << indent() << declare_field(&returnfield) << endl; + } + + out << indent() << resultname << " result;" << endl; + + if (!(*f_iter)->get_returntype()->is_void()) { + out << indent() << "result.success = &_return;" << endl; + } + + out << indent() << "result.read(" << _this << "iprot_);" << endl << indent() << _this + << "iprot_->readMessageEnd();" << endl << indent() << _this + << "iprot_->getTransport()->readEnd();" << endl << endl; + + // Careful, only look for _result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + if (is_complex_type((*f_iter)->get_returntype())) { + out << + indent() << "if (result.__isset.success) {" << endl; + out << + indent() << " // _return pointer has now been filled" << endl; + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << " completed = true;" << endl << indent() << " completed__(true);" + << endl; + } + if (style == "Concurrent") { + out << indent() << " sentry.commit();" << endl; + } + out << + indent() << " return;" << endl << + indent() << "}" << endl; + } else { + out << indent() << "if (result.__isset.success) {" << endl; + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << " completed = true;" << endl << indent() << " completed__(true);" + << endl; + } + if (style == "Concurrent") { + out << indent() << " sentry.commit();" << endl; + } + out << indent() << " return _return;" << endl << indent() << "}" << endl; + } + } + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + out << indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl; + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << " completed = true;" << endl << indent() << " completed__(true);" + << endl; + } + if (style == "Concurrent") { + out << indent() << " sentry.commit();" << endl; + } + out << indent() << " throw result." << (*x_iter)->get_name() << ";" << endl << indent() + << "}" << endl; + } + + // We only get here if we are a void function + if ((*f_iter)->get_returntype()->is_void()) { + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << "completed = true;" << endl << indent() << "completed__(true);" + << endl; + } + if (style == "Concurrent") { + out << indent() << "sentry.commit();" << endl; + } + indent(out) << "return;" << endl; + } else { + if (style == "Cob" && !gen_no_client_completion_) { + out << indent() << "completed = true;" << endl << indent() << "completed__(true);" + << endl; + } + if (style == "Concurrent") { + out << indent() << "// in a bad state, don't commit" << endl; + } + out << indent() << "throw " + "::apache::thrift::TApplicationException(::apache::thrift::" + "TApplicationException::MISSING_RESULT, \"" << (*f_iter)->get_name() + << " failed: unknown result\");" << endl; + } + if (style == "Concurrent") { + indent_down(); + indent_down(); + out << + indent() << " }" << endl << + indent() << " // seqid != rseqid" << endl << + indent() << " this->sync_.updatePending(fname, mtype, rseqid);" << endl << + endl << + indent() << " // this will temporarily unlock the readMutex, and let other clients get work done" << endl << + indent() << " this->sync_.waitForWork(seqid);" << endl << + indent() << "} // end while(true)" << endl; + } + if (style == "Cob" && !gen_no_client_completion_) { + indent_down(); + out << indent() << "} catch (...) {" << endl << indent() << " if (!completed) {" << endl + << indent() << " completed__(false);" << endl << indent() << " }" << endl + << indent() << " throw;" << endl << indent() << "}" << endl; + } + // Close function + scope_down(out); + out << endl; + } + } + } +} + +class ProcessorGenerator { +public: + ProcessorGenerator(t_cpp_generator* generator, t_service* service, const string& style); + + void run() { + generate_class_definition(); + + // Generate the dispatchCall() function + generate_dispatch_call(false); + if (generator_->gen_templates_) { + generate_dispatch_call(true); + } + + // Generate all of the process subfunctions + generate_process_functions(); + + generate_factory(); + } + + void generate_class_definition(); + void generate_dispatch_call(bool template_protocol); + void generate_process_functions(); + void generate_factory(); + +protected: + std::string type_name(t_type* ttype, bool in_typedef = false, bool arg = false) { + return generator_->type_name(ttype, in_typedef, arg); + } + + std::string indent() { return generator_->indent(); } + std::ostream& indent(std::ostream& os) { return generator_->indent(os); } + + void indent_up() { generator_->indent_up(); } + void indent_down() { generator_->indent_down(); } + + t_cpp_generator* generator_; + t_service* service_; + std::ofstream& f_header_; + std::ofstream& f_out_; + string service_name_; + string style_; + string pstyle_; + string class_name_; + string if_name_; + string factory_class_name_; + string finish_cob_; + string finish_cob_decl_; + string ret_type_; + string call_context_; + string cob_arg_; + string call_context_arg_; + string call_context_decl_; + string template_header_; + string template_suffix_; + string typename_str_; + string class_suffix_; + string extends_; +}; + +ProcessorGenerator::ProcessorGenerator(t_cpp_generator* generator, + t_service* service, + const string& style) + : generator_(generator), + service_(service), + f_header_(generator->f_header_), + f_out_(generator->gen_templates_ ? generator->f_service_tcc_ : generator->f_service_), + service_name_(generator->service_name_), + style_(style) { + if (style_ == "Cob") { + pstyle_ = "Async"; + class_name_ = service_name_ + pstyle_ + "Processor"; + if_name_ = service_name_ + "CobSvIf"; + + finish_cob_ = "::apache::thrift::stdcxx::function cob, "; + finish_cob_decl_ = "::apache::thrift::stdcxx::function, "; + cob_arg_ = "cob, "; + ret_type_ = "void "; + } else { + class_name_ = service_name_ + "Processor"; + if_name_ = service_name_ + "If"; + + ret_type_ = "bool "; + // TODO(edhall) callContext should eventually be added to TAsyncProcessor + call_context_ = ", void* callContext"; + call_context_arg_ = ", callContext"; + call_context_decl_ = ", void*"; + } + + factory_class_name_ = class_name_ + "Factory"; + + if (generator->gen_templates_) { + template_header_ = "template \n"; + template_suffix_ = ""; + typename_str_ = "typename "; + class_name_ += "T"; + factory_class_name_ += "T"; + } + + if (service_->get_extends() != NULL) { + extends_ = type_name(service_->get_extends()) + pstyle_ + "Processor"; + if (generator_->gen_templates_) { + // TODO(simpkins): If gen_templates_ is enabled, we currently assume all + // parent services were also generated with templates enabled. + extends_ += "T"; + } + } +} + +void ProcessorGenerator::generate_class_definition() { + // Generate the dispatch methods + vector functions = service_->get_functions(); + vector::iterator f_iter; + + string parent_class; + if (service_->get_extends() != NULL) { + parent_class = extends_; + } else { + if (style_ == "Cob") { + parent_class = "::apache::thrift::async::TAsyncDispatchProcessor"; + } else { + parent_class = "::apache::thrift::TDispatchProcessor"; + } + + if (generator_->gen_templates_) { + parent_class += "T"; + } + } + + // Generate the header portion + f_header_ << template_header_ << "class " << class_name_ << " : public " << parent_class << " {" + << endl; + + // Protected data members + f_header_ << " protected:" << endl; + indent_up(); + f_header_ << indent() << "::apache::thrift::stdcxx::shared_ptr<" << if_name_ << "> iface_;" << endl; + f_header_ << indent() << "virtual " << ret_type_ << "dispatchCall(" << finish_cob_ + << "::apache::thrift::protocol::TProtocol* iprot, " + << "::apache::thrift::protocol::TProtocol* oprot, " + << "const std::string& fname, int32_t seqid" << call_context_ << ");" << endl; + if (generator_->gen_templates_) { + f_header_ << indent() << "virtual " << ret_type_ << "dispatchCallTemplated(" << finish_cob_ + << "Protocol_* iprot, Protocol_* oprot, " + << "const std::string& fname, int32_t seqid" << call_context_ << ");" << endl; + } + indent_down(); + + // Process function declarations + f_header_ << " private:" << endl; + indent_up(); + + // Declare processMap_ + f_header_ << indent() << "typedef void (" << class_name_ << "::*" + << "ProcessFunction)(" << finish_cob_decl_ << "int32_t, " + << "::apache::thrift::protocol::TProtocol*, " + << "::apache::thrift::protocol::TProtocol*" << call_context_decl_ << ");" << endl; + if (generator_->gen_templates_) { + f_header_ << indent() << "typedef void (" << class_name_ << "::*" + << "SpecializedProcessFunction)(" << finish_cob_decl_ << "int32_t, " + << "Protocol_*, Protocol_*" << call_context_decl_ << ");" << endl << indent() + << "struct ProcessFunctions {" << endl << indent() << " ProcessFunction generic;" + << endl << indent() << " SpecializedProcessFunction specialized;" << endl << indent() + << " ProcessFunctions(ProcessFunction g, " + << "SpecializedProcessFunction s) :" << endl << indent() << " generic(g)," << endl + << indent() << " specialized(s) {}" << endl << indent() + << " ProcessFunctions() : generic(NULL), specialized(NULL) " + << "{}" << endl << indent() << "};" << endl << indent() + << "typedef std::map " + << "ProcessMap;" << endl; + } else { + f_header_ << indent() << "typedef std::map " + << "ProcessMap;" << endl; + } + f_header_ << indent() << "ProcessMap processMap_;" << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + indent(f_header_) << "void process_" << (*f_iter)->get_name() << "(" << finish_cob_ + << "int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, " + "::apache::thrift::protocol::TProtocol* oprot" << call_context_ << ");" + << endl; + if (generator_->gen_templates_) { + indent(f_header_) << "void process_" << (*f_iter)->get_name() << "(" << finish_cob_ + << "int32_t seqid, Protocol_* iprot, Protocol_* oprot" << call_context_ + << ");" << endl; + } + if (style_ == "Cob") { + // XXX Factor this out, even if it is a pain. + string ret_arg = ((*f_iter)->get_returntype()->is_void() + ? "" + : ", const " + type_name((*f_iter)->get_returntype()) + "& _return"); + f_header_ << indent() << "void return_" << (*f_iter)->get_name() + << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << "::apache::thrift::protocol::TProtocol* oprot, " + << "void* ctx" << ret_arg << ");" << endl; + if (generator_->gen_templates_) { + f_header_ << indent() << "void return_" << (*f_iter)->get_name() + << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << "Protocol_* oprot, void* ctx" << ret_arg << ");" << endl; + } + // XXX Don't declare throw if it doesn't exist + f_header_ << indent() << "void throw_" << (*f_iter)->get_name() + << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << "::apache::thrift::protocol::TProtocol* oprot, void* ctx, " + << "::apache::thrift::TDelayedException* _throw);" << endl; + if (generator_->gen_templates_) { + f_header_ << indent() << "void throw_" << (*f_iter)->get_name() + << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << "Protocol_* oprot, void* ctx, " + << "::apache::thrift::TDelayedException* _throw);" << endl; + } + } + } + + f_header_ << " public:" << endl << indent() << class_name_ << "(::apache::thrift::stdcxx::shared_ptr<" << if_name_ + << "> iface) :" << endl; + if (!extends_.empty()) { + f_header_ << indent() << " " << extends_ << "(iface)," << endl; + } + f_header_ << indent() << " iface_(iface) {" << endl; + indent_up(); + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_header_ << indent() << "processMap_[\"" << (*f_iter)->get_name() << "\"] = "; + if (generator_->gen_templates_) { + f_header_ << "ProcessFunctions(" << endl; + if (generator_->gen_templates_only_) { + indent(f_header_) << " NULL," << endl; + } else { + indent(f_header_) << " &" << class_name_ << "::process_" << (*f_iter)->get_name() << "," + << endl; + } + indent(f_header_) << " &" << class_name_ << "::process_" << (*f_iter)->get_name() << ")"; + } else { + f_header_ << "&" << class_name_ << "::process_" << (*f_iter)->get_name(); + } + f_header_ << ";" << endl; + } + + indent_down(); + f_header_ << indent() << "}" << endl << endl << indent() << "virtual ~" << class_name_ << "() {}" + << endl; + indent_down(); + f_header_ << "};" << endl << endl; + + if (generator_->gen_templates_) { + // Generate a backwards compatible typedef, for callers who don't know + // about the new template-style code. + // + // We can't use TProtocol as the template parameter, since ProcessorT + // provides overloaded versions of most methods, one of which accepts + // TProtocol pointers, and one which accepts Protocol_ pointers. This + // results in a compile error if instantiated with Protocol_ == TProtocol. + // Therefore, we define TDummyProtocol solely so we can use it as the + // template parameter here. + f_header_ << "typedef " << class_name_ << "< ::apache::thrift::protocol::TDummyProtocol > " + << service_name_ << pstyle_ << "Processor;" << endl << endl; + } +} + +void ProcessorGenerator::generate_dispatch_call(bool template_protocol) { + string protocol = "::apache::thrift::protocol::TProtocol"; + string function_suffix; + if (template_protocol) { + protocol = "Protocol_"; + // We call the generic version dispatchCall(), and the specialized + // version dispatchCallTemplated(). We can't call them both + // dispatchCall(), since this will cause the compiler to issue a warning if + // a service that doesn't use templates inherits from a service that does + // use templates: the compiler complains that the subclass only implements + // the generic version of dispatchCall(), and hides the templated version. + // Using different names for the two functions prevents this. + function_suffix = "Templated"; + } + + f_out_ << template_header_ << ret_type_ << class_name_ << template_suffix_ << "::dispatchCall" + << function_suffix << "(" << finish_cob_ << protocol << "* iprot, " << protocol + << "* oprot, " + << "const std::string& fname, int32_t seqid" << call_context_ << ") {" << endl; + indent_up(); + + // HOT: member function pointer map + f_out_ << indent() << typename_str_ << "ProcessMap::iterator pfn;" << endl << indent() + << "pfn = processMap_.find(fname);" << endl << indent() + << "if (pfn == processMap_.end()) {" << endl; + if (extends_.empty()) { + f_out_ << indent() << " iprot->skip(::apache::thrift::protocol::T_STRUCT);" << endl << indent() + << " iprot->readMessageEnd();" << endl << indent() + << " iprot->getTransport()->readEnd();" << endl << indent() + << " ::apache::thrift::TApplicationException " + "x(::apache::thrift::TApplicationException::UNKNOWN_METHOD, \"Invalid method name: " + "'\"+fname+\"'\");" << endl << indent() + << " oprot->writeMessageBegin(fname, ::apache::thrift::protocol::T_EXCEPTION, seqid);" + << endl << indent() << " x.write(oprot);" << endl << indent() + << " oprot->writeMessageEnd();" << endl << indent() + << " oprot->getTransport()->writeEnd();" << endl << indent() + << " oprot->getTransport()->flush();" << endl << indent() + << (style_ == "Cob" ? " return cob(true);" : " return true;") << endl; + } else { + f_out_ << indent() << " return " << extends_ << "::dispatchCall(" + << (style_ == "Cob" ? "cob, " : "") << "iprot, oprot, fname, seqid" << call_context_arg_ + << ");" << endl; + } + f_out_ << indent() << "}" << endl; + if (template_protocol) { + f_out_ << indent() << "(this->*(pfn->second.specialized))"; + } else { + if (generator_->gen_templates_only_) { + // TODO: This is a null pointer, so nothing good will come from calling + // it. Throw an exception instead. + f_out_ << indent() << "(this->*(pfn->second.generic))"; + } else if (generator_->gen_templates_) { + f_out_ << indent() << "(this->*(pfn->second.generic))"; + } else { + f_out_ << indent() << "(this->*(pfn->second))"; + } + } + f_out_ << "(" << cob_arg_ << "seqid, iprot, oprot" << call_context_arg_ << ");" << endl; + + // TODO(dreiss): return pfn ret? + if (style_ == "Cob") { + f_out_ << indent() << "return;" << endl; + } else { + f_out_ << indent() << "return true;" << endl; + } + + indent_down(); + f_out_ << "}" << endl << endl; +} + +void ProcessorGenerator::generate_process_functions() { + vector functions = service_->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + if (generator_->gen_templates_) { + generator_->generate_process_function(service_, *f_iter, style_, false); + generator_->generate_process_function(service_, *f_iter, style_, true); + } else { + generator_->generate_process_function(service_, *f_iter, style_, false); + } + } +} + +void ProcessorGenerator::generate_factory() { + string if_factory_name = if_name_ + "Factory"; + + // Generate the factory class definition + f_header_ << template_header_ << "class " << factory_class_name_ << " : public ::apache::thrift::" + << (style_ == "Cob" ? "async::TAsyncProcessorFactory" : "TProcessorFactory") << " {" + << endl << " public:" << endl; + indent_up(); + + f_header_ << indent() << factory_class_name_ << "(const ::apache::thrift::stdcxx::shared_ptr< " << if_factory_name + << " >& handlerFactory) :" << endl << indent() + << " handlerFactory_(handlerFactory) {}" << endl << endl << indent() + << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::" + << (style_ == "Cob" ? "async::TAsyncProcessor" : "TProcessor") << " > " + << "getProcessor(const ::apache::thrift::TConnectionInfo& connInfo);" << endl; + + f_header_ << endl << " protected:" << endl << indent() << "::apache::thrift::stdcxx::shared_ptr< " + << if_factory_name << " > handlerFactory_;" << endl; + + indent_down(); + f_header_ << "};" << endl << endl; + + // If we are generating templates, output a typedef for the plain + // factory name. + if (generator_->gen_templates_) { + f_header_ << "typedef " << factory_class_name_ + << "< ::apache::thrift::protocol::TDummyProtocol > " << service_name_ << pstyle_ + << "ProcessorFactory;" << endl << endl; + } + + // Generate the getProcessor() method + f_out_ << template_header_ << indent() << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::" + << (style_ == "Cob" ? "async::TAsyncProcessor" : "TProcessor") << " > " + << factory_class_name_ << template_suffix_ << "::getProcessor(" + << "const ::apache::thrift::TConnectionInfo& connInfo) {" << endl; + indent_up(); + + f_out_ << indent() << "::apache::thrift::ReleaseHandler< " << if_factory_name + << " > cleanup(handlerFactory_);" << endl << indent() << "::apache::thrift::stdcxx::shared_ptr< " + << if_name_ << " > handler(" + << "handlerFactory_->getHandler(connInfo), cleanup);" << endl << indent() + << "::apache::thrift::stdcxx::shared_ptr< ::apache::thrift::" + << (style_ == "Cob" ? "async::TAsyncProcessor" : "TProcessor") << " > " + << "processor(new " << class_name_ << template_suffix_ << "(handler));" << endl << indent() + << "return processor;" << endl; + + indent_down(); + f_out_ << indent() << "}" << endl << endl; +} + +/** + * Generates a service processor definition. + * + * @param tservice The service to generate a processor for. + */ +void t_cpp_generator::generate_service_processor(t_service* tservice, string style) { + ProcessorGenerator generator(this, tservice, style); + generator.run(); +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_cpp_generator::generate_function_helpers(t_service* tservice, t_function* tfunction) { + if (tfunction->is_oneway()) { + return; + } + + std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_); + + t_struct result(program_, tservice->get_name() + "_" + tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + generate_struct_declaration(f_header_, &result, false); + generate_struct_definition(out, f_service_, &result, false); + generate_struct_reader(out, &result); + generate_struct_result_writer(out, &result); + + result.set_name(tservice->get_name() + "_" + tfunction->get_name() + "_presult"); + generate_struct_declaration(f_header_, &result, false, true, true, gen_cob_style_); + generate_struct_definition(out, f_service_, &result, false); + generate_struct_reader(out, &result, true); + if (gen_cob_style_) { + generate_struct_writer(out, &result, true); + } +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_cpp_generator::generate_process_function(t_service* tservice, + t_function* tfunction, + string style, + bool specialized) { + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + string service_func_name = "\"" + tservice->get_name() + "." + tfunction->get_name() + "\""; + + std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_); + + string prot_type = (specialized ? "Protocol_" : "::apache::thrift::protocol::TProtocol"); + string class_suffix; + if (gen_templates_) { + class_suffix = "T"; + } + + // I tried to do this as one function. I really did. But it was too hard. + if (style != "Cob") { + // Open function + if (gen_templates_) { + out << indent() << "template " << endl; + } + const bool unnamed_oprot_seqid = tfunction->is_oneway() && !(gen_templates_ && !specialized); + out << "void " << tservice->get_name() << "Processor" << class_suffix << "::" + << "process_" << tfunction->get_name() << "(" + << "int32_t" << (unnamed_oprot_seqid ? ", " : " seqid, ") << prot_type << "* iprot, " + << prot_type << "*" << (unnamed_oprot_seqid ? ", " : " oprot, ") << "void* callContext)" + << endl; + scope_up(out); + + string argsname = tservice->get_name() + "_" + tfunction->get_name() + "_args"; + string resultname = tservice->get_name() + "_" + tfunction->get_name() + "_result"; + + if (tfunction->is_oneway() && !unnamed_oprot_seqid) { + out << indent() << "(void) seqid;" << endl << indent() << "(void) oprot;" << endl; + } + + out << indent() << "void* ctx = NULL;" << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " ctx = this->eventHandler_->getContext(" << service_func_name << ", callContext);" + << endl << indent() << "}" << endl << indent() + << "::apache::thrift::TProcessorContextFreer freer(" + << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl + << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->preRead(ctx, " << service_func_name << ");" << endl << indent() + << "}" << endl << endl << indent() << argsname << " args;" << endl << indent() + << "args.read(iprot);" << endl << indent() << "iprot->readMessageEnd();" << endl << indent() + << "uint32_t bytes = iprot->getTransport()->readEnd();" << endl << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->postRead(ctx, " << service_func_name << ", bytes);" << endl + << indent() << "}" << endl << endl; + + // Declare result + if (!tfunction->is_oneway()) { + out << indent() << resultname << " result;" << endl; + } + + // Try block for functions with exceptions + out << indent() << "try {" << endl; + indent_up(); + + // Generate the function call + bool first = true; + out << indent(); + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + if (is_complex_type(tfunction->get_returntype())) { + first = false; + out << "iface_->" << tfunction->get_name() << "(result.success"; + } else { + out << "result.success = iface_->" << tfunction->get_name() << "("; + } + } else { + out << "iface_->" << tfunction->get_name() << "("; + } + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + out << ", "; + } + out << "args." << (*f_iter)->get_name(); + } + out << ");" << endl; + + // Set isset on success field + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { + out << indent() << "result.__isset.success = true;" << endl; + } + + indent_down(); + out << indent() << "}"; + + if (!tfunction->is_oneway()) { + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + out << " catch (" << type_name((*x_iter)->get_type()) << " &" << (*x_iter)->get_name() + << ") {" << endl; + if (!tfunction->is_oneway()) { + indent_up(); + out << indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() + << ";" << endl << indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" + << endl; + indent_down(); + out << indent() << "}"; + } else { + out << "}"; + } + } + } + + if (!tfunction->is_oneway()) { + out << " catch (const std::exception& e) {" << endl; + } else { + out << " catch (const std::exception&) {" << endl; + } + + indent_up(); + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->handlerError(ctx, " << service_func_name << ");" << endl + << indent() << "}" << endl; + + if (!tfunction->is_oneway()) { + out << endl << indent() << "::apache::thrift::TApplicationException x(e.what());" << endl + << indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() + << "\", ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl << indent() + << "x.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl + << indent() << "oprot->getTransport()->writeEnd();" << endl << indent() + << "oprot->getTransport()->flush();" << endl; + } + out << indent() << "return;" << endl; + indent_down(); + out << indent() << "}" << endl << endl; + + // Shortcut out here for oneway functions + if (tfunction->is_oneway()) { + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->asyncComplete(ctx, " << service_func_name << ");" << endl + << indent() << "}" << endl << endl << indent() << "return;" << endl; + indent_down(); + out << "}" << endl << endl; + return; + } + + // Serialize the result into a struct + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->preWrite(ctx, " << service_func_name << ");" << endl << indent() + << "}" << endl << endl << indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() + << "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl << indent() + << "result.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl + << indent() << "bytes = oprot->getTransport()->writeEnd();" << endl << indent() + << "oprot->getTransport()->flush();" << endl << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->postWrite(ctx, " << service_func_name << ", bytes);" << endl + << indent() << "}" << endl; + + // Close function + scope_down(out); + out << endl; + } + + // Cob style. + else { + // Processor entry point. + // TODO(edhall) update for callContext when TEventServer is ready + if (gen_templates_) { + out << indent() << "template " << endl; + } + out << "void " << tservice->get_name() << "AsyncProcessor" << class_suffix << "::process_" + << tfunction->get_name() << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << prot_type << "* iprot, " << prot_type << "* oprot)" << endl; + scope_up(out); + + // TODO(simpkins): we could try to consoldate this + // with the non-cob code above + if (gen_templates_ && !specialized) { + // If these are instances of Protocol_, instead of any old TProtocol, + // use the specialized process function instead. + out << indent() << "Protocol_* _iprot = dynamic_cast(iprot);" << endl << indent() + << "Protocol_* _oprot = dynamic_cast(oprot);" << endl << indent() + << "if (_iprot && _oprot) {" << endl << indent() << " return process_" + << tfunction->get_name() << "(cob, seqid, _iprot, _oprot);" << endl << indent() << "}" + << endl << indent() << "T_GENERIC_PROTOCOL(this, iprot, _iprot);" << endl << indent() + << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" << endl << endl; + } + + if (tfunction->is_oneway()) { + out << indent() << "(void) seqid;" << endl << indent() << "(void) oprot;" << endl; + } + + out << indent() << tservice->get_name() + "_" + tfunction->get_name() << "_args args;" << endl + << indent() << "void* ctx = NULL;" << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " ctx = this->eventHandler_->getContext(" << service_func_name << ", NULL);" << endl + << indent() << "}" << endl << indent() << "::apache::thrift::TProcessorContextFreer freer(" + << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl + << indent() << "try {" << endl; + indent_up(); + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->preRead(ctx, " << service_func_name << ");" << endl << indent() + << "}" << endl << indent() << "args.read(iprot);" << endl << indent() + << "iprot->readMessageEnd();" << endl << indent() + << "uint32_t bytes = iprot->getTransport()->readEnd();" << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->postRead(ctx, " << service_func_name << ", bytes);" << endl + << indent() << "}" << endl; + scope_down(out); + + // TODO(dreiss): Handle TExceptions? Expose to server? + out << indent() << "catch (const std::exception&) {" << endl << indent() + << " if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->handlerError(ctx, " << service_func_name << ");" << endl + << indent() << " }" << endl << indent() << " return cob(false);" << endl << indent() + << "}" << endl; + + if (tfunction->is_oneway()) { + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->asyncComplete(ctx, " << service_func_name << ");" << endl + << indent() << "}" << endl; + } + // TODO(dreiss): Figure out a strategy for exceptions in async handlers. + out << indent() << "freer.unregister();" << endl; + if (tfunction->is_oneway()) { + // No return. Just hand off our cob. + // TODO(dreiss): Call the cob immediately? + out << indent() << "iface_->" << tfunction->get_name() << "(" + << "::apache::thrift::stdcxx::bind(cob, true)" << endl; + indent_up(); + indent_up(); + } else { + string ret_arg, ret_placeholder; + if (!tfunction->get_returntype()->is_void()) { + ret_arg = ", const " + type_name(tfunction->get_returntype()) + "& _return"; + ret_placeholder = ", ::apache::thrift::stdcxx::placeholders::_1"; + } + + // When gen_templates_ is true, the return_ and throw_ functions are + // overloaded. We have to declare pointers to them so that the compiler + // can resolve the correct overloaded version. + out << indent() << "void (" << tservice->get_name() << "AsyncProcessor" << class_suffix + << "::*return_fn)(::apache::thrift::stdcxx::function " + << "cob, int32_t seqid, " << prot_type << "* oprot, void* ctx" << ret_arg + << ") =" << endl; + out << indent() << " &" << tservice->get_name() << "AsyncProcessor" << class_suffix + << "::return_" << tfunction->get_name() << ";" << endl; + if (!xceptions.empty()) { + out << indent() << "void (" << tservice->get_name() << "AsyncProcessor" << class_suffix + << "::*throw_fn)(::apache::thrift::stdcxx::function " + << "cob, int32_t seqid, " << prot_type << "* oprot, void* ctx, " + << "::apache::thrift::TDelayedException* _throw) =" << endl; + out << indent() << " &" << tservice->get_name() << "AsyncProcessor" << class_suffix + << "::throw_" << tfunction->get_name() << ";" << endl; + } + + out << indent() << "iface_->" << tfunction->get_name() << "(" << endl; + indent_up(); + indent_up(); + out << indent() << "::apache::thrift::stdcxx::bind(return_fn, this, cob, seqid, oprot, ctx" << ret_placeholder + << ")"; + if (!xceptions.empty()) { + out << ',' << endl << indent() << "::apache::thrift::stdcxx::bind(throw_fn, this, cob, seqid, oprot, " + << "ctx, ::apache::thrift::stdcxx::placeholders::_1)"; + } + } + + // XXX Whitespace cleanup. + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + out << ',' << endl << indent() << "args." << (*f_iter)->get_name(); + } + out << ");" << endl; + indent_down(); + indent_down(); + scope_down(out); + out << endl; + + // Normal return. + if (!tfunction->is_oneway()) { + string ret_arg_decl, ret_arg_name; + if (!tfunction->get_returntype()->is_void()) { + ret_arg_decl = ", const " + type_name(tfunction->get_returntype()) + "& _return"; + ret_arg_name = ", _return"; + } + if (gen_templates_) { + out << indent() << "template " << endl; + } + out << "void " << tservice->get_name() << "AsyncProcessor" << class_suffix << "::return_" + << tfunction->get_name() << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << prot_type << "* oprot, void* ctx" << ret_arg_decl << ')' << endl; + scope_up(out); + + if (gen_templates_ && !specialized) { + // If oprot is a Protocol_ instance, + // use the specialized return function instead. + out << indent() << "Protocol_* _oprot = dynamic_cast(oprot);" << endl + << indent() << "if (_oprot) {" << endl << indent() << " return return_" + << tfunction->get_name() << "(cob, seqid, _oprot, ctx" << ret_arg_name << ");" << endl + << indent() << "}" << endl << indent() << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" + << endl << endl; + } + + out << indent() << tservice->get_name() << "_" << tfunction->get_name() << "_presult result;" + << endl; + if (!tfunction->get_returntype()->is_void()) { + // The const_cast here is unfortunate, but it would be a pain to avoid, + // and we only do a write with this struct, which is const-safe. + out << indent() << "result.success = const_cast<" << type_name(tfunction->get_returntype()) + << "*>(&_return);" << endl << indent() << "result.__isset.success = true;" << endl; + } + // Serialize the result into a struct + out << endl << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " ctx = this->eventHandler_->getContext(" << service_func_name << ", NULL);" << endl + << indent() << "}" << endl << indent() + << "::apache::thrift::TProcessorContextFreer freer(" + << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl + << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->preWrite(ctx, " << service_func_name << ");" << endl + << indent() << "}" << endl << endl << indent() << "oprot->writeMessageBegin(\"" + << tfunction->get_name() << "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl + << indent() << "result.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" + << endl << indent() << "uint32_t bytes = oprot->getTransport()->writeEnd();" << endl + << indent() << "oprot->getTransport()->flush();" << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->postWrite(ctx, " << service_func_name << ", bytes);" << endl + << indent() << "}" << endl << indent() << "return cob(true);" << endl; + scope_down(out); + out << endl; + } + + // Exception return. + if (!tfunction->is_oneway() && !xceptions.empty()) { + if (gen_templates_) { + out << indent() << "template " << endl; + } + out << "void " << tservice->get_name() << "AsyncProcessor" << class_suffix << "::throw_" + << tfunction->get_name() << "(::apache::thrift::stdcxx::function cob, int32_t seqid, " + << prot_type << "* oprot, void* ctx, " + << "::apache::thrift::TDelayedException* _throw)" << endl; + scope_up(out); + + if (gen_templates_ && !specialized) { + // If oprot is a Protocol_ instance, + // use the specialized throw function instead. + out << indent() << "Protocol_* _oprot = dynamic_cast(oprot);" << endl + << indent() << "if (_oprot) {" << endl << indent() << " return throw_" + << tfunction->get_name() << "(cob, seqid, _oprot, ctx, _throw);" << endl << indent() + << "}" << endl << indent() << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" << endl + << endl; + } + + // Get the event handler context + out << endl << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " ctx = this->eventHandler_->getContext(" << service_func_name << ", NULL);" << endl + << indent() << "}" << endl << indent() + << "::apache::thrift::TProcessorContextFreer freer(" + << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl; + + // Throw the TDelayedException, and catch the result + out << indent() << tservice->get_name() << "_" << tfunction->get_name() << "_result result;" + << endl << endl << indent() << "try {" << endl; + indent_up(); + out << indent() << "_throw->throw_it();" << endl << indent() << "return cob(false);" + << endl; // Is this possible? TBD. + indent_down(); + out << indent() << '}'; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + out << " catch (" << type_name((*x_iter)->get_type()) << " &" << (*x_iter)->get_name() + << ") {" << endl; + indent_up(); + out << indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() + << ";" << endl << indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" + << endl; + scope_down(out); + } + + // Handle the case where an undeclared exception is thrown + out << " catch (std::exception& e) {" << endl; + indent_up(); + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->handlerError(ctx, " << service_func_name << ");" << endl + << indent() << "}" << endl << endl << indent() + << "::apache::thrift::TApplicationException x(e.what());" << endl << indent() + << "oprot->writeMessageBegin(\"" << tfunction->get_name() + << "\", ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl << indent() + << "x.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl + << indent() << "oprot->getTransport()->writeEnd();" << endl << indent() + << "oprot->getTransport()->flush();" << endl << + // We pass true to the cob here, since we did successfully write a + // response, even though it is an exception response. + // It looks like the argument is currently ignored, anyway. + indent() << "return cob(true);" << endl; + scope_down(out); + + // Serialize the result into a struct + out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->preWrite(ctx, " << service_func_name << ");" << endl + << indent() << "}" << endl << endl << indent() << "oprot->writeMessageBegin(\"" + << tfunction->get_name() << "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl + << indent() << "result.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" + << endl << indent() << "uint32_t bytes = oprot->getTransport()->writeEnd();" << endl + << indent() << "oprot->getTransport()->flush();" << endl << indent() + << "if (this->eventHandler_.get() != NULL) {" << endl << indent() + << " this->eventHandler_->postWrite(ctx, " << service_func_name << ", bytes);" << endl + << indent() << "}" << endl << indent() << "return cob(true);" << endl; + scope_down(out); + out << endl; + } // for each function + } // cob style +} + +/** + * Generates a skeleton file of a server + * + * @param tservice The service to generate a server for. + */ +void t_cpp_generator::generate_service_skeleton(t_service* tservice) { + string svcname = tservice->get_name(); + + // Service implementation file includes + string f_skeleton_name = get_out_dir() + svcname + "_server.skeleton.cpp"; + + string ns = namespace_prefix(tservice->get_program()->get_namespace("cpp")); + + ofstream f_skeleton; + f_skeleton.open(f_skeleton_name.c_str()); + f_skeleton << "// This autogenerated skeleton file illustrates how to build a server." << endl + << "// You should copy it to another filename to avoid overwriting it." << endl << endl + << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl + << "#include " << endl + << "#include " << endl + << "#include " << endl + << "#include " << endl << endl + << "using namespace ::apache::thrift;" << endl + << "using namespace ::apache::thrift::protocol;" << endl + << "using namespace ::apache::thrift::transport;" << endl + << "using namespace ::apache::thrift::server;" << endl << endl; + + // the following code would not compile: + // using namespace ; + // using namespace ::; + if ((!ns.empty()) && (ns.compare(" ::") != 0)) { + f_skeleton << "using namespace " << string(ns, 0, ns.size() - 2) << ";" << endl << endl; + } + + f_skeleton << "class " << svcname << "Handler : virtual public " << svcname << "If {" << endl + << " public:" << endl; + indent_up(); + f_skeleton << indent() << svcname << "Handler() {" << endl << indent() + << " // Your initialization goes here" << endl << indent() << "}" << endl << endl; + + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_java_doc(f_skeleton, *f_iter); + f_skeleton << indent() << function_signature(*f_iter, "") << " {" << endl << indent() + << " // Your implementation goes here" << endl << indent() << " printf(\"" + << (*f_iter)->get_name() << "\\n\");" << endl << indent() << "}" << endl << endl; + } + + indent_down(); + f_skeleton << "};" << endl << endl; + + f_skeleton << indent() << "int main(int argc, char **argv) {" << endl; + indent_up(); + f_skeleton + << indent() << "int port = 9090;" << endl << indent() << "::apache::thrift::stdcxx::shared_ptr<" << svcname + << "Handler> handler(new " << svcname << "Handler());" << endl << indent() + << "::apache::thrift::stdcxx::shared_ptr processor(new " << svcname << "Processor(handler));" << endl + << indent() << "::apache::thrift::stdcxx::shared_ptr serverTransport(new TServerSocket(port));" + << endl << indent() + << "::apache::thrift::stdcxx::shared_ptr transportFactory(new TBufferedTransportFactory());" << endl + << indent() << "::apache::thrift::stdcxx::shared_ptr protocolFactory(new TBinaryProtocolFactory());" + << endl << endl << indent() + << "TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);" + << endl << indent() << "server.serve();" << endl << indent() << "return 0;" << endl; + indent_down(); + f_skeleton << "}" << endl << endl; + + // Close the files + f_skeleton.close(); +} + +/** + * Deserializes a field of any type. + */ +void t_cpp_generator::generate_deserialize_field(ofstream& out, + t_field* tfield, + string prefix, + string suffix) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_void()) { + throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); + } + + string name = prefix + tfield->get_name() + suffix; + + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, (t_struct*)type, name, is_reference(tfield)); + } else if (type->is_container()) { + generate_deserialize_container(out, type, name); + } else if (type->is_base_type()) { + indent(out) << "xfer += iprot->"; + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "readBinary(" << name << ");"; + } else { + out << "readString(" << name << ");"; + } + break; + case t_base_type::TYPE_BOOL: + out << "readBool(" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "readByte(" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "readI16(" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "readI32(" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "readI64(" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "readDouble(" << name << ");"; + break; + default: + throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + name; + } + out << endl; + } else if (type->is_enum()) { + string t = tmp("ecast"); + out << indent() << "int32_t " << t << ";" << endl << indent() << "xfer += iprot->readI32(" << t + << ");" << endl << indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl; + } else { + printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", + tfield->get_name().c_str(), + type_name(type).c_str()); + } +} + +/** + * Generates an unserializer for a variable. This makes two key assumptions, + * first that there is a const char* variable named data that points to the + * buffer for deserialization, and that there is a variable protocol which + * is a reference to a TProtocol serialization object. + */ +void t_cpp_generator::generate_deserialize_struct(ofstream& out, + t_struct* tstruct, + string prefix, + bool pointer) { + if (pointer) { + indent(out) << "if (!" << prefix << ") { " << endl; + indent(out) << " " << prefix << " = ::apache::thrift::stdcxx::shared_ptr<" << type_name(tstruct) << ">(new " + << type_name(tstruct) << ");" << endl; + indent(out) << "}" << endl; + indent(out) << "xfer += " << prefix << "->read(iprot);" << endl; + indent(out) << "bool wasSet = false;" << endl; + const vector& members = tstruct->get_members(); + vector::const_iterator f_iter; + for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) { + + indent(out) << "if (" << prefix << "->__isset." << (*f_iter)->get_name() + << ") { wasSet = true; }" << endl; + } + indent(out) << "if (!wasSet) { " << prefix << ".reset(); }" << endl; + } else { + indent(out) << "xfer += " << prefix << ".read(iprot);" << endl; + } +} + +void t_cpp_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) { + scope_up(out); + + string size = tmp("_size"); + string ktype = tmp("_ktype"); + string vtype = tmp("_vtype"); + string etype = tmp("_etype"); + + t_container* tcontainer = (t_container*)ttype; + bool use_push = tcontainer->has_cpp_name(); + + indent(out) << prefix << ".clear();" << endl << indent() << "uint32_t " << size << ";" << endl; + + // Declare variables, read header + if (ttype->is_map()) { + out << indent() << "::apache::thrift::protocol::TType " << ktype << ";" << endl << indent() + << "::apache::thrift::protocol::TType " << vtype << ";" << endl << indent() + << "xfer += iprot->readMapBegin(" << ktype << ", " << vtype << ", " << size << ");" << endl; + } else if (ttype->is_set()) { + out << indent() << "::apache::thrift::protocol::TType " << etype << ";" << endl << indent() + << "xfer += iprot->readSetBegin(" << etype << ", " << size << ");" << endl; + } else if (ttype->is_list()) { + out << indent() << "::apache::thrift::protocol::TType " << etype << ";" << endl << indent() + << "xfer += iprot->readListBegin(" << etype << ", " << size << ");" << endl; + if (!use_push) { + indent(out) << prefix << ".resize(" << size << ");" << endl; + } + } + + // For loop iterates over elements + string i = tmp("_i"); + out << indent() << "uint32_t " << i << ";" << endl << indent() << "for (" << i << " = 0; " << i + << " < " << size << "; ++" << i << ")" << endl; + + scope_up(out); + + if (ttype->is_map()) { + generate_deserialize_map_element(out, (t_map*)ttype, prefix); + } else if (ttype->is_set()) { + generate_deserialize_set_element(out, (t_set*)ttype, prefix); + } else if (ttype->is_list()) { + generate_deserialize_list_element(out, (t_list*)ttype, prefix, use_push, i); + } + + scope_down(out); + + // Read container end + if (ttype->is_map()) { + indent(out) << "xfer += iprot->readMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "xfer += iprot->readSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "xfer += iprot->readListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Generates code to deserialize a map + */ +void t_cpp_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) { + string key = tmp("_key"); + string val = tmp("_val"); + t_field fkey(tmap->get_key_type(), key); + t_field fval(tmap->get_val_type(), val); + + out << indent() << declare_field(&fkey) << endl; + + generate_deserialize_field(out, &fkey); + indent(out) << declare_field(&fval, false, false, false, true) << " = " << prefix << "[" << key + << "];" << endl; + + generate_deserialize_field(out, &fval); +} + +void t_cpp_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) { + string elem = tmp("_elem"); + t_field felem(tset->get_elem_type(), elem); + + indent(out) << declare_field(&felem) << endl; + + generate_deserialize_field(out, &felem); + + indent(out) << prefix << ".insert(" << elem << ");" << endl; +} + +void t_cpp_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, + string prefix, + bool use_push, + string index) { + if (use_push) { + string elem = tmp("_elem"); + t_field felem(tlist->get_elem_type(), elem); + indent(out) << declare_field(&felem) << endl; + generate_deserialize_field(out, &felem); + indent(out) << prefix << ".push_back(" << elem << ");" << endl; + } else { + t_field felem(tlist->get_elem_type(), prefix + "[" + index + "]"); + generate_deserialize_field(out, &felem); + } +} + +/** + * Serializes a field of any type. + * + * @param tfield The field to serialize + * @param prefix Name to prepend to field name + */ +void t_cpp_generator::generate_serialize_field(ofstream& out, + t_field* tfield, + string prefix, + string suffix) { + t_type* type = get_true_type(tfield->get_type()); + + string name = prefix + tfield->get_name() + suffix; + + // Do nothing for void types + if (type->is_void()) { + throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name; + } + + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, (t_struct*)type, name, is_reference(tfield)); + } else if (type->is_container()) { + generate_serialize_container(out, type, name); + } else if (type->is_base_type() || type->is_enum()) { + + indent(out) << "xfer += oprot->"; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "compiler error: cannot serialize void field in a struct: " + name; + break; + case t_base_type::TYPE_STRING: + if (type->is_binary()) { + out << "writeBinary(" << name << ");"; + } else { + out << "writeString(" << name << ");"; + } + break; + case t_base_type::TYPE_BOOL: + out << "writeBool(" << name << ");"; + break; + case t_base_type::TYPE_I8: + out << "writeByte(" << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "writeI16(" << name << ");"; + break; + case t_base_type::TYPE_I32: + out << "writeI32(" << name << ");"; + break; + case t_base_type::TYPE_I64: + out << "writeI64(" << name << ");"; + break; + case t_base_type::TYPE_DOUBLE: + out << "writeDouble(" << name << ");"; + break; + default: + throw "compiler error: no C++ writer for base type " + t_base_type::t_base_name(tbase) + + name; + } + } else if (type->is_enum()) { + out << "writeI32((int32_t)" << name << ");"; + } + out << endl; + } else { + printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n", + name.c_str(), + type_name(type).c_str()); + } +} + +/** + * Serializes all the members of a struct. + * + * @param tstruct The struct to serialize + * @param prefix String prefix to attach to all fields + */ +void t_cpp_generator::generate_serialize_struct(ofstream& out, + t_struct* tstruct, + string prefix, + bool pointer) { + if (pointer) { + indent(out) << "if (" << prefix << ") {" << endl; + indent(out) << " xfer += " << prefix << "->write(oprot); " << endl; + indent(out) << "} else {" + << "oprot->writeStructBegin(\"" << tstruct->get_name() << "\"); " << endl; + indent(out) << " oprot->writeStructEnd();" << endl; + indent(out) << " oprot->writeFieldStop();" << endl; + indent(out) << "}" << endl; + } else { + indent(out) << "xfer += " << prefix << ".write(oprot);" << endl; + } +} + +void t_cpp_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { + scope_up(out); + + if (ttype->is_map()) { + indent(out) << "xfer += oprot->writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) + << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " + << "static_cast(" << prefix << ".size()));" << endl; + } else if (ttype->is_set()) { + indent(out) << "xfer += oprot->writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) + << ", " + << "static_cast(" << prefix << ".size()));" << endl; + } else if (ttype->is_list()) { + indent(out) << "xfer += oprot->writeListBegin(" + << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " + << "static_cast(" << prefix << ".size()));" << endl; + } + + string iter = tmp("_iter"); + out << indent() << type_name(ttype) << "::const_iterator " << iter << ";" << endl << indent() + << "for (" << iter << " = " << prefix << ".begin(); " << iter << " != " << prefix + << ".end(); ++" << iter << ")" << endl; + scope_up(out); + if (ttype->is_map()) { + generate_serialize_map_element(out, (t_map*)ttype, iter); + } else if (ttype->is_set()) { + generate_serialize_set_element(out, (t_set*)ttype, iter); + } else if (ttype->is_list()) { + generate_serialize_list_element(out, (t_list*)ttype, iter); + } + scope_down(out); + + if (ttype->is_map()) { + indent(out) << "xfer += oprot->writeMapEnd();" << endl; + } else if (ttype->is_set()) { + indent(out) << "xfer += oprot->writeSetEnd();" << endl; + } else if (ttype->is_list()) { + indent(out) << "xfer += oprot->writeListEnd();" << endl; + } + + scope_down(out); +} + +/** + * Serializes the members of a map. + * + */ +void t_cpp_generator::generate_serialize_map_element(ofstream& out, t_map* tmap, string iter) { + t_field kfield(tmap->get_key_type(), iter + "->first"); + generate_serialize_field(out, &kfield, ""); + + t_field vfield(tmap->get_val_type(), iter + "->second"); + generate_serialize_field(out, &vfield, ""); +} + +/** + * Serializes the members of a set. + */ +void t_cpp_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) { + t_field efield(tset->get_elem_type(), "(*" + iter + ")"); + generate_serialize_field(out, &efield, ""); +} + +/** + * Serializes the members of a list. + */ +void t_cpp_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) { + t_field efield(tlist->get_elem_type(), "(*" + iter + ")"); + generate_serialize_field(out, &efield, ""); +} + +/** + * Makes a :: prefix for a namespace + * + * @param ns The namespace, w/ periods in it + * @return Namespaces + */ +string t_cpp_generator::namespace_prefix(string ns) { + // Always start with "::", to avoid possible name collisions with + // other names in one of the current namespaces. + // + // We also need a leading space, in case the name is used inside of a + // template parameter. "MyTemplate<::foo::Bar>" is not valid C++, + // since "<:" is an alternative token for "[". + string result = " ::"; + + if (ns.size() == 0) { + return result; + } + string::size_type loc; + while ((loc = ns.find(".")) != string::npos) { + result += ns.substr(0, loc); + result += "::"; + ns = ns.substr(loc + 1); + } + if (ns.size() > 0) { + result += ns + "::"; + } + return result; +} + +/** + * Opens namespace. + * + * @param ns The namespace, w/ periods in it + * @return Namespaces + */ +string t_cpp_generator::namespace_open(string ns) { + if (ns.size() == 0) { + return ""; + } + string result = ""; + string separator = ""; + string::size_type loc; + while ((loc = ns.find(".")) != string::npos) { + result += separator; + result += "namespace "; + result += ns.substr(0, loc); + result += " {"; + separator = " "; + ns = ns.substr(loc + 1); + } + if (ns.size() > 0) { + result += separator + "namespace " + ns + " {"; + } + return result; +} + +/** + * Closes namespace. + * + * @param ns The namespace, w/ periods in it + * @return Namespaces + */ +string t_cpp_generator::namespace_close(string ns) { + if (ns.size() == 0) { + return ""; + } + string result = "}"; + string::size_type loc; + while ((loc = ns.find(".")) != string::npos) { + result += "}"; + ns = ns.substr(loc + 1); + } + result += " // namespace"; + return result; +} + +/** + * Returns a C++ type name + * + * @param ttype The type + * @return String of the type name, i.e. std::set + */ +string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) { + if (ttype->is_base_type()) { + string bname = base_type_name(((t_base_type*)ttype)->get_base()); + std::map::iterator it = ttype->annotations_.find("cpp.type"); + if (it != ttype->annotations_.end()) { + bname = it->second; + } + + if (!arg) { + return bname; + } + + if (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING) { + return "const " + bname + "&"; + } else { + return "const " + bname; + } + } + + // Check for a custom overloaded C++ name + if (ttype->is_container()) { + string cname; + + t_container* tcontainer = (t_container*)ttype; + if (tcontainer->has_cpp_name()) { + cname = tcontainer->get_cpp_name(); + } else if (ttype->is_map()) { + t_map* tmap = (t_map*)ttype; + cname = "std::map<" + type_name(tmap->get_key_type(), in_typedef) + ", " + + type_name(tmap->get_val_type(), in_typedef) + "> "; + } else if (ttype->is_set()) { + t_set* tset = (t_set*)ttype; + cname = "std::set<" + type_name(tset->get_elem_type(), in_typedef) + "> "; + } else if (ttype->is_list()) { + t_list* tlist = (t_list*)ttype; + cname = "std::vector<" + type_name(tlist->get_elem_type(), in_typedef) + "> "; + } + + if (arg) { + return "const " + cname + "&"; + } else { + return cname; + } + } + + string class_prefix; + if (in_typedef && (ttype->is_struct() || ttype->is_xception())) { + class_prefix = "class "; + } + + // Check if it needs to be namespaced + string pname; + t_program* program = ttype->get_program(); + if (program != NULL && program != program_) { + pname = class_prefix + namespace_prefix(program->get_namespace("cpp")) + ttype->get_name(); + } else { + pname = class_prefix + ttype->get_name(); + } + + if (ttype->is_enum() && !gen_pure_enums_) { + pname += "::type"; + } + + if (arg) { + if (is_complex_type(ttype)) { + return "const " + pname + "&"; + } else { + return "const " + pname; + } + } else { + return pname; + } +} + +/** + * Returns the C++ type that corresponds to the thrift type. + * + * @param tbase The base type + * @return Explicit C++ type, i.e. "int32_t" + */ +string t_cpp_generator::base_type_name(t_base_type::t_base tbase) { + switch (tbase) { + case t_base_type::TYPE_VOID: + return "void"; + case t_base_type::TYPE_STRING: + return "std::string"; + case t_base_type::TYPE_BOOL: + return "bool"; + case t_base_type::TYPE_I8: + return "int8_t"; + case t_base_type::TYPE_I16: + return "int16_t"; + case t_base_type::TYPE_I32: + return "int32_t"; + case t_base_type::TYPE_I64: + return "int64_t"; + case t_base_type::TYPE_DOUBLE: + return "double"; + default: + throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase); + } +} + +/** + * Declares a field, which may include initialization as necessary. + * + * @param ttype The type + * @return Field declaration, i.e. int x = 0; + */ +string t_cpp_generator::declare_field(t_field* tfield, + bool init, + bool pointer, + bool constant, + bool reference) { + // TODO(mcslee): do we ever need to initialize the field? + string result = ""; + if (constant) { + result += "const "; + } + result += type_name(tfield->get_type()); + if (is_reference(tfield)) { + result = "::apache::thrift::stdcxx::shared_ptr<" + result + ">"; + } + if (pointer) { + result += "*"; + } + if (reference) { + result += "&"; + } + result += " " + tfield->get_name(); + if (init) { + t_type* type = get_true_type(tfield->get_type()); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + case t_base_type::TYPE_STRING: + break; + case t_base_type::TYPE_BOOL: + result += " = false"; + break; + case t_base_type::TYPE_I8: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + result += " = 0"; + break; + case t_base_type::TYPE_DOUBLE: + result += " = (double)0"; + break; + default: + throw "compiler error: no C++ initializer for base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + result += " = (" + type_name(type) + ")0"; + } + } + if (!reference) { + result += ";"; + } + return result; +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_cpp_generator::function_signature(t_function* tfunction, + string style, + string prefix, + bool name_params) { + t_type* ttype = tfunction->get_returntype(); + t_struct* arglist = tfunction->get_arglist(); + bool has_xceptions = !tfunction->get_xceptions()->get_members().empty(); + + if (style == "") { + if (is_complex_type(ttype)) { + return "void " + prefix + tfunction->get_name() + "(" + type_name(ttype) + + (name_params ? "& _return" : "& /* _return */") + + argument_list(arglist, name_params, true) + ")"; + } else { + return type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + + argument_list(arglist, name_params) + ")"; + } + } else if (style.substr(0, 3) == "Cob") { + string cob_type; + string exn_cob; + if (style == "CobCl") { + cob_type = "(" + service_name_ + "CobClient"; + if (gen_templates_) { + cob_type += "T"; + } + cob_type += "* client)"; + } else if (style == "CobSv") { + cob_type = (ttype->is_void() ? "()" : ("(" + type_name(ttype) + " const& _return)")); + if (has_xceptions) { + exn_cob + = ", ::apache::thrift::stdcxx::function /* exn_cob */"; + } + } else { + throw "UNKNOWN STYLE"; + } + + return "void " + prefix + tfunction->get_name() + "(::apache::thrift::stdcxx::function cob" + + exn_cob + argument_list(arglist, name_params, true) + ")"; + } else { + throw "UNKNOWN STYLE"; + } +} + +/** + * Renders a field list + * + * @param tstruct The struct definition + * @return Comma sepearated list of all field names in that struct + */ +string t_cpp_generator::argument_list(t_struct* tstruct, bool name_params, bool start_comma) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + bool first = !start_comma; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + result += ", "; + } + result += type_name((*f_iter)->get_type(), false, true) + " " + + (name_params ? (*f_iter)->get_name() : "/* " + (*f_iter)->get_name() + " */"); + } + return result; +} + +/** + * Converts the parse type to a C++ enum string for the given type. + * + * @param type Thrift Type + * @return String of C++ code to definition of that type constant + */ +string t_cpp_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "::apache::thrift::protocol::T_STRING"; + case t_base_type::TYPE_BOOL: + return "::apache::thrift::protocol::T_BOOL"; + case t_base_type::TYPE_I8: + return "::apache::thrift::protocol::T_BYTE"; + case t_base_type::TYPE_I16: + return "::apache::thrift::protocol::T_I16"; + case t_base_type::TYPE_I32: + return "::apache::thrift::protocol::T_I32"; + case t_base_type::TYPE_I64: + return "::apache::thrift::protocol::T_I64"; + case t_base_type::TYPE_DOUBLE: + return "::apache::thrift::protocol::T_DOUBLE"; + } + } else if (type->is_enum()) { + return "::apache::thrift::protocol::T_I32"; + } else if (type->is_struct()) { + return "::apache::thrift::protocol::T_STRUCT"; + } else if (type->is_xception()) { + return "::apache::thrift::protocol::T_STRUCT"; + } else if (type->is_map()) { + return "::apache::thrift::protocol::T_MAP"; + } else if (type->is_set()) { + return "::apache::thrift::protocol::T_SET"; + } else if (type->is_list()) { + return "::apache::thrift::protocol::T_LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +string t_cpp_generator::get_include_prefix(const t_program& program) const { + string include_prefix = program.get_include_prefix(); + if (!use_include_prefix_ || (include_prefix.size() > 0 && include_prefix[0] == '/')) { + // if flag is turned off or this is absolute path, return empty prefix + return ""; + } + + string::size_type last_slash = string::npos; + if ((last_slash = include_prefix.rfind("/")) != string::npos) { + return include_prefix.substr(0, last_slash) + + (get_program()->is_out_path_absolute() ? "/" : "/" + out_dir_base_ + "/"); + } + + return ""; +} + +THRIFT_REGISTER_GENERATOR( + cpp, + "C++", + " cob_style: Generate \"Continuation OBject\"-style classes.\n" + " no_client_completion:\n" + " Omit calls to completion__() in CobClient class.\n" + " no_default_operators:\n" + " Omits generation of default operators ==, != and <\n" + " templates: Generate templatized reader/writer methods.\n" + " pure_enums: Generate pure enums instead of wrapper classes.\n" + " include_prefix: Use full include paths in generated files.\n" + " moveable_types: Generate move constructors and assignment operators.\n" + " no_ostream_operators:\n" + " Omit generation of ostream definitions.\n" + " no_skeleton: Omits generation of skeleton.\n") diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..9d6454e --- /dev/null +++ b/composer.json @@ -0,0 +1,30 @@ +{ + "name": "apache/thrift", + "description": "Apache Thrift RPC system", + "homepage": "http://thrift.apache.org/", + "type": "library", + "license": "Apache-2.0", + "authors": [ + { + "name": "Apache Thrift Developers", + "email": "dev@thrift.apache.org", + "homepage": "http://thrift.apache.org" + } + ], + "support": { + "email": "dev@thrift.apache.org", + "issues": "https://issues.apache.org/jira/browse/THRIFT" + }, + "require": { + "php": ">=5.3.0" + }, + "autoload": { + "psr-0": {"Thrift": "lib/php/lib/"} + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "0.11.0" + } + } +} diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..1659250 --- /dev/null +++ b/config.guess @@ -0,0 +1,1441 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2015 Free Software Foundation, Inc. + +timestamp='2015-08-20' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2015 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.h b/config.h new file mode 100644 index 0000000..15c0fcd --- /dev/null +++ b/config.h @@ -0,0 +1,461 @@ +/* config.h. Generated from config.hin by configure. */ +/* config.hin. Generated from configure.ac by autoheader. */ + + +#ifndef CONFIG_H +#define CONFIG_H + + +/* Define if the AI_ADDRCONFIG symbol is unavailable */ +/* #undef AI_ADDRCONFIG */ + +/* Possible value for SIGNED_RIGHT_SHIFT_IS */ +#define ARITHMETIC_RIGHT_SHIFT 1 + +/* Defines automake version */ +#define AUTOMAKE_VERSION 1.15 + +/* Use *.h extension for parser header file */ +/* #undef BISON_USE_PARSER_H_EXTENSION */ + +/* Defines bison version */ +#define BISON_VERSION 3.0.4 + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if you have the `alarm' function. */ +#define HAVE_ALARM 1 + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* define if the Boost library is available */ +#define HAVE_BOOST /**/ + +/* Define to 1 if you have the `bzero' function. */ +#define HAVE_BZERO 1 + +/* Define to 1 if you have the `clock_gettime' function. */ +#define HAVE_CLOCK_GETTIME 1 + +/* define if the compiler supports basic C++11 syntax */ +#define HAVE_CXX11 1 + +/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you + don't. */ +#define HAVE_DECL_STRERROR_R 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE 1 + +/* Define to 1 if you have the `gethostbyname' function. */ +#define HAVE_GETHOSTBYNAME 1 + +/* Define to 1 if you have the `gethostbyname_r' function. */ +#define HAVE_GETHOSTBYNAME_R 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `inet_ntoa' function. */ +#define HAVE_INET_NTOA 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LAUXLIB_H 1 + +/* define if libevent is available */ +#define HAVE_LIBEVENT /**/ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIBINTL_H 1 + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#define HAVE_LIBPTHREAD 1 + +/* Define to 1 if you have the `rt' library (-lrt). */ +#define HAVE_LIBRT 1 + +/* Define to 1 if you have the `socket' library (-lsocket). */ +/* #undef HAVE_LIBSOCKET */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LUACONF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LUALIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LUA_H 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MALLOC_H 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the `mkdir' function. */ +#define HAVE_MKDIR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_OPENSSL_RAND_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_OPENSSL_SSL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_OPENSSL_X509V3_H 1 + +/* Define to 1 if you have the `pow' function. */ +#define HAVE_POW 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PTHREAD_H 1 + +/* Define to 1 if the system has the type `ptrdiff_t'. */ +#define HAVE_PTRDIFF_T 1 + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC 1 + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define to 1 if you have the `sched_get_priority_max' function. */ +#define HAVE_SCHED_GET_PRIORITY_MAX 1 + +/* Define to 1 if you have the `sched_get_priority_min' function. */ +#define HAVE_SCHED_GET_PRIORITY_MIN 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SCHED_H 1 + +/* Define to 1 if you have the `select' function. */ +#define HAVE_SELECT 1 + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if you have the `sqrt' function. */ +#define HAVE_SQRT 1 + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +/* #undef HAVE_STAT_EMPTY_STRING_BUG */ + +/* Define to 1 if stdbool.h conforms to C99. */ +/* #undef HAVE_STDBOOL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strerror_r' function. */ +#define HAVE_STRERROR_R 1 + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strstr' function. */ +#define HAVE_STRSTR 1 + +/* Define to 1 if you have the `strtol' function. */ +#define HAVE_STRTOL 1 + +/* Define to 1 if you have the `strtoul' function. */ +#define HAVE_STRTOUL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_POLL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UN_H 1 + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK 1 + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK 1 + +/* define if zlib is available */ +#define HAVE_ZLIB /**/ + +/* Define to 1 if the system has the type `_Bool'. */ +/* #undef HAVE__BOOL */ + +/* Possible value for SIGNED_RIGHT_SHIFT_IS */ +#define LOGICAL_RIGHT_SHIFT 2 + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +#define PACKAGE "thrift" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "thrift" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "thrift 0.11.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "thrift" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.11.0" + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the type of arg 1 for `select'. */ +#define SELECT_TYPE_ARG1 int + +/* Define to the type of args 2, 3 and 4 for `select'. */ +#define SELECT_TYPE_ARG234 (fd_set *) + +/* Define to the type of arg 5 for `select'. */ +#define SELECT_TYPE_ARG5 (struct timeval *) + +/* Indicates the effect of the right shift operator on negative signed + integers */ +#define SIGNED_RIGHT_SHIFT_IS 1 + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if strerror_r returns char *. */ +#define STRERROR_R_CHAR_P 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 if your declares `struct tm'. */ +/* #undef TM_IN_SYS_TIME */ + +/* Possible value for SIGNED_RIGHT_SHIFT_IS */ +#define UNKNOWN_RIGHT_SHIFT 3 + +/* experimental --enable-boostthreads that replaces POSIX pthread by + boost::thread */ +/* #undef USE_BOOST_THREAD */ + +/* Version number of package */ + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#define YYTEXT_POINTER 1 + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT64_T */ + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT8_T */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to the type of a signed integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int16_t */ + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int32_t */ + +/* Define to the type of a signed integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int64_t */ + +/* Define to the type of a signed integer type of width exactly 8 bits if such + a type exists and the standard includes do not define it. */ +/* #undef int8_t */ + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to `int' if does not define. */ +/* #undef mode_t */ + +/* Define to `long int' if does not define. */ +/* #undef off_t */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if does not define. */ +/* #undef ssize_t */ + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint16_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint64_t */ + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint8_t */ + +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ + +/* Define to empty if the keyword `volatile' does not work. Warning: valid + code using `volatile' can become incorrect without. Disable with care. */ +/* #undef volatile */ + + +#endif + diff --git a/config.hin b/config.hin new file mode 100644 index 0000000..cb60778 --- /dev/null +++ b/config.hin @@ -0,0 +1,460 @@ +/* config.hin. Generated from configure.ac by autoheader. */ + + +#ifndef CONFIG_H +#define CONFIG_H + + +/* Define if the AI_ADDRCONFIG symbol is unavailable */ +#undef AI_ADDRCONFIG + +/* Possible value for SIGNED_RIGHT_SHIFT_IS */ +#undef ARITHMETIC_RIGHT_SHIFT + +/* Defines automake version */ +#undef AUTOMAKE_VERSION + +/* Use *.h extension for parser header file */ +#undef BISON_USE_PARSER_H_EXTENSION + +/* Defines bison version */ +#undef BISON_VERSION + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +#undef CRAY_STACKSEG_END + +/* Define to 1 if using `alloca.c'. */ +#undef C_ALLOCA + +/* Define to 1 if you have the `alarm' function. */ +#undef HAVE_ALARM + +/* Define to 1 if you have `alloca', as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#undef HAVE_ALLOCA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* define if the Boost library is available */ +#undef HAVE_BOOST + +/* Define to 1 if you have the `bzero' function. */ +#undef HAVE_BZERO + +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + +/* define if the compiler supports basic C++11 syntax */ +#undef HAVE_CXX11 + +/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you + don't. */ +#undef HAVE_DECL_STRERROR_R + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `fork' function. */ +#undef HAVE_FORK + +/* Define to 1 if you have the `ftruncate' function. */ +#undef HAVE_FTRUNCATE + +/* Define to 1 if you have the `gethostbyname' function. */ +#undef HAVE_GETHOSTBYNAME + +/* Define to 1 if you have the `gethostbyname_r' function. */ +#undef HAVE_GETHOSTBYNAME_R + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the `inet_ntoa' function. */ +#undef HAVE_INET_NTOA + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LAUXLIB_H + +/* define if libevent is available */ +#undef HAVE_LIBEVENT + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBINTL_H + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#undef HAVE_LIBPTHREAD + +/* Define to 1 if you have the `rt' library (-lrt). */ +#undef HAVE_LIBRT + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUACONF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUALIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUA_H + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the `mkdir' function. */ +#undef HAVE_MKDIR + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_RAND_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_SSL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_X509V3_H + +/* Define to 1 if you have the `pow' function. */ +#undef HAVE_POW + +/* Define to 1 if you have the header file. */ +#undef HAVE_PTHREAD_H + +/* Define to 1 if the system has the type `ptrdiff_t'. */ +#undef HAVE_PTRDIFF_T + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#undef HAVE_REALLOC + +/* Define to 1 if you have the `realpath' function. */ +#undef HAVE_REALPATH + +/* Define to 1 if you have the `sched_get_priority_max' function. */ +#undef HAVE_SCHED_GET_PRIORITY_MAX + +/* Define to 1 if you have the `sched_get_priority_min' function. */ +#undef HAVE_SCHED_GET_PRIORITY_MIN + +/* Define to 1 if you have the header file. */ +#undef HAVE_SCHED_H + +/* Define to 1 if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the `socket' function. */ +#undef HAVE_SOCKET + +/* Define to 1 if you have the `sqrt' function. */ +#undef HAVE_SQRT + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +#undef HAVE_STAT_EMPTY_STRING_BUG + +/* Define to 1 if stdbool.h conforms to C99. */ +#undef HAVE_STDBOOL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the `strerror_r' function. */ +#undef HAVE_STRERROR_R + +/* Define to 1 if you have the `strftime' function. */ +#undef HAVE_STRFTIME + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strstr' function. */ +#undef HAVE_STRSTR + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the `strtoul' function. */ +#undef HAVE_STRTOUL + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_POLL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UN_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#undef HAVE_VFORK + +/* Define to 1 if you have the header file. */ +#undef HAVE_VFORK_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_WCHAR_H + +/* Define to 1 if `fork' works. */ +#undef HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#undef HAVE_WORKING_VFORK + +/* define if zlib is available */ +#undef HAVE_ZLIB + +/* Define to 1 if the system has the type `_Bool'. */ +#undef HAVE__BOOL + +/* Possible value for SIGNED_RIGHT_SHIFT_IS */ +#undef LOGICAL_RIGHT_SHIFT + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#undef LSTAT_FOLLOWS_SLASHED_SYMLINK + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to the type of arg 1 for `select'. */ +#undef SELECT_TYPE_ARG1 + +/* Define to the type of args 2, 3 and 4 for `select'. */ +#undef SELECT_TYPE_ARG234 + +/* Define to the type of arg 5 for `select'. */ +#undef SELECT_TYPE_ARG5 + +/* Indicates the effect of the right shift operator on negative signed + integers */ +#undef SIGNED_RIGHT_SHIFT_IS + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#undef STACK_DIRECTION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if strerror_r returns char *. */ +#undef STRERROR_R_CHAR_P + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define to 1 if your declares `struct tm'. */ +#undef TM_IN_SYS_TIME + +/* Possible value for SIGNED_RIGHT_SHIFT_IS */ +#undef UNKNOWN_RIGHT_SHIFT + +/* experimental --enable-boostthreads that replaces POSIX pthread by + boost::thread */ +#undef USE_BOOST_THREAD + +/* Version number of package */ + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT32_T + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT64_T + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT8_T + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to the type of a signed integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +#undef int16_t + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef int32_t + +/* Define to the type of a signed integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +#undef int64_t + +/* Define to the type of a signed integer type of width exactly 8 bits if such + a type exists and the standard includes do not define it. */ +#undef int8_t + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to `int' if does not define. */ +#undef mode_t + +/* Define to `long int' if does not define. */ +#undef off_t + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to rpl_realloc if the replacement function should be used. */ +#undef realloc + +/* Define to `unsigned int' if does not define. */ +#undef size_t + +/* Define to `int' if does not define. */ +#undef ssize_t + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +#undef uint16_t + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef uint32_t + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +#undef uint64_t + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +#undef uint8_t + +/* Define as `fork' if `vfork' does not work. */ +#undef vfork + +/* Define to empty if the keyword `volatile' does not work. Warning: valid + code using `volatile' can become incorrect without. Disable with care. */ +#undef volatile + + +#endif + diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..1acc966 --- /dev/null +++ b/config.sub @@ -0,0 +1,1813 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2015 Free Software Foundation, Inc. + +timestamp='2015-08-20' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2015 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + asmjs) + basic_machine=asmjs-unknown + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 0000000..3a90fdc --- /dev/null +++ b/configure @@ -0,0 +1,30103 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for thrift 0.11.0. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='thrift' +PACKAGE_TARNAME='thrift' +PACKAGE_VERSION='0.11.0' +PACKAGE_STRING='thrift 0.11.0' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +enable_option_checking=no +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +MAYBE_DOTNETCORE +MAYBE_RS +MAYBE_LUA +MAYBE_ERLANG +MAYBE_NODEJS +MAYBE_GO +MAYBE_DART +MAYBE_PHP +MAYBE_PERL +MAYBE_HASKELL +MAYBE_RUBY +MAYBE_PY3 +MAYBE_PYTHON +MAYBE_CSHARP +MAYBE_JAVA +MAYBE_D +MAYBE_C_GLIB +MAYBE_CPP +WITH_BOOSTTHREADS_FALSE +WITH_BOOSTTHREADS_TRUE +GCOV_LDFLAGS +GCOV_CXXFLAGS +GCOV_CFLAGS +ENABLE_COVERAGE +LIBOBJS +ALLOCA +MINGW_FALSE +MINGW_TRUE +WITH_TUTORIAL_FALSE +WITH_TUTORIAL_TRUE +WITH_PLUGIN_FALSE +WITH_PLUGIN_TRUE +WITH_TESTS_FALSE +WITH_TESTS_TRUE +WITH_D_SSL_TESTS_FALSE +WITH_D_SSL_TESTS_TRUE +HAVE_DEIMOS_OPENSSL_FALSE +HAVE_DEIMOS_OPENSSL_TRUE +WITH_D_EVENT_TESTS_FALSE +WITH_D_EVENT_TESTS_TRUE +HAVE_DEIMOS_EVENT2_FALSE +HAVE_DEIMOS_EVENT2_TRUE +DMD_OF_DIRSEP +DMD_OPTLINK_FALSE +DMD_OPTLINK_TRUE +WITH_D_FALSE +WITH_D_TRUE +D_SSL_LIB_NAME +D_EVENT_LIB_NAME +D_LIB_NAME +DMD +WITH_DOTNETCORE_FALSE +WITH_DOTNETCORE_TRUE +DOTNETCORE_VERSION +DOTNETCORE +WITH_HAXE_FALSE +WITH_HAXE_TRUE +HAXE_VERSION +HAXE +WITH_RS_FALSE +WITH_RS_TRUE +rustc_version +RUSTC +CARGO +GOVERSION_LT_17_FALSE +GOVERSION_LT_17_TRUE +WITH_GO_FALSE +WITH_GO_TRUE +golang_version +GO +WITH_HASKELL_FALSE +WITH_HASKELL_TRUE +RUNHASKELL +CABAL +HAVE_BUNDLER_FALSE +HAVE_BUNDLER_TRUE +WITH_RUBY_FALSE +WITH_RUBY_TRUE +BUNDLER +RUBY +WITH_DART_FALSE +WITH_DART_TRUE +DARTPUB +DART +HAVE_PHPUNIT_FALSE +HAVE_PHPUNIT_TRUE +PHPUNIT +WITH_PHP_EXTENSION_FALSE +WITH_PHP_EXTENSION_TRUE +subdirs +PHP_CONFIG +WITH_PHP_FALSE +WITH_PHP_TRUE +PHP +WITH_PERL_FALSE +WITH_PERL_TRUE +PERL +WITH_PY3_FALSE +WITH_PY3_TRUE +PYTHON3 +WITH_TWISTED_TEST_FALSE +WITH_TWISTED_TEST_TRUE +WITH_PYTHON_FALSE +WITH_PYTHON_TRUE +TRIAL +pkgpyexecdir +pyexecdir +pkgpythondir +pythondir +PYTHON_PLATFORM +PYTHON_EXEC_PREFIX +PYTHON_PREFIX +PYTHON_VERSION +PYTHON +WITH_LUA_FALSE +WITH_LUA_TRUE +LUA_LIB +LUA_INCLUDE +pkgluaexecdir +luaexecdir +pkgluadir +luadir +LUA_EXEC_PREFIX +LUA_PREFIX +LUA_PLATFORM +LUA_SHORT_VERSION +LUA_VERSION +LUA +HAVE_NPM_FALSE +HAVE_NPM_TRUE +WITH_NODEJS_FALSE +WITH_NODEJS_TRUE +NPM +NODEJS +ERLANG_OTP16_FALSE +ERLANG_OTP16_TRUE +WITH_ERLANG_FALSE +WITH_ERLANG_TRUE +ERLANG_INSTALL_LIB_DIR_thrift +ERLANG_INSTALL_LIB_DIR +ERLANG_LIB_DIR +REBAR +ERLCFLAGS +ERLC +ERL +WITH_JAVA_FALSE +WITH_JAVA_TRUE +ANT_FLAGS +CLASSPATH +ANT +MONO_MCS_FALSE +MONO_MCS_TRUE +NET_2_0_FALSE +NET_2_0_TRUE +WITH_MONO_FALSE +WITH_MONO_TRUE +MCS +MONO_LIBS +MONO_CFLAGS +OPENSSL_LDFLAGS +OPENSSL_LIBS +OPENSSL_INCLUDES +WITH_C_GLIB_FALSE +WITH_C_GLIB_TRUE +GOBJECT_LIBS +GOBJECT_CFLAGS +GLIB_LIBS +GLIB_CFLAGS +QT5_REDUCE_RELOCATIONS_FALSE +QT5_REDUCE_RELOCATIONS_TRUE +AMX_HAVE_QT5_FALSE +AMX_HAVE_QT5_TRUE +AMX_HAVE_QT_FALSE +AMX_HAVE_QT_TRUE +AMX_HAVE_ZLIB_FALSE +AMX_HAVE_ZLIB_TRUE +AMX_HAVE_LIBEVENT_FALSE +AMX_HAVE_LIBEVENT_TRUE +WITH_CPP_FALSE +WITH_CPP_TRUE +QT5_MOC +QT5_LIBS +QT5_CFLAGS +QT_MOC +QT_LIBS +QT_CFLAGS +ZLIB_LIBS +ZLIB_LDFLAGS +ZLIB_CPPFLAGS +LIBEVENT_LIBS +LIBEVENT_LDFLAGS +LIBEVENT_CPPFLAGS +BOOST_THREAD_LDADD +BOOST_TEST_LDADD +BOOST_SYSTEM_LDADD +BOOST_FILESYSTEM_LDADD +BOOST_CHRONO_LDADD +BOOST_LIB_DIR +BOOST_LDFLAGS +BOOST_CPPFLAGS +CPPSTYLE_CMD +HAVE_CXX11 +LEXLIB +LEX_OUTPUT_ROOT +LEX +YFLAGS +YACC +BISON_USE_PARSER_H_EXTENSION_FALSE +BISON_USE_PARSER_H_EXTENSION_TRUE +BISON +have_prog_bison +CXXCPP +LT_SYS_LIBRARY_PATH +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +MANIFEST_TOOL +RANLIB +ac_ct_AR +AR +DLLTOOL +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +SED +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +LIBTOOL +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +CPP +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +THRIFT +DMD_OPENSSL_FLAGS +DMD_LIBEVENT_FLAGS +D_IMPORT_PREFIX +CABAL_CONFIGURE_FLAGS +PERL_PREFIX +INSTALLDIRS +PHP_CONFIG_PREFIX +PHP_PREFIX +RUBY_PREFIX +JAVA_PREFIX +PY_PREFIX +PKG_CONFIG_LIBDIR +PKG_CONFIG_PATH +PKG_CONFIG +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_silent_rules +enable_dependency_tracking +enable_shared +enable_static +with_pic +enable_fast_install +with_aix_soname +with_gnu_ld +with_sysroot +enable_libtool_lock +enable_libs +with_cpp +with_boost +with_boost_libdir +with_libevent +with_zlib +with_qt4 +with_qt5 +with_c_glib +with_openssl +with_csharp +with_java +with_erlang +with_nodejs +with_lua +with_python +with_perl +with_php +with_php_extension +with_dart +with_ruby +with_haskell +with_go +with_rs +with_haxe +with_dotnetcore +with_d +enable_tests +enable_plugin +enable_tutorial +enable_coverage +enable_boostthreads +' + ac_precious_vars='build_alias +host_alias +target_alias +PKG_CONFIG +PKG_CONFIG_PATH +PKG_CONFIG_LIBDIR +PY_PREFIX +JAVA_PREFIX +RUBY_PREFIX +PHP_PREFIX +PHP_CONFIG_PREFIX +INSTALLDIRS +PERL_PREFIX +CABAL_CONFIGURE_FLAGS +D_IMPORT_PREFIX +DMD_LIBEVENT_FLAGS +DMD_OPENSSL_FLAGS +THRIFT +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +CXX +CXXFLAGS +CCC +LT_SYS_LIBRARY_PATH +CXXCPP +YACC +YFLAGS +QT_CFLAGS +QT_LIBS +QT5_CFLAGS +QT5_LIBS +GLIB_CFLAGS +GLIB_LIBS +GOBJECT_CFLAGS +GOBJECT_LIBS +MONO_CFLAGS +MONO_LIBS +ERL +ERLC +ERLCFLAGS +ERLANG_INSTALL_LIB_DIR +ERLANG_INSTALL_LIB_DIR_thrift +LUA +LUA_INCLUDE +LUA_LIB +PYTHON' +ac_subdirs_all='lib/php/src/ext/thrift_protocol' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures thrift 0.11.0 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/thrift] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of thrift 0.11.0:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-silent-rules less verbose build output (undo: "make V=1") + --disable-silent-rules verbose build output (undo: "make V=0") + --enable-dependency-tracking + do not reject slow dependency extractors + --disable-dependency-tracking + speeds up one-time build + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --enable-libs build the Apache Thrift libraries [default=yes] + --enable-tests build tests [default=yes] + --enable-plugin build compiler plugin support [default=no] + --enable-tutorial build tutorial [default=yes] + --enable-coverage turn on -fprofile-arcs -ftest-coverage + --enable-boostthreads use boost threads, instead of POSIX pthread (experimental) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use + both] + --with-aix-soname=aix|svr4|both + shared library versioning (aka "SONAME") variant to + provide on AIX, [default=aix]. + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot[=DIR] Search for dependent libraries within DIR (or the + compiler's sysroot if not specified). + --with-cpp build the C++ library [default=yes] + --with-boost[=ARG] use Boost library from a standard location + (ARG=yes), from the specified location (ARG=), + or disable it (ARG=no) [ARG=yes] + --with-boost-libdir=LIB_DIR + Force given directory for boost libraries. Note that + this will override library path detection, so use + this parameter only if default library detection + fails and you know exactly where your boost + libraries are located. + --with-libevent[=DIR] use libevent [default=yes]. Optionally specify the + root prefix dir where libevent is installed + --with-zlib[=DIR] use zlib (default is yes) - it is possible to + specify an alternate root directory for zlib + --with-qt4 build the Qt library [default=yes] + --with-qt5 build the Qt5 library [default=yes] + --with-c_glib build the C (GLib) library [default=yes] + --with-openssl=DIR root of the OpenSSL directory + --with-csharp build the C# library [default=yes] + --with-java build the Java library [default=yes] + --with-erlang build the Erlang library [default=yes] + --with-nodejs build the Nodejs library [default=yes] + --with-lua build the Lua library [default=yes] + --with-python build the Python library [default=yes] + --with-perl build the Perl library [default=yes] + --with-php build the PHP library [default=yes] + --with-php_extension build the PHP_EXTENSION library [default=yes] + --with-dart build the DART library [default=yes] + --with-ruby build the Ruby library [default=yes] + --with-haskell build the Haskell library [default=yes] + --with-go build the Go library [default=yes] + --with-rs build the Rust library [default=yes] + --with-haxe build the Haxe library [default=yes] + --with-dotnetcore build the .NET Core library [default=yes] + --with-d build the D library [default=yes] + +Some influential environment variables: + PKG_CONFIG path to pkg-config utility + PKG_CONFIG_PATH + directories to add to pkg-config's search path + PKG_CONFIG_LIBDIR + path overriding pkg-config's built-in search path + PY_PREFIX Prefix for installing Python modules. (Normal --prefix is + ignored for Python because Python has different conventions.) + Default = "/usr" + JAVA_PREFIX Prefix for installing the Java lib jar. Default = + "/usr/local/lib" + RUBY_PREFIX Prefix for installing Ruby modules. (Normal --prefix is ignored + for Ruby because Ruby has different conventions.) Default = + none, let ruby setup decide + PHP_PREFIX Prefix for installing PHP modules. (Normal --prefix is ignored + for PHP because PHP has different conventions.) Default = + "/usr/lib/php" + PHP_CONFIG_PREFIX + Prefix for installing PHP extension module .ini file. (Normal + --prefix is ignored for PHP because PHP has different + conventions.) Default = "/etc/php.d" + INSTALLDIRS When installing Perl modules, specifies which of the sets of + installation directories to choose: perl, site or vendor. + Default = "vendor" + PERL_PREFIX Prefix for installing Perl modules. (Normal --prefix is ignored + for Perl because Perl has different conventions.) Ignored, when + INSTALLDIRS set to site or vendor. Default = "/usr/local/lib" + CABAL_CONFIGURE_FLAGS + Extra flags to pass to cabal: "cabal Setup.lhs configure + $CABAL_CONFIGURE_FLAGS". (Typically used to set --user or force + --global.) + D_IMPORT_PREFIX + Prefix for installing D modules. [INCLUDEDIR/d2] + DMD_LIBEVENT_FLAGS + DMD flags for linking libevent (auto-detected if not set). + DMD_OPENSSL_FLAGS + DMD flags for linking OpenSSL (auto-detected if not set). + THRIFT Path to the thrift tool (needed for cross-compilation). + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + CXX C++ compiler command + CXXFLAGS C++ compiler flags + LT_SYS_LIBRARY_PATH + User-defined run-time library search path. + CXXCPP C++ preprocessor + YACC The `Yet Another Compiler Compiler' implementation to use. + Defaults to the first program found out of: `bison -y', `byacc', + `yacc'. + YFLAGS The list of arguments that will be passed by default to $YACC. + This script will default YFLAGS to the empty string to avoid a + default value of `-d' given by some make applications. + QT_CFLAGS C compiler flags for QT, overriding pkg-config + QT_LIBS linker flags for QT, overriding pkg-config + QT5_CFLAGS C compiler flags for QT5, overriding pkg-config + QT5_LIBS linker flags for QT5, overriding pkg-config + GLIB_CFLAGS C compiler flags for GLIB, overriding pkg-config + GLIB_LIBS linker flags for GLIB, overriding pkg-config + GOBJECT_CFLAGS + C compiler flags for GOBJECT, overriding pkg-config + GOBJECT_LIBS + linker flags for GOBJECT, overriding pkg-config + MONO_CFLAGS C compiler flags for MONO, overriding pkg-config + MONO_LIBS linker flags for MONO, overriding pkg-config + ERL Erlang/OTP interpreter command [autodetected] + ERLC Erlang/OTP compiler command [autodetected] + ERLCFLAGS Erlang/OTP compiler flags [none] + ERLANG_INSTALL_LIB_DIR + Erlang/OTP library installation base directory + [LIBDIR/erlang/lib] + ERLANG_INSTALL_LIB_DIR_thrift + Erlang/OTP 'thrift' library installation subdirectory + [ERLANG_INSTALL_LIB_DIR/thrift-0.11.0] + LUA The Lua interpreter, e.g. /usr/bin/lua5.1 + LUA_INCLUDE The Lua includes, e.g. -I/usr/include/lua5.1 + LUA_LIB The Lua library, e.g. -llua5.1 + PYTHON the Python interpreter + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +thrift configure 0.11.0 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link + +# ac_fn_erl_try_run LINENO +# ------------------------ +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_erl_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_erl_try_run + +# ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES +# --------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_cxx_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_header_mongrel + +# ac_fn_cxx_try_run LINENO +# ------------------------ +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_cxx_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_run + +# ac_fn_cxx_check_type LINENO TYPE VAR INCLUDES +# --------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_cxx_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_type + +# ac_fn_c_find_intX_t LINENO BITS VAR +# ----------------------------------- +# Finds a signed integer type with width BITS, setting cache variable VAR +# accordingly. +ac_fn_c_find_intX_t () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 +$as_echo_n "checking for int$2_t... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + # Order is important - never check a type that is potentially smaller + # than half of the expected target width. + for ac_type in int$2_t 'int' 'long int' \ + 'long long int' 'short int' 'signed char'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default + enum { N = $2 / 2 - 1 }; +int +main () +{ +static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default + enum { N = $2 / 2 - 1 }; +int +main () +{ +static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) + < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + case $ac_type in #( + int$2_t) : + eval "$3=yes" ;; #( + *) : + eval "$3=\$ac_type" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if eval test \"x\$"$3"\" = x"no"; then : + +else + break +fi + done +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_find_intX_t + +# ac_fn_c_find_uintX_t LINENO BITS VAR +# ------------------------------------ +# Finds an unsigned integer type with width BITS, setting cache variable VAR +# accordingly. +ac_fn_c_find_uintX_t () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 +$as_echo_n "checking for uint$2_t... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + # Order is important - never check a type that is potentially smaller + # than half of the expected target width. + for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ + 'unsigned long long int' 'unsigned short int' 'unsigned char'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + case $ac_type in #( + uint$2_t) : + eval "$3=yes" ;; #( + *) : + eval "$3=\$ac_type" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if eval test \"x\$"$3"\" = x"no"; then : + +else + break +fi + done +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_find_uintX_t + +# ac_fn_cxx_check_decl LINENO SYMBOL VAR INCLUDES +# ----------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_cxx_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_decl + +# ac_fn_cxx_check_func LINENO FUNC VAR +# ------------------------------------ +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_cxx_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_func +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by thrift $as_me 0.11.0, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_aux_dir= +for ac_dir in . "$srcdir"/.; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in . \"$srcdir\"/." "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + + +am__api_version='1.15' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken + alias in your environment" "$LINENO" 5 + fi + if test "$2" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi + +rm -f conftest.file + +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=1;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='thrift' + VERSION='0.11.0' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +mkdir_p='$(MKDIR_P)' + +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar plaintar pax cpio none' + +# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5 +$as_echo_n "checking whether UID '$am_uid' is supported by ustar format... " >&6; } + if test $am_uid -le $am_max_uid; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + _am_tools=none + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5 +$as_echo_n "checking whether GID '$am_gid' is supported by ustar format... " >&6; } + if test $am_gid -le $am_max_gid; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + _am_tools=none + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5 +$as_echo_n "checking how to create a ustar tar archive... " >&6; } + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_ustar-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + { echo "$as_me:$LINENO: $_am_tar --version" >&5 + ($_am_tar --version) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && break + done + am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=ustar -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x ustar -w "$$tardir"' + am__tar_='pax -L -x ustar -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H ustar -L' + am__tar_='find "$tardir" -print | cpio -o -H ustar -L' + am__untar='cpio -i -H ustar -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_ustar}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5 + (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + rm -rf conftest.dir + if test -s conftest.tar; then + { echo "$as_me:$LINENO: $am__untar &5 + ($am__untar &5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + { echo "$as_me:$LINENO: cat conftest.dir/file" >&5 + (cat conftest.dir/file) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + if ${am_cv_prog_tar_ustar+:} false; then : + $as_echo_n "(cached) " >&6 +else + am_cv_prog_tar_ustar=$_am_tool +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5 +$as_echo "$am_cv_prog_tar_ustar" >&6; } + + + + + + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 + fi +fi + + + + + + + + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +$as_echo "$ac_pt_PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=0.9.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 +$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + PKG_CONFIG="" + fi +fi + + +if test "x$PY_PREFIX" = x; then : + PY_PREFIX="/usr" +fi + + +if test "x$JAVA_PREFIX" != x; then : + JAVA_PREFIX="$JAVA_PREFIX/usr/local/lib" +elif test "x$PREFIX" != x; then : + JAVA_PREFIX="$PREFIX/usr/local/lib" +else + JAVA_PREFIX="/usr/local/lib" +fi + + + + +if test "x$PHP_PREFIX" = x; then : + PHP_PREFIX="/usr/lib/php" +fi + + +if test "x$PHP_CONFIG_PREFIX" = x; then : + PHP_CONFIG_PREFIX="/etc/php.d" +fi + + +if test "x$INSTALLDIRS" = x; then : + INSTALLDIRS="vendor" +fi + + +if test "x$PERL_PREFIX" = x; then : + PERL_PREFIX="/usr/local" +fi + + + + + + +if test "x$D_IMPORT_PREFIX" = x; then : + D_IMPORT_PREFIX="${includedir}/d2" +fi + + + + + +if test "x$THRIFT" = x; then : + THRIFT=`pwd`/compiler/cpp/thrift +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } +if ${am_cv_prog_cc_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +$as_echo "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CXX_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.4.6' +macro_revision='2.4.6' + + + + + + + + + + + + + +ltmain=$ac_aux_dir/ltmain.sh + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case $ECHO in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if ${ac_cv_path_FGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_FGREP" || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test yes = "$GCC"; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return, which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD=$ac_prog + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test yes = "$with_gnu_ld"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD=$ac_dir/$ac_prog + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if ${lt_cv_path_NM+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM=$NM +else + lt_nm_to_check=${ac_tool_prefix}nm + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/$lt_tmp_nm + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the 'sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty + case $build_os in + mingw*) lt_bad_file=conftest.nm/nofile ;; + *) lt_bad_file=/dev/null ;; + esac + case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in + *$lt_bad_file* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break 2 + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break 2 + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS=$lt_save_ifs + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test no != "$lt_cv_path_NM"; then + NM=$lt_cv_path_NM +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols -headers" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test : != "$DUMPBIN"; then + NM=$DUMPBIN + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if ${lt_cv_nm_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if ${lt_cv_sys_max_cmd_len+:} false; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring=ABCD + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len" && \ + test undefined != "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test X`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test 17 != "$i" # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n "$lt_cv_sys_max_cmd_len"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 +$as_echo_n "checking how to convert $build file names to $host format... " >&6; } +if ${lt_cv_to_host_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +$as_echo "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } +if ${lt_cv_to_tool_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +$as_echo "$lt_cv_to_tool_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if ${lt_cv_ld_reload_flag+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + if test yes != "$GCC"; then + reload_cmds=false + fi + ;; + darwin*) + if test yes = "$GCC"; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if ${lt_cv_deplibs_check_method+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# 'unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# that responds to the $file_magic_cmd with a given extended regex. +# If you have 'file' or equivalent on your system and you're not sure +# whether 'pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd* | bitrig*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +os2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +$as_echo_n "checking how to associate runtime and link libraries... " >&6; } +if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh; + # decide which one to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd=$ECHO + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} +: ${AR_FLAGS=cru} + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +$as_echo_n "checking for archiver @FILE support... " >&6; } +if ${lt_cv_ar_at_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test 0 -eq "$ac_status"; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test 0 -ne "$ac_status"; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +$as_echo "$lt_cv_ar_at_file" >&6; } + +if test no = "$lt_cv_ar_at_file"; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + bitrig* | openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if ${lt_cv_sys_global_symbol_pipe+:} false; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test ia64 = "$host_cpu"; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n"\ +$lt_cdecl_hook\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ +$lt_c_name_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ +$lt_c_name_lib_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function, + # D for any global variable and I for any imported variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ +" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ +" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ +" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS=conftstm.$ac_objext + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest$ac_exeext; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test yes = "$pipe_works"; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; +else + with_sysroot=no +fi + + +lt_sysroot= +case $with_sysroot in #( + yes) + if test yes = "$GCC"; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 +$as_echo "$with_sysroot" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +$as_echo "${lt_sysroot:-no}" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 +$as_echo_n "checking for a working dd... " >&6; } +if ${ac_cv_path_lt_DD+:} false; then : + $as_echo_n "(cached) " >&6 +else + printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +: ${lt_DD:=$DD} +if test -z "$lt_DD"; then + ac_path_lt_DD_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in dd; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_lt_DD" || continue +if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: +fi + $ac_path_lt_DD_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_lt_DD"; then + : + fi +else + ac_cv_path_lt_DD=$lt_DD +fi + +rm -f conftest.i conftest2.i conftest.out +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 +$as_echo "$ac_cv_path_lt_DD" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 +$as_echo_n "checking how to truncate binary pipes... " >&6; } +if ${lt_cv_truncate_bin+:} false; then : + $as_echo_n "(cached) " >&6 +else + printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +lt_cv_truncate_bin= +if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" +fi +rm -f conftest.i conftest2.i conftest.out +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 +$as_echo "$lt_cv_truncate_bin" >&6; } + + + + + + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test no = "$enable_libtool_lock" || enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out what ABI is being produced by ac_compile, and set mode + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE=32 + ;; + *ELF-64*) + HPUX_IA64_MODE=64 + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test yes = "$lt_cv_prog_gnu_ld"; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +mips64*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + emul=elf + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + emul="${emul}32" + ;; + *64-bit*) + emul="${emul}64" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *MSB*) + emul="${emul}btsmip" + ;; + *LSB*) + emul="${emul}ltsmip" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *N32*) + emul="${emul}n32" + ;; + esac + LD="${LD-ld} -m $emul" + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. Note that the listed cases only cover the + # situations where additional linker options are needed (such as when + # doing 32-bit compilation for a host where ld defaults to 64-bit, or + # vice versa); the common cases where no linker options are needed do + # not appear in the list. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if ${lt_cv_cc_needs_belf+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test yes != "$lt_cv_cc_needs_belf"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS=$SAVE_CFLAGS + fi + ;; +*-*solaris*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*|x86_64-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD=${LD-ld}_sol2 + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks=$enable_libtool_lock + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +$as_echo "$MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if ${lt_cv_path_mainfest_tool+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +$as_echo "$lt_cv_path_mainfest_tool" >&6; } +if test yes != "$lt_cv_path_mainfest_tool"; then + MANIFEST_TOOL=: +fi + + + + + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if ${lt_cv_apple_cc_single_mod+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "$LT_MULTI_MODULE"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&5 + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test 0 = "$_lt_result"; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if ${lt_cv_ld_exported_symbols_list+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&5 + elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + 10.[012][,.]*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test yes = "$lt_cv_apple_cc_single_mod"; then + _lt_dar_single_mod='$single_module' + fi + if test yes = "$lt_cv_ld_exported_symbols_list"; then + _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' + fi + if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + + +func_stripname_cnf () +{ + case $2 in + .*) func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%\\\\$2\$%%"`;; + *) func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%$2\$%%"`;; + esac +} # func_stripname_cnf + + + + + +# Set options + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $withval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else + pic_mode=default +fi + + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + shared_archive_member_spec= +case $host,$enable_shared in +power*-*-aix[5-9]*,yes) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 +$as_echo_n "checking which variant of shared library versioning to provide... " >&6; } + +# Check whether --with-aix-soname was given. +if test "${with_aix_soname+set}" = set; then : + withval=$with_aix_soname; case $withval in + aix|svr4|both) + ;; + *) + as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname +else + if ${lt_cv_with_aix_soname+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_with_aix_soname=aix +fi + + with_aix_soname=$lt_cv_with_aix_soname +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 +$as_echo "$with_aix_soname" >&6; } + if test aix != "$with_aix_soname"; then + # For the AIX way of multilib, we name the shared archive member + # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', + # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. + # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, + # the AIX toolchain works better with OBJECT_MODE set (default 32). + if test 64 = "${OBJECT_MODE-32}"; then + shared_archive_member_spec=shr_64 + else + shared_archive_member_spec=shr + fi + fi + ;; +*) + with_aix_soname=aix + ;; +esac + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS=$ltmain + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if ${lt_cv_objdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a '.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld=$lt_cv_prog_gnu_ld + +old_CC=$CC +old_CFLAGS=$CFLAGS + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +func_cc_basename $compiler +cc_basename=$func_cc_basename_result + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/${ac_tool_prefix}file"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD=$lt_cv_path_MAGIC_CMD + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac +fi + +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/file"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD=$lt_cv_path_MAGIC_CMD + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac +fi + +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC=$CC +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test yes = "$GCC"; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + + + if test yes = "$GCC"; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + lt_prog_compiler_pic='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + if test -n "$lt_prog_compiler_pic"; then + lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + case $cc_basename in + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='$wl-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64, which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ F* | *Sun*Fortran*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Intel*\ [CF]*Compiler*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + *Portland\ Group*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms that do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +$as_echo "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if ${lt_cv_prog_compiler_pic_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test yes = "$lt_cv_prog_compiler_pic_works"; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test yes = "$lt_cv_prog_compiler_static_works"; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links=nottested +if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test no = "$hard_links"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ' (' and ')$', so one must not match beginning or + # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', + # as well as any symbol that contains 'd'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test yes != "$GCC"; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd* | bitrig*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test yes = "$with_gnu_ld"; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test yes = "$lt_use_gnu_ld_interface"; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='$wl' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + export_dynamic_flag_spec='$wl--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test ia64 != "$host_cpu"; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='$wl--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + export_dynamic_flag_spec='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test linux-dietlibc = "$host_os"; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test no = "$tmp_diet" + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + nagfor*) # NAGFOR 5.3 + tmp_sharedflag='-Wl,-shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + + if test yes = "$supports_anon_versioning"; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + tcc*) + export_dynamic_flag_spec='-rdynamic' + ;; + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test yes = "$supports_anon_versioning"; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test no = "$ld_shlibs"; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then + aix_use_runtimelinking=yes + break + fi + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # traditional, no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + hardcode_direct=no + hardcode_direct_absolute=no + ;; + esac + + if test yes = "$GCC"; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag="$shared_flag "'$wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + export_dynamic_flag_spec='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' $wl-bernotok' + allow_undefined_flag=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + enable_shared_with_static_runtimes=yes + ;; + esac + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test yes = "$lt_cv_ld_force_load"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" + archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test yes = "$GCC"; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='$wl-E' + ;; + + hpux10*) + if test yes,no = "$GCC,$with_gnu_ld"; then + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='$wl-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test yes,no = "$GCC,$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test yes = "$lt_cv_prog_compiler__b"; then + archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='$wl-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test yes = "$GCC"; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if ${lt_cv_irix_exported_symbol+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo (void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_irix_exported_symbol=yes +else + lt_cv_irix_exported_symbol=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 +$as_echo "$lt_cv_irix_exported_symbol" >&6; } + if test yes = "$lt_cv_irix_exported_symbol"; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' + fi + link_all_deplibs=no + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + linux*) + case $cc_basename in + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + ld_shlibs=yes + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + export_dynamic_flag_spec='$wl-E' + else + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes + ;; + + osf3*) + if test yes = "$GCC"; then + allow_undefined_flag=' $wl-expect_unresolved $wl\*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test yes = "$GCC"; then + allow_undefined_flag=' $wl-expect_unresolved $wl\*' + archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test yes = "$GCC"; then + wlarc='$wl' + archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='$wl' + archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. GCC discards it without '$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test yes = "$GCC"; then + whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test sequent = "$host_vendor"; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='$wl-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='$wl-z,text' + allow_undefined_flag='$wl-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='$wl-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test sni = "$host_vendor"; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='$wl-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test no = "$ld_shlibs" && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test yes,yes = "$GCC,$enable_shared"; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test yes = "$GCC"; then + case $host_os in + darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; + *) lt_awk_arg='/^libraries:/' ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; + *) lt_sed_strip_eq='s|=/|/|g' ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary... + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + # ...but if some path component already ends with the multilib dir we assume + # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). + case "$lt_multi_os_dir; $lt_search_path_spec " in + "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) + lt_multi_os_dir= + ;; + esac + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" + elif test -n "$lt_multi_os_dir"; then + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS = " "; FS = "/|\n";} { + lt_foo = ""; + lt_count = 0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo = "/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's|/\([A-Za-z]:\)|\1|g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=.so +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + + + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='$libname$release$shared_ext$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; then + # AIX 5 supports IA64 + library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line '#! .'. This would cause the generated library to + # depend on '.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a(lib.so.V)' + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='$libname$shared_ext' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' + soname_spec='$libname$release$major$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + if test 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" + sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + hardcode_libdir_flag_spec='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) to the search path. + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec; then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' + soname_spec='$libname$shared_ext.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=sco + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test yes = "$with_gnu_ld"; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test yes = "$hardcode_automatic"; then + + # We can hardcode non-existent directories. + if test no != "$hardcode_direct" && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && + test no != "$hardcode_minus_L"; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test relink = "$hardcode_action" || + test yes = "$inherit_rpath"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test yes != "$enable_dlopen"; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen=load_add_on + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen=LoadLibrary + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl +else + + lt_cv_dlopen=dyld + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + tpf*) + # Don't try to run any link tests for TPF. We know it's impossible + # because TPF is a cross-compiler, and we know how we open DSOs. + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + lt_cv_dlopen_self=no + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes; then : + lt_cv_dlopen=shl_load +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if ${ac_cv_lib_dld_shl_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : + lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes; then : + lt_cv_dlopen=dlopen +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if ${ac_cv_lib_svld_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = xyes; then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if ${ac_cv_lib_dld_dld_link+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = xyes; then : + lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test no = "$lt_cv_dlopen"; then + enable_dlopen=no + else + enable_dlopen=yes + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS=$CPPFLAGS + test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS=$LDFLAGS + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS=$LIBS + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test yes = "$cross_compiling"; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test yes = "$lt_cv_dlopen_self"; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self_static+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test yes = "$cross_compiling"; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS=$save_CPPFLAGS + LDFLAGS=$save_LDFLAGS + LIBS=$save_LIBS + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP"; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report what library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC=$lt_save_CC + + if test -n "$CXX" && ( test no != "$CXX" && + ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || + (test g++ != "$CXX"))); then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if ${ac_cv_prog_CXXCPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +else + _lt_caught_CXX_error=yes +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +compiler_needs_object_CXX=no +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_direct_absolute_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +inherit_rpath_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +reload_flag_CXX=$reload_flag +reload_cmds_CXX=$reload_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_caught_CXX_error"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + + # save warnings/boilerplate of simple test code + ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + + ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + compiler_CXX=$CC + func_cc_basename $compiler +cc_basename=$func_cc_basename_result + + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test yes = "$GXX"; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' + else + lt_prog_compiler_no_builtin_flag_CXX= + fi + + if test yes = "$GXX"; then + # Set up default GNU C++ configuration + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test yes = "$GCC"; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return, which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD=$ac_prog + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test yes = "$with_gnu_ld"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD=$ac_dir/$ac_prog + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test yes = "$with_gnu_ld"; then + archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' + export_dynamic_flag_spec_CXX='$wl--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='$wl' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + ld_shlibs_CXX=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix[4-9]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + file_list_spec_CXX='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + hardcode_direct_CXX=no + hardcode_direct_absolute_CXX=no + ;; + esac + + if test yes = "$GXX"; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag=$shared_flag' $wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + export_dynamic_flag_spec_CXX='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + always_export_symbols_CXX=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + # The "-G" linker flag allows undefined symbols. + no_undefined_flag_CXX='-bernotok' + # Determine the default libpath from the value encoded in an empty + # executable. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + hardcode_libdir_flag_spec_CXX='$wl-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' $wl-bernotok' + allow_undefined_flag_CXX=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + fi + archive_cmds_need_lc_CXX=yes + archive_expsym_cmds_CXX='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared + # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. + archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_CXX=' ' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=yes + file_list_spec_CXX='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + archive_expsym_cmds_CXX='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' + enable_shared_with_static_runtimes_CXX=yes + # Don't use ranlib + old_postinstall_cmds_CXX='chmod 644 $oldlib' + postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + export_dynamic_flag_spec_CXX='$wl--export-all-symbols' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + archive_expsym_cmds_CXX='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + + + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + if test yes = "$lt_cv_ld_force_load"; then + whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec_CXX='' + fi + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" + archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + module_expsym_cmds_CXX="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + if test yes != "$lt_cv_apple_cc_single_mod"; then + archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" + archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" + fi + + else + ld_shlibs_CXX=no + fi + + ;; + + os2*) + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_minus_L_CXX=yes + allow_undefined_flag_CXX=unsupported + shrext_cmds=.dll + archive_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds_CXX='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes_CXX=yes + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + ld_shlibs_CXX=no + ;; + + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + + haiku*) + archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + link_all_deplibs_CXX=yes + ;; + + hpux9*) + hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='$wl-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + export_dynamic_flag_spec_CXX='$wl-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' + export_dynamic_flag_spec_CXX='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' + hardcode_libdir_separator_CXX=: + inherit_rpath_CXX=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' + export_dynamic_flag_spec_CXX='$wl--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' + export_dynamic_flag_spec_CXX='$wl--export-dynamic' + whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [1-5].* | *pgcpp\ [1-5].*) + prelink_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + old_archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='$wl--rpath $wl$libdir' + export_dynamic_flag_spec_CXX='$wl--export-dynamic' + whole_archive_flag_spec_CXX='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' + export_dynamic_flag_spec_CXX='$wl--export-dynamic' + archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + if test yes = "$supports_anon_versioning"; then + archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + compiler_needs_object_CXX=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + ld_shlibs_CXX=yes + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + hardcode_direct_absolute_CXX=yes + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='$wl-E' + whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + ld_shlibs_CXX=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + case $host in + osf3*) + allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*' + archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' + ;; + *) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ + $RM $lib.exp' + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + ;; + esac + + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes,no = "$GXX,$with_gnu_ld"; then + allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*' + case $host in + osf3*) + archive_cmds_CXX='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + *) + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test yes,no = "$GXX,$with_gnu_ld"; then + no_undefined_flag_CXX=' $wl-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require '-G' NOT '-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + hardcode_libdir_flag_spec_CXX='$wl-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='$wl-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_CXX='$wl-z,text' + allow_undefined_flag_CXX='$wl-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='$wl-R,$libdir' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ + '"$old_archive_cmds_CXX" + reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ + '"$reload_cmds_CXX" + ;; + *) + archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } + test no = "$ld_shlibs_CXX" && can_build_shared=no + + GCC_CXX=$GXX + LD_CXX=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + # Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF + + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $prev$p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test x-L = "$p" || + test x-R = "$p"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test no = "$pre_test_object_deps_done"; then + case $prev in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX=$prev$p + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} $prev$p" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX=$prev$p + else + postdeps_CXX="${postdeps_CXX} $prev$p" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test no = "$pre_test_object_deps_done"; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX=$p + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX=$p + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + compiler_lib_search_dirs_CXX= +if test -n "${compiler_lib_search_path_CXX}"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | $SED -e 's! -L! !g' -e 's!^ !!'` +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + + + # C++ specific cases for pic, static, wl, etc. + if test yes = "$GXX"; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + lt_prog_compiler_pic_CXX='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic_CXX='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + case $host_os in + os2*) + lt_prog_compiler_static_CXX='$wl-static' + ;; + esac + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix[4-9]*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='$wl-a ${wl}archive' + if test ia64 != "$host_cpu"; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='$wl-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64, which still supported -KPIC. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-qpic' + lt_prog_compiler_static_CXX='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +case $host_os in + # For platforms that do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; } +lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } +if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_CXX=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test yes = "$lt_cv_prog_compiler_pic_works_CXX"; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works_CXX=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test yes = "$lt_cv_prog_compiler_static_works_CXX"; then + : +else + lt_prog_compiler_static_CXX= +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + +hard_links=nottested +if test no = "$lt_cv_prog_compiler_c_o_CXX" && test no != "$need_locks"; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test no = "$hard_links"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + case $host_os in + aix[4-9]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX=$ltdll_cmds + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs_CXX=no + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } +test no = "$ld_shlibs_CXX" && can_build_shared=no + +with_gnu_ld_CXX=$with_gnu_ld + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test yes,yes = "$GCC,$enable_shared"; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc_CXX=no + else + lt_cv_archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } + archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=.so +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + + + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='$libname$release$shared_ext$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; then + # AIX 5 supports IA64 + library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line '#! .'. This would cause the generated library to + # depend on '.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a(lib.so.V)' + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='$libname$shared_ext' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' + soname_spec='$libname$release$major$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + if test 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" + sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + hardcode_libdir_flag_spec_CXX='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) to the search path. + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec; then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' + soname_spec='$libname$shared_ext.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=sco + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test yes = "$with_gnu_ld"; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || + test -n "$runpath_var_CXX" || + test yes = "$hardcode_automatic_CXX"; then + + # We can hardcode non-existent directories. + if test no != "$hardcode_direct_CXX" && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" && + test no != "$hardcode_minus_L_CXX"; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 +$as_echo "$hardcode_action_CXX" >&6; } + +if test relink = "$hardcode_action_CXX" || + test yes = "$inherit_rpath_CXX"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test yes != "$_lt_caught_CXX_error" + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + + +if test "x2.5" = "x" ; then + bison_required_version="2.4" +else + bison_required_version="2.5" +fi + +# Extract the first word of "bison", so it can be a program name with args. +set dummy bison; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_have_prog_bison+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$have_prog_bison"; then + ac_cv_prog_have_prog_bison="$have_prog_bison" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_have_prog_bison="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_have_prog_bison" && ac_cv_prog_have_prog_bison="no" +fi +fi +have_prog_bison=$ac_cv_prog_have_prog_bison +if test -n "$have_prog_bison"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_prog_bison" >&5 +$as_echo "$have_prog_bison" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + +cat >>confdefs.h <<_ACEOF +#define BISON_VERSION 0.0 +_ACEOF + + +#Do not use *.h extension for parser header files, use newer *.hh +bison_use_parser_h_extension=false + +if test "$have_prog_bison" = "yes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for bison version >= $bison_required_version" >&5 +$as_echo_n "checking for bison version >= $bison_required_version... " >&6; } + bison_version=`bison --version | head -n 1 | cut '-d ' -f 4` + +cat >>confdefs.h <<_ACEOF +#define BISON_VERSION $bison_version +_ACEOF + + if test "$bison_version" \< "$bison_required_version" ; then + BISON=: + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "Bison version $bison_required_version or higher must be installed on the system!" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + BISON=bison + + + #Verify automake version 1.11 headers for yy files are .h, > 1.12 uses .hh + automake_version=`automake --version | head -n 1 | cut '-d ' -f 4` + +cat >>confdefs.h <<_ACEOF +#define AUTOMAKE_VERSION $automake_version +_ACEOF + + + if test "$automake_version" \< "1.12" ; then + #Use *.h extension for parser header file + bison_use_parser_h_extension=true + echo "Automake version < 1.12" + +$as_echo "#define BISON_USE_PARSER_H_EXTENSION 1" >>confdefs.h + + fi + fi +else + BISON=: + { $as_echo "$as_me:${as_lineno-$LINENO}: result: NO" >&5 +$as_echo "NO" >&6; } +fi + + if test x$bison_use_parser_h_extension = xtrue; then + BISON_USE_PARSER_H_EXTENSION_TRUE= + BISON_USE_PARSER_H_EXTENSION_FALSE='#' +else + BISON_USE_PARSER_H_EXTENSION_TRUE='#' + BISON_USE_PARSER_H_EXTENSION_FALSE= +fi + + + +for ac_prog in 'bison -y' byacc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_YACC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_YACC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 +$as_echo "$YACC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +for ac_prog in flex lex +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LEX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_LEX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LEX=$ac_cv_prog_LEX +if test -n "$LEX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 +$as_echo "$LEX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$LEX" && break +done +test -n "$LEX" || LEX=":" + +if test "x$LEX" != "x:"; then + cat >conftest.l <<_ACEOF +%% +a { ECHO; } +b { REJECT; } +c { yymore (); } +d { yyless (1); } +e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument. */ + yyless ((input () != 0)); } +f { unput (yytext[0]); } +. { BEGIN INITIAL; } +%% +#ifdef YYTEXT_POINTER +extern char *yytext; +#endif +int +main (void) +{ + return ! yylex () + ! yywrap (); +} +_ACEOF +{ { ac_try="$LEX conftest.l" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$LEX conftest.l") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 +$as_echo_n "checking lex output file root... " >&6; } +if ${ac_cv_prog_lex_root+:} false; then : + $as_echo_n "(cached) " >&6 +else + +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 +$as_echo "$ac_cv_prog_lex_root" >&6; } +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +if test -z "${LEXLIB+set}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 +$as_echo_n "checking lex library... " >&6; } +if ${ac_cv_lib_lex+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ac_save_LIBS=$LIBS + ac_cv_lib_lex='none needed' + for ac_lib in '' -lfl -ll; do + LIBS="$ac_lib $ac_save_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_lex=$ac_lib +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + test "$ac_cv_lib_lex" != 'none needed' && break + done + LIBS=$ac_save_LIBS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 +$as_echo "$ac_cv_lib_lex" >&6; } + test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 +$as_echo_n "checking whether yytext is a pointer... " >&6; } +if ${ac_cv_prog_lex_yytext_pointer+:} false; then : + $as_echo_n "(cached) " >&6 +else + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +ac_save_LIBS=$LIBS +LIBS="$LEXLIB $ac_save_LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #define YYTEXT_POINTER 1 +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_prog_lex_yytext_pointer=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_save_LIBS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 +$as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; } +if test $ac_cv_prog_lex_yytext_pointer = yes; then + +$as_echo "#define YYTEXT_POINTER 1" >>confdefs.h + +fi +rm -f conftest.l $LEX_OUTPUT_ROOT.c + +fi +if test "$LEX" = :; then + LEX=${am_missing_run}flex +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ax_cxx_compile_alternatives="11 0x" ax_cxx_compile_cxx11_required=false + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + ac_success=no + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5 +$as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; } +if ${ax_cv_cxx_compile_cxx11+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ax_cv_cxx_compile_cxx11=yes +else + ax_cv_cxx_compile_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5 +$as_echo "$ax_cv_cxx_compile_cxx11" >&6; } + if test x$ax_cv_cxx_compile_cxx11 = xyes; then + ac_success=yes + fi + + + + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 +$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; } +if eval \${$cachevar+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_CXX="$CXX" + CXX="$CXX $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval $cachevar=yes +else + eval $cachevar=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXX="$ac_save_CXX" +fi +eval ac_res=\$$cachevar + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then + break + fi + done + fi + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + if test x$ax_cxx_compile_cxx11_required = xtrue; then + if test x$ac_success = xno; then + as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5 + fi + fi + if test x$ac_success = xno; then + HAVE_CXX11=0 + { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5 +$as_echo "$as_me: No compiler with C++11 support was found" >&6;} + else + HAVE_CXX11=1 + +$as_echo "#define HAVE_CXX11 1" >>confdefs.h + + fi + + + +if test "$ac_success" = "no"; then + CXXFLAGS="$CXXFLAGS -Wno-variadic-macros -Wno-long-long -Wno-c++11-long-long" +fi + + +CPPSTYLE_CMD='find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;' + + +# Check whether --enable-libs was given. +if test "${enable_libs+set}" = set; then : + enableval=$enable_libs; +else + enable_libs=yes + +fi + +have_libs=yes +if test "$enable_libs" = "no"; then + have_libs="no" + with_cpp="no" + with_c_glib="no" + with_java="no" + with_csharp="no" + with_python="no" + with_py3="no" + with_ruby="no" + with_haskell="no" + with_haxe="no" + with_dotnetcore="no" + with_perl="no" + with_php="no" + with_php_extension="no" + with_dart="no" + with_erlang="no" + with_go="no" + with_d="no" + with_nodejs="no" + with_lua="no" + with_rs="no" +fi + + + +# Check whether --with-cpp was given. +if test "${with_cpp+set}" = set; then : + withval=$with_cpp; with_cpp="$withval" +else + with_cpp=yes + +fi + + have_cpp=no + +have_cpp=no +if test "$with_cpp" = "yes"; then + + +# Check whether --with-boost was given. +if test "${with_boost+set}" = set; then : + withval=$with_boost; + case $withval in #( + no) : + want_boost="no";_AX_BOOST_BASE_boost_path="" ;; #( + yes) : + want_boost="yes";_AX_BOOST_BASE_boost_path="" ;; #( + *) : + want_boost="yes";_AX_BOOST_BASE_boost_path="$withval" ;; +esac + +else + want_boost="yes" +fi + + + + +# Check whether --with-boost-libdir was given. +if test "${with_boost_libdir+set}" = set; then : + withval=$with_boost_libdir; + if test -d "$withval"; then : + _AX_BOOST_BASE_boost_lib_path="$withval" +else + as_fn_error $? "--with-boost-libdir expected directory name" "$LINENO" 5 +fi + +else + _AX_BOOST_BASE_boost_lib_path="" +fi + + +BOOST_LDFLAGS="" +BOOST_CPPFLAGS="" +if test "x$want_boost" = "xyes"; then : + + + if test "x1.53.0" = "x"; then : + _AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0" +else + _AX_BOOST_BASE_TONUMERICVERSION_req="1.53.0" +fi + _AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([0-9]*\.[0-9]*\)'` + _AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([0-9]*\)'` + if test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_major" = "x"; then : + as_fn_error $? "You should at least specify libboost major version" "$LINENO" 5 +fi + _AX_BOOST_BASE_TONUMERICVERSION_req_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[0-9]*\.\([0-9]*\)'` + if test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_minor" = "x"; then : + _AX_BOOST_BASE_TONUMERICVERSION_req_minor="0" +fi + _AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[0-9]*\.[0-9]*\.\([0-9]*\)'` + if test "X$_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor" = "X"; then : + _AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor="0" +fi + _AX_BOOST_BASE_TONUMERICVERSION_RET=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req_major \* 100000 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_minor \* 100 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor` + WANT_BOOST_VERSION=$_AX_BOOST_BASE_TONUMERICVERSION_RET + + succeeded=no + + + + case ${host_cpu} in #( + x86_64) : + libsubdirs="lib64 libx32 lib lib64" ;; #( + ppc64|s390x|sparc64|aarch64|ppc64le) : + libsubdirs="lib64 lib lib64" ;; #( + libsubdirs="lib") : + ;; #( + *) : + ;; +esac + + case ${host_cpu} in #( + i?86) : + multiarch_libsubdir="lib/i386-${host_os}" ;; #( + *) : + multiarch_libsubdir="lib/${host_cpu}-${host_os}" + ;; +esac + + if test "x$_AX_BOOST_BASE_boost_path" != "x"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for boostlib >= 1.53.0 ($WANT_BOOST_VERSION) includes in \"$_AX_BOOST_BASE_boost_path/include\"" >&5 +$as_echo_n "checking for boostlib >= 1.53.0 ($WANT_BOOST_VERSION) includes in \"$_AX_BOOST_BASE_boost_path/include\"... " >&6; } + if test -d "$_AX_BOOST_BASE_boost_path/include" && test -r "$_AX_BOOST_BASE_boost_path/include"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include" + for _AX_BOOST_BASE_boost_path_tmp in $multiarch_libsubdir $libsubdirs; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for boostlib >= 1.53.0 ($WANT_BOOST_VERSION) lib path in \"$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp\"" >&5 +$as_echo_n "checking for boostlib >= 1.53.0 ($WANT_BOOST_VERSION) lib path in \"$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp\"... " >&6; } + if test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"; + break; + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + done +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +else + + if test X"$cross_compiling" = Xyes; then + search_libsubdirs=$multiarch_libsubdir + else + search_libsubdirs="$multiarch_libsubdir $libsubdirs" + fi + for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local ; do + if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then + for libsubdir in $search_libsubdirs ; do + if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path_tmp/$libsubdir" + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include" + break; + fi + done + +fi + + if test "x$_AX_BOOST_BASE_boost_lib_path" != "x"; then : + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_lib_path" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for boostlib >= 1.53.0 ($WANT_BOOST_VERSION)" >&5 +$as_echo_n "checking for boostlib >= 1.53.0 ($WANT_BOOST_VERSION)... " >&6; } + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +int +main () +{ + +(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($WANT_BOOST_VERSION))])); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + succeeded=yes + found_system=yes + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + + + if test "x$succeeded" != "xyes" ; then + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + BOOST_CPPFLAGS= + if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + BOOST_LDFLAGS= + fi + _version=0 + if test -n "$_AX_BOOST_BASE_boost_path" ; then + if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then + for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "x$V_CHECK" = "x1" ; then + _version=$_version_tmp + fi + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include/boost-$VERSION_UNDERSCORE" + done + if test -z "$BOOST_CPPFLAGS"; then + if test -d "$_AX_BOOST_BASE_boost_path/boost" && test -r "$_AX_BOOST_BASE_boost_path/boost"; then + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path" + fi + fi + if test -n "$BOOST_CPPFLAGS" && test -z "$BOOST_LDFLAGS"; then + for libsubdir in $libsubdirs ; do + if ls "$_AX_BOOST_BASE_boost_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$libsubdir" + fi + fi + else + if test "x$cross_compiling" != "xyes" ; then + for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local ; do + if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then + for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "x$V_CHECK" = "x1" ; then + _version=$_version_tmp + best_path=$_AX_BOOST_BASE_boost_path + fi + done + fi + done + + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" + if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + for libsubdir in $libsubdirs ; do + if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$best_path/$libsubdir" + fi + fi + + if test -n "$BOOST_ROOT" ; then + for libsubdir in $libsubdirs ; do + if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then + version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'` + stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` + stage_version_shorten=`expr $stage_version : '\([0-9]*\.[0-9]*\)'` + V_CHECK=`expr $stage_version_shorten \>\= $_version` + if test "x$V_CHECK" = "x1" && test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: We will use a staged boost library from $BOOST_ROOT" >&5 +$as_echo "$as_me: We will use a staged boost library from $BOOST_ROOT" >&6;} + BOOST_CPPFLAGS="-I$BOOST_ROOT" + BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir" + fi + fi + fi + fi + + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +int +main () +{ + +(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($WANT_BOOST_VERSION))])); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + succeeded=yes + found_system=yes + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + fi + + if test "x$succeeded" != "xyes" ; then + if test "x$_version" = "x0" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: We could not detect the boost libraries (version 1.53.0 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation." >&5 +$as_echo "$as_me: We could not detect the boost libraries (version 1.53.0 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation." >&6;} + else + { $as_echo "$as_me:${as_lineno-$LINENO}: Your boost libraries seems to old (version $_version)." >&5 +$as_echo "$as_me: Your boost libraries seems to old (version $_version)." >&6;} + fi + # execute ACTION-IF-NOT-FOUND (if present): + : + else + +$as_echo "#define HAVE_BOOST /**/" >>confdefs.h + + # execute ACTION-IF-FOUND (if present): + : + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + + +fi + + + + if test "x$succeeded" = "xyes" ; then + BOOST_LIB_DIR=$(echo "$BOOST_LDFLAGS" | sed -e 's/^\-L//') + + BOOST_CHRONO_LDADD=$(echo "$BOOST_LIB_DIR/libboost_chrono.a") + + BOOST_FILESYSTEM_LDADD=$(echo "$BOOST_LIB_DIR/libboost_filesystem.a") + + BOOST_SYSTEM_LDADD=$(echo "$BOOST_LIB_DIR/libboost_system.a") + + BOOST_TEST_LDADD=$(echo "$BOOST_LIB_DIR/libboost_unit_test_framework.a") + + BOOST_THREAD_LDADD=$(echo "$BOOST_LIB_DIR/libboost_thread.a") + + have_cpp="yes" + fi + + + + +# Check whether --with-libevent was given. +if test "${with_libevent+set}" = set; then : + withval=$with_libevent; + if test "x$withval" = "xno"; then + want_libevent="no" + elif test "x$withval" = "xyes"; then + want_libevent="yes" + ax_libevent_path="" + else + want_libevent="yes" + ax_libevent_path="$withval" + fi + +else + want_libevent="yes" ; ax_libevent_path="" +fi + + + + if test "$want_libevent" = "yes"; then + WANT_LIBEVENT_VERSION=1.0 + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libevent >= $WANT_LIBEVENT_VERSION" >&5 +$as_echo_n "checking for libevent >= $WANT_LIBEVENT_VERSION... " >&6; } + + # Run tests. + if test -n "$ax_libevent_path"; then + + # Save our flags. + CPPFLAGS_SAVED="$CPPFLAGS" + LDFLAGS_SAVED="$LDFLAGS" + LIBS_SAVED="$LIBS" + LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH" + + # Set our flags if we are checking a specific directory. + if test -n "$ax_libevent_path" ; then + LIBEVENT_CPPFLAGS="-I$ax_libevent_path/include" + LIBEVENT_LDFLAGS="-L$ax_libevent_path/lib" + LD_LIBRARY_PATH="$ax_libevent_path/lib:$LD_LIBRARY_PATH" + else + LIBEVENT_CPPFLAGS="" + LIBEVENT_LDFLAGS="" + fi + + # Required flag for libevent. + LIBEVENT_LIBS="-levent" + + # Prepare the environment for compilation. + CPPFLAGS="$CPPFLAGS $LIBEVENT_CPPFLAGS" + LDFLAGS="$LDFLAGS $LIBEVENT_LDFLAGS" + LIBS="$LIBS $LIBEVENT_LIBS" + export CPPFLAGS + export LDFLAGS + export LIBS + export LD_LIBRARY_PATH + + success=no + + # Compile, link, and run the program. This checks: + # - event.h is available for including. + # - event_get_version() is available for linking. + # - The event version string is lexicographically greater + # than the required version. + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main () +{ + + const char* lib_version = event_get_version(); + const char* wnt_version = "$WANT_LIBEVENT_VERSION"; + int lib_digits; + int wnt_digits; + for (;;) { + /* If we reached the end of the want version. We have it. */ + if (*wnt_version == '\0' || *wnt_version == '-') { + return 0; + } + /* If the want version continues but the lib version does not, */ + /* we are missing a letter. We don't have it. */ + if (*lib_version == '\0' || *lib_version == '-') { + return 1; + } + /* In the 1.4 version numbering style, if there are more digits */ + /* in one version than the other, that one is higher. */ + for (lib_digits = 0; + lib_version[lib_digits] >= '0' && + lib_version[lib_digits] <= '9'; + lib_digits++) + ; + for (wnt_digits = 0; + wnt_version[wnt_digits] >= '0' && + wnt_version[wnt_digits] <= '9'; + wnt_digits++) + ; + if (lib_digits > wnt_digits) { + return 0; + } + if (lib_digits < wnt_digits) { + return 1; + } + /* If we have greater than what we want. We have it. */ + if (*lib_version > *wnt_version) { + return 0; + } + /* If we have less, we don't. */ + if (*lib_version < *wnt_version) { + return 1; + } + lib_version++; + wnt_version++; + } + return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + success=yes + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + # Restore flags. + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + LIBS="$LIBS_SAVED" + LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED" + + else + for ax_libevent_path in "" $lt_sysroot/usr $lt_sysroot/usr/local $lt_sysroot/opt $lt_sysroot/opt/local $lt_sysroot/opt/libevent "$LIBEVENT_ROOT" ; do + + # Save our flags. + CPPFLAGS_SAVED="$CPPFLAGS" + LDFLAGS_SAVED="$LDFLAGS" + LIBS_SAVED="$LIBS" + LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH" + + # Set our flags if we are checking a specific directory. + if test -n "$ax_libevent_path" ; then + LIBEVENT_CPPFLAGS="-I$ax_libevent_path/include" + LIBEVENT_LDFLAGS="-L$ax_libevent_path/lib" + LD_LIBRARY_PATH="$ax_libevent_path/lib:$LD_LIBRARY_PATH" + else + LIBEVENT_CPPFLAGS="" + LIBEVENT_LDFLAGS="" + fi + + # Required flag for libevent. + LIBEVENT_LIBS="-levent" + + # Prepare the environment for compilation. + CPPFLAGS="$CPPFLAGS $LIBEVENT_CPPFLAGS" + LDFLAGS="$LDFLAGS $LIBEVENT_LDFLAGS" + LIBS="$LIBS $LIBEVENT_LIBS" + export CPPFLAGS + export LDFLAGS + export LIBS + export LD_LIBRARY_PATH + + success=no + + # Compile, link, and run the program. This checks: + # - event.h is available for including. + # - event_get_version() is available for linking. + # - The event version string is lexicographically greater + # than the required version. + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main () +{ + + const char* lib_version = event_get_version(); + const char* wnt_version = "$WANT_LIBEVENT_VERSION"; + int lib_digits; + int wnt_digits; + for (;;) { + /* If we reached the end of the want version. We have it. */ + if (*wnt_version == '\0' || *wnt_version == '-') { + return 0; + } + /* If the want version continues but the lib version does not, */ + /* we are missing a letter. We don't have it. */ + if (*lib_version == '\0' || *lib_version == '-') { + return 1; + } + /* In the 1.4 version numbering style, if there are more digits */ + /* in one version than the other, that one is higher. */ + for (lib_digits = 0; + lib_version[lib_digits] >= '0' && + lib_version[lib_digits] <= '9'; + lib_digits++) + ; + for (wnt_digits = 0; + wnt_version[wnt_digits] >= '0' && + wnt_version[wnt_digits] <= '9'; + wnt_digits++) + ; + if (lib_digits > wnt_digits) { + return 0; + } + if (lib_digits < wnt_digits) { + return 1; + } + /* If we have greater than what we want. We have it. */ + if (*lib_version > *wnt_version) { + return 0; + } + /* If we have less, we don't. */ + if (*lib_version < *wnt_version) { + return 1; + } + lib_version++; + wnt_version++; + } + return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + success=yes + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + # Restore flags. + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + LIBS="$LIBS_SAVED" + LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED" + + if test "$success" = "yes"; then + break; + fi + done + fi + + if test "$success" != "yes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + LIBEVENT_CPPFLAGS="" + LIBEVENT_LDFLAGS="" + LIBEVENT_LIBS="" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_LIBEVENT /**/" >>confdefs.h + + ax_have_libevent_1_0="yes" + fi + + ax_have_libevent="$success" + + + + + fi + + + have_libevent=$success + + + + +# Check whether --with-zlib was given. +if test "${with_zlib+set}" = set; then : + withval=$with_zlib; + if test "x$withval" = "xno"; then + want_zlib="no" + elif test "x$withval" = "xyes"; then + want_zlib="yes" + ax_zlib_path="" + else + want_zlib="yes" + ax_zlib_path="$withval" + fi + +else + want_zlib="yes" ; ax_zlib_path="" +fi + + + + if test "$want_zlib" = "yes"; then + # Parse out the version. + zlib_version_req=1.2.3 + zlib_version_req_major=`expr $zlib_version_req : '\([0-9]*\)'` + zlib_version_req_minor=`expr $zlib_version_req : '[0-9]*\.\([0-9]*\)'` + zlib_version_req_patch=`expr $zlib_version_req : '[0-9]*\.[0-9]*\.\([0-9]*\)'` + if test -z "$zlib_version_req_patch" ; then + zlib_version_req_patch="0" + fi + WANT_ZLIB_VERSION=`expr $zlib_version_req_major \* 1000 \+ $zlib_version_req_minor \* 100 \+ $zlib_version_req_patch \* 10` + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for zlib >= $zlib_version_req" >&5 +$as_echo_n "checking for zlib >= $zlib_version_req... " >&6; } + + # Run tests. + if test -n "$ax_zlib_path"; then + + # Save our flags. + CPPFLAGS_SAVED="$CPPFLAGS" + LDFLAGS_SAVED="$LDFLAGS" + LIBS_SAVED="$LIBS" + LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH" + + # Set our flags if we are checking a specific directory. + if test -n "$ax_zlib_path" ; then + ZLIB_CPPFLAGS="-I$ax_zlib_path/include" + ZLIB_LDFLAGS="-L$ax_zlib_path/lib" + LD_LIBRARY_PATH="$ax_zlib_path/lib:$LD_LIBRARY_PATH" + else + ZLIB_CPPFLAGS="" + ZLIB_LDFLAGS="" + fi + + # Required flag for zlib. + ZLIB_LIBS="-lz" + + # Prepare the environment for compilation. + CPPFLAGS="$CPPFLAGS $ZLIB_CPPFLAGS" + LDFLAGS="$LDFLAGS $ZLIB_LDFLAGS" + LIBS="$LIBS $ZLIB_LIBS" + export CPPFLAGS + export LDFLAGS + export LIBS + export LD_LIBRARY_PATH + + success=no + + # Compile, link, and run the program. This checks: + # - zlib.h is available for including. + # - zlibVersion() is available for linking. + # - ZLIB_VERNUM is greater than or equal to the desired version. + # - ZLIB_VERSION (defined in zlib.h) matches zlibVersion() + # (defined in the library). + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #if ZLIB_VERNUM >= 0x$WANT_ZLIB_VERSION + #else + # error zlib is too old + #endif + +int +main () +{ + + const char* lib_version = zlibVersion(); + const char* hdr_version = ZLIB_VERSION; + for (;;) { + if (*lib_version != *hdr_version) { + /* If this happens, your zlib header doesn't match your zlib */ + /* library. That is really bad. */ + return 1; + } + if (*lib_version == '\0') { + break; + } + lib_version++; + hdr_version++; + } + return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + success=yes + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + # Restore flags. + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + LIBS="$LIBS_SAVED" + LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED" + + else + for ax_zlib_path in "" /usr /usr/local /opt /opt/zlib "$ZLIB_ROOT" ; do + + # Save our flags. + CPPFLAGS_SAVED="$CPPFLAGS" + LDFLAGS_SAVED="$LDFLAGS" + LIBS_SAVED="$LIBS" + LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH" + + # Set our flags if we are checking a specific directory. + if test -n "$ax_zlib_path" ; then + ZLIB_CPPFLAGS="-I$ax_zlib_path/include" + ZLIB_LDFLAGS="-L$ax_zlib_path/lib" + LD_LIBRARY_PATH="$ax_zlib_path/lib:$LD_LIBRARY_PATH" + else + ZLIB_CPPFLAGS="" + ZLIB_LDFLAGS="" + fi + + # Required flag for zlib. + ZLIB_LIBS="-lz" + + # Prepare the environment for compilation. + CPPFLAGS="$CPPFLAGS $ZLIB_CPPFLAGS" + LDFLAGS="$LDFLAGS $ZLIB_LDFLAGS" + LIBS="$LIBS $ZLIB_LIBS" + export CPPFLAGS + export LDFLAGS + export LIBS + export LD_LIBRARY_PATH + + success=no + + # Compile, link, and run the program. This checks: + # - zlib.h is available for including. + # - zlibVersion() is available for linking. + # - ZLIB_VERNUM is greater than or equal to the desired version. + # - ZLIB_VERSION (defined in zlib.h) matches zlibVersion() + # (defined in the library). + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #if ZLIB_VERNUM >= 0x$WANT_ZLIB_VERSION + #else + # error zlib is too old + #endif + +int +main () +{ + + const char* lib_version = zlibVersion(); + const char* hdr_version = ZLIB_VERSION; + for (;;) { + if (*lib_version != *hdr_version) { + /* If this happens, your zlib header doesn't match your zlib */ + /* library. That is really bad. */ + return 1; + } + if (*lib_version == '\0') { + break; + } + lib_version++; + hdr_version++; + } + return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + success=yes + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + # Restore flags. + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + LIBS="$LIBS_SAVED" + LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED" + + if test "$success" = "yes"; then + break; + fi + done + fi + + if test "$success" != "yes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ZLIB_CPPFLAGS="" + ZLIB_LDFLAGS="" + ZLIB_LIBS="" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_ZLIB /**/" >>confdefs.h + + fi + + ax_have_zlib="$success" + + + + + fi + + + have_zlib=$success + + + +# Check whether --with-qt4 was given. +if test "${with_qt4+set}" = set; then : + withval=$with_qt4; with_qt4="$withval" +else + with_qt4=yes + +fi + + have_qt4=no + + have_qt=no + if test "$with_qt4" = "yes"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for QT" >&5 +$as_echo_n "checking for QT... " >&6; } + +if test -n "$QT_CFLAGS"; then + pkg_cv_QT_CFLAGS="$QT_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"QtCore >= 4.3, QtNetwork >= 4.3\""; } >&5 + ($PKG_CONFIG --exists --print-errors "QtCore >= 4.3, QtNetwork >= 4.3") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_QT_CFLAGS=`$PKG_CONFIG --cflags "QtCore >= 4.3, QtNetwork >= 4.3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$QT_LIBS"; then + pkg_cv_QT_LIBS="$QT_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"QtCore >= 4.3, QtNetwork >= 4.3\""; } >&5 + ($PKG_CONFIG --exists --print-errors "QtCore >= 4.3, QtNetwork >= 4.3") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_QT_LIBS=`$PKG_CONFIG --libs "QtCore >= 4.3, QtNetwork >= 4.3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + QT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "QtCore >= 4.3, QtNetwork >= 4.3" 2>&1` + else + QT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "QtCore >= 4.3, QtNetwork >= 4.3" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$QT_PKG_ERRORS" >&5 + + have_qt=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + have_qt=no +else + QT_CFLAGS=$pkg_cv_QT_CFLAGS + QT_LIBS=$pkg_cv_QT_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + have_qt=yes +fi + fi + if test "$have_qt" = "yes"; then + for ac_prog in moc-qt4 moc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_QT_MOC+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $QT_MOC in + [\\/]* | ?:[\\/]*) + ac_cv_path_QT_MOC="$QT_MOC" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_QT_MOC="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +QT_MOC=$ac_cv_path_QT_MOC +if test -n "$QT_MOC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $QT_MOC" >&5 +$as_echo "$QT_MOC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$QT_MOC" && break +done +test -n "$QT_MOC" || QT_MOC=""fail"" + + if test "$QT_MOC" = "fail"; then + have_qt=no + fi + fi + + + +# Check whether --with-qt5 was given. +if test "${with_qt5+set}" = set; then : + withval=$with_qt5; with_qt5="$withval" +else + with_qt5=yes + +fi + + have_qt5=no + + have_qt5=no + qt_reduce_reloc="" + if test "$with_qt5" = "yes"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for QT5" >&5 +$as_echo_n "checking for QT5... " >&6; } + +if test -n "$QT5_CFLAGS"; then + pkg_cv_QT5_CFLAGS="$QT5_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.0, Qt5Network >= 5.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.0, Qt5Network >= 5.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_QT5_CFLAGS=`$PKG_CONFIG --cflags "Qt5Core >= 5.0, Qt5Network >= 5.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$QT5_LIBS"; then + pkg_cv_QT5_LIBS="$QT5_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.0, Qt5Network >= 5.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.0, Qt5Network >= 5.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_QT5_LIBS=`$PKG_CONFIG --libs "Qt5Core >= 5.0, Qt5Network >= 5.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + QT5_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "Qt5Core >= 5.0, Qt5Network >= 5.0" 2>&1` + else + QT5_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "Qt5Core >= 5.0, Qt5Network >= 5.0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$QT5_PKG_ERRORS" >&5 + + have_qt5=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + have_qt5=no +else + QT5_CFLAGS=$pkg_cv_QT5_CFLAGS + QT5_LIBS=$pkg_cv_QT5_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + have_qt5=yes;qt_reduce_reloc=`$PKG_CONFIG --variable=qt_config Qt5Core | grep "reduce_relocations"` +fi + fi + if test "$have_qt5" = "yes"; then + for ac_prog in moc-qt5 moc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_QT5_MOC+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $QT5_MOC in + [\\/]* | ?:[\\/]*) + ac_cv_path_QT5_MOC="$QT5_MOC" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_QT5_MOC="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +QT5_MOC=$ac_cv_path_QT5_MOC +if test -n "$QT5_MOC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $QT5_MOC" >&5 +$as_echo "$QT5_MOC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$QT5_MOC" && break +done +test -n "$QT5_MOC" || QT5_MOC=""fail"" + + if test "$QT5_MOC" = "fail"; then + have_qt5=no + fi + fi +fi + if test "$have_cpp" = "yes"; then + WITH_CPP_TRUE= + WITH_CPP_FALSE='#' +else + WITH_CPP_TRUE='#' + WITH_CPP_FALSE= +fi + + if test "$have_libevent" = "yes"; then + AMX_HAVE_LIBEVENT_TRUE= + AMX_HAVE_LIBEVENT_FALSE='#' +else + AMX_HAVE_LIBEVENT_TRUE='#' + AMX_HAVE_LIBEVENT_FALSE= +fi + + if test "$have_zlib" = "yes"; then + AMX_HAVE_ZLIB_TRUE= + AMX_HAVE_ZLIB_FALSE='#' +else + AMX_HAVE_ZLIB_TRUE='#' + AMX_HAVE_ZLIB_FALSE= +fi + + if test "$have_qt" = "yes"; then + AMX_HAVE_QT_TRUE= + AMX_HAVE_QT_FALSE='#' +else + AMX_HAVE_QT_TRUE='#' + AMX_HAVE_QT_FALSE= +fi + + if test "$have_qt5" = "yes"; then + AMX_HAVE_QT5_TRUE= + AMX_HAVE_QT5_FALSE='#' +else + AMX_HAVE_QT5_TRUE='#' + AMX_HAVE_QT5_FALSE= +fi + + if test "x$qt_reduce_reloc" != "x"; then + QT5_REDUCE_RELOCATIONS_TRUE= + QT5_REDUCE_RELOCATIONS_FALSE='#' +else + QT5_REDUCE_RELOCATIONS_TRUE='#' + QT5_REDUCE_RELOCATIONS_FALSE= +fi + + + + +# Check whether --with-c_glib was given. +if test "${with_c_glib+set}" = set; then : + withval=$with_c_glib; with_c_glib="$withval" +else + with_c_glib=yes + +fi + + have_c_glib=no + +if test "$with_c_glib" = "yes"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLIB" >&5 +$as_echo_n "checking for GLIB... " >&6; } + +if test -n "$GLIB_CFLAGS"; then + pkg_cv_GLIB_CFLAGS="$GLIB_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GLIB_CFLAGS=`$PKG_CONFIG --cflags "glib-2.0 >= 2.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$GLIB_LIBS"; then + pkg_cv_GLIB_LIBS="$GLIB_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GLIB_LIBS=`$PKG_CONFIG --libs "glib-2.0 >= 2.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + GLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "glib-2.0 >= 2.0" 2>&1` + else + GLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "glib-2.0 >= 2.0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$GLIB_PKG_ERRORS" >&5 + + have_glib2=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + have_glib2=no +else + GLIB_CFLAGS=$pkg_cv_GLIB_CFLAGS + GLIB_LIBS=$pkg_cv_GLIB_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + have_glib2=yes +fi + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GOBJECT" >&5 +$as_echo_n "checking for GOBJECT... " >&6; } + +if test -n "$GOBJECT_CFLAGS"; then + pkg_cv_GOBJECT_CFLAGS="$GOBJECT_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gobject-2.0 >= 2.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gobject-2.0 >= 2.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GOBJECT_CFLAGS=`$PKG_CONFIG --cflags "gobject-2.0 >= 2.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$GOBJECT_LIBS"; then + pkg_cv_GOBJECT_LIBS="$GOBJECT_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gobject-2.0 >= 2.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gobject-2.0 >= 2.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GOBJECT_LIBS=`$PKG_CONFIG --libs "gobject-2.0 >= 2.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + GOBJECT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gobject-2.0 >= 2.0" 2>&1` + else + GOBJECT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gobject-2.0 >= 2.0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$GOBJECT_PKG_ERRORS" >&5 + + have_gobject2=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + have_gobject2=no +else + GOBJECT_CFLAGS=$pkg_cv_GOBJECT_CFLAGS + GOBJECT_LIBS=$pkg_cv_GOBJECT_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + have_gobject2=yes +fi + if test "$have_glib2" = "yes" -a "$have_gobject2" = "yes" ; then + have_c_glib="yes" + fi +fi + if test "$have_glib2" = "yes" -a "$have_gobject2" = "yes"; then + WITH_C_GLIB_TRUE= + WITH_C_GLIB_FALSE='#' +else + WITH_C_GLIB_TRUE='#' + WITH_C_GLIB_FALSE= +fi + + +echo "OpenSSL check" +if test "$have_cpp" = "yes" -o "$have_c_glib" = "yes"; then + echo "Have cpp or c so we check for OpenSSL" + + found=false + +# Check whether --with-openssl was given. +if test "${with_openssl+set}" = set; then : + withval=$with_openssl; + case "$withval" in + "" | y | ye | yes | n | no) + as_fn_error $? "Invalid --with-openssl value" "$LINENO" 5 + ;; + *) ssldirs="$withval" + ;; + esac + +else + + # if pkg-config is installed and openssl has installed a .pc file, + # then use that information and don't search ssldirs + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PKG_CONFIG"; then + ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_PKG_CONFIG="${ac_tool_prefix}pkg-config" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +PKG_CONFIG=$ac_cv_prog_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_PKG_CONFIG"; then + ac_ct_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_PKG_CONFIG"; then + ac_cv_prog_ac_ct_PKG_CONFIG="$ac_ct_PKG_CONFIG" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_PKG_CONFIG="pkg-config" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_PKG_CONFIG=$ac_cv_prog_ac_ct_PKG_CONFIG +if test -n "$ac_ct_PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PKG_CONFIG" >&5 +$as_echo "$ac_ct_PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_ct_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_prog_PKG_CONFIG" +fi + + if test x"$PKG_CONFIG" != x""; then + OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` + if test $? = 0; then + OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` + OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` + found=true + fi + fi + + # no such luck; use some default ssldirs + if ! $found; then + ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" + fi + + +fi + + + + # note that we #include , so the OpenSSL headers have to be in + # an 'openssl' subdirectory + + if ! $found; then + OPENSSL_INCLUDES= + for ssldir in $ssldirs; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $ssldir" >&5 +$as_echo_n "checking for openssl/ssl.h in $ssldir... " >&6; } + if test -f "$ssldir/include/openssl/ssl.h"; then + OPENSSL_INCLUDES="-I$ssldir/include" + OPENSSL_LDFLAGS="-L$ssldir/lib" + OPENSSL_LIBS="-lssl -lcrypto" + found=true + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + done + + # if the file wasn't found, well, go ahead and try the link anyway -- maybe + # it will just work! + fi + + # try the preprocessor and linker with our new flags, + # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL works" >&5 +$as_echo_n "checking whether compiling and linking against OpenSSL works... " >&6; } + echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ + "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&5 + + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + save_CPPFLAGS="$CPPFLAGS" + LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" + LIBS="$OPENSSL_LIBS $LIBS" + CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +SSL_new(NULL) + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + + + + + +fi + + + +# Check whether --with-csharp was given. +if test "${with_csharp+set}" = set; then : + withval=$with_csharp; with_csharp="$withval" +else + with_csharp=yes + +fi + + have_csharp=no + +if test "$with_csharp" = "yes"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for MONO" >&5 +$as_echo_n "checking for MONO... " >&6; } + +if test -n "$MONO_CFLAGS"; then + pkg_cv_MONO_CFLAGS="$MONO_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"mono >= 2.11.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "mono >= 2.11.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_MONO_CFLAGS=`$PKG_CONFIG --cflags "mono >= 2.11.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$MONO_LIBS"; then + pkg_cv_MONO_LIBS="$MONO_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"mono >= 2.11.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "mono >= 2.11.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_MONO_LIBS=`$PKG_CONFIG --libs "mono >= 2.11.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + MONO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "mono >= 2.11.0" 2>&1` + else + MONO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "mono >= 2.11.0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$MONO_PKG_ERRORS" >&5 + + mono_2_11=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + mono_2_11=no +else + MONO_CFLAGS=$pkg_cv_MONO_CFLAGS + MONO_LIBS=$pkg_cv_MONO_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + mono_2_11=yes +fi + if test "$mono_2_11" == "yes"; then + # Extract the first word of "mcs", so it can be a program name with args. +set dummy mcs; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_MCS+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MCS in + [\\/]* | ?:[\\/]*) + ac_cv_path_MCS="$MCS" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_MCS="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +MCS=$ac_cv_path_MCS +if test -n "$MCS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MCS" >&5 +$as_echo "$MCS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$MCS" != "x"; then + mono_mcs="yes" + fi + fi + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for MONO" >&5 +$as_echo_n "checking for MONO... " >&6; } + +if test -n "$MONO_CFLAGS"; then + pkg_cv_MONO_CFLAGS="$MONO_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"mono >= 2.0.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "mono >= 2.0.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_MONO_CFLAGS=`$PKG_CONFIG --cflags "mono >= 2.0.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$MONO_LIBS"; then + pkg_cv_MONO_LIBS="$MONO_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"mono >= 2.0.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "mono >= 2.0.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_MONO_LIBS=`$PKG_CONFIG --libs "mono >= 2.0.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + MONO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "mono >= 2.0.0" 2>&1` + else + MONO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "mono >= 2.0.0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$MONO_PKG_ERRORS" >&5 + + net_3_5=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + net_3_5=no +else + MONO_CFLAGS=$pkg_cv_MONO_CFLAGS + MONO_LIBS=$pkg_cv_MONO_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + net_3_5=yes +fi + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for MONO" >&5 +$as_echo_n "checking for MONO... " >&6; } + +if test -n "$MONO_CFLAGS"; then + pkg_cv_MONO_CFLAGS="$MONO_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"mono >= 1.2.4\""; } >&5 + ($PKG_CONFIG --exists --print-errors "mono >= 1.2.4") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_MONO_CFLAGS=`$PKG_CONFIG --cflags "mono >= 1.2.4" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$MONO_LIBS"; then + pkg_cv_MONO_LIBS="$MONO_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"mono >= 1.2.4\""; } >&5 + ($PKG_CONFIG --exists --print-errors "mono >= 1.2.4") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_MONO_LIBS=`$PKG_CONFIG --libs "mono >= 1.2.4" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + MONO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "mono >= 1.2.4" 2>&1` + else + MONO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "mono >= 1.2.4" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$MONO_PKG_ERRORS" >&5 + + have_mono=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + have_mono=no +else + MONO_CFLAGS=$pkg_cv_MONO_CFLAGS + MONO_LIBS=$pkg_cv_MONO_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + have_mono=yes +fi + if test "$have_mono" = "yes" ; then + have_csharp="yes" + fi +fi + if test "$have_csharp" = "yes"; then + WITH_MONO_TRUE= + WITH_MONO_FALSE='#' +else + WITH_MONO_TRUE='#' + WITH_MONO_FALSE= +fi + + if test "$net_3_5" = "no"; then + NET_2_0_TRUE= + NET_2_0_FALSE='#' +else + NET_2_0_TRUE='#' + NET_2_0_FALSE= +fi + + if test "$mono_mcs" = "yes"; then + MONO_MCS_TRUE= + MONO_MCS_FALSE='#' +else + MONO_MCS_TRUE='#' + MONO_MCS_FALSE= +fi + + + + +# Check whether --with-java was given. +if test "${with_java+set}" = set; then : + withval=$with_java; with_java="$withval" +else + with_java=yes + +fi + + have_java=no + +if test "$with_java" = "yes"; then + + + JAVAC_PROGS="javac,jikes,gcj -C" + JAVA_PROGS="java,kaffe" + + if test -n "$JAVAC" ; then + JAVAC_PROGS="$JAVAC" + fi + if test -n "$JAVA" ; then + JAVA_PROGS="$JAVA" + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for javac and java" >&5 +$as_echo_n "checking for javac and java... " >&6; } + + echo "public class configtest_ax_javac_and_java { public static void main(String args[]) { } }" > configtest_ax_javac_and_java.java + success=no + oIFS="$IFS" + + IFS="," + for JAVAC in $JAVAC_PROGS ; do + IFS="$oIFS" + + echo "Running \"$JAVAC configtest_ax_javac_and_java.java\"" >&5 + if $JAVAC configtest_ax_javac_and_java.java >&5 2>&1 ; then + + # prevent $JAVA VM issues with UTF-8 path names (THRIFT-3271) + oLC_ALL="$LC_ALL" + LC_ALL="" + + IFS="," + for JAVA in $JAVA_PROGS ; do + IFS="$oIFS" + + echo "Running \"$JAVA configtest_ax_javac_and_java\"" >&5 + if $JAVA configtest_ax_javac_and_java >&5 2>&1 ; then + success=yes + break 2 + fi + + done + + # restore LC_ALL + LC_ALL="$oLC_ALL" + oLC_ALL="" + + fi + + done + + rm -f configtest_ax_javac_and_java.java configtest_ax_javac_and_java.class + + if test "$success" != "yes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + JAVAC="" + JAVA="" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi + + ax_javac_and_java="$success" + + + # Extract the first word of "ant", so it can be a program name with args. +set dummy ant; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ANT+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ANT in + [\\/]* | ?:[\\/]*) + ac_cv_path_ANT="$ANT" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ANT="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ANT=$ac_cv_path_ANT +if test -n "$ANT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ANT" >&5 +$as_echo "$ANT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ant version > 1.7" >&5 +$as_echo_n "checking for ant version > 1.7... " >&6; } + ANT_VALID=`expr "x$(printf "1.7\n$($ANT -version 2>/dev/null | sed -n 's/.*version \([0-9\.]*\).*/\1/p')" | sort -t '.' -k 1,1 -k 2,2 -k 3,3 -g | sed -n 1p)" = "x1.7"` + if test "x$ANT_VALID" = "x1" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ANT="" + fi + + + + if test "x$JAVA" != "x" && test "x$JAVAC" != "x" && test "x$ANT" != "x" ; then + have_java="yes" + fi +fi + if test "$have_java" = "yes"; then + WITH_JAVA_TRUE= + WITH_JAVA_FALSE='#' +else + WITH_JAVA_TRUE='#' + WITH_JAVA_FALSE= +fi + + + + +# Check whether --with-erlang was given. +if test "${with_erlang+set}" = set; then : + withval=$with_erlang; with_erlang="$withval" +else + with_erlang=yes + +fi + + have_erlang=no + +if test "$with_erlang" = "yes"; then + if test -n "$ERL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for erl" >&5 +$as_echo_n "checking for erl... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERL" >&5 +$as_echo "$ERL" >&6; } +else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}erl", so it can be a program name with args. +set dummy ${ac_tool_prefix}erl; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ERL+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ERL in + [\\/]* | ?:[\\/]*) + ac_cv_path_ERL="$ERL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ERL="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ERL=$ac_cv_path_ERL +if test -n "$ERL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERL" >&5 +$as_echo "$ERL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_ERL"; then + ac_pt_ERL=$ERL + # Extract the first word of "erl", so it can be a program name with args. +set dummy erl; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_ERL+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_ERL in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_ERL="$ac_pt_ERL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_ERL="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_ERL=$ac_cv_path_ac_pt_ERL +if test -n "$ac_pt_ERL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_ERL" >&5 +$as_echo "$ac_pt_ERL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_ERL" = x; then + ERL="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + ERL=$ac_pt_ERL + fi +else + ERL="$ac_cv_path_ERL" +fi +fi + + if test -n "$ERLC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for erlc" >&5 +$as_echo_n "checking for erlc... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERLC" >&5 +$as_echo "$ERLC" >&6; } +else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}erlc", so it can be a program name with args. +set dummy ${ac_tool_prefix}erlc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ERLC+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ERLC in + [\\/]* | ?:[\\/]*) + ac_cv_path_ERLC="$ERLC" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ERLC="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ERLC=$ac_cv_path_ERLC +if test -n "$ERLC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERLC" >&5 +$as_echo "$ERLC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_ERLC"; then + ac_pt_ERLC=$ERLC + # Extract the first word of "erlc", so it can be a program name with args. +set dummy erlc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_ERLC+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_ERLC in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_ERLC="$ac_pt_ERLC" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_ERLC="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_ERLC=$ac_cv_path_ac_pt_ERLC +if test -n "$ac_pt_ERLC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_ERLC" >&5 +$as_echo "$ac_pt_ERLC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_ERLC" = x; then + ERLC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + ERLC=$ac_pt_ERLC + fi +else + ERLC="$ac_cv_path_ERLC" +fi + +fi + + # Extract the first word of "rebar", so it can be a program name with args. +set dummy rebar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_REBAR+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $REBAR in + [\\/]* | ?:[\\/]*) + ac_cv_path_REBAR="$REBAR" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_REBAR="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +REBAR=$ac_cv_path_REBAR +if test -n "$REBAR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $REBAR" >&5 +$as_echo "$REBAR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test -n "$ERLC" ; then + if test -n "$ERLC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for erlc" >&5 +$as_echo_n "checking for erlc... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERLC" >&5 +$as_echo "$ERLC" >&6; } +else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}erlc", so it can be a program name with args. +set dummy ${ac_tool_prefix}erlc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ERLC+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ERLC in + [\\/]* | ?:[\\/]*) + ac_cv_path_ERLC="$ERLC" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ERLC="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ERLC=$ac_cv_path_ERLC +if test -n "$ERLC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERLC" >&5 +$as_echo "$ERLC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_ERLC"; then + ac_pt_ERLC=$ERLC + # Extract the first word of "erlc", so it can be a program name with args. +set dummy erlc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_ERLC+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_ERLC in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_ERLC="$ac_pt_ERLC" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_ERLC="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_ERLC=$ac_cv_path_ac_pt_ERLC +if test -n "$ac_pt_ERLC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_ERLC" >&5 +$as_echo "$ac_pt_ERLC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_ERLC" = x; then + ERLC="not found" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + ERLC=$ac_pt_ERLC + fi +else + ERLC="$ac_cv_path_ERLC" +fi + +fi + +if test "$ERLC" = "not found"; then + as_fn_error $? "Erlang/OTP compiler (erlc) not found but required" "$LINENO" 5 +fi + +if test -n "$ERL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for erl" >&5 +$as_echo_n "checking for erl... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERL" >&5 +$as_echo "$ERL" >&6; } +else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}erl", so it can be a program name with args. +set dummy ${ac_tool_prefix}erl; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ERL+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ERL in + [\\/]* | ?:[\\/]*) + ac_cv_path_ERL="$ERL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ERL="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ERL=$ac_cv_path_ERL +if test -n "$ERL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERL" >&5 +$as_echo "$ERL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_ERL"; then + ac_pt_ERL=$ERL + # Extract the first word of "erl", so it can be a program name with args. +set dummy erl; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_ERL+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_ERL in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_ERL="$ac_pt_ERL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_ERL="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_ERL=$ac_cv_path_ac_pt_ERL +if test -n "$ac_pt_ERL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_ERL" >&5 +$as_echo "$ac_pt_ERL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_ERL" = x; then + ERL="not found" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + ERL=$ac_pt_ERL + fi +else + ERL="$ac_cv_path_ERL" +fi +fi + +if test "$ERL" = "not found"; then + as_fn_error $? "Erlang/OTP interpreter (erl) not found but required" "$LINENO" 5 +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Erlang/OTP library base directory" >&5 +$as_echo_n "checking for Erlang/OTP library base directory... " >&6; } +if ${ac_cv_erlang_lib_dir+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=erl +ac_compile='$ERLC $ERLCFLAGS -b beam conftest.$ac_ext >&5' +ac_link='$ERLC $ERLCFLAGS -b beam conftest.$ac_ext >&5 && echo "#!/bin/sh" > conftest$ac_exeext && $as_echo "\"$ERL\" -run conftest start -run init stop -noshell" >> conftest$ac_exeext && chmod +x conftest$ac_exeext' + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat > conftest.$ac_ext <<_ACEOF +-module(conftest). +-export([start/0]). + +start() -> + LibDir = code:lib_dir(), + file:write_file("conftest.out", LibDir), + ReturnValue = 0, + halt(ReturnValue) +. + +_ACEOF +if ac_fn_erl_try_run "$LINENO"; then : + ac_cv_erlang_lib_dir=`cat conftest.out` + rm -f conftest.out +else + rm -f conftest.out + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "test Erlang program execution failed +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_erlang_lib_dir" >&5 +$as_echo "$ac_cv_erlang_lib_dir" >&6; } +ERLANG_LIB_DIR=$ac_cv_erlang_lib_dir + + + # Install into the detected Erlang directory instead of $libdir/erlang/lib + ERLANG_INSTALL_LIB_DIR="$ERLANG_LIB_DIR" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Erlang/OTP library installation base directory" >&5 +$as_echo_n "checking for Erlang/OTP library installation base directory... " >&6; } + +if test -n "$ERLANG_INSTALL_LIB_DIR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERLANG_INSTALL_LIB_DIR" >&5 +$as_echo "$ERLANG_INSTALL_LIB_DIR" >&6; } +else + ERLANG_INSTALL_LIB_DIR='${libdir}/erlang/lib' + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libdir/erlang/lib" >&5 +$as_echo "$libdir/erlang/lib" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Erlang/OTP 'thrift' library installation subdirectory" >&5 +$as_echo_n "checking for Erlang/OTP 'thrift' library installation subdirectory... " >&6; } + +if test -n "$ERLANG_INSTALL_LIB_DIR_thrift"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERLANG_INSTALL_LIB_DIR_thrift" >&5 +$as_echo "$ERLANG_INSTALL_LIB_DIR_thrift" >&6; } +else + ERLANG_INSTALL_LIB_DIR_thrift='${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0' + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERLANG_INSTALL_LIB_DIR/thrift-0.11.0" >&5 +$as_echo "$ERLANG_INSTALL_LIB_DIR/thrift-0.11.0" >&6; } +fi + + fi + if test -n "$ERL" -a -n "$ERLC" && test "x$REBAR" != "x" ; then + have_erlang="yes" + + # otp_release is simply a number (like "17") for OTP17+ while "R16..." for OTP16 or less. + # OTP version is currently only used for running tests. + if $ERL -eval 'erlang:display(erlang:system_info(otp_release)),halt().' -noshell | grep "^\"R" >/dev/null; then + erlang_otp16_or_less="yes" + fi + fi +fi + if test "$have_erlang" = "yes"; then + WITH_ERLANG_TRUE= + WITH_ERLANG_FALSE='#' +else + WITH_ERLANG_TRUE='#' + WITH_ERLANG_FALSE= +fi + + if test "$erlang_otp16_or_less" = "yes"; then + ERLANG_OTP16_TRUE= + ERLANG_OTP16_FALSE='#' +else + ERLANG_OTP16_TRUE='#' + ERLANG_OTP16_FALSE= +fi + + + + +# Check whether --with-nodejs was given. +if test "${with_nodejs+set}" = set; then : + withval=$with_nodejs; with_nodejs="$withval" +else + with_nodejs=yes + +fi + + have_nodejs=no + +have_nodejs=no +if test "$with_nodejs" = "yes"; then + for ac_prog in nodejs node +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_NODEJS+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $NODEJS in + [\\/]* | ?:[\\/]*) + ac_cv_path_NODEJS="$NODEJS" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_NODEJS="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +NODEJS=$ac_cv_path_NODEJS +if test -n "$NODEJS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NODEJS" >&5 +$as_echo "$NODEJS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$NODEJS" && break +done + + # Extract the first word of "npm", so it can be a program name with args. +set dummy npm; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_NPM+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $NPM in + [\\/]* | ?:[\\/]*) + ac_cv_path_NPM="$NPM" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_NPM="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +NPM=$ac_cv_path_NPM +if test -n "$NPM"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NPM" >&5 +$as_echo "$NPM" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$NODEJS" != "x" -a "x$NPM" != "x"; then + have_nodejs="yes" + fi +fi + if test "$have_nodejs" = "yes"; then + WITH_NODEJS_TRUE= + WITH_NODEJS_FALSE='#' +else + WITH_NODEJS_TRUE='#' + WITH_NODEJS_FALSE= +fi + + if test "x$NPM" != "x"; then + HAVE_NPM_TRUE= + HAVE_NPM_FALSE='#' +else + HAVE_NPM_TRUE='#' + HAVE_NPM_FALSE= +fi + + + + +# Check whether --with-lua was given. +if test "${with_lua+set}" = set; then : + withval=$with_lua; with_lua="$withval" +else + with_lua=yes + +fi + + have_lua=no + +have_lua=no +if test "$with_lua" = "yes"; then + + + + + + + + + if test "x$LUA" != 'x'; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $LUA is a Lua interpreter" >&5 +$as_echo_n "checking if $LUA is a Lua interpreter... " >&6; } + + _ax_lua_factorial=`$LUA 2>/dev/null -e ' + -- a simple factorial + function fact (n) + if n == 0 then + return 1 + else + return n * fact(n-1) + end + end + print("fact(5) is " .. fact(5))'` + if test "$_ax_lua_factorial" = 'fact(5) is 120'; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "not a Lua interpreter" "$LINENO" 5 + +fi + + _ax_check_text="whether $LUA version >= 5.2" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking $_ax_check_text" >&5 +$as_echo_n "checking $_ax_check_text... " >&6; } + + _ax_lua_good_version=`$LUA -e ' + -- a script to compare versions + function verstr2num(verstr) + local _, _, majorver, minorver = string.find(verstr, "^(%d+)%.(%d+)") + if majorver and minorver then + return tonumber(majorver) * 100 + tonumber(minorver) + end + end + local minver = verstr2num("5.2") + local _, _, trimver = string.find(_VERSION, "^Lua (.*)") + local ver = verstr2num(trimver) + local maxver = verstr2num("") or 1e9 + if minver <= ver and ver < maxver then + print("yes") + else + print("no") + end'` + if test "x$_ax_lua_good_version" = "xyes"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "version is out of range for specified LUA" "$LINENO" 5 +fi + + ax_display_LUA=$LUA + +else + _ax_check_text="for a Lua interpreter with version >= 5.2" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking $_ax_check_text" >&5 +$as_echo_n "checking $_ax_check_text... " >&6; } +if ${ax_cv_pathless_LUA+:} false; then : + $as_echo_n "(cached) " >&6 +else + for ax_cv_pathless_LUA in lua lua5.3 lua53 lua5.2 lua52 lua5.1 lua51 lua50 none; do + test "x$ax_cv_pathless_LUA" = 'xnone' && break + + _ax_lua_factorial=`$ax_cv_pathless_LUA 2>/dev/null -e ' + -- a simple factorial + function fact (n) + if n == 0 then + return 1 + else + return n * fact(n-1) + end + end + print("fact(5) is " .. fact(5))'` + if test "$_ax_lua_factorial" = 'fact(5) is 120'; then : + +else + continue +fi + + + _ax_lua_good_version=`$ax_cv_pathless_LUA -e ' + -- a script to compare versions + function verstr2num(verstr) + local _, _, majorver, minorver = string.find(verstr, "^(%d+)%.(%d+)") + if majorver and minorver then + return tonumber(majorver) * 100 + tonumber(minorver) + end + end + local minver = verstr2num("5.2") + local _, _, trimver = string.find(_VERSION, "^Lua (.*)") + local ver = verstr2num(trimver) + local maxver = verstr2num("") or 1e9 + if minver <= ver and ver < maxver then + print("yes") + else + print("no") + end'` + if test "x$_ax_lua_good_version" = "xyes"; then : + break +fi + + done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_pathless_LUA" >&5 +$as_echo "$ax_cv_pathless_LUA" >&6; } + if test "x$ax_cv_pathless_LUA" = 'xnone'; then : + LUA=':' +else + # Extract the first word of "$ax_cv_pathless_LUA", so it can be a program name with args. +set dummy $ax_cv_pathless_LUA; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_LUA+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $LUA in + [\\/]* | ?:[\\/]*) + ac_cv_path_LUA="$LUA" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_LUA="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +LUA=$ac_cv_path_LUA +if test -n "$LUA"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LUA" >&5 +$as_echo "$LUA" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi + ax_display_LUA=$ax_cv_pathless_LUA + +fi + + + if test "x$LUA" = 'x:'; then : + have_lua="no" + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA version" >&5 +$as_echo_n "checking for $ax_display_LUA version... " >&6; } +if ${ax_cv_lua_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_lua_version=`$LUA -e ' + -- return a version number in X.Y format + local _, _, ver = string.find(_VERSION, "^Lua (%d+%.%d+)") + print(ver)'` + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_version" >&5 +$as_echo "$ax_cv_lua_version" >&6; } + if test "x$ax_cv_lua_version" = 'x'; then : + as_fn_error $? "invalid Lua version number" "$LINENO" 5 +fi + LUA_VERSION=$ax_cv_lua_version + + LUA_SHORT_VERSION=`echo "$LUA_VERSION" | $SED 's|\.||'` + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA platform" >&5 +$as_echo_n "checking for $ax_display_LUA platform... " >&6; } +if ${ax_cv_lua_platform+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_lua_platform=`$LUA -e 'print("unknown")'` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_platform" >&5 +$as_echo "$ax_cv_lua_platform" >&6; } + LUA_PLATFORM=$ax_cv_lua_platform + + + LUA_PREFIX='${prefix}' + + LUA_EXEC_PREFIX='${exec_prefix}' + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA script directory" >&5 +$as_echo_n "checking for $ax_display_LUA script directory... " >&6; } +if ${ax_cv_lua_luadir+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$prefix" = 'xNONE'; then : + ax_lua_prefix=$ac_default_prefix +else + ax_lua_prefix=$prefix +fi + + ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION" + + + + ax_lua_prefixed_path=`$LUA -e ' + -- get the path based on search type + local searchtype = "script" + local paths = "" + if searchtype == "script" then + paths = (package and package.path) or LUA_PATH + elseif searchtype == "module" then + paths = (package and package.cpath) or LUA_CPATH + end + -- search for the prefix + local prefix = "'$ax_lua_prefix'" + local minpath = "" + local mindepth = 1e9 + string.gsub(paths, "([^;]+)", + function (path) + path = string.gsub(path, "%?.*$", "") + path = string.gsub(path, "/[^/]*$", "") + if string.find(path, prefix) then + local depth = string.len(string.gsub(path, "[^/]", "")) + if depth < mindepth then + minpath = path + mindepth = depth + end + end + end) + print(minpath)'` + + if test "x$ax_lua_prefixed_path" != 'x'; then : + _ax_strip_prefix=`echo "$ax_lua_prefix" | $SED 's|.|.|g'` + ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \ + $SED "s|^$_ax_strip_prefix|$LUA_PREFIX|"` + +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_luadir" >&5 +$as_echo "$ax_cv_lua_luadir" >&6; } + luadir=$ax_cv_lua_luadir + + pkgluadir=\${luadir}/$PACKAGE + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA module directory" >&5 +$as_echo_n "checking for $ax_display_LUA module directory... " >&6; } +if ${ax_cv_lua_luaexecdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$exec_prefix" = 'xNONE'; then : + ax_lua_exec_prefix=$ax_lua_prefix +else + ax_lua_exec_prefix=$exec_prefix +fi + + ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION" + + + + ax_lua_prefixed_path=`$LUA -e ' + -- get the path based on search type + local searchtype = "module" + local paths = "" + if searchtype == "script" then + paths = (package and package.path) or LUA_PATH + elseif searchtype == "module" then + paths = (package and package.cpath) or LUA_CPATH + end + -- search for the prefix + local prefix = "'$ax_lua_exec_prefix'" + local minpath = "" + local mindepth = 1e9 + string.gsub(paths, "([^;]+)", + function (path) + path = string.gsub(path, "%?.*$", "") + path = string.gsub(path, "/[^/]*$", "") + if string.find(path, prefix) then + local depth = string.len(string.gsub(path, "[^/]", "")) + if depth < mindepth then + minpath = path + mindepth = depth + end + end + end) + print(minpath)'` + + if test "x$ax_lua_prefixed_path" != 'x'; then : + _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | $SED 's|.|.|g'` + ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \ + $SED "s|^$_ax_strip_prefix|$LUA_EXEC_PREFIX|"` + +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_luaexecdir" >&5 +$as_echo "$ax_cv_lua_luaexecdir" >&6; } + luaexecdir=$ax_cv_lua_luaexecdir + + pkgluaexecdir=\${luaexecdir}/$PACKAGE + + + have_lua="yes" + +fi + + if test "$have_lua" = "yes"; then + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if LUA_VERSION is defined" >&5 +$as_echo_n "checking if LUA_VERSION is defined... " >&6; } + if test "x$LUA_VERSION" != 'x'; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "cannot check Lua headers without knowing LUA_VERSION" "$LINENO" 5 + +fi + + + + LUA_SHORT_VERSION=`echo "$LUA_VERSION" | $SED 's|\.||'` + + + _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" + for ac_header in lua.h lualib.h lauxlib.h luaconf.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + CPPFLAGS=$_ax_lua_saved_cppflags + + if test "x$LUA_INCLUDE" = 'x' && + test "x$ac_cv_header_lua_h" != 'xyes'; then : + for _ax_include_path in /usr/include/lua$LUA_VERSION \ + /usr/include/lua-$LUA_VERSION \ + /usr/include/lua/$LUA_VERSION \ + /usr/include/lua$LUA_SHORT_VERSION \ + /usr/local/include/lua$LUA_VERSION \ + /usr/local/include/lua-$LUA_VERSION \ + /usr/local/include/lua/$LUA_VERSION \ + /usr/local/include/lua$LUA_SHORT_VERSION \ + ; do + test ! -d "$_ax_include_path" && continue + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Lua headers in" >&5 +$as_echo_n "checking for Lua headers in... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_ax_include_path" >&5 +$as_echo "$_ax_include_path" >&6; } + + { ac_cv_header_lua_h=; unset ac_cv_header_lua_h;} + { ac_cv_header_lualib_h=; unset ac_cv_header_lualib_h;} + { ac_cv_header_lauxlib_h=; unset ac_cv_header_lauxlib_h;} + { ac_cv_header_luaconf_h=; unset ac_cv_header_luaconf_h;} + + _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS -I$_ax_include_path" + for ac_header in lua.h lualib.h lauxlib.h luaconf.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + CPPFLAGS=$_ax_lua_saved_cppflags + + if test "x$ac_cv_header_lua_h" = 'xyes'; then : + LUA_INCLUDE="-I$_ax_include_path" + break + +fi + done + +fi + + if test "x$ac_cv_header_lua_h" = 'xyes'; then : + + if test "x$cross_compiling" != 'xyes'; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Lua header version" >&5 +$as_echo_n "checking for Lua header version... " >&6; } +if ${ax_cv_lua_header_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +int main(int argc, char ** argv) +{ + if(argc > 1) printf("%s", LUA_VERSION); + exit(EXIT_SUCCESS); +} + + +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + ax_cv_lua_header_version=`./conftest$EXEEXT p | \ + $SED -n "s|^Lua \([0-9]\{1,\}\.[0-9]\{1,\}\).\{0,\}|\1|p"` + +else + ax_cv_lua_header_version='unknown' +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CPPFLAGS=$_ax_lua_saved_cppflags + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_header_version" >&5 +$as_echo "$ax_cv_lua_header_version" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Lua header version matches $LUA_VERSION" >&5 +$as_echo_n "checking if Lua header version matches $LUA_VERSION... " >&6; } + if test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ax_header_version_match='yes' + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ax_header_version_match='no' + +fi + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling so assuming header version number matches" >&5 +$as_echo "$as_me: WARNING: cross compiling so assuming header version number matches" >&2;} + ax_header_version_match='yes' + +fi + +fi + + if test "x$ax_header_version_match" != 'xyes' && + test "x$LUA_INCLUDE" != 'x'; then : + as_fn_error $? "cannot find headers for specified LUA_INCLUDE" "$LINENO" 5 +fi + + if test "x$ax_header_version_match" = 'xyes'; then : + +else + have_lua="no" +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if LUA_VERSION is defined" >&5 +$as_echo_n "checking if LUA_VERSION is defined... " >&6; } + if test "x$LUA_VERSION" != 'x'; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "cannot check Lua libs without knowing LUA_VERSION" "$LINENO" 5 + +fi + + + + if test "x$LUA_LIB" != 'x'; then : + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing lua_load" >&5 +$as_echo_n "checking for library containing lua_load... " >&6; } +if ${ac_cv_search_lua_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char lua_load (); +int +main () +{ +return lua_load (); + ; + return 0; +} +_ACEOF +for ac_lib in '' ; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_search_lua_load=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_lua_load+:} false; then : + break +fi +done +if ${ac_cv_search_lua_load+:} false; then : + +else + ac_cv_search_lua_load=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_lua_load" >&5 +$as_echo "$ac_cv_search_lua_load" >&6; } +ac_res=$ac_cv_search_lua_load +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + _ax_found_lua_libs='yes' +else + _ax_found_lua_libs='no' +fi + + LIBS=$_ax_lua_saved_libs + + if test "x$_ax_found_lua_libs" != 'xyes'; then : + as_fn_error $? "cannot find libs for specified LUA_LIB" "$LINENO" 5 +fi + +else + _ax_lua_extra_libs='' + + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing exp" >&5 +$as_echo_n "checking for library containing exp... " >&6; } +if ${ac_cv_search_exp+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char exp (); +int +main () +{ +return exp (); + ; + return 0; +} +_ACEOF +for ac_lib in '' m; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_search_exp=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_exp+:} false; then : + break +fi +done +if ${ac_cv_search_exp+:} false; then : + +else + ac_cv_search_exp=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_exp" >&5 +$as_echo "$ac_cv_search_exp" >&6; } +ac_res=$ac_cv_search_exp +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 +$as_echo_n "checking for library containing dlopen... " >&6; } +if ${ac_cv_search_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +for ac_lib in '' dl; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_search_dlopen=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_dlopen+:} false; then : + break +fi +done +if ${ac_cv_search_dlopen+:} false; then : + +else + ac_cv_search_dlopen=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 +$as_echo "$ac_cv_search_dlopen" >&6; } +ac_res=$ac_cv_search_dlopen +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + LIBS=$_ax_lua_saved_libs + + if test "x$ac_cv_search_exp" != 'xno' && + test "x$ac_cv_search_exp" != 'xnone required'; then : + _ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp" +fi + + if test "x$ac_cv_search_dlopen" != 'xno' && + test "x$ac_cv_search_dlopen" != 'xnone required'; then : + _ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen" +fi + + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing lua_load" >&5 +$as_echo_n "checking for library containing lua_load... " >&6; } +if ${ac_cv_search_lua_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char lua_load (); +int +main () +{ +return lua_load (); + ; + return 0; +} +_ACEOF +for ac_lib in '' lua$LUA_VERSION \ + lua$LUA_SHORT_VERSION \ + lua-$LUA_VERSION \ + lua-$LUA_SHORT_VERSION \ + lua \ + ; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $_ax_lua_extra_libs $ac_func_search_save_LIBS" + fi + if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_search_lua_load=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_lua_load+:} false; then : + break +fi +done +if ${ac_cv_search_lua_load+:} false; then : + +else + ac_cv_search_lua_load=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_lua_load" >&5 +$as_echo "$ac_cv_search_lua_load" >&6; } +ac_res=$ac_cv_search_lua_load +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + _ax_found_lua_libs='yes' +else + _ax_found_lua_libs='no' +fi + + LIBS=$_ax_lua_saved_libs + + if test "x$ac_cv_search_lua_load" != 'xno' && + test "x$ac_cv_search_lua_load" != 'xnone required'; then : + LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs" +fi + +fi + + if test "x$_ax_found_lua_libs" = 'xyes'; then : + +else + have_lua="no" +fi + + fi +fi + if test "$have_lua" = "yes"; then + WITH_LUA_TRUE= + WITH_LUA_FALSE='#' +else + WITH_LUA_TRUE='#' + WITH_LUA_FALSE= +fi + + +# Find python regardless of with_python value, because it's needed by make cross + + + + + + + if test -n "$PYTHON"; then + # If the user set $PYTHON, use it and don't search something else. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $PYTHON version is >= 2.6" >&5 +$as_echo_n "checking whether $PYTHON version is >= 2.6... " >&6; } + prog="import sys +# split strings by '.' and convert to numeric. Append some zeros +# because we need at least 4 digits for the hex conversion. +# map returns an iterator in Python 3.0 and a list in 2.x +minver = list(map(int, '2.6'.split('.'))) + [0, 0, 0] +minverhex = 0 +# xrange is not present in Python 3.0 and range returns an iterator +for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i] +sys.exit(sys.hexversion < minverhex)" + if { echo "$as_me:$LINENO: $PYTHON -c "$prog"" >&5 + ($PYTHON -c "$prog") >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "Python interpreter is too old" "$LINENO" 5 +fi + am_display_PYTHON=$PYTHON + else + # Otherwise, try each interpreter until we find one that satisfies + # VERSION. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a Python interpreter with version >= 2.6" >&5 +$as_echo_n "checking for a Python interpreter with version >= 2.6... " >&6; } +if ${am_cv_pathless_PYTHON+:} false; then : + $as_echo_n "(cached) " >&6 +else + + for am_cv_pathless_PYTHON in python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do + test "$am_cv_pathless_PYTHON" = none && break + prog="import sys +# split strings by '.' and convert to numeric. Append some zeros +# because we need at least 4 digits for the hex conversion. +# map returns an iterator in Python 3.0 and a list in 2.x +minver = list(map(int, '2.6'.split('.'))) + [0, 0, 0] +minverhex = 0 +# xrange is not present in Python 3.0 and range returns an iterator +for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i] +sys.exit(sys.hexversion < minverhex)" + if { echo "$as_me:$LINENO: $am_cv_pathless_PYTHON -c "$prog"" >&5 + ($am_cv_pathless_PYTHON -c "$prog") >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then : + break +fi + done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_pathless_PYTHON" >&5 +$as_echo "$am_cv_pathless_PYTHON" >&6; } + # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. + if test "$am_cv_pathless_PYTHON" = none; then + PYTHON=: + else + # Extract the first word of "$am_cv_pathless_PYTHON", so it can be a program name with args. +set dummy $am_cv_pathless_PYTHON; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PYTHON+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PYTHON in + [\\/]* | ?:[\\/]*) + ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PYTHON=$ac_cv_path_PYTHON +if test -n "$PYTHON"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5 +$as_echo "$PYTHON" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + am_display_PYTHON=$am_cv_pathless_PYTHON + fi + + + if test "$PYTHON" = :; then + : + else + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON version" >&5 +$as_echo_n "checking for $am_display_PYTHON version... " >&6; } +if ${am_cv_python_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[:3])"` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_version" >&5 +$as_echo "$am_cv_python_version" >&6; } + PYTHON_VERSION=$am_cv_python_version + + + + PYTHON_PREFIX='${prefix}' + + PYTHON_EXEC_PREFIX='${exec_prefix}' + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON platform" >&5 +$as_echo_n "checking for $am_display_PYTHON platform... " >&6; } +if ${am_cv_python_platform+:} false; then : + $as_echo_n "(cached) " >&6 +else + am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_platform" >&5 +$as_echo "$am_cv_python_platform" >&6; } + PYTHON_PLATFORM=$am_cv_python_platform + + + # Just factor out some code duplication. + am_python_setup_sysconfig="\ +import sys +# Prefer sysconfig over distutils.sysconfig, for better compatibility +# with python 3.x. See automake bug#10227. +try: + import sysconfig +except ImportError: + can_use_sysconfig = 0 +else: + can_use_sysconfig = 1 +# Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs: +# +try: + from platform import python_implementation + if python_implementation() == 'CPython' and sys.version[:3] == '2.7': + can_use_sysconfig = 0 +except ImportError: + pass" + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON script directory" >&5 +$as_echo_n "checking for $am_display_PYTHON script directory... " >&6; } +if ${am_cv_python_pythondir+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$prefix" = xNONE + then + am_py_prefix=$ac_default_prefix + else + am_py_prefix=$prefix + fi + am_cv_python_pythondir=`$PYTHON -c " +$am_python_setup_sysconfig +if can_use_sysconfig: + sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) +else: + from distutils import sysconfig + sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') +sys.stdout.write(sitedir)"` + case $am_cv_python_pythondir in + $am_py_prefix*) + am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` + am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` + ;; + *) + case $am_py_prefix in + /usr|/System*) ;; + *) + am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages + ;; + esac + ;; + esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pythondir" >&5 +$as_echo "$am_cv_python_pythondir" >&6; } + pythondir=$am_cv_python_pythondir + + + + pkgpythondir=\${pythondir}/$PACKAGE + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON extension module directory" >&5 +$as_echo_n "checking for $am_display_PYTHON extension module directory... " >&6; } +if ${am_cv_python_pyexecdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$exec_prefix" = xNONE + then + am_py_exec_prefix=$am_py_prefix + else + am_py_exec_prefix=$exec_prefix + fi + am_cv_python_pyexecdir=`$PYTHON -c " +$am_python_setup_sysconfig +if can_use_sysconfig: + sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'}) +else: + from distutils import sysconfig + sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix') +sys.stdout.write(sitedir)"` + case $am_cv_python_pyexecdir in + $am_py_exec_prefix*) + am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` + am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` + ;; + *) + case $am_py_exec_prefix in + /usr|/System*) ;; + *) + am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages + ;; + esac + ;; + esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pyexecdir" >&5 +$as_echo "$am_cv_python_pyexecdir" >&6; } + pyexecdir=$am_cv_python_pyexecdir + + + + pkgpyexecdir=\${pyexecdir}/$PACKAGE + + + + fi + + + + +# Check whether --with-python was given. +if test "${with_python+set}" = set; then : + withval=$with_python; with_python="$withval" +else + with_python=yes + +fi + + have_python=no + +if test "$with_python" = "yes"; then + if test -n "$PYTHON"; then + have_python="yes" + fi + # Extract the first word of "trial", so it can be a program name with args. +set dummy trial; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_TRIAL+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $TRIAL in + [\\/]* | ?:[\\/]*) + ac_cv_path_TRIAL="$TRIAL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_TRIAL="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +TRIAL=$ac_cv_path_TRIAL +if test -n "$TRIAL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TRIAL" >&5 +$as_echo "$TRIAL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test -n "$TRIAL"; then + have_trial="yes" + fi +fi + if test "$have_python" = "yes"; then + WITH_PYTHON_TRUE= + WITH_PYTHON_FALSE='#' +else + WITH_PYTHON_TRUE='#' + WITH_PYTHON_FALSE= +fi + + if test "$have_trial" = "yes"; then + WITH_TWISTED_TEST_TRUE= + WITH_TWISTED_TEST_FALSE='#' +else + WITH_TWISTED_TEST_TRUE='#' + WITH_TWISTED_TEST_FALSE= +fi + + +# Find "python3" executable. +# It's distro specific and far from ideal but needed to cross test py2-3 at once. +# TODO: find "python2" if it's 3.x +have_py3="no" +if python --version 2>&1 | grep -q "Python 2"; then + for ac_prog in python3 python3.5 python35 python3.4 python34 +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PYTHON3+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PYTHON3 in + [\\/]* | ?:[\\/]*) + ac_cv_path_PYTHON3="$PYTHON3" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PYTHON3="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PYTHON3=$ac_cv_path_PYTHON3 +if test -n "$PYTHON3"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON3" >&5 +$as_echo "$PYTHON3" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$PYTHON3" && break +done + + if test -n "$PYTHON3"; then + have_py3="yes" + fi +fi + if test "$have_py3" = "yes"; then + WITH_PY3_TRUE= + WITH_PY3_FALSE='#' +else + WITH_PY3_TRUE='#' + WITH_PY3_FALSE= +fi + + + + +# Check whether --with-perl was given. +if test "${with_perl+set}" = set; then : + withval=$with_perl; with_perl="$withval" +else + with_perl=yes + +fi + + have_perl=no + +if test "$with_perl" = "yes"; then + # Extract the first word of "perl", so it can be a program name with args. +set dummy perl; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PERL+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PERL in + [\\/]* | ?:[\\/]*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PERL=$ac_cv_path_PERL +if test -n "$PERL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 +$as_echo "$PERL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test -n "$PERL" ; then + + + + + + +# Make sure we have perl +if test -z "$PERL"; then +# Extract the first word of "perl", so it can be a program name with args. +set dummy perl; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_PERL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PERL"; then + ac_cv_prog_PERL="$PERL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_PERL="perl" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +PERL=$ac_cv_prog_PERL +if test -n "$PERL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 +$as_echo "$PERL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi + +if test "x$PERL" != x; then + ax_perl_modules_failed=0 + for ax_perl_module in 'Bit::Vector' ; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for perl module $ax_perl_module" >&5 +$as_echo_n "checking for perl module $ax_perl_module... " >&6; } + + # Would be nice to log result here, but can't rely on autoconf internals + $PERL -e "use $ax_perl_module; exit" > /dev/null 2>&1 + if test $? -ne 0; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; + ax_perl_modules_failed=1 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; }; + fi + done + + # Run optional shell commands + if test "$ax_perl_modules_failed" = 0; then + : + success="yes" + else + : + success="no" + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not find perl" >&5 +$as_echo "$as_me: WARNING: could not find perl" >&2;} +fi + have_perl_bit_vector="$success" + + + + + + +# Make sure we have perl +if test -z "$PERL"; then +# Extract the first word of "perl", so it can be a program name with args. +set dummy perl; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_PERL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PERL"; then + ac_cv_prog_PERL="$PERL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_PERL="perl" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +PERL=$ac_cv_prog_PERL +if test -n "$PERL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 +$as_echo "$PERL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi + +if test "x$PERL" != x; then + ax_perl_modules_failed=0 + for ax_perl_module in 'Class::Accessor' ; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for perl module $ax_perl_module" >&5 +$as_echo_n "checking for perl module $ax_perl_module... " >&6; } + + # Would be nice to log result here, but can't rely on autoconf internals + $PERL -e "use $ax_perl_module; exit" > /dev/null 2>&1 + if test $? -ne 0; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; + ax_perl_modules_failed=1 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; }; + fi + done + + # Run optional shell commands + if test "$ax_perl_modules_failed" = 0; then + : + success="yes" + else + : + success="no" + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not find perl" >&5 +$as_echo "$as_me: WARNING: could not find perl" >&2;} +fi + have_perl_class_accessor="$success" + fi + if test -n "$PERL" -a "$have_perl_bit_vector" = "yes" ; then + if test -n "$PERL" -a "$have_perl_class_accessor" = "yes" ; then + have_perl="yes" + fi + fi +fi + if test "$have_perl" = "yes"; then + WITH_PERL_TRUE= + WITH_PERL_FALSE='#' +else + WITH_PERL_TRUE='#' + WITH_PERL_FALSE= +fi + + + + +# Check whether --with-php was given. +if test "${with_php+set}" = set; then : + withval=$with_php; with_php="$withval" +else + with_php=yes + +fi + + have_php=no + +if test "$with_php" = "yes"; then + # Extract the first word of "php", so it can be a program name with args. +set dummy php; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PHP+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PHP in + [\\/]* | ?:[\\/]*) + ac_cv_path_PHP="$PHP" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PHP="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PHP=$ac_cv_path_PHP +if test -n "$PHP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PHP" >&5 +$as_echo "$PHP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test -n "$PHP" ; then + have_php="yes" + fi +fi + if test "$have_php" = "yes"; then + WITH_PHP_TRUE= + WITH_PHP_FALSE='#' +else + WITH_PHP_TRUE='#' + WITH_PHP_FALSE= +fi + + + + +# Check whether --with-php_extension was given. +if test "${with_php_extension+set}" = set; then : + withval=$with_php_extension; with_php_extension="$withval" +else + with_php_extension=yes + +fi + + have_php_extension=no + +if test "$with_php_extension" = "yes"; then + if test -f "lib/php/src/ext/thrift_protocol/configure"; then + # Extract the first word of "php-config", so it can be a program name with args. +set dummy php-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PHP_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PHP_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PHP_CONFIG="$PHP_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PHP_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PHP_CONFIG=$ac_cv_path_PHP_CONFIG +if test -n "$PHP_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PHP_CONFIG" >&5 +$as_echo "$PHP_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test -n "$PHP_CONFIG" ; then + + +subdirs="$subdirs lib/php/src/ext/thrift_protocol" + + have_php_extension="yes" + fi + fi +fi + if test "$have_php_extension" = "yes"; then + WITH_PHP_EXTENSION_TRUE= + WITH_PHP_EXTENSION_FALSE='#' +else + WITH_PHP_EXTENSION_TRUE='#' + WITH_PHP_EXTENSION_FALSE= +fi + + +# Extract the first word of "phpunit", so it can be a program name with args. +set dummy phpunit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PHPUNIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PHPUNIT in + [\\/]* | ?:[\\/]*) + ac_cv_path_PHPUNIT="$PHPUNIT" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PHPUNIT="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PHPUNIT=$ac_cv_path_PHPUNIT +if test -n "$PHPUNIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PHPUNIT" >&5 +$as_echo "$PHPUNIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$PHPUNIT" != "x"; then + HAVE_PHPUNIT_TRUE= + HAVE_PHPUNIT_FALSE='#' +else + HAVE_PHPUNIT_TRUE='#' + HAVE_PHPUNIT_FALSE= +fi + + + + +# Check whether --with-dart was given. +if test "${with_dart+set}" = set; then : + withval=$with_dart; with_dart="$withval" +else + with_dart=yes + +fi + + have_dart=no + +if test "$with_dart" = "yes"; then + # Extract the first word of "dart", so it can be a program name with args. +set dummy dart; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_DART+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $DART in + [\\/]* | ?:[\\/]*) + ac_cv_path_DART="$DART" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_DART="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +DART=$ac_cv_path_DART +if test -n "$DART"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DART" >&5 +$as_echo "$DART" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + # Extract the first word of "pub", so it can be a program name with args. +set dummy pub; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_DARTPUB+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $DARTPUB in + [\\/]* | ?:[\\/]*) + ac_cv_path_DARTPUB="$DARTPUB" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_DARTPUB="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +DARTPUB=$ac_cv_path_DARTPUB +if test -n "$DARTPUB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DARTPUB" >&5 +$as_echo "$DARTPUB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$DART" != "x" -a "x$DARTPUB" != "x"; then + have_dart="yes" + fi +fi + if test "$have_dart" = "yes"; then + WITH_DART_TRUE= + WITH_DART_FALSE='#' +else + WITH_DART_TRUE='#' + WITH_DART_FALSE= +fi + + + + +# Check whether --with-ruby was given. +if test "${with_ruby+set}" = set; then : + withval=$with_ruby; with_ruby="$withval" +else + with_ruby=yes + +fi + + have_ruby=no + +have_ruby=no +if test "$with_ruby" = "yes"; then + # Extract the first word of "ruby", so it can be a program name with args. +set dummy ruby; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_RUBY+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $RUBY in + [\\/]* | ?:[\\/]*) + ac_cv_path_RUBY="$RUBY" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_RUBY="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +RUBY=$ac_cv_path_RUBY +if test -n "$RUBY"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY" >&5 +$as_echo "$RUBY" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + # Extract the first word of "bundle", so it can be a program name with args. +set dummy bundle; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_BUNDLER+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $BUNDLER in + [\\/]* | ?:[\\/]*) + ac_cv_path_BUNDLER="$BUNDLER" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_BUNDLER="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +BUNDLER=$ac_cv_path_BUNDLER +if test -n "$BUNDLER"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUNDLER" >&5 +$as_echo "$BUNDLER" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$RUBY" != "x" -a "x$BUNDLER" != "x"; then + have_ruby="yes" + fi +fi + if test "$have_ruby" = "yes"; then + WITH_RUBY_TRUE= + WITH_RUBY_FALSE='#' +else + WITH_RUBY_TRUE='#' + WITH_RUBY_FALSE= +fi + + if test "x$BUNDLER" != "x"; then + HAVE_BUNDLER_TRUE= + HAVE_BUNDLER_FALSE='#' +else + HAVE_BUNDLER_TRUE='#' + HAVE_BUNDLER_FALSE= +fi + + + + +# Check whether --with-haskell was given. +if test "${with_haskell+set}" = set; then : + withval=$with_haskell; with_haskell="$withval" +else + with_haskell=yes + +fi + + have_haskell=no + +have_haskell=no +RUNHASKELL=true +CABAL=true +if test "$with_haskell" = "yes"; then + # Extract the first word of "cabal", so it can be a program name with args. +set dummy cabal; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_CABAL+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $CABAL in + [\\/]* | ?:[\\/]*) + ac_cv_path_CABAL="$CABAL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_CABAL="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +CABAL=$ac_cv_path_CABAL +if test -n "$CABAL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CABAL" >&5 +$as_echo "$CABAL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + # Extract the first word of "runhaskell", so it can be a program name with args. +set dummy runhaskell; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_RUNHASKELL+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $RUNHASKELL in + [\\/]* | ?:[\\/]*) + ac_cv_path_RUNHASKELL="$RUNHASKELL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_RUNHASKELL="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +RUNHASKELL=$ac_cv_path_RUNHASKELL +if test -n "$RUNHASKELL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUNHASKELL" >&5 +$as_echo "$RUNHASKELL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$CABAL" != "x" -a "x$RUNHASKELL" != "x"; then + have_haskell="yes" + else + RUNHASKELL=true + CABAL=true + fi +fi + + + if test "$have_haskell" = "yes"; then + WITH_HASKELL_TRUE= + WITH_HASKELL_FALSE='#' +else + WITH_HASKELL_TRUE='#' + WITH_HASKELL_FALSE= +fi + + + + +# Check whether --with-go was given. +if test "${with_go+set}" = set; then : + withval=$with_go; with_go="$withval" +else + with_go=yes + +fi + + have_go=no + +if test "$with_go" = "yes"; then + # Extract the first word of "go", so it can be a program name with args. +set dummy go; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_GO+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $GO in + [\\/]* | ?:[\\/]*) + ac_cv_path_GO="$GO" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_GO="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +GO=$ac_cv_path_GO +if test -n "$GO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GO" >&5 +$as_echo "$GO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if [ -x "$GO" ] ; then + if test -n "$GO"; then : + + ax_go_version="1.4" + ax_go17_version="1.7" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Go version" >&5 +$as_echo_n "checking for Go version... " >&6; } + golang_version=`$GO version 2>&1 | $SED -e 's/\(go \)\(version \)\(go\)\([0-9].[0-9].[0-9]\)\([\*]*\).*/\4/'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $golang_version" >&5 +$as_echo "$golang_version" >&6; } + golang_version=$golang_version + + + + + # Used to indicate true or false condition + ax_compare_version=false + + # Convert the two version strings to be compared into a format that + # allows a simple string comparison. The end result is that a version + # string of the form 1.12.5-r617 will be converted to the form + # 0001001200050617. In other words, each number is zero padded to four + # digits, and non digits are removed. + + ax_compare_version_A=`echo "$ax_go_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ + -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/[^0-9]//g'` + + + ax_compare_version_B=`echo "$golang_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ + -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/[^0-9]//g'` + + + ax_compare_version=`echo "x$ax_compare_version_A +x$ax_compare_version_B" | sed 's/^ *//' | sort | sed "s/x${ax_compare_version_A}/true/;s/x${ax_compare_version_B}/false/;1q"` + + + + if test "$ax_compare_version" = "true" ; then + + : + have_go="yes" + + else + : + have_go="no" + + fi + + + + + # Used to indicate true or false condition + ax_compare_version=false + + # Convert the two version strings to be compared into a format that + # allows a simple string comparison. The end result is that a version + # string of the form 1.12.5-r617 will be converted to the form + # 0001001200050617. In other words, each number is zero padded to four + # digits, and non digits are removed. + + ax_compare_version_A=`echo "$golang_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ + -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/[^0-9]//g'` + + + ax_compare_version_B=`echo "$ax_go17_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ + -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/[^0-9]//g'` + + + ax_compare_version=`echo "x$ax_compare_version_A +x$ax_compare_version_B" | sed 's/^ *//' | sort -r | sed "s/x${ax_compare_version_A}/false/;s/x${ax_compare_version_B}/true/;1q"` + + + + if test "$ax_compare_version" = "true" ; then + + : + go_version_lt_17="yes" + + else + : + go_version_lt_17="no" + + fi + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not find Go " >&5 +$as_echo "$as_me: WARNING: could not find Go " >&2;} + have_go="no" + +fi + fi +fi + if test "$have_go" = "yes"; then + WITH_GO_TRUE= + WITH_GO_FALSE='#' +else + WITH_GO_TRUE='#' + WITH_GO_FALSE= +fi + + if test "$go_version_lt_17" = "yes"; then + GOVERSION_LT_17_TRUE= + GOVERSION_LT_17_FALSE='#' +else + GOVERSION_LT_17_TRUE='#' + GOVERSION_LT_17_FALSE= +fi + + + + +# Check whether --with-rs was given. +if test "${with_rs+set}" = set; then : + withval=$with_rs; with_rs="$withval" +else + with_rs=yes + +fi + + have_rs=no + +have_rs="no" +if test "$with_rs" = "yes"; then + # Extract the first word of "cargo", so it can be a program name with args. +set dummy cargo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_CARGO+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $CARGO in + [\\/]* | ?:[\\/]*) + ac_cv_path_CARGO="$CARGO" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_CARGO="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +CARGO=$ac_cv_path_CARGO +if test -n "$CARGO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CARGO" >&5 +$as_echo "$CARGO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + # Extract the first word of "rustc", so it can be a program name with args. +set dummy rustc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_RUSTC+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $RUSTC in + [\\/]* | ?:[\\/]*) + ac_cv_path_RUSTC="$RUSTC" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_RUSTC="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +RUSTC=$ac_cv_path_RUSTC +if test -n "$RUSTC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUSTC" >&5 +$as_echo "$RUSTC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if [ -x "$CARGO" ] && [ -x "$RUSTC" ]; then + min_rustc_version="1.13" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rustc version" >&5 +$as_echo_n "checking for rustc version... " >&6; } + rustc_version=`$RUSTC --version 2>&1 | $SED -e 's/\(rustc \)\(0-9\)\.\(0-90-9*\)\.\(0-90-9*\).*/\2.\3/'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rustc_version" >&5 +$as_echo "$rustc_version" >&6; } + rustc_version=$rustc_version + + + + + + # Used to indicate true or false condition + ax_compare_version=false + + # Convert the two version strings to be compared into a format that + # allows a simple string comparison. The end result is that a version + # string of the form 1.12.5-r617 will be converted to the form + # 0001001200050617. In other words, each number is zero padded to four + # digits, and non digits are removed. + + ax_compare_version_A=`echo "$min_rustc_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ + -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/[^0-9]//g'` + + + ax_compare_version_B=`echo "$rustc_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ + -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/[^0-9]//g'` + + + ax_compare_version=`echo "x$ax_compare_version_A +x$ax_compare_version_B" | sed 's/^ *//' | sort | sed "s/x${ax_compare_version_A}/true/;s/x${ax_compare_version_B}/false/;1q"` + + + + if test "$ax_compare_version" = "true" ; then + + : + have_rs="yes" + + else + : + have_rs="no" + + fi + + fi +fi + if test "$have_rs" = "yes"; then + WITH_RS_TRUE= + WITH_RS_FALSE='#' +else + WITH_RS_TRUE='#' + WITH_RS_FALSE= +fi + + + + +# Check whether --with-haxe was given. +if test "${with_haxe+set}" = set; then : + withval=$with_haxe; with_haxe="$withval" +else + with_haxe=yes + +fi + + have_haxe=no + +if test "$with_haxe" = "yes"; then + # Extract the first word of "haxe", so it can be a program name with args. +set dummy haxe; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_HAXE+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $HAXE in + [\\/]* | ?:[\\/]*) + ac_cv_path_HAXE="$HAXE" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_HAXE="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +HAXE=$ac_cv_path_HAXE +if test -n "$HAXE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAXE" >&5 +$as_echo "$HAXE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if [ -x "$HAXE" ] ; then + + + + if test -n "$HAXE"; then : + + ax_haxe_version="3.1.3" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for haxe version" >&5 +$as_echo_n "checking for haxe version... " >&6; } + haxe_version=`$HAXE -version 2>&1 | $SED -e 's/^.* \( [0-9]*\.[0-9]*\.[0-9]*\) .*/\1/'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $haxe_version" >&5 +$as_echo "$haxe_version" >&6; } + + HAXE_VERSION=$haxe_version + + + + + + # Used to indicate true or false condition + ax_compare_version=false + + # Convert the two version strings to be compared into a format that + # allows a simple string comparison. The end result is that a version + # string of the form 1.12.5-r617 will be converted to the form + # 0001001200050617. In other words, each number is zero padded to four + # digits, and non digits are removed. + + ax_compare_version_A=`echo "$ax_haxe_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ + -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/[^0-9]//g'` + + + ax_compare_version_B=`echo "$haxe_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ + -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/[^0-9]//g'` + + + ax_compare_version=`echo "x$ax_compare_version_A +x$ax_compare_version_B" | sed 's/^ *//' | sort | sed "s/x${ax_compare_version_A}/true/;s/x${ax_compare_version_B}/false/;1q"` + + + + if test "$ax_compare_version" = "true" ; then + + : + have_haxe="yes" + + else + : + have_haxe="no" + + fi + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not find Haxe" >&5 +$as_echo "$as_me: WARNING: could not find Haxe" >&2;} + have_haxe="no" + +fi + + fi +fi + if test "$have_haxe" = "yes"; then + WITH_HAXE_TRUE= + WITH_HAXE_FALSE='#' +else + WITH_HAXE_TRUE='#' + WITH_HAXE_FALSE= +fi + + + + + +# Check whether --with-dotnetcore was given. +if test "${with_dotnetcore+set}" = set; then : + withval=$with_dotnetcore; with_dotnetcore="$withval" +else + with_dotnetcore=yes + +fi + + have_dotnetcore=no + +if test "$with_dotnetcore" = "yes"; then + # Extract the first word of "dotnet", so it can be a program name with args. +set dummy dotnet; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_DOTNETCORE+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $DOTNETCORE in + [\\/]* | ?:[\\/]*) + ac_cv_path_DOTNETCORE="$DOTNETCORE" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_DOTNETCORE="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +DOTNETCORE=$ac_cv_path_DOTNETCORE +if test -n "$DOTNETCORE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DOTNETCORE" >&5 +$as_echo "$DOTNETCORE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if [ -x "$DOTNETCORE" ] ; then + + + + if test -n "$DOTNETCORE"; then : + + ax_dotnetcore_version="2.0.0" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for .NET Core version" >&5 +$as_echo_n "checking for .NET Core version... " >&6; } + dotnetcore_version=`$DOTNETCORE --version 2>&1 | $SED -e 's/\([0-9]*\.[0-9]*\.[0-9]*\)\(.*\)/\1/'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dotnetcore_version" >&5 +$as_echo "$dotnetcore_version" >&6; } + + DOTNETCORE_VERSION=$dotnetcore_version + + + + + + # Used to indicate true or false condition + ax_compare_version=false + + # Convert the two version strings to be compared into a format that + # allows a simple string comparison. The end result is that a version + # string of the form 1.12.5-r617 will be converted to the form + # 0001001200050617. In other words, each number is zero padded to four + # digits, and non digits are removed. + + ax_compare_version_A=`echo "$ax_dotnetcore_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ + -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/[^0-9]//g'` + + + ax_compare_version_B=`echo "$dotnetcore_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ + -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/[^0-9]//g'` + + + ax_compare_version=`echo "x$ax_compare_version_A +x$ax_compare_version_B" | sed 's/^ *//' | sort | sed "s/x${ax_compare_version_A}/true/;s/x${ax_compare_version_B}/false/;1q"` + + + + if test "$ax_compare_version" = "true" ; then + + : + have_dotnetcore="yes" + + else + : + have_dotnetcore="no" + + fi + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not find .NET Core" >&5 +$as_echo "$as_me: WARNING: could not find .NET Core" >&2;} + have_dotnetcore="no" + +fi + + fi +fi + if test "$have_dotnetcore" = "yes"; then + WITH_DOTNETCORE_TRUE= + WITH_DOTNETCORE_FALSE='#' +else + WITH_DOTNETCORE_TRUE='#' + WITH_DOTNETCORE_FALSE= +fi + + + + + +# Check whether --with-d was given. +if test "${with_d+set}" = set; then : + withval=$with_d; with_d="$withval" +else + with_d=yes + +fi + + have_d=no + +if test "$with_d" = "yes"; then + + DMD_PROGS="dmd,gdmd,ldmd" + + if test -n "$DMD" ; then + DMD_PROGS="$DMD" + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DMD" >&5 +$as_echo_n "checking for DMD... " >&6; } + + # std.algorithm as a quick way to check for D2/Phobos. + echo "import std.algorithm; void main() {}" > configtest_ax_dmd.d + success=no + oIFS="$IFS" + + IFS="," + for DMD in $DMD_PROGS ; do + IFS="$oIFS" + + echo "Running \"$DMD configtest_ax_dmd.d\"" >&5 + if $DMD configtest_ax_dmd.d >&5 2>&1 ; then + success=yes + break + fi + done + + if test "$success" != "yes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + DMD="" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi + + ax_dmd="$success" + + # Test whether OPTLINK is used by trying if DMD accepts -L/? without + # erroring out. + if test "$success" == "yes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether DMD uses OPTLINK" >&5 +$as_echo_n "checking whether DMD uses OPTLINK... " >&6; } + echo "Running \”$DMD -L/? configtest_ax_dmd.d\"" >&5 + if $DMD -L/? configtest_ax_dmd.d >&5 2>&1 ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + dmd_optlink="yes" + + # This actually produces double slashes in the final configure + # output, but at least it works. + dmd_of_dirsep="\\\\" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + dmd_optlink="no" + dmd_of_dirsep="/" + fi + fi + + rm -f configtest_ax_dmd* + + + if test "x$DMD" != "x"; then + have_d="yes" + fi +fi + +# Determine actual name of the generated D library for use in the command line +# when compiling tests. This is needed because the -l syntax doesn't work +# with OPTLINK (Windows). +lib_prefix=lib +lib_suffix=a +case "$host_os" in + cygwin* | mingw* | pw32* | cegcc*) + lib_prefix="" + lib_suffix=lib + ;; +esac +D_LIB_NAME="${lib_prefix}thriftd.${lib_suffix}" + +D_EVENT_LIB_NAME="${lib_prefix}thriftd-event.${lib_suffix}" + +D_SSL_LIB_NAME="${lib_prefix}thriftd-ssl.${lib_suffix}" + + +if test "$have_d" = "yes"; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for D module deimos.event2.event" >&5 +$as_echo_n "checking for D module deimos.event2.event... " >&6; } + + echo "import deimos.event2.event; void main() {}" > configtest_ax_dmd.d + + echo "Running \"$DMD configtest_ax_dmd.d\"" >&5 + if $DMD -c configtest_ax_dmd.d >&5 2>&1 ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + success=yes + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + success=no + fi + + rm -f configtest_ax_dmd* + + have_deimos_event2=$success + + with_d_event_tests="no" + if test "$have_deimos_event2" = "yes"; then + if test "x$DMD_LIBEVENT_FLAGS" = "x"; then + if test "$dmd_optlink" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: D libevent interface found, but cannot auto-detect \ +linker flags for OPTLINK. Please set DMD_LIBEVENT_FLAGS manually." >&5 +$as_echo "$as_me: WARNING: D libevent interface found, but cannot auto-detect \ +linker flags for OPTLINK. Please set DMD_LIBEVENT_FLAGS manually." >&2;} + else + + + +# Check whether --with-libevent was given. +if test "${with_libevent+set}" = set; then : + withval=$with_libevent; + if test "x$withval" = "xno"; then + want_libevent="no" + elif test "x$withval" = "xyes"; then + want_libevent="yes" + ax_libevent_path="" + else + want_libevent="yes" + ax_libevent_path="$withval" + fi + +else + want_libevent="yes" ; ax_libevent_path="" +fi + + + + if test "$want_libevent" = "yes"; then + WANT_LIBEVENT_VERSION=2.0 + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libevent >= $WANT_LIBEVENT_VERSION" >&5 +$as_echo_n "checking for libevent >= $WANT_LIBEVENT_VERSION... " >&6; } + + # Run tests. + if test -n "$ax_libevent_path"; then + + # Save our flags. + CPPFLAGS_SAVED="$CPPFLAGS" + LDFLAGS_SAVED="$LDFLAGS" + LIBS_SAVED="$LIBS" + LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH" + + # Set our flags if we are checking a specific directory. + if test -n "$ax_libevent_path" ; then + LIBEVENT_CPPFLAGS="-I$ax_libevent_path/include" + LIBEVENT_LDFLAGS="-L$ax_libevent_path/lib" + LD_LIBRARY_PATH="$ax_libevent_path/lib:$LD_LIBRARY_PATH" + else + LIBEVENT_CPPFLAGS="" + LIBEVENT_LDFLAGS="" + fi + + # Required flag for libevent. + LIBEVENT_LIBS="-levent" + + # Prepare the environment for compilation. + CPPFLAGS="$CPPFLAGS $LIBEVENT_CPPFLAGS" + LDFLAGS="$LDFLAGS $LIBEVENT_LDFLAGS" + LIBS="$LIBS $LIBEVENT_LIBS" + export CPPFLAGS + export LDFLAGS + export LIBS + export LD_LIBRARY_PATH + + success=no + + # Compile, link, and run the program. This checks: + # - event.h is available for including. + # - event_get_version() is available for linking. + # - The event version string is lexicographically greater + # than the required version. + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main () +{ + + const char* lib_version = event_get_version(); + const char* wnt_version = "$WANT_LIBEVENT_VERSION"; + int lib_digits; + int wnt_digits; + for (;;) { + /* If we reached the end of the want version. We have it. */ + if (*wnt_version == '\0' || *wnt_version == '-') { + return 0; + } + /* If the want version continues but the lib version does not, */ + /* we are missing a letter. We don't have it. */ + if (*lib_version == '\0' || *lib_version == '-') { + return 1; + } + /* In the 1.4 version numbering style, if there are more digits */ + /* in one version than the other, that one is higher. */ + for (lib_digits = 0; + lib_version[lib_digits] >= '0' && + lib_version[lib_digits] <= '9'; + lib_digits++) + ; + for (wnt_digits = 0; + wnt_version[wnt_digits] >= '0' && + wnt_version[wnt_digits] <= '9'; + wnt_digits++) + ; + if (lib_digits > wnt_digits) { + return 0; + } + if (lib_digits < wnt_digits) { + return 1; + } + /* If we have greater than what we want. We have it. */ + if (*lib_version > *wnt_version) { + return 0; + } + /* If we have less, we don't. */ + if (*lib_version < *wnt_version) { + return 1; + } + lib_version++; + wnt_version++; + } + return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + success=yes + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + # Restore flags. + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + LIBS="$LIBS_SAVED" + LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED" + + else + for ax_libevent_path in "" $lt_sysroot/usr $lt_sysroot/usr/local $lt_sysroot/opt $lt_sysroot/opt/local $lt_sysroot/opt/libevent "$LIBEVENT_ROOT" ; do + + # Save our flags. + CPPFLAGS_SAVED="$CPPFLAGS" + LDFLAGS_SAVED="$LDFLAGS" + LIBS_SAVED="$LIBS" + LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH" + + # Set our flags if we are checking a specific directory. + if test -n "$ax_libevent_path" ; then + LIBEVENT_CPPFLAGS="-I$ax_libevent_path/include" + LIBEVENT_LDFLAGS="-L$ax_libevent_path/lib" + LD_LIBRARY_PATH="$ax_libevent_path/lib:$LD_LIBRARY_PATH" + else + LIBEVENT_CPPFLAGS="" + LIBEVENT_LDFLAGS="" + fi + + # Required flag for libevent. + LIBEVENT_LIBS="-levent" + + # Prepare the environment for compilation. + CPPFLAGS="$CPPFLAGS $LIBEVENT_CPPFLAGS" + LDFLAGS="$LDFLAGS $LIBEVENT_LDFLAGS" + LIBS="$LIBS $LIBEVENT_LIBS" + export CPPFLAGS + export LDFLAGS + export LIBS + export LD_LIBRARY_PATH + + success=no + + # Compile, link, and run the program. This checks: + # - event.h is available for including. + # - event_get_version() is available for linking. + # - The event version string is lexicographically greater + # than the required version. + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main () +{ + + const char* lib_version = event_get_version(); + const char* wnt_version = "$WANT_LIBEVENT_VERSION"; + int lib_digits; + int wnt_digits; + for (;;) { + /* If we reached the end of the want version. We have it. */ + if (*wnt_version == '\0' || *wnt_version == '-') { + return 0; + } + /* If the want version continues but the lib version does not, */ + /* we are missing a letter. We don't have it. */ + if (*lib_version == '\0' || *lib_version == '-') { + return 1; + } + /* In the 1.4 version numbering style, if there are more digits */ + /* in one version than the other, that one is higher. */ + for (lib_digits = 0; + lib_version[lib_digits] >= '0' && + lib_version[lib_digits] <= '9'; + lib_digits++) + ; + for (wnt_digits = 0; + wnt_version[wnt_digits] >= '0' && + wnt_version[wnt_digits] <= '9'; + wnt_digits++) + ; + if (lib_digits > wnt_digits) { + return 0; + } + if (lib_digits < wnt_digits) { + return 1; + } + /* If we have greater than what we want. We have it. */ + if (*lib_version > *wnt_version) { + return 0; + } + /* If we have less, we don't. */ + if (*lib_version < *wnt_version) { + return 1; + } + lib_version++; + wnt_version++; + } + return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + success=yes + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + # Restore flags. + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + LIBS="$LIBS_SAVED" + LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED" + + if test "$success" = "yes"; then + break; + fi + done + fi + + if test "$success" != "yes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + LIBEVENT_CPPFLAGS="" + LIBEVENT_LDFLAGS="" + LIBEVENT_LIBS="" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_LIBEVENT /**/" >>confdefs.h + + ax_have_libevent_2_0="yes" + fi + + ax_have_libevent="$success" + + + + + fi + + + if test "$success" = "yes"; then + DMD_LIBEVENT_FLAGS=$(echo "$LIBEVENT_LDFLAGS $LIBEVENT_LIBS" | \ + sed -e 's/^ *//g;s/ *$//g;s/^\(.\)/-L\1/g;s/ */ -L/g') + with_d_event_tests="yes" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: D libevent interface present, but libevent library not found." >&5 +$as_echo "$as_me: WARNING: D libevent interface present, but libevent library not found." >&2;} + fi + fi + else + with_d_event_tests="yes" + fi + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for D module deimos.openssl.ssl" >&5 +$as_echo_n "checking for D module deimos.openssl.ssl... " >&6; } + + echo "import deimos.openssl.ssl; void main() {}" > configtest_ax_dmd.d + + echo "Running \"$DMD configtest_ax_dmd.d\"" >&5 + if $DMD -c configtest_ax_dmd.d >&5 2>&1 ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + success=yes + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + success=no + fi + + rm -f configtest_ax_dmd* + + have_deimos_openssl=$success + + with_d_ssl_tests="no" + if test "$have_deimos_openssl" = "yes"; then + if test "x$DMD_OPENSSL_FLAGS" = "x"; then + if test "$dmd_optlink" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: D OpenSSL interface found, but cannot auto-detect \ +linker flags for OPTLINK. Please set DMD_OPENSSL_FLAGS manually." >&5 +$as_echo "$as_me: WARNING: D OpenSSL interface found, but cannot auto-detect \ +linker flags for OPTLINK. Please set DMD_OPENSSL_FLAGS manually." >&2;} + else + + found=false + +# Check whether --with-openssl was given. +if test "${with_openssl+set}" = set; then : + withval=$with_openssl; + case "$withval" in + "" | y | ye | yes | n | no) + as_fn_error $? "Invalid --with-openssl value" "$LINENO" 5 + ;; + *) ssldirs="$withval" + ;; + esac + +else + + # if pkg-config is installed and openssl has installed a .pc file, + # then use that information and don't search ssldirs + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PKG_CONFIG"; then + ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_PKG_CONFIG="${ac_tool_prefix}pkg-config" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +PKG_CONFIG=$ac_cv_prog_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_PKG_CONFIG"; then + ac_ct_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_PKG_CONFIG"; then + ac_cv_prog_ac_ct_PKG_CONFIG="$ac_ct_PKG_CONFIG" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_PKG_CONFIG="pkg-config" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_PKG_CONFIG=$ac_cv_prog_ac_ct_PKG_CONFIG +if test -n "$ac_ct_PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PKG_CONFIG" >&5 +$as_echo "$ac_ct_PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_ct_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_prog_PKG_CONFIG" +fi + + if test x"$PKG_CONFIG" != x""; then + OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` + if test $? = 0; then + OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` + OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` + found=true + fi + fi + + # no such luck; use some default ssldirs + if ! $found; then + ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" + fi + + +fi + + + + # note that we #include , so the OpenSSL headers have to be in + # an 'openssl' subdirectory + + if ! $found; then + OPENSSL_INCLUDES= + for ssldir in $ssldirs; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $ssldir" >&5 +$as_echo_n "checking for openssl/ssl.h in $ssldir... " >&6; } + if test -f "$ssldir/include/openssl/ssl.h"; then + OPENSSL_INCLUDES="-I$ssldir/include" + OPENSSL_LDFLAGS="-L$ssldir/lib" + OPENSSL_LIBS="-lssl -lcrypto" + found=true + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + done + + # if the file wasn't found, well, go ahead and try the link anyway -- maybe + # it will just work! + fi + + # try the preprocessor and linker with our new flags, + # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL works" >&5 +$as_echo_n "checking whether compiling and linking against OpenSSL works... " >&6; } + echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ + "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&5 + + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + save_CPPFLAGS="$CPPFLAGS" + LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" + LIBS="$OPENSSL_LIBS $LIBS" + CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +SSL_new(NULL) + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + with_d_ssl_tests="yes" + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + + + + + + if test "$with_d_ssl_tests" = "yes"; then + DMD_OPENSSL_FLAGS=$(echo "$OPENSSL_LDFLAGS $OPENSSL_LIBS" | \ + sed -e 's/^ *//g;s/ *$//g;s/^\(.\)/-L\1/g;s/ */ -L/g') + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: D OpenSSL interface present, but OpenSSL library not found." >&5 +$as_echo "$as_me: WARNING: D OpenSSL interface present, but OpenSSL library not found." >&2;} + fi + fi + else + with_d_ssl_tests="yes" + fi + fi +fi + + if test "$have_d" = "yes"; then + WITH_D_TRUE= + WITH_D_FALSE='#' +else + WITH_D_TRUE='#' + WITH_D_FALSE= +fi + + if test "$dmd_optlink" = "yes"; then + DMD_OPTLINK_TRUE= + DMD_OPTLINK_FALSE='#' +else + DMD_OPTLINK_TRUE='#' + DMD_OPTLINK_FALSE= +fi + +DMD_OF_DIRSEP="$dmd_of_dirsep" + + if test "$have_deimos_event2" = "yes"; then + HAVE_DEIMOS_EVENT2_TRUE= + HAVE_DEIMOS_EVENT2_FALSE='#' +else + HAVE_DEIMOS_EVENT2_TRUE='#' + HAVE_DEIMOS_EVENT2_FALSE= +fi + + if test "$with_d_event_tests" = "yes"; then + WITH_D_EVENT_TESTS_TRUE= + WITH_D_EVENT_TESTS_FALSE='#' +else + WITH_D_EVENT_TESTS_TRUE='#' + WITH_D_EVENT_TESTS_FALSE= +fi + + + if test "$have_deimos_openssl" = "yes"; then + HAVE_DEIMOS_OPENSSL_TRUE= + HAVE_DEIMOS_OPENSSL_FALSE='#' +else + HAVE_DEIMOS_OPENSSL_TRUE='#' + HAVE_DEIMOS_OPENSSL_FALSE= +fi + + if test "$with_d_ssl_tests" = "yes"; then + WITH_D_SSL_TESTS_TRUE= + WITH_D_SSL_TESTS_FALSE='#' +else + WITH_D_SSL_TESTS_TRUE='#' + WITH_D_SSL_TESTS_FALSE= +fi + + + +# Check whether --enable-tests was given. +if test "${enable_tests+set}" = set; then : + enableval=$enable_tests; +else + enable_tests=yes + +fi + +have_tests=yes +if test "$enable_tests" = "no"; then + have_tests="no" +fi + if test "$have_tests" = "yes"; then + WITH_TESTS_TRUE= + WITH_TESTS_FALSE='#' +else + WITH_TESTS_TRUE='#' + WITH_TESTS_FALSE= +fi + + +# Check whether --enable-plugin was given. +if test "${enable_plugin+set}" = set; then : + enableval=$enable_plugin; +else + enable_plugin=no + +fi + +have_plugin=yes +if test "$have_cpp" = "no" ; then + have_plugin="no" +fi +if test "$enable_plugin" = "no"; then + have_plugin="no" +fi +ac_config_links="$ac_config_links compiler/cpp/test/plugin/t_cpp_generator.cc:compiler/cpp/src/thrift/generate/t_cpp_generator.cc" + + if test "$have_plugin" = "yes"; then + WITH_PLUGIN_TRUE= + WITH_PLUGIN_FALSE='#' +else + WITH_PLUGIN_TRUE='#' + WITH_PLUGIN_FALSE= +fi + + +# Check whether --enable-tutorial was given. +if test "${enable_tutorial+set}" = set; then : + enableval=$enable_tutorial; +else + enable_tutorial=yes + +fi + +have_tutorial=yes +if test "$enable_tutorial" = "no"; then + have_tutorial="no" +fi + if test "$have_tutorial" = "yes"; then + WITH_TUTORIAL_TRUE= + WITH_TUTORIAL_FALSE='#' +else + WITH_TUTORIAL_TRUE='#' + WITH_TUTORIAL_FALSE= +fi + + + if false; then + MINGW_TRUE= + MINGW_FALSE='#' +else + MINGW_TRUE='#' + MINGW_FALSE= +fi + +case "${host_os}" in +*mingw*) + mingw32_support="yes" + ac_fn_cxx_check_header_mongrel "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default" +if test "x$ac_cv_header_windows_h" = xyes; then : + +fi + + + if true; then + MINGW_TRUE= + MINGW_FALSE='#' +else + MINGW_TRUE='#' + MINGW_FALSE= +fi + + ;; +*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5 +$as_echo_n "checking for library containing strerror... " >&6; } +if ${ac_cv_search_strerror+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char strerror (); +int +main () +{ +return strerror (); + ; + return 0; +} +_ACEOF +for ac_lib in '' cposix; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_search_strerror=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_strerror+:} false; then : + break +fi +done +if ${ac_cv_search_strerror+:} false; then : + +else + ac_cv_search_strerror=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_strerror" >&5 +$as_echo "$ac_cv_search_strerror" >&6; } +ac_res=$ac_cv_search_strerror +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 +$as_echo_n "checking for an ANSI C-conforming const... " >&6; } +if ${ac_cv_c_const+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + +#ifndef __cplusplus + /* Ultrix mips cc rejects this sort of thing. */ + typedef int charset[2]; + const charset cs = { 0, 0 }; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *pcpcc; + char **ppc; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + pcpcc = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++pcpcc; + ppc = (char**) pcpcc; + pcpcc = (char const *const *) ppc; + { /* SCO 3.2v4 cc rejects this sort of thing. */ + char tx; + char *t = &tx; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; } bx; + struct s *b = &bx; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !cs[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_c_const=yes +else + ac_cv_c_const=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 +$as_echo "$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +$as_echo "#define const /**/" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if ${ac_cv_c_inline+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_c_inline=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 +$as_echo "$ac_cv_c_inline" >&6; } + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working volatile" >&5 +$as_echo_n "checking for working volatile... " >&6; } +if ${ac_cv_c_volatile+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + +volatile int x; +int * volatile y = (int *) 0; +return !x && !y; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_c_volatile=yes +else + ac_cv_c_volatile=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_volatile" >&5 +$as_echo "$ac_cv_c_volatile" >&6; } +if test $ac_cv_c_volatile = no; then + +$as_echo "#define volatile /**/" >>confdefs.h + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 +$as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } +if ${ac_cv_header_stdbool_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #ifndef bool + "error: bool is not defined" + #endif + #ifndef false + "error: false is not defined" + #endif + #if false + "error: false is not 0" + #endif + #ifndef true + "error: true is not defined" + #endif + #if true != 1 + "error: true is not 1" + #endif + #ifndef __bool_true_false_are_defined + "error: __bool_true_false_are_defined is not defined" + #endif + + struct s { _Bool s: 1; _Bool t; } s; + + char a[true == 1 ? 1 : -1]; + char b[false == 0 ? 1 : -1]; + char c[__bool_true_false_are_defined == 1 ? 1 : -1]; + char d[(bool) 0.5 == true ? 1 : -1]; + /* See body of main program for 'e'. */ + char f[(_Bool) 0.0 == false ? 1 : -1]; + char g[true]; + char h[sizeof (_Bool)]; + char i[sizeof s.t]; + enum { j = false, k = true, l = false * true, m = true * 256 }; + /* The following fails for + HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ + _Bool n[m]; + char o[sizeof n == m * sizeof n[0] ? 1 : -1]; + char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; + /* Catch a bug in an HP-UX C compiler. See + http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html + http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html + */ + _Bool q = true; + _Bool *pq = &q; + +int +main () +{ + + bool e = &s; + *pq |= q; + *pq |= ! q; + /* Refer to every declared value, to avoid compiler optimizations. */ + return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l + + !m + !n + !o + !p + !q + !pq); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_header_stdbool_h=yes +else + ac_cv_header_stdbool_h=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 +$as_echo "$ac_cv_header_stdbool_h" >&6; } + ac_fn_cxx_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" +if test "x$ac_cv_type__Bool" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE__BOOL 1 +_ACEOF + + +fi + + +if test $ac_cv_header_stdbool_h = yes; then + +$as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 +$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } +if ${ac_cv_header_time+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +if ((struct tm *) 0) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_header_time=yes +else + ac_cv_header_time=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 +$as_echo "$ac_cv_header_time" >&6; } +if test $ac_cv_header_time = yes; then + +$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 +$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } +if ${ac_cv_header_sys_wait_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +int +main () +{ + int s; + wait (&s); + s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_header_sys_wait_h=yes +else + ac_cv_header_sys_wait_h=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 +$as_echo "$ac_cv_header_sys_wait_h" >&6; } +if test $ac_cv_header_sys_wait_h = yes; then + +$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 +$as_echo_n "checking return type of signal handlers... " >&6; } +if ${ac_cv_type_signal+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include + +int +main () +{ +return *(signal (0, 0)) (0) == 1; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_type_signal=int +else + ac_cv_type_signal=void +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 +$as_echo "$ac_cv_type_signal" >&6; } + +cat >>confdefs.h <<_ACEOF +#define RETSIGTYPE $ac_cv_type_signal +_ACEOF + + +for ac_header in arpa/inet.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "$ac_includes_default" +if test "x$ac_cv_header_arpa_inet_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ARPA_INET_H 1 +_ACEOF + +fi + +done + +for ac_header in sys/param.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_param_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_PARAM_H 1 +_ACEOF + +fi + +done + +for ac_header in fcntl.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default" +if test "x$ac_cv_header_fcntl_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FCNTL_H 1 +_ACEOF + +fi + +done + +for ac_header in inttypes.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "inttypes.h" "ac_cv_header_inttypes_h" "$ac_includes_default" +if test "x$ac_cv_header_inttypes_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_INTTYPES_H 1 +_ACEOF + +fi + +done + +for ac_header in limits.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" +if test "x$ac_cv_header_limits_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIMITS_H 1 +_ACEOF + +fi + +done + +for ac_header in netdb.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default" +if test "x$ac_cv_header_netdb_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_NETDB_H 1 +_ACEOF + +fi + +done + +for ac_header in netinet/in.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "$ac_includes_default" +if test "x$ac_cv_header_netinet_in_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_NETINET_IN_H 1 +_ACEOF + +fi + +done + +for ac_header in pthread.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PTHREAD_H 1 +_ACEOF + +fi + +done + +for ac_header in stddef.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "stddef.h" "ac_cv_header_stddef_h" "$ac_includes_default" +if test "x$ac_cv_header_stddef_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDDEF_H 1 +_ACEOF + +fi + +done + +for ac_header in stdlib.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" +if test "x$ac_cv_header_stdlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDLIB_H 1 +_ACEOF + +fi + +done + +for ac_header in sys/socket.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_socket_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_SOCKET_H 1 +_ACEOF + +fi + +done + +for ac_header in sys/time.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_time_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_TIME_H 1 +_ACEOF + +fi + +done + +for ac_header in sys/un.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_un_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_UN_H 1 +_ACEOF + +fi + +done + +for ac_header in sys/poll.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_poll_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_POLL_H 1 +_ACEOF + +fi + +done + +for ac_header in sys/resource.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "sys/resource.h" "ac_cv_header_sys_resource_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_resource_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_RESOURCE_H 1 +_ACEOF + +fi + +done + +for ac_header in unistd.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" +if test "x$ac_cv_header_unistd_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_UNISTD_H 1 +_ACEOF + +fi + +done + +for ac_header in libintl.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "libintl.h" "ac_cv_header_libintl_h" "$ac_includes_default" +if test "x$ac_cv_header_libintl_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBINTL_H 1 +_ACEOF + +fi + +done + +for ac_header in malloc.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default" +if test "x$ac_cv_header_malloc_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MALLOC_H 1 +_ACEOF + +fi + +done + +for ac_header in openssl/ssl.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_ssl_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_OPENSSL_SSL_H 1 +_ACEOF + +fi + +done + +for ac_header in openssl/rand.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "openssl/rand.h" "ac_cv_header_openssl_rand_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_rand_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_OPENSSL_RAND_H 1 +_ACEOF + +fi + +done + +for ac_header in openssl/x509v3.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "openssl/x509v3.h" "ac_cv_header_openssl_x509v3_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_x509v3_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_OPENSSL_X509V3_H 1 +_ACEOF + +fi + +done + +for ac_header in sched.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "sched.h" "ac_cv_header_sched_h" "$ac_includes_default" +if test "x$ac_cv_header_sched_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SCHED_H 1 +_ACEOF + +fi + +done + +for ac_header in wchar.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" +if test "x$ac_cv_header_wchar_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_WCHAR_H 1 +_ACEOF + +fi + +done + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +$as_echo_n "checking for pthread_create in -lpthread... " >&6; } +if ${ac_cv_lib_pthread_pthread_create+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_create (); +int +main () +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_lib_pthread_pthread_create=yes +else + ac_cv_lib_pthread_pthread_create=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPTHREAD 1 +_ACEOF + + LIBS="-lpthread $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +$as_echo_n "checking for clock_gettime in -lrt... " >&6; } +if ${ac_cv_lib_rt_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_lib_rt_clock_gettime=yes +else + ac_cv_lib_rt_clock_gettime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBRT 1 +_ACEOF + + LIBS="-lrt $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for setsockopt in -lsocket" >&5 +$as_echo_n "checking for setsockopt in -lsocket... " >&6; } +if ${ac_cv_lib_socket_setsockopt+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char setsockopt (); +int +main () +{ +return setsockopt (); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_lib_socket_setsockopt=yes +else + ac_cv_lib_socket_setsockopt=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_setsockopt" >&5 +$as_echo "$ac_cv_lib_socket_setsockopt" >&6; } +if test "x$ac_cv_lib_socket_setsockopt" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + + +ac_fn_c_find_intX_t "$LINENO" "16" "ac_cv_c_int16_t" +case $ac_cv_c_int16_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int16_t $ac_cv_c_int16_t +_ACEOF +;; +esac + +ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t" +case $ac_cv_c_int32_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int32_t $ac_cv_c_int32_t +_ACEOF +;; +esac + +ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t" +case $ac_cv_c_int64_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int64_t $ac_cv_c_int64_t +_ACEOF +;; +esac + +ac_fn_c_find_intX_t "$LINENO" "8" "ac_cv_c_int8_t" +case $ac_cv_c_int8_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int8_t $ac_cv_c_int8_t +_ACEOF +;; +esac + +ac_fn_cxx_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" +if test "x$ac_cv_type_mode_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define mode_t int +_ACEOF + +fi + +ac_fn_cxx_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" +if test "x$ac_cv_type_off_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define off_t long int +_ACEOF + +fi + +ac_fn_cxx_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +ac_fn_cxx_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" +if test "x$ac_cv_type_ssize_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define ssize_t int +_ACEOF + +fi + +ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" +case $ac_cv_c_uint16_t in #( + no|yes) ;; #( + *) + + +cat >>confdefs.h <<_ACEOF +#define uint16_t $ac_cv_c_uint16_t +_ACEOF +;; + esac + +ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" +case $ac_cv_c_uint32_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT32_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint32_t $ac_cv_c_uint32_t +_ACEOF +;; + esac + +ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t" +case $ac_cv_c_uint64_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT64_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint64_t $ac_cv_c_uint64_t +_ACEOF +;; + esac + +ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" +case $ac_cv_c_uint8_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT8_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint8_t $ac_cv_c_uint8_t +_ACEOF +;; + esac + +ac_fn_cxx_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default" +if test "x$ac_cv_type_ptrdiff_t" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_PTRDIFF_T 1 +_ACEOF + + +else + echo "ptrdiff_t not found or g++ not installed - cannot continue" && exit 1 +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 +$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } +if ${ac_cv_struct_tm+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include + +int +main () +{ +struct tm tm; + int *p = &tm.tm_sec; + return !p; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_struct_tm=time.h +else + ac_cv_struct_tm=sys/time.h +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 +$as_echo "$ac_cv_struct_tm" >&6; } +if test $ac_cv_struct_tm = sys/time.h; then + +$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h + +fi + + +ac_fn_cxx_check_decl "$LINENO" "AI_ADDRCONFIG" "ac_cv_have_decl_AI_ADDRCONFIG" " + #include + #include + #include + +" +if test "x$ac_cv_have_decl_AI_ADDRCONFIG" = xyes; then : + +else + +$as_echo "#define AI_ADDRCONFIG 0" >>confdefs.h + +fi + + +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 +$as_echo_n "checking for working alloca.h... " >&6; } +if ${ac_cv_working_alloca_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +char *p = (char *) alloca (2 * sizeof (int)); + if (p) return 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_working_alloca_h=yes +else + ac_cv_working_alloca_h=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 +$as_echo "$ac_cv_working_alloca_h" >&6; } +if test $ac_cv_working_alloca_h = yes; then + +$as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 +$as_echo_n "checking for alloca... " >&6; } +if ${ac_cv_func_alloca_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# ifdef _MSC_VER +# include +# define alloca _alloca +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +void *alloca (size_t); +# endif +# endif +# endif +# endif +#endif + +int +main () +{ +char *p = (char *) alloca (1); + if (p) return 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_func_alloca_works=yes +else + ac_cv_func_alloca_works=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 +$as_echo "$ac_cv_func_alloca_works" >&6; } + +if test $ac_cv_func_alloca_works = yes; then + +$as_echo "#define HAVE_ALLOCA 1" >>confdefs.h + +else + # The SVR3 libPW and SVR4 libucb both contain incompatible functions +# that cause trouble. Some versions do not even contain alloca or +# contain a buggy version. If you still want to use their alloca, +# use ar to extract alloca.o from them instead of compiling alloca.c. + +ALLOCA=\${LIBOBJDIR}alloca.$ac_objext + +$as_echo "#define C_ALLOCA 1" >>confdefs.h + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 +$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } +if ${ac_cv_os_cray+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined CRAY && ! defined CRAY2 +webecray +#else +wenotbecray +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "webecray" >/dev/null 2>&1; then : + ac_cv_os_cray=yes +else + ac_cv_os_cray=no +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 +$as_echo "$ac_cv_os_cray" >&6; } +if test $ac_cv_os_cray = yes; then + for ac_func in _getb67 GETB67 getb67; do + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + +cat >>confdefs.h <<_ACEOF +#define CRAY_STACKSEG_END $ac_func +_ACEOF + + break +fi + + done +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 +$as_echo_n "checking stack direction for C alloca... " >&6; } +if ${ac_cv_c_stack_direction+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_c_stack_direction=0 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +find_stack_direction (int *addr, int depth) +{ + int dir, dummy = 0; + if (! addr) + addr = &dummy; + *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; + dir = depth ? find_stack_direction (addr, depth - 1) : 0; + return dir + dummy; +} + +int +main (int argc, char **argv) +{ + return find_stack_direction (0, argc + !argv + 20) < 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + ac_cv_c_stack_direction=1 +else + ac_cv_c_stack_direction=-1 +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 +$as_echo "$ac_cv_c_stack_direction" >&6; } +cat >>confdefs.h <<_ACEOF +#define STACK_DIRECTION $ac_cv_c_stack_direction +_ACEOF + + +fi + +ac_fn_cxx_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" +if test "x$ac_cv_type_pid_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + +for ac_header in vfork.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" +if test "x$ac_cv_header_vfork_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_VFORK_H 1 +_ACEOF + +fi + +done + +for ac_func in fork vfork +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +if test "x$ac_cv_func_fork" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 +$as_echo_n "checking for working fork... " >&6; } +if ${ac_cv_func_fork_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_fork_works=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* By Ruediger Kuhlmann. */ + return fork () < 0; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + ac_cv_func_fork_works=yes +else + ac_cv_func_fork_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 +$as_echo "$ac_cv_func_fork_works" >&6; } + +else + ac_cv_func_fork_works=$ac_cv_func_fork +fi +if test "x$ac_cv_func_fork_works" = xcross; then + case $host in + *-*-amigaos* | *-*-msdosdjgpp*) + # Override, as these systems have only a dummy fork() stub + ac_cv_func_fork_works=no + ;; + *) + ac_cv_func_fork_works=yes + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 +$as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} +fi +ac_cv_func_vfork_works=$ac_cv_func_vfork +if test "x$ac_cv_func_vfork" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 +$as_echo_n "checking for working vfork... " >&6; } +if ${ac_cv_func_vfork_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_vfork_works=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Thanks to Paul Eggert for this test. */ +$ac_includes_default +#include +#ifdef HAVE_VFORK_H +# include +#endif +/* On some sparc systems, changes by the child to local and incoming + argument registers are propagated back to the parent. The compiler + is told about this with #include , but some compilers + (e.g. gcc -O) don't grok . Test for this by using a + static variable whose address is put into a register that is + clobbered by the vfork. */ +static void +#ifdef __cplusplus +sparc_address_test (int arg) +# else +sparc_address_test (arg) int arg; +#endif +{ + static pid_t child; + if (!child) { + child = vfork (); + if (child < 0) { + perror ("vfork"); + _exit(2); + } + if (!child) { + arg = getpid(); + write(-1, "", 0); + _exit (arg); + } + } +} + +int +main () +{ + pid_t parent = getpid (); + pid_t child; + + sparc_address_test (0); + + child = vfork (); + + if (child == 0) { + /* Here is another test for sparc vfork register problems. This + test uses lots of local variables, at least as many local + variables as main has allocated so far including compiler + temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris + 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should + reuse the register of parent for one of the local variables, + since it will think that parent can't possibly be used any more + in this routine. Assigning to the local variable will thus + munge parent in the parent process. */ + pid_t + p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), + p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); + /* Convince the compiler that p..p7 are live; otherwise, it might + use the same hardware register for all 8 local variables. */ + if (p != p1 || p != p2 || p != p3 || p != p4 + || p != p5 || p != p6 || p != p7) + _exit(1); + + /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent + from child file descriptors. If the child closes a descriptor + before it execs or exits, this munges the parent's descriptor + as well. Test for this by closing stdout in the child. */ + _exit(close(fileno(stdout)) != 0); + } else { + int status; + struct stat st; + + while (wait(&status) != child) + ; + return ( + /* Was there some problem with vforking? */ + child < 0 + + /* Did the child fail? (This shouldn't happen.) */ + || status + + /* Did the vfork/compiler bug occur? */ + || parent != getpid() + + /* Did the file descriptor bug occur? */ + || fstat(fileno(stdout), &st) != 0 + ); + } +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + ac_cv_func_vfork_works=yes +else + ac_cv_func_vfork_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 +$as_echo "$ac_cv_func_vfork_works" >&6; } + +fi; +if test "x$ac_cv_func_fork_works" = xcross; then + ac_cv_func_vfork_works=$ac_cv_func_vfork + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 +$as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} +fi + +if test "x$ac_cv_func_vfork_works" = xyes; then + +$as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h + +else + +$as_echo "#define vfork fork" >>confdefs.h + +fi +if test "x$ac_cv_func_fork_works" = xyes; then + +$as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h + +fi + +for ac_header in stdlib.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" +if test "x$ac_cv_header_stdlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDLIB_H 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 +$as_echo_n "checking for GNU libc compatible malloc... " >&6; } +if ${ac_cv_func_malloc_0_nonnull+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_malloc_0_nonnull=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined STDC_HEADERS || defined HAVE_STDLIB_H +# include +#else +char *malloc (); +#endif + +int +main () +{ +return ! malloc (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + ac_cv_func_malloc_0_nonnull=yes +else + ac_cv_func_malloc_0_nonnull=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 +$as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } +if test $ac_cv_func_malloc_0_nonnull = yes; then : + +$as_echo "#define HAVE_MALLOC 1" >>confdefs.h + +else + $as_echo "#define HAVE_MALLOC 0" >>confdefs.h + + case " $LIBOBJS " in + *" malloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS malloc.$ac_objext" + ;; +esac + + +$as_echo "#define malloc rpl_malloc" >>confdefs.h + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5 +$as_echo_n "checking for working memcmp... " >&6; } +if ${ac_cv_func_memcmp_working+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_memcmp_working=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Some versions of memcmp are not 8-bit clean. */ + char c0 = '\100', c1 = '\200', c2 = '\201'; + if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0) + return 1; + + /* The Next x86 OpenStep bug shows up only when comparing 16 bytes + or more and with at least one buffer not starting on a 4-byte boundary. + William Lewis provided this test program. */ + { + char foo[21]; + char bar[21]; + int i; + for (i = 0; i < 4; i++) + { + char *a = foo + i; + char *b = bar + i; + strcpy (a, "--------01111111"); + strcpy (b, "--------10000000"); + if (memcmp (a, b, 16) >= 0) + return 1; + } + return 0; + } + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + ac_cv_func_memcmp_working=yes +else + ac_cv_func_memcmp_working=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memcmp_working" >&5 +$as_echo "$ac_cv_func_memcmp_working" >&6; } +test $ac_cv_func_memcmp_working = no && case " $LIBOBJS " in + *" memcmp.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" + ;; +esac + + +for ac_header in stdlib.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" +if test "x$ac_cv_header_stdlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDLIB_H 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5 +$as_echo_n "checking for GNU libc compatible realloc... " >&6; } +if ${ac_cv_func_realloc_0_nonnull+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_realloc_0_nonnull=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined STDC_HEADERS || defined HAVE_STDLIB_H +# include +#else +char *realloc (); +#endif + +int +main () +{ +return ! realloc (0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + ac_cv_func_realloc_0_nonnull=yes +else + ac_cv_func_realloc_0_nonnull=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5 +$as_echo "$ac_cv_func_realloc_0_nonnull" >&6; } +if test $ac_cv_func_realloc_0_nonnull = yes; then : + +$as_echo "#define HAVE_REALLOC 1" >>confdefs.h + +else + $as_echo "#define HAVE_REALLOC 0" >>confdefs.h + + case " $LIBOBJS " in + *" realloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS realloc.$ac_objext" + ;; +esac + + +$as_echo "#define realloc rpl_realloc" >>confdefs.h + +fi + + +for ac_header in sys/select.h sys/socket.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for select" >&5 +$as_echo_n "checking types of arguments for select... " >&6; } +if ${ac_cv_func_select_args+:} false; then : + $as_echo_n "(cached) " >&6 +else + for ac_arg234 in 'fd_set *' 'int *' 'void *'; do + for ac_arg1 in 'int' 'size_t' 'unsigned long int' 'unsigned int'; do + for ac_arg5 in 'struct timeval *' 'const struct timeval *'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +#ifdef HAVE_SYS_SELECT_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif + +int +main () +{ +extern int select ($ac_arg1, + $ac_arg234, $ac_arg234, $ac_arg234, + $ac_arg5); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_func_select_args="$ac_arg1,$ac_arg234,$ac_arg5"; break 3 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done + done +done +# Provide a safe default value. +: "${ac_cv_func_select_args=int,int *,struct timeval *}" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_select_args" >&5 +$as_echo "$ac_cv_func_select_args" >&6; } +ac_save_IFS=$IFS; IFS=',' +set dummy `echo "$ac_cv_func_select_args" | sed 's/\*/\*/g'` +IFS=$ac_save_IFS +shift + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG1 $1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG234 ($2) +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG5 ($3) +_ACEOF + +rm -f conftest* + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 +$as_echo_n "checking whether lstat correctly handles trailing slash... " >&6; } +if ${ac_cv_func_lstat_dereferences_slashed_symlink+:} false; then : + $as_echo_n "(cached) " >&6 +else + rm -f conftest.sym conftest.file +echo >conftest.file +if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then + if test "$cross_compiling" = yes; then : + ac_cv_func_lstat_dereferences_slashed_symlink=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +struct stat sbuf; + /* Linux will dereference the symlink and fail, as required by POSIX. + That is better in the sense that it means we will not + have to compile and use the lstat wrapper. */ + return lstat ("conftest.sym/", &sbuf) == 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + ac_cv_func_lstat_dereferences_slashed_symlink=yes +else + ac_cv_func_lstat_dereferences_slashed_symlink=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +else + # If the `ln -s' command failed, then we probably don't even + # have an lstat function. + ac_cv_func_lstat_dereferences_slashed_symlink=no +fi +rm -f conftest.sym conftest.file + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5 +$as_echo "$ac_cv_func_lstat_dereferences_slashed_symlink" >&6; } + +test $ac_cv_func_lstat_dereferences_slashed_symlink = yes && + +cat >>confdefs.h <<_ACEOF +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +_ACEOF + + +if test "x$ac_cv_func_lstat_dereferences_slashed_symlink" = xno; then + case " $LIBOBJS " in + *" lstat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS lstat.$ac_objext" + ;; +esac + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat accepts an empty string" >&5 +$as_echo_n "checking whether stat accepts an empty string... " >&6; } +if ${ac_cv_func_stat_empty_string_bug+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_stat_empty_string_bug=yes +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +struct stat sbuf; + return stat ("", &sbuf) == 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + ac_cv_func_stat_empty_string_bug=no +else + ac_cv_func_stat_empty_string_bug=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_stat_empty_string_bug" >&5 +$as_echo "$ac_cv_func_stat_empty_string_bug" >&6; } +if test $ac_cv_func_stat_empty_string_bug = yes; then + case " $LIBOBJS " in + *" stat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS stat.$ac_objext" + ;; +esac + + +cat >>confdefs.h <<_ACEOF +#define HAVE_STAT_EMPTY_STRING_BUG 1 +_ACEOF + +fi + +ac_fn_cxx_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default" +if test "x$ac_cv_have_decl_strerror_r" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRERROR_R $ac_have_decl +_ACEOF + +for ac_func in strerror_r +do : + ac_fn_cxx_check_func "$LINENO" "strerror_r" "ac_cv_func_strerror_r" +if test "x$ac_cv_func_strerror_r" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRERROR_R 1 +_ACEOF + +fi +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5 +$as_echo_n "checking whether strerror_r returns char *... " >&6; } +if ${ac_cv_func_strerror_r_char_p+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ac_cv_func_strerror_r_char_p=no + if test $ac_cv_have_decl_strerror_r = yes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + char buf[100]; + char x = *strerror_r (0, buf, sizeof buf); + char *p = strerror_r (0, buf, sizeof buf); + return !p || x; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_func_strerror_r_char_p=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + else + # strerror_r is not declared. Choose between + # systems that have relatively inaccessible declarations for the + # function. BeOS and DEC UNIX 4.0 fall in this category, but the + # former has a strerror_r that returns char*, while the latter + # has a strerror_r that returns `int'. + # This test should segfault on the DEC system. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default + extern char *strerror_r (); +int +main () +{ +char buf[100]; + char x = *strerror_r (0, buf, sizeof buf); + return ! isalpha (x); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + ac_cv_func_strerror_r_char_p=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5 +$as_echo "$ac_cv_func_strerror_r_char_p" >&6; } +if test $ac_cv_func_strerror_r_char_p = yes; then + +$as_echo "#define STRERROR_R_CHAR_P 1" >>confdefs.h + +fi + +for ac_func in strftime +do : + ac_fn_cxx_check_func "$LINENO" "strftime" "ac_cv_func_strftime" +if test "x$ac_cv_func_strftime" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRFTIME 1 +_ACEOF + +else + # strftime is in -lintl on SCO UNIX. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strftime in -lintl" >&5 +$as_echo_n "checking for strftime in -lintl... " >&6; } +if ${ac_cv_lib_intl_strftime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lintl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char strftime (); +int +main () +{ +return strftime (); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_lib_intl_strftime=yes +else + ac_cv_lib_intl_strftime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_strftime" >&5 +$as_echo "$ac_cv_lib_intl_strftime" >&6; } +if test "x$ac_cv_lib_intl_strftime" = xyes; then : + $as_echo "#define HAVE_STRFTIME 1" >>confdefs.h + +LIBS="-lintl $LIBS" +fi + +fi +done + +for ac_func in vprintf +do : + ac_fn_cxx_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf" +if test "x$ac_cv_func_vprintf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_VPRINTF 1 +_ACEOF + +ac_fn_cxx_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt" +if test "x$ac_cv_func__doprnt" = xyes; then : + +$as_echo "#define HAVE_DOPRNT 1" >>confdefs.h + +fi + +fi +done + + +for ac_func in strtoul +do : + ac_fn_cxx_check_func "$LINENO" "strtoul" "ac_cv_func_strtoul" +if test "x$ac_cv_func_strtoul" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOUL 1 +_ACEOF + +fi +done + +for ac_func in bzero +do : + ac_fn_cxx_check_func "$LINENO" "bzero" "ac_cv_func_bzero" +if test "x$ac_cv_func_bzero" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_BZERO 1 +_ACEOF + +fi +done + +for ac_func in ftruncate +do : + ac_fn_cxx_check_func "$LINENO" "ftruncate" "ac_cv_func_ftruncate" +if test "x$ac_cv_func_ftruncate" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FTRUNCATE 1 +_ACEOF + +fi +done + +for ac_func in gethostbyname +do : + ac_fn_cxx_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" +if test "x$ac_cv_func_gethostbyname" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETHOSTBYNAME 1 +_ACEOF + +fi +done + +for ac_func in gethostbyname_r +do : + ac_fn_cxx_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r" +if test "x$ac_cv_func_gethostbyname_r" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETHOSTBYNAME_R 1 +_ACEOF + +fi +done + +for ac_func in gettimeofday +do : + ac_fn_cxx_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" +if test "x$ac_cv_func_gettimeofday" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETTIMEOFDAY 1 +_ACEOF + +fi +done + +for ac_func in memmove +do : + ac_fn_cxx_check_func "$LINENO" "memmove" "ac_cv_func_memmove" +if test "x$ac_cv_func_memmove" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MEMMOVE 1 +_ACEOF + +fi +done + +for ac_func in memset +do : + ac_fn_cxx_check_func "$LINENO" "memset" "ac_cv_func_memset" +if test "x$ac_cv_func_memset" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MEMSET 1 +_ACEOF + +fi +done + +for ac_func in mkdir +do : + ac_fn_cxx_check_func "$LINENO" "mkdir" "ac_cv_func_mkdir" +if test "x$ac_cv_func_mkdir" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MKDIR 1 +_ACEOF + +fi +done + +for ac_func in realpath +do : + ac_fn_cxx_check_func "$LINENO" "realpath" "ac_cv_func_realpath" +if test "x$ac_cv_func_realpath" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_REALPATH 1 +_ACEOF + +fi +done + +for ac_func in select +do : + ac_fn_cxx_check_func "$LINENO" "select" "ac_cv_func_select" +if test "x$ac_cv_func_select" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SELECT 1 +_ACEOF + +fi +done + +for ac_func in setlocale +do : + ac_fn_cxx_check_func "$LINENO" "setlocale" "ac_cv_func_setlocale" +if test "x$ac_cv_func_setlocale" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SETLOCALE 1 +_ACEOF + +fi +done + +for ac_func in socket +do : + ac_fn_cxx_check_func "$LINENO" "socket" "ac_cv_func_socket" +if test "x$ac_cv_func_socket" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SOCKET 1 +_ACEOF + +fi +done + +for ac_func in strchr +do : + ac_fn_cxx_check_func "$LINENO" "strchr" "ac_cv_func_strchr" +if test "x$ac_cv_func_strchr" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRCHR 1 +_ACEOF + +fi +done + +for ac_func in strdup +do : + ac_fn_cxx_check_func "$LINENO" "strdup" "ac_cv_func_strdup" +if test "x$ac_cv_func_strdup" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRDUP 1 +_ACEOF + +fi +done + +for ac_func in strerror +do : + ac_fn_cxx_check_func "$LINENO" "strerror" "ac_cv_func_strerror" +if test "x$ac_cv_func_strerror" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRERROR 1 +_ACEOF + +fi +done + +for ac_func in strstr +do : + ac_fn_cxx_check_func "$LINENO" "strstr" "ac_cv_func_strstr" +if test "x$ac_cv_func_strstr" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRSTR 1 +_ACEOF + +fi +done + +for ac_func in strtol +do : + ac_fn_cxx_check_func "$LINENO" "strtol" "ac_cv_func_strtol" +if test "x$ac_cv_func_strtol" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOL 1 +_ACEOF + +fi +done + +for ac_func in sqrt +do : + ac_fn_cxx_check_func "$LINENO" "sqrt" "ac_cv_func_sqrt" +if test "x$ac_cv_func_sqrt" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRT 1 +_ACEOF + +fi +done + +for ac_func in alarm +do : + ac_fn_cxx_check_func "$LINENO" "alarm" "ac_cv_func_alarm" +if test "x$ac_cv_func_alarm" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ALARM 1 +_ACEOF + +fi +done + +for ac_func in clock_gettime +do : + ac_fn_cxx_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime" +if test "x$ac_cv_func_clock_gettime" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_CLOCK_GETTIME 1 +_ACEOF + +fi +done + +for ac_func in sched_get_priority_min +do : + ac_fn_cxx_check_func "$LINENO" "sched_get_priority_min" "ac_cv_func_sched_get_priority_min" +if test "x$ac_cv_func_sched_get_priority_min" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SCHED_GET_PRIORITY_MIN 1 +_ACEOF + +fi +done + +for ac_func in sched_get_priority_max +do : + ac_fn_cxx_check_func "$LINENO" "sched_get_priority_max" "ac_cv_func_sched_get_priority_max" +if test "x$ac_cv_func_sched_get_priority_max" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SCHED_GET_PRIORITY_MAX 1 +_ACEOF + +fi +done + +for ac_func in inet_ntoa +do : + ac_fn_cxx_check_func "$LINENO" "inet_ntoa" "ac_cv_func_inet_ntoa" +if test "x$ac_cv_func_inet_ntoa" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_INET_NTOA 1 +_ACEOF + +fi +done + +for ac_func in pow +do : + ac_fn_cxx_check_func "$LINENO" "pow" "ac_cv_func_pow" +if test "x$ac_cv_func_pow" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POW 1 +_ACEOF + +fi +done + + +if test "$cross_compiling" = "no" ; then + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking the behavior of a signed right shift" >&5 +$as_echo_n "checking the behavior of a signed right shift... " >&6; } + + success_arithmetic=no + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + return + /* 0xffffffff */ + -1 >> 1 != -1 || + -1 >> 2 != -1 || + -1 >> 3 != -1 || + -1 >> 4 != -1 || + -1 >> 8 != -1 || + -1 >> 16 != -1 || + -1 >> 24 != -1 || + -1 >> 31 != -1 || + /* 0x80000000 */ + (-2147483647 - 1) >> 1 != -1073741824 || + (-2147483647 - 1) >> 2 != -536870912 || + (-2147483647 - 1) >> 3 != -268435456 || + (-2147483647 - 1) >> 4 != -134217728 || + (-2147483647 - 1) >> 8 != -8388608 || + (-2147483647 - 1) >> 16 != -32768 || + (-2147483647 - 1) >> 24 != -128 || + (-2147483647 - 1) >> 31 != -1 || + /* 0x90800000 */ + -1870659584 >> 1 != -935329792 || + -1870659584 >> 2 != -467664896 || + -1870659584 >> 3 != -233832448 || + -1870659584 >> 4 != -116916224 || + -1870659584 >> 8 != -7307264 || + -1870659584 >> 16 != -28544 || + -1870659584 >> 24 != -112 || + -1870659584 >> 31 != -1 || + 0; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + + success_arithmetic=yes + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + + + success_logical=no + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + return + /* 0xffffffff */ + -1 >> 1 != (signed)((unsigned)-1 >> 1) || + -1 >> 2 != (signed)((unsigned)-1 >> 2) || + -1 >> 3 != (signed)((unsigned)-1 >> 3) || + -1 >> 4 != (signed)((unsigned)-1 >> 4) || + -1 >> 8 != (signed)((unsigned)-1 >> 8) || + -1 >> 16 != (signed)((unsigned)-1 >> 16) || + -1 >> 24 != (signed)((unsigned)-1 >> 24) || + -1 >> 31 != (signed)((unsigned)-1 >> 31) || + /* 0x80000000 */ + (-2147483647 - 1) >> 1 != (signed)((unsigned)(-2147483647 - 1) >> 1) || + (-2147483647 - 1) >> 2 != (signed)((unsigned)(-2147483647 - 1) >> 2) || + (-2147483647 - 1) >> 3 != (signed)((unsigned)(-2147483647 - 1) >> 3) || + (-2147483647 - 1) >> 4 != (signed)((unsigned)(-2147483647 - 1) >> 4) || + (-2147483647 - 1) >> 8 != (signed)((unsigned)(-2147483647 - 1) >> 8) || + (-2147483647 - 1) >> 16 != (signed)((unsigned)(-2147483647 - 1) >> 16) || + (-2147483647 - 1) >> 24 != (signed)((unsigned)(-2147483647 - 1) >> 24) || + (-2147483647 - 1) >> 31 != (signed)((unsigned)(-2147483647 - 1) >> 31) || + /* 0x90800000 */ + -1870659584 >> 1 != (signed)((unsigned)-1870659584 >> 1) || + -1870659584 >> 2 != (signed)((unsigned)-1870659584 >> 2) || + -1870659584 >> 3 != (signed)((unsigned)-1870659584 >> 3) || + -1870659584 >> 4 != (signed)((unsigned)-1870659584 >> 4) || + -1870659584 >> 8 != (signed)((unsigned)-1870659584 >> 8) || + -1870659584 >> 16 != (signed)((unsigned)-1870659584 >> 16) || + -1870659584 >> 24 != (signed)((unsigned)-1870659584 >> 24) || + -1870659584 >> 31 != (signed)((unsigned)-1870659584 >> 31) || + 0; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + + success_logical=yes + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + + + +$as_echo "#define ARITHMETIC_RIGHT_SHIFT 1" >>confdefs.h + + +$as_echo "#define LOGICAL_RIGHT_SHIFT 2" >>confdefs.h + + +$as_echo "#define UNKNOWN_RIGHT_SHIFT 3" >>confdefs.h + + + if test "$success_arithmetic" = "yes" && test "$success_logical" = "yes" ; then + as_fn_error $? "\"Right shift appears to be both arithmetic and logical!\"" "$LINENO" 5 + elif test "$success_arithmetic" = "yes" ; then + ax_signed_right_shift=arithmetic + +$as_echo "#define SIGNED_RIGHT_SHIFT_IS 1" >>confdefs.h + + elif test "$success_logical" = "yes" ; then + ax_signed_right_shift=logical + +$as_echo "#define SIGNED_RIGHT_SHIFT_IS 2" >>confdefs.h + + else + ax_signed_right_shift=unknown + +$as_echo "#define SIGNED_RIGHT_SHIFT_IS 3" >>confdefs.h + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_signed_right_shift" >&5 +$as_echo "$ax_signed_right_shift" >&6; } + +fi + +if false ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for error_at_line" >&5 +$as_echo_n "checking for error_at_line... " >&6; } +if ${ac_cv_lib_error_at_line+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +error_at_line (0, 0, "", 0, "an error occurred"); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_lib_error_at_line=yes +else + ac_cv_lib_error_at_line=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_error_at_line" >&5 +$as_echo "$ac_cv_lib_error_at_line" >&6; } +if test $ac_cv_lib_error_at_line = no; then + case " $LIBOBJS " in + *" error.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS error.$ac_objext" + ;; +esac + +fi + +fi + +# --- Coverage hooks --- + +# Check whether --enable-coverage was given. +if test "${enable_coverage+set}" = set; then : + enableval=$enable_coverage; case "${enableval}" in + yes) ENABLE_COVERAGE=1 ;; + no) ENABLE_COVERAGE=0 ;; + *) as_fn_error $? "bad value ${enableval} for --enable-cov" "$LINENO" 5 ;; + esac +else + ENABLE_COVERAGE=2 +fi + + +if test "x$ENABLE_COVERAGE" = "x1"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: enable coverage" >&5 +$as_echo "$as_me: WARNING: enable coverage" >&2;} + GCOV_CFLAGS="`echo \"$CFLAGS\" | perl -pe 's/-O\d+//g;'` -fprofile-arcs -ftest-coverage" + GCOV_CXXFLAGS="`echo \"$CXXFLAGS\" | perl -pe 's/-O\d+//g;'` -fprofile-arcs -ftest-coverage" + GCOV_LDFLAGS="-XCClinker -fprofile-arcs -XCClinker -ftest-coverage" +fi + + + + + + +# Check whether --enable-boostthreads was given. +if test "${enable_boostthreads+set}" = set; then : + enableval=$enable_boostthreads; case "${enableval}" in + yes) ENABLE_BOOSTTHREADS=1 ;; + no) ENABLE_BOOSTTHREADS=0 ;; + *) as_fn_error $? "bad value ${enableval} for --enable-cov" "$LINENO" 5 ;; + esac +else + ENABLE_BOOSTTHREADS=2 +fi + + + +if test "x$ENABLE_BOOSTTHREADS" = "x1"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: enable boostthreads" >&5 +$as_echo "$as_me: WARNING: enable boostthreads" >&2;} + +$as_echo "#define USE_BOOST_THREAD 1" >>confdefs.h + + LIBS="-lboost_thread $LIBS" +fi + + if test "x$ENABLE_BOOSTTHREADS" = "x1"; then + WITH_BOOSTTHREADS_TRUE= + WITH_BOOSTTHREADS_FALSE='#' +else + WITH_BOOSTTHREADS_TRUE='#' + WITH_BOOSTTHREADS_FALSE= +fi + + +ac_config_headers="$ac_config_headers config.h:config.hin" + +ac_config_headers="$ac_config_headers lib/cpp/src/thrift/config.h:config.hin" + +ac_config_headers="$ac_config_headers lib/c_glib/src/thrift/config.h:config.hin" + +# gruard against pre defined config.h + + + + +ac_config_files="$ac_config_files Makefile compiler/cpp/Makefile compiler/cpp/src/Makefile compiler/cpp/src/thrift/plugin/Makefile compiler/cpp/test/Makefile compiler/cpp/src/thrift/version.h lib/Makefile lib/cpp/Makefile lib/cpp/test/Makefile lib/cpp/thrift-nb.pc lib/cpp/thrift-z.pc lib/cpp/thrift-qt.pc lib/cpp/thrift-qt5.pc lib/cpp/thrift.pc lib/c_glib/Makefile lib/c_glib/thrift_c_glib.pc lib/c_glib/test/Makefile lib/csharp/Makefile lib/csharp/test/Multiplex/Makefile lib/d/Makefile lib/d/test/Makefile lib/erl/Makefile lib/go/Makefile lib/go/test/Makefile lib/haxe/test/Makefile lib/hs/Makefile lib/java/Makefile lib/js/Makefile lib/js/test/Makefile lib/json/Makefile lib/json/test/Makefile lib/netcore/Makefile lib/nodejs/Makefile lib/perl/Makefile lib/perl/test/Makefile lib/php/Makefile lib/php/test/Makefile lib/dart/Makefile lib/py/Makefile lib/rb/Makefile lib/rs/Makefile lib/rs/test/Makefile lib/lua/Makefile lib/xml/Makefile lib/xml/test/Makefile test/Makefile test/features/Makefile test/c_glib/Makefile test/cpp/Makefile test/csharp/Makefile test/erl/Makefile test/go/Makefile test/haxe/Makefile test/hs/Makefile test/lua/Makefile test/netcore/Makefile test/php/Makefile test/dart/Makefile test/perl/Makefile test/py/Makefile test/py.twisted/Makefile test/py.tornado/Makefile test/rb/Makefile test/rs/Makefile tutorial/Makefile tutorial/c_glib/Makefile tutorial/cpp/Makefile tutorial/d/Makefile tutorial/go/Makefile tutorial/haxe/Makefile tutorial/hs/Makefile tutorial/java/Makefile tutorial/js/Makefile tutorial/netcore/Makefile tutorial/nodejs/Makefile tutorial/dart/Makefile tutorial/py/Makefile tutorial/py.twisted/Makefile tutorial/py.tornado/Makefile tutorial/rb/Makefile tutorial/rs/Makefile" + + +if test "$have_cpp" = "yes" ; then MAYBE_CPP="cpp" ; else MAYBE_CPP="" ; fi + +if test "$have_c_glib" = "yes" ; then MAYBE_C_GLIB="c_glib" ; else MAYBE_C_GLIB="" ; fi + +if test "$have_d" = "yes" -a "$have_deimos_event2" = "yes" -a "$have_deimos_openssl" = "yes"; then MAYBE_D="d" ; else MAYBE_D="" ; fi + +if test "$have_java" = "yes" ; then MAYBE_JAVA="java" ; else MAYBE_JAVA="" ; fi + +if test "$have_csharp" = "yes" ; then MAYBE_CSHARP="csharp" ; else MAYBE_CSHARP="" ; fi + +if test "$have_python" = "yes" ; then MAYBE_PYTHON="py" ; else MAYBE_PYTHON="" ; fi + +if test "$have_py3" = "yes" ; then MAYBE_PY3="py3" ; else MAYBE_PY3="" ; fi + +if test "$have_ruby" = "yes" ; then MAYBE_RUBY="rb" ; else MAYBE_RUBY="" ; fi + +if test "$have_haskell" = "yes" ; then MAYBE_HASKELL="hs" ; else MAYBE_HASKELL="" ; fi + +if test "$have_perl" = "yes" ; then MAYBE_PERL="perl" ; else MAYBE_PERL="" ; fi + +if test "$have_php" = "yes" ; then MAYBE_PHP="php" ; else MAYBE_PHP="" ; fi + +if test "$have_dart" = "yes" ; then MAYBE_DART="dart" ; else MAYBE_DART="" ; fi + +if test "$have_go" = "yes" ; then MAYBE_GO="go" ; else MAYBE_GO="" ; fi + +if test "$have_nodejs" = "yes" ; then MAYBE_NODEJS="nodejs" ; else MAYBE_NODEJS="" ; fi + +if test "$have_erlang" = "yes" ; then MAYBE_ERLANG="erl" ; else MAYBE_ERLANG="" ; fi + +if test "$have_lua" = "yes" ; then MAYBE_LUA="lua" ; else MAYBE_LUA="" ; fi + +if test "$have_rs" = "yes" ; then MAYBE_RS="rs" ; else MAYBE_RS="" ; fi + +if test "$have_dotnetcore" = "yes" ; then MAYBE_DOTNETCORE="netcore" ; else MAYBE_DOTNETCORE="" ; fi + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +$as_echo_n "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 +$as_echo "done" >&6; } + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BISON_USE_PARSER_H_EXTENSION_TRUE}" && test -z "${BISON_USE_PARSER_H_EXTENSION_FALSE}"; then + as_fn_error $? "conditional \"BISON_USE_PARSER_H_EXTENSION\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_CPP_TRUE}" && test -z "${WITH_CPP_FALSE}"; then + as_fn_error $? "conditional \"WITH_CPP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AMX_HAVE_LIBEVENT_TRUE}" && test -z "${AMX_HAVE_LIBEVENT_FALSE}"; then + as_fn_error $? "conditional \"AMX_HAVE_LIBEVENT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AMX_HAVE_ZLIB_TRUE}" && test -z "${AMX_HAVE_ZLIB_FALSE}"; then + as_fn_error $? "conditional \"AMX_HAVE_ZLIB\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AMX_HAVE_QT_TRUE}" && test -z "${AMX_HAVE_QT_FALSE}"; then + as_fn_error $? "conditional \"AMX_HAVE_QT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AMX_HAVE_QT5_TRUE}" && test -z "${AMX_HAVE_QT5_FALSE}"; then + as_fn_error $? "conditional \"AMX_HAVE_QT5\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${QT5_REDUCE_RELOCATIONS_TRUE}" && test -z "${QT5_REDUCE_RELOCATIONS_FALSE}"; then + as_fn_error $? "conditional \"QT5_REDUCE_RELOCATIONS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_C_GLIB_TRUE}" && test -z "${WITH_C_GLIB_FALSE}"; then + as_fn_error $? "conditional \"WITH_C_GLIB\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_MONO_TRUE}" && test -z "${WITH_MONO_FALSE}"; then + as_fn_error $? "conditional \"WITH_MONO\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${NET_2_0_TRUE}" && test -z "${NET_2_0_FALSE}"; then + as_fn_error $? "conditional \"NET_2_0\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MONO_MCS_TRUE}" && test -z "${MONO_MCS_FALSE}"; then + as_fn_error $? "conditional \"MONO_MCS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_JAVA_TRUE}" && test -z "${WITH_JAVA_FALSE}"; then + as_fn_error $? "conditional \"WITH_JAVA\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_ERLANG_TRUE}" && test -z "${WITH_ERLANG_FALSE}"; then + as_fn_error $? "conditional \"WITH_ERLANG\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ERLANG_OTP16_TRUE}" && test -z "${ERLANG_OTP16_FALSE}"; then + as_fn_error $? "conditional \"ERLANG_OTP16\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_NODEJS_TRUE}" && test -z "${WITH_NODEJS_FALSE}"; then + as_fn_error $? "conditional \"WITH_NODEJS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_NPM_TRUE}" && test -z "${HAVE_NPM_FALSE}"; then + as_fn_error $? "conditional \"HAVE_NPM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_LUA_TRUE}" && test -z "${WITH_LUA_FALSE}"; then + as_fn_error $? "conditional \"WITH_LUA\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_PYTHON_TRUE}" && test -z "${WITH_PYTHON_FALSE}"; then + as_fn_error $? "conditional \"WITH_PYTHON\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_TWISTED_TEST_TRUE}" && test -z "${WITH_TWISTED_TEST_FALSE}"; then + as_fn_error $? "conditional \"WITH_TWISTED_TEST\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_PY3_TRUE}" && test -z "${WITH_PY3_FALSE}"; then + as_fn_error $? "conditional \"WITH_PY3\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_PERL_TRUE}" && test -z "${WITH_PERL_FALSE}"; then + as_fn_error $? "conditional \"WITH_PERL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_PHP_TRUE}" && test -z "${WITH_PHP_FALSE}"; then + as_fn_error $? "conditional \"WITH_PHP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_PHP_EXTENSION_TRUE}" && test -z "${WITH_PHP_EXTENSION_FALSE}"; then + as_fn_error $? "conditional \"WITH_PHP_EXTENSION\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_PHPUNIT_TRUE}" && test -z "${HAVE_PHPUNIT_FALSE}"; then + as_fn_error $? "conditional \"HAVE_PHPUNIT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_DART_TRUE}" && test -z "${WITH_DART_FALSE}"; then + as_fn_error $? "conditional \"WITH_DART\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_RUBY_TRUE}" && test -z "${WITH_RUBY_FALSE}"; then + as_fn_error $? "conditional \"WITH_RUBY\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_BUNDLER_TRUE}" && test -z "${HAVE_BUNDLER_FALSE}"; then + as_fn_error $? "conditional \"HAVE_BUNDLER\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_HASKELL_TRUE}" && test -z "${WITH_HASKELL_FALSE}"; then + as_fn_error $? "conditional \"WITH_HASKELL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_GO_TRUE}" && test -z "${WITH_GO_FALSE}"; then + as_fn_error $? "conditional \"WITH_GO\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GOVERSION_LT_17_TRUE}" && test -z "${GOVERSION_LT_17_FALSE}"; then + as_fn_error $? "conditional \"GOVERSION_LT_17\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_RS_TRUE}" && test -z "${WITH_RS_FALSE}"; then + as_fn_error $? "conditional \"WITH_RS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_HAXE_TRUE}" && test -z "${WITH_HAXE_FALSE}"; then + as_fn_error $? "conditional \"WITH_HAXE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_DOTNETCORE_TRUE}" && test -z "${WITH_DOTNETCORE_FALSE}"; then + as_fn_error $? "conditional \"WITH_DOTNETCORE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_D_TRUE}" && test -z "${WITH_D_FALSE}"; then + as_fn_error $? "conditional \"WITH_D\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DMD_OPTLINK_TRUE}" && test -z "${DMD_OPTLINK_FALSE}"; then + as_fn_error $? "conditional \"DMD_OPTLINK\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_DEIMOS_EVENT2_TRUE}" && test -z "${HAVE_DEIMOS_EVENT2_FALSE}"; then + as_fn_error $? "conditional \"HAVE_DEIMOS_EVENT2\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_D_EVENT_TESTS_TRUE}" && test -z "${WITH_D_EVENT_TESTS_FALSE}"; then + as_fn_error $? "conditional \"WITH_D_EVENT_TESTS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_DEIMOS_OPENSSL_TRUE}" && test -z "${HAVE_DEIMOS_OPENSSL_FALSE}"; then + as_fn_error $? "conditional \"HAVE_DEIMOS_OPENSSL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_D_SSL_TESTS_TRUE}" && test -z "${WITH_D_SSL_TESTS_FALSE}"; then + as_fn_error $? "conditional \"WITH_D_SSL_TESTS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_TESTS_TRUE}" && test -z "${WITH_TESTS_FALSE}"; then + as_fn_error $? "conditional \"WITH_TESTS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_PLUGIN_TRUE}" && test -z "${WITH_PLUGIN_FALSE}"; then + as_fn_error $? "conditional \"WITH_PLUGIN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_TUTORIAL_TRUE}" && test -z "${WITH_TUTORIAL_FALSE}"; then + as_fn_error $? "conditional \"WITH_TUTORIAL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MINGW_TRUE}" && test -z "${MINGW_FALSE}"; then + as_fn_error $? "conditional \"MINGW\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MINGW_TRUE}" && test -z "${MINGW_FALSE}"; then + as_fn_error $? "conditional \"MINGW\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WITH_BOOSTTHREADS_TRUE}" && test -z "${WITH_BOOSTTHREADS_FALSE}"; then + as_fn_error $? "conditional \"WITH_BOOSTTHREADS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by thrift $as_me 0.11.0, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_links="$ac_config_links" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration links: +$config_links + +Configuration commands: +$config_commands + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +thrift config.status 0.11.0 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' +configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' +predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' +postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' +predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' +postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' +reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' +reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +DLLTOOL \ +sharedlib_from_linklib_cmd \ +AR \ +AR_FLAGS \ +archiver_list_spec \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_import \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +lt_cv_nm_interface \ +nm_file_list_spec \ +lt_cv_truncate_bin \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib \ +compiler_lib_search_dirs \ +predep_objects \ +postdep_objects \ +predeps \ +postdeps \ +compiler_lib_search_path \ +LD_CXX \ +reload_flag_CXX \ +compiler_CXX \ +lt_prog_compiler_no_builtin_flag_CXX \ +lt_prog_compiler_pic_CXX \ +lt_prog_compiler_wl_CXX \ +lt_prog_compiler_static_CXX \ +lt_cv_prog_compiler_c_o_CXX \ +export_dynamic_flag_spec_CXX \ +whole_archive_flag_spec_CXX \ +compiler_needs_object_CXX \ +with_gnu_ld_CXX \ +allow_undefined_flag_CXX \ +no_undefined_flag_CXX \ +hardcode_libdir_flag_spec_CXX \ +hardcode_libdir_separator_CXX \ +exclude_expsyms_CXX \ +include_expsyms_CXX \ +file_list_spec_CXX \ +compiler_lib_search_dirs_CXX \ +predep_objects_CXX \ +postdep_objects_CXX \ +predeps_CXX \ +postdeps_CXX \ +compiler_lib_search_path_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +configure_time_dlsearch_path \ +configure_time_lt_sys_library_path \ +reload_cmds_CXX \ +old_archive_cmds_CXX \ +old_archive_from_new_cmds_CXX \ +old_archive_from_expsyms_cmds_CXX \ +archive_cmds_CXX \ +archive_expsym_cmds_CXX \ +module_cmds_CXX \ +module_expsym_cmds_CXX \ +export_symbols_cmds_CXX \ +prelink_cmds_CXX \ +postlink_cmds_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' + +# See if we are running on zsh, and set the options that allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + RM='$RM' + ofile='$ofile' + + + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "compiler/cpp/test/plugin/t_cpp_generator.cc") CONFIG_LINKS="$CONFIG_LINKS compiler/cpp/test/plugin/t_cpp_generator.cc:compiler/cpp/src/thrift/generate/t_cpp_generator.cc" ;; + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h:config.hin" ;; + "lib/cpp/src/thrift/config.h") CONFIG_HEADERS="$CONFIG_HEADERS lib/cpp/src/thrift/config.h:config.hin" ;; + "lib/c_glib/src/thrift/config.h") CONFIG_HEADERS="$CONFIG_HEADERS lib/c_glib/src/thrift/config.h:config.hin" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "compiler/cpp/Makefile") CONFIG_FILES="$CONFIG_FILES compiler/cpp/Makefile" ;; + "compiler/cpp/src/Makefile") CONFIG_FILES="$CONFIG_FILES compiler/cpp/src/Makefile" ;; + "compiler/cpp/src/thrift/plugin/Makefile") CONFIG_FILES="$CONFIG_FILES compiler/cpp/src/thrift/plugin/Makefile" ;; + "compiler/cpp/test/Makefile") CONFIG_FILES="$CONFIG_FILES compiler/cpp/test/Makefile" ;; + "compiler/cpp/src/thrift/version.h") CONFIG_FILES="$CONFIG_FILES compiler/cpp/src/thrift/version.h" ;; + "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; + "lib/cpp/Makefile") CONFIG_FILES="$CONFIG_FILES lib/cpp/Makefile" ;; + "lib/cpp/test/Makefile") CONFIG_FILES="$CONFIG_FILES lib/cpp/test/Makefile" ;; + "lib/cpp/thrift-nb.pc") CONFIG_FILES="$CONFIG_FILES lib/cpp/thrift-nb.pc" ;; + "lib/cpp/thrift-z.pc") CONFIG_FILES="$CONFIG_FILES lib/cpp/thrift-z.pc" ;; + "lib/cpp/thrift-qt.pc") CONFIG_FILES="$CONFIG_FILES lib/cpp/thrift-qt.pc" ;; + "lib/cpp/thrift-qt5.pc") CONFIG_FILES="$CONFIG_FILES lib/cpp/thrift-qt5.pc" ;; + "lib/cpp/thrift.pc") CONFIG_FILES="$CONFIG_FILES lib/cpp/thrift.pc" ;; + "lib/c_glib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/c_glib/Makefile" ;; + "lib/c_glib/thrift_c_glib.pc") CONFIG_FILES="$CONFIG_FILES lib/c_glib/thrift_c_glib.pc" ;; + "lib/c_glib/test/Makefile") CONFIG_FILES="$CONFIG_FILES lib/c_glib/test/Makefile" ;; + "lib/csharp/Makefile") CONFIG_FILES="$CONFIG_FILES lib/csharp/Makefile" ;; + "lib/csharp/test/Multiplex/Makefile") CONFIG_FILES="$CONFIG_FILES lib/csharp/test/Multiplex/Makefile" ;; + "lib/d/Makefile") CONFIG_FILES="$CONFIG_FILES lib/d/Makefile" ;; + "lib/d/test/Makefile") CONFIG_FILES="$CONFIG_FILES lib/d/test/Makefile" ;; + "lib/erl/Makefile") CONFIG_FILES="$CONFIG_FILES lib/erl/Makefile" ;; + "lib/go/Makefile") CONFIG_FILES="$CONFIG_FILES lib/go/Makefile" ;; + "lib/go/test/Makefile") CONFIG_FILES="$CONFIG_FILES lib/go/test/Makefile" ;; + "lib/haxe/test/Makefile") CONFIG_FILES="$CONFIG_FILES lib/haxe/test/Makefile" ;; + "lib/hs/Makefile") CONFIG_FILES="$CONFIG_FILES lib/hs/Makefile" ;; + "lib/java/Makefile") CONFIG_FILES="$CONFIG_FILES lib/java/Makefile" ;; + "lib/js/Makefile") CONFIG_FILES="$CONFIG_FILES lib/js/Makefile" ;; + "lib/js/test/Makefile") CONFIG_FILES="$CONFIG_FILES lib/js/test/Makefile" ;; + "lib/json/Makefile") CONFIG_FILES="$CONFIG_FILES lib/json/Makefile" ;; + "lib/json/test/Makefile") CONFIG_FILES="$CONFIG_FILES lib/json/test/Makefile" ;; + "lib/netcore/Makefile") CONFIG_FILES="$CONFIG_FILES lib/netcore/Makefile" ;; + "lib/nodejs/Makefile") CONFIG_FILES="$CONFIG_FILES lib/nodejs/Makefile" ;; + "lib/perl/Makefile") CONFIG_FILES="$CONFIG_FILES lib/perl/Makefile" ;; + "lib/perl/test/Makefile") CONFIG_FILES="$CONFIG_FILES lib/perl/test/Makefile" ;; + "lib/php/Makefile") CONFIG_FILES="$CONFIG_FILES lib/php/Makefile" ;; + "lib/php/test/Makefile") CONFIG_FILES="$CONFIG_FILES lib/php/test/Makefile" ;; + "lib/dart/Makefile") CONFIG_FILES="$CONFIG_FILES lib/dart/Makefile" ;; + "lib/py/Makefile") CONFIG_FILES="$CONFIG_FILES lib/py/Makefile" ;; + "lib/rb/Makefile") CONFIG_FILES="$CONFIG_FILES lib/rb/Makefile" ;; + "lib/rs/Makefile") CONFIG_FILES="$CONFIG_FILES lib/rs/Makefile" ;; + "lib/rs/test/Makefile") CONFIG_FILES="$CONFIG_FILES lib/rs/test/Makefile" ;; + "lib/lua/Makefile") CONFIG_FILES="$CONFIG_FILES lib/lua/Makefile" ;; + "lib/xml/Makefile") CONFIG_FILES="$CONFIG_FILES lib/xml/Makefile" ;; + "lib/xml/test/Makefile") CONFIG_FILES="$CONFIG_FILES lib/xml/test/Makefile" ;; + "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; + "test/features/Makefile") CONFIG_FILES="$CONFIG_FILES test/features/Makefile" ;; + "test/c_glib/Makefile") CONFIG_FILES="$CONFIG_FILES test/c_glib/Makefile" ;; + "test/cpp/Makefile") CONFIG_FILES="$CONFIG_FILES test/cpp/Makefile" ;; + "test/csharp/Makefile") CONFIG_FILES="$CONFIG_FILES test/csharp/Makefile" ;; + "test/erl/Makefile") CONFIG_FILES="$CONFIG_FILES test/erl/Makefile" ;; + "test/go/Makefile") CONFIG_FILES="$CONFIG_FILES test/go/Makefile" ;; + "test/haxe/Makefile") CONFIG_FILES="$CONFIG_FILES test/haxe/Makefile" ;; + "test/hs/Makefile") CONFIG_FILES="$CONFIG_FILES test/hs/Makefile" ;; + "test/lua/Makefile") CONFIG_FILES="$CONFIG_FILES test/lua/Makefile" ;; + "test/netcore/Makefile") CONFIG_FILES="$CONFIG_FILES test/netcore/Makefile" ;; + "test/php/Makefile") CONFIG_FILES="$CONFIG_FILES test/php/Makefile" ;; + "test/dart/Makefile") CONFIG_FILES="$CONFIG_FILES test/dart/Makefile" ;; + "test/perl/Makefile") CONFIG_FILES="$CONFIG_FILES test/perl/Makefile" ;; + "test/py/Makefile") CONFIG_FILES="$CONFIG_FILES test/py/Makefile" ;; + "test/py.twisted/Makefile") CONFIG_FILES="$CONFIG_FILES test/py.twisted/Makefile" ;; + "test/py.tornado/Makefile") CONFIG_FILES="$CONFIG_FILES test/py.tornado/Makefile" ;; + "test/rb/Makefile") CONFIG_FILES="$CONFIG_FILES test/rb/Makefile" ;; + "test/rs/Makefile") CONFIG_FILES="$CONFIG_FILES test/rs/Makefile" ;; + "tutorial/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/Makefile" ;; + "tutorial/c_glib/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/c_glib/Makefile" ;; + "tutorial/cpp/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/cpp/Makefile" ;; + "tutorial/d/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/d/Makefile" ;; + "tutorial/go/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/go/Makefile" ;; + "tutorial/haxe/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/haxe/Makefile" ;; + "tutorial/hs/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/hs/Makefile" ;; + "tutorial/java/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/java/Makefile" ;; + "tutorial/js/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/js/Makefile" ;; + "tutorial/netcore/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/netcore/Makefile" ;; + "tutorial/nodejs/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/nodejs/Makefile" ;; + "tutorial/dart/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/dart/Makefile" ;; + "tutorial/py/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/py/Makefile" ;; + "tutorial/py.twisted/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/py.twisted/Makefile" ;; + "tutorial/py.tornado/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/py.tornado/Makefile" ;; + "tutorial/rb/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/rb/Makefile" ;; + "tutorial/rs/Makefile") CONFIG_FILES="$CONFIG_FILES tutorial/rs/Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_LINKS+set}" = set || CONFIG_LINKS=$config_links + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :L $CONFIG_LINKS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + :L) + # + # CONFIG_LINK + # + + if test "$ac_source" = "$ac_file" && test "$srcdir" = '.'; then + : + else + # Prefer the file from the source tree if names are identical. + if test "$ac_source" = "$ac_file" || test ! -r "$ac_source"; then + ac_source=$srcdir/$ac_source + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: linking $ac_source to $ac_file" >&5 +$as_echo "$as_me: linking $ac_source to $ac_file" >&6;} + + if test ! -r "$ac_source"; then + as_fn_error $? "$ac_source: file not found" "$LINENO" 5 + fi + rm -f "$ac_file" + + # Try a relative symlink, then a hard link, then a copy. + case $ac_source in + [\\/$]* | ?:[\\/]* ) ac_rel_source=$ac_source ;; + *) ac_rel_source=$ac_top_build_prefix$ac_source ;; + esac + ln -s "$ac_rel_source" "$ac_file" 2>/dev/null || + ln "$ac_source" "$ac_file" 2>/dev/null || + cp -p "$ac_source" "$ac_file" || + as_fn_error $? "cannot link or copy $ac_source to $ac_file" "$LINENO" 5 + fi + ;; + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options that allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST + fi + + cfgfile=${ofile}T + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL +# Generated automatically by $as_me ($PACKAGE) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +# Copyright (C) 2014 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program or library that is built +# using GNU Libtool, you may include this file under the same +# distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# The names of the tagged configurations supported by this script. +available_tags='CXX ' + +# Configured defaults for sys_lib_dlsearch_path munging. +: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shared archive member basename,for filename based shared library versioning on AIX. +shared_archive_member_spec=$shared_archive_member_spec + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method = "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive. +AR_FLAGS=$lt_AR_FLAGS + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm into a list of symbols to manually relocate. +global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name lister interface. +nm_interface=$lt_lt_cv_nm_interface + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and where our libraries should be installed. +lt_sysroot=$lt_sysroot + +# Command to truncate a binary pipe. +lt_truncate_bin=$lt_lt_cv_truncate_bin + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Detected run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path + +# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. +configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \$shlibpath_var if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# ### END LIBTOOL CONFIG + +_LT_EOF + + cat <<'_LT_EOF' >> "$cfgfile" + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain=$ac_aux_dir/ltmain.sh + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# How to create reloadable object files. +reload_flag=$lt_reload_flag_CXX +reload_cmds=$lt_reload_cmds_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \$shlibpath_var if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi + +# +# CONFIG_SUBDIRS section. +# +if test "$no_recursion" != yes; then + + # Remove --cache-file, --srcdir, and --disable-option-checking arguments + # so they do not pile up. + ac_sub_configure_args= + ac_prev= + eval "set x $ac_configure_args" + shift + for ac_arg + do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case $ac_arg in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ + | --c=*) + ;; + --config-cache | -C) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + ;; + --disable-option-checking) + ;; + *) + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_sub_configure_args " '$ac_arg'" ;; + esac + done + + # Always prepend --prefix to ensure using the same prefix + # in subdir configurations. + ac_arg="--prefix=$prefix" + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" + + # Pass --silent + if test "$silent" = yes; then + ac_sub_configure_args="--silent $ac_sub_configure_args" + fi + + # Always prepend --disable-option-checking to silence warnings, since + # different subdirs can have different --enable and --with options. + ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" + + ac_popdir=`pwd` + for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue + + # Do not complain, so a configure script can configure whichever + # parts of a large source tree are present. + test -d "$srcdir/$ac_dir" || continue + + ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" + $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 + $as_echo "$ac_msg" >&6 + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + cd "$ac_dir" + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f "$ac_srcdir/configure.gnu"; then + ac_sub_configure=$ac_srcdir/configure.gnu + elif test -f "$ac_srcdir/configure"; then + ac_sub_configure=$ac_srcdir/configure + elif test -f "$ac_srcdir/configure.in"; then + # This should be Cygnus configure. + ac_sub_configure=$ac_aux_dir/configure + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 +$as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} + ac_sub_configure= + fi + + # The recursion is here. + if test -n "$ac_sub_configure"; then + # Make the cache file name correct relative to the subdirectory. + case $cache_file in + [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; + *) # Relative name. + ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 +$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} + # The eval makes quoting arguments work. + eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ + --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || + as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 + fi + + cd "$ac_popdir" + done +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + + +echo +echo "$PACKAGE $VERSION" +echo +echo "Building C (GLib) Library .... : $have_c_glib" +echo "Building C# (Mono) Library ... : $have_csharp" +echo "Building C++ Library ......... : $have_cpp" +echo "Building D Library ........... : $have_d" +echo "Building Dart Library ........ : $have_dart" +echo "Building dotnetcore Library .. : $have_dotnetcore" +echo "Building Erlang Library ...... : $have_erlang" +echo "Building Go Library .......... : $have_go" +echo "Building Haskell Library ..... : $have_haskell" +echo "Building Haxe Library ........ : $have_haxe" +echo "Building Java Library ........ : $have_java" +echo "Building Lua Library ......... : $have_lua" +echo "Building NodeJS Library ...... : $have_nodejs" +echo "Building Perl Library ........ : $have_perl" +echo "Building PHP Library ......... : $have_php" +echo "Building Plugin Support ...... : $have_plugin" +echo "Building Python Library ...... : $have_python" +echo "Building Py3 Library ......... : $have_py3" +echo "Building Ruby Library ........ : $have_ruby" +echo "Building Rust Library ........ : $have_rs" + +if test "$have_csharp" = "yes" ; then + echo + echo "C# Library:" + echo " Using .NET 3.5 ............ : $net_3_5" + echo " Using mono version ........ : $($MCS --version | head -1)" +fi +if test "$have_cpp" = "yes" ; then + echo + echo "C++ Library:" + echo " C++ compiler .............. : $CXX" + echo " Build TZlibTransport ...... : $have_zlib" + echo " Build TNonblockingServer .. : $have_libevent" + echo " Build TQTcpServer (Qt4) ... : $have_qt" + echo " Build TQTcpServer (Qt5) ... : $have_qt5" + echo " C++ compiler version ...... : $($CXX --version | head -1)" +fi +if test "$have_d" = "yes" ; then + echo + echo "D Library:" + echo " Using D Compiler .......... : $DMD" + echo " Building D libevent tests . : $with_d_event_tests" + echo " Building D SSL tests ...... : $with_d_ssl_tests" + echo " Using D version ........... : $($DMD --version | head -1)" +fi +if test "$have_dart" = "yes" ; then + echo + echo "Dart Library:" + echo " Using Dart ................ : $DART" + echo " Using Pub ................. : $DARTPUB" + echo " Using Dart version ........ : $($DART --version 2>&1)" +fi +if test "$have_dotnetcore" = "yes" ; then + echo + echo ".NET Core Library:" + echo " Using .NET Core ........... : $DOTNETCORE" + echo " Using .NET Core version ... : $DOTNETCORE_VERSION" +fi +if test "$have_erlang" = "yes" ; then + echo + echo "Erlang Library:" + echo " Using erlc ................ : $ERLC" + echo " Using rebar ............... : $REBAR" + echo " Using erlc version ........ : $($ERL -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell | tr -d '\"')" +fi +if test "$have_go" = "yes" ; then + echo + echo "Go Library:" + echo " Using Go................... : $GO" + echo " Using Go version........... : $($GO version)" +fi +if test "$have_haskell" = "yes" ; then + echo + echo "Haskell Library:" + echo " Using Cabal ............... : $CABAL" + echo " Using Haskell ............. : $RUNHASKELL" + echo " Using Haskell version ..... : $($RUNHASKELL --version)" +fi +if test "$have_haxe" = "yes" ; then + echo + echo "Haxe Library:" + echo " Using Haxe ................ : $HAXE" + echo " Using Haxe version ........ : $HAXE_VERSION" +fi +if test "$have_java" = "yes" ; then + echo + echo "Java Library:" + echo " Using ant ................. : $ANT" + echo " Using java ................ : $JAVA" + echo " Using javac ............... : $JAVAC" + echo " Using ant version ......... : $($ANT -version 2>&1)" + echo " Using java version ........ : $($JAVA -version 2>&1 | grep 'version ')" +fi +if test "$have_lua" = "yes" ; then + echo + echo "Lua Library:" + echo " Using Lua ................. : $LUA" + echo " Using Lua version.......... : $($LUA -v)" +fi +if test "$have_nodejs" = "yes" ; then + echo + echo "NodeJS Library:" + echo " Using NodeJS .............. : $NODEJS" + echo " Using NodeJS version....... : $($NODEJS --version)" +fi +if test "$have_perl" = "yes" ; then + echo + echo "Perl Library:" + echo " Using Perl ................ : $PERL" + echo " Using Perl version ........ : $($PERL -v | grep 'version ')" +fi +if test "$have_php" = "yes" ; then + echo + echo "PHP Library:" + echo " Using php-config .......... : $PHP_CONFIG" + echo " Using php version ......... : $($PHP --version | head -1)" +fi +if test "$have_python" = "yes" ; then + echo + echo "Python Library:" + echo " Using Python .............. : $PYTHON" + echo " Using Python version ...... : $($PYTHON --version 2>&1)" + if test "$have_py3" = "yes" ; then + echo " Using Python3 ............. : $PYTHON3" + echo " Using Python3 version ..... : $($PYTHON3 --version)" + fi + if test "$have_trial" = "yes"; then + echo " Using trial ............... : $TRIAL" + fi +fi +if test "$have_ruby" = "yes" ; then + echo + echo "Ruby Library:" + echo " Using Ruby ................ : $RUBY" + echo " Using Ruby version ........ : $($RUBY --version)" +fi +if test "$have_rs" = "yes" ; then + echo + echo "Rust Library:" + echo " Using Cargo................ : $CARGO" + echo " Using rustc................ : $RUSTC" + echo " Using Rust version......... : $($RUSTC --version)" +fi +echo +echo "If something is missing that you think should be present," +echo "please skim the output of configure to find the missing" +echo "component. Details are present in config.log." +echo diff --git a/configure.ac b/configure.ac new file mode 100755 index 0000000..6a7a1a5 --- /dev/null +++ b/configure.ac @@ -0,0 +1,1055 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +AC_PREREQ(2.65) +AC_CONFIG_MACRO_DIR([./aclocal]) + +AC_INIT([thrift], [0.11.0]) + +AC_CONFIG_AUX_DIR([.]) + +AM_INIT_AUTOMAKE([1.13 subdir-objects tar-ustar]) +PKG_PROG_PKG_CONFIG + +AC_ARG_VAR([PY_PREFIX], [Prefix for installing Python modules. + (Normal --prefix is ignored for Python because + Python has different conventions.) + Default = "/usr"]) +AS_IF([test "x$PY_PREFIX" = x], [PY_PREFIX="/usr"]) + +AC_ARG_VAR([JAVA_PREFIX], [Prefix for installing the Java lib jar. + Default = "/usr/local/lib"]) +AS_IF([test "x$JAVA_PREFIX" != x], [JAVA_PREFIX="$JAVA_PREFIX/usr/local/lib"], + [test "x$PREFIX" != x], [JAVA_PREFIX="$PREFIX/usr/local/lib"], + [JAVA_PREFIX="/usr/local/lib"]) + +AC_ARG_VAR([RUBY_PREFIX], [Prefix for installing Ruby modules. + (Normal --prefix is ignored for Ruby because + Ruby has different conventions.) + Default = none, let ruby setup decide]) + +AC_ARG_VAR([PHP_PREFIX], [Prefix for installing PHP modules. + (Normal --prefix is ignored for PHP because + PHP has different conventions.) + Default = "/usr/lib/php"]) +AS_IF([test "x$PHP_PREFIX" = x], [PHP_PREFIX="/usr/lib/php"]) + +AC_ARG_VAR([PHP_CONFIG_PREFIX], + [Prefix for installing PHP extension module .ini file. + (Normal --prefix is ignored for PHP because PHP has + different conventions.) + Default = "/etc/php.d"]) +AS_IF([test "x$PHP_CONFIG_PREFIX" = x], [PHP_CONFIG_PREFIX="/etc/php.d"]) + +AC_ARG_VAR([INSTALLDIRS], [When installing Perl modules, specifies which + of the sets of installation directories + to choose: perl, site or vendor. + Default = "vendor"]) +AS_IF([test "x$INSTALLDIRS" = x], [INSTALLDIRS="vendor"]) + +AC_ARG_VAR([PERL_PREFIX], [Prefix for installing Perl modules. + (Normal --prefix is ignored for Perl because + Perl has different conventions.) + Ignored, when INSTALLDIRS set to site or vendor. + Default = "/usr/local/lib"]) +AS_IF([test "x$PERL_PREFIX" = x], [PERL_PREFIX="/usr/local"]) + +AC_ARG_VAR([CABAL_CONFIGURE_FLAGS], + [Extra flags to pass to cabal: "cabal Setup.lhs configure $CABAL_CONFIGURE_FLAGS". + (Typically used to set --user or force --global.)]) + +AC_SUBST(CABAL_CONFIGURE_FLAGS) + +AC_ARG_VAR([D_IMPORT_PREFIX], [Prefix for installing D modules. + [INCLUDEDIR/d2]]) +AS_IF([test "x$D_IMPORT_PREFIX" = x], [D_IMPORT_PREFIX="${includedir}/d2"]) + +AC_ARG_VAR([DMD_LIBEVENT_FLAGS], [DMD flags for linking libevent (auto-detected if not set).]) +AC_ARG_VAR([DMD_OPENSSL_FLAGS], [DMD flags for linking OpenSSL (auto-detected if not set).]) + +AC_ARG_VAR([THRIFT], [Path to the thrift tool (needed for cross-compilation).]) +AS_IF([test "x$THRIFT" = x], [THRIFT=`pwd`/compiler/cpp/thrift]) + +AC_PROG_CC +AC_PROG_CPP +AC_PROG_CXX +AC_PROG_INSTALL +AC_PROG_LIBTOOL +AC_PROG_MAKE_SET +AC_PROG_BISON(2.5) +AC_PROG_YACC +AC_PROG_LEX +AM_PROG_LEX +AC_PROG_LN_S +AC_PROG_MKDIR_P +AC_PROG_AWK +AC_PROG_RANLIB + +AC_LANG([C++]) +AX_CXX_COMPILE_STDCXX_11([noext], [optional]) +if test "$ac_success" = "no"; then + CXXFLAGS="$CXXFLAGS -Wno-variadic-macros -Wno-long-long -Wno-c++11-long-long" +fi + +AM_EXTRA_RECURSIVE_TARGETS([style]) +AC_SUBST(CPPSTYLE_CMD, 'find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;') + +AC_ARG_ENABLE([libs], + AS_HELP_STRING([--enable-libs], [build the Apache Thrift libraries [default=yes]]), + [], enable_libs=yes +) +have_libs=yes +if test "$enable_libs" = "no"; then + have_libs="no" + with_cpp="no" + with_c_glib="no" + with_java="no" + with_csharp="no" + with_python="no" + with_py3="no" + with_ruby="no" + with_haskell="no" + with_haxe="no" + with_dotnetcore="no" + with_perl="no" + with_php="no" + with_php_extension="no" + with_dart="no" + with_erlang="no" + with_go="no" + with_d="no" + with_nodejs="no" + with_lua="no" + with_rs="no" +fi + +AX_THRIFT_LIB(cpp, [C++], yes) +have_cpp=no +if test "$with_cpp" = "yes"; then + AX_BOOST_BASE([1.53.0]) + if test "x$succeeded" = "xyes" ; then + AC_SUBST([BOOST_LIB_DIR], [$(echo "$BOOST_LDFLAGS" | sed -e 's/^\-L//')]) + AC_SUBST([BOOST_CHRONO_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_chrono.a")]) + AC_SUBST([BOOST_FILESYSTEM_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_filesystem.a")]) + AC_SUBST([BOOST_SYSTEM_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_system.a")]) + AC_SUBST([BOOST_TEST_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_unit_test_framework.a")]) + AC_SUBST([BOOST_THREAD_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_thread.a")]) + have_cpp="yes" + fi + + AX_LIB_EVENT([1.0]) + have_libevent=$success + + AX_LIB_ZLIB([1.2.3]) + have_zlib=$success + + AX_THRIFT_LIB(qt4, [Qt], yes) + have_qt=no + if test "$with_qt4" = "yes"; then + PKG_CHECK_MODULES([QT], [QtCore >= 4.3, QtNetwork >= 4.3], have_qt=yes, have_qt=no) + fi + if test "$have_qt" = "yes"; then + AC_PATH_PROGS([QT_MOC], [moc-qt4 moc], "fail") + if test "$QT_MOC" = "fail"; then + have_qt=no + fi + fi + + AX_THRIFT_LIB(qt5, [Qt5], yes) + have_qt5=no + qt_reduce_reloc="" + if test "$with_qt5" = "yes"; then + PKG_CHECK_MODULES([QT5], [Qt5Core >= 5.0, Qt5Network >= 5.0], + [have_qt5=yes;qt_reduce_reloc=`$PKG_CONFIG --variable=qt_config Qt5Core | grep "reduce_relocations"`], + [have_qt5=no]) + fi + if test "$have_qt5" = "yes"; then + AC_PATH_PROGS([QT5_MOC], [moc-qt5 moc], "fail") + if test "$QT5_MOC" = "fail"; then + have_qt5=no + fi + fi +fi +AM_CONDITIONAL([WITH_CPP], [test "$have_cpp" = "yes"]) +AM_CONDITIONAL([AMX_HAVE_LIBEVENT], [test "$have_libevent" = "yes"]) +AM_CONDITIONAL([AMX_HAVE_ZLIB], [test "$have_zlib" = "yes"]) +AM_CONDITIONAL([AMX_HAVE_QT], [test "$have_qt" = "yes"]) +AM_CONDITIONAL([AMX_HAVE_QT5], [test "$have_qt5" = "yes"]) +AM_CONDITIONAL([QT5_REDUCE_RELOCATIONS], [test "x$qt_reduce_reloc" != "x"]) + +AX_THRIFT_LIB(c_glib, [C (GLib)], yes) +if test "$with_c_glib" = "yes"; then + PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.0], have_glib2=yes, have_glib2=no) + PKG_CHECK_MODULES([GOBJECT], [gobject-2.0 >= 2.0], have_gobject2=yes, have_gobject2=no) + if test "$have_glib2" = "yes" -a "$have_gobject2" = "yes" ; then + have_c_glib="yes" + fi +fi +AM_CONDITIONAL(WITH_C_GLIB, [test "$have_glib2" = "yes" -a "$have_gobject2" = "yes"]) + +echo "OpenSSL check" +if test "$have_cpp" = "yes" -o "$have_c_glib" = "yes"; then + echo "Have cpp or c so we check for OpenSSL" + AX_CHECK_OPENSSL() +fi + +AX_THRIFT_LIB(csharp, [C#], yes) +if test "$with_csharp" = "yes"; then + PKG_CHECK_MODULES(MONO, mono >= 2.11.0, mono_2_11=yes, mono_2_11=no) + if test "$mono_2_11" == "yes"; then + AC_PATH_PROG([MCS], [mcs]) + if test "x$MCS" != "x"; then + mono_mcs="yes" + fi + fi + PKG_CHECK_MODULES(MONO, mono >= 2.0.0, net_3_5=yes, net_3_5=no) + PKG_CHECK_MODULES(MONO, mono >= 1.2.4, have_mono=yes, have_mono=no) + if test "$have_mono" = "yes" ; then + have_csharp="yes" + fi +fi +AM_CONDITIONAL(WITH_MONO, [test "$have_csharp" = "yes"]) +AM_CONDITIONAL(NET_2_0, [test "$net_3_5" = "no"]) +AM_CONDITIONAL(MONO_MCS, [test "$mono_mcs" = "yes"]) + +AX_THRIFT_LIB(java, [Java], yes) +if test "$with_java" = "yes"; then + AX_JAVAC_AND_JAVA + AC_PATH_PROG([ANT], [ant]) + AX_CHECK_ANT_VERSION($ANT, 1.7) + AC_SUBST(CLASSPATH) + AC_SUBST(ANT_FLAGS) + if test "x$JAVA" != "x" && test "x$JAVAC" != "x" && test "x$ANT" != "x" ; then + have_java="yes" + fi +fi +AM_CONDITIONAL([WITH_JAVA], [test "$have_java" = "yes"]) + +AX_THRIFT_LIB(erlang, [Erlang], yes) +if test "$with_erlang" = "yes"; then + AC_ERLANG_PATH_ERL + AC_ERLANG_PATH_ERLC + AC_PATH_PROG([REBAR], [rebar]) + if test -n "$ERLC" ; then + AC_ERLANG_SUBST_LIB_DIR + # Install into the detected Erlang directory instead of $libdir/erlang/lib + ERLANG_INSTALL_LIB_DIR="$ERLANG_LIB_DIR" + AC_ERLANG_SUBST_INSTALL_LIB_SUBDIR(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) + fi + if test -n "$ERL" -a -n "$ERLC" && test "x$REBAR" != "x" ; then + have_erlang="yes" + + # otp_release is simply a number (like "17") for OTP17+ while "R16..." for OTP16 or less. + # OTP version is currently only used for running tests. + if $ERL -eval 'erlang:display(erlang:system_info(otp_release)),halt().' -noshell | grep "^\"R" >/dev/null; then + erlang_otp16_or_less="yes" + fi + fi +fi +AM_CONDITIONAL(WITH_ERLANG, [test "$have_erlang" = "yes"]) +AM_CONDITIONAL(ERLANG_OTP16, [test "$erlang_otp16_or_less" = "yes"]) + +AX_THRIFT_LIB(nodejs, [Nodejs], yes) +have_nodejs=no +if test "$with_nodejs" = "yes"; then + AC_PATH_PROGS([NODEJS], [nodejs node]) + AC_PATH_PROG([NPM], [npm]) + if test "x$NODEJS" != "x" -a "x$NPM" != "x"; then + have_nodejs="yes" + fi +fi +AM_CONDITIONAL(WITH_NODEJS, [test "$have_nodejs" = "yes"]) +AM_CONDITIONAL(HAVE_NPM, [test "x$NPM" != "x"]) + +AX_THRIFT_LIB(lua, [Lua], yes) +have_lua=no +if test "$with_lua" = "yes"; then + AX_PROG_LUA(5.2,, have_lua="yes", have_lua="no") + if test "$have_lua" = "yes"; then + AX_LUA_HEADERS(, have_lua="no") + AX_LUA_LIBS(, have_lua="no") + fi +fi +AM_CONDITIONAL(WITH_LUA, [test "$have_lua" = "yes"]) + +# Find python regardless of with_python value, because it's needed by make cross +AM_PATH_PYTHON(2.6,, :) +AX_THRIFT_LIB(python, [Python], yes) +if test "$with_python" = "yes"; then + if test -n "$PYTHON"; then + have_python="yes" + fi + AC_PATH_PROG([TRIAL], [trial]) + if test -n "$TRIAL"; then + have_trial="yes" + fi +fi +AM_CONDITIONAL(WITH_PYTHON, [test "$have_python" = "yes"]) +AM_CONDITIONAL(WITH_TWISTED_TEST, [test "$have_trial" = "yes"]) + +# Find "python3" executable. +# It's distro specific and far from ideal but needed to cross test py2-3 at once. +# TODO: find "python2" if it's 3.x +have_py3="no" +if python --version 2>&1 | grep -q "Python 2"; then + AC_PATH_PROGS([PYTHON3], [python3 python3.5 python35 python3.4 python34]) + if test -n "$PYTHON3"; then + have_py3="yes" + fi +fi +AM_CONDITIONAL(WITH_PY3, [test "$have_py3" = "yes"]) + +AX_THRIFT_LIB(perl, [Perl], yes) +if test "$with_perl" = "yes"; then + AC_PATH_PROG([PERL], [perl]) + if test -n "$PERL" ; then + AC_PROG_PERL_MODULES([Bit::Vector], success="yes", success="no") + have_perl_bit_vector="$success" + AC_PROG_PERL_MODULES([Class::Accessor], success="yes", success="no") + have_perl_class_accessor="$success" + fi + if test -n "$PERL" -a "$have_perl_bit_vector" = "yes" ; then + if test -n "$PERL" -a "$have_perl_class_accessor" = "yes" ; then + have_perl="yes" + fi + fi +fi +AM_CONDITIONAL(WITH_PERL, [test "$have_perl" = "yes"]) + +AX_THRIFT_LIB(php, [PHP], yes) +if test "$with_php" = "yes"; then + AC_PATH_PROG([PHP], [php]) + if test -n "$PHP" ; then + have_php="yes" + fi +fi +AM_CONDITIONAL(WITH_PHP, [test "$have_php" = "yes"]) + +AX_THRIFT_LIB(php_extension, [PHP_EXTENSION], yes) +if test "$with_php_extension" = "yes"; then + if test -f "lib/php/src/ext/thrift_protocol/configure"; then + AC_PATH_PROG([PHP_CONFIG], [php-config]) + if test -n "$PHP_CONFIG" ; then + AC_CONFIG_SUBDIRS([lib/php/src/ext/thrift_protocol]) + have_php_extension="yes" + fi + fi +fi +AM_CONDITIONAL(WITH_PHP_EXTENSION, [test "$have_php_extension" = "yes"]) + +AC_PATH_PROG([PHPUNIT], [phpunit]) +AM_CONDITIONAL(HAVE_PHPUNIT, [test "x$PHPUNIT" != "x"]) + +AX_THRIFT_LIB(dart, [DART], yes) +if test "$with_dart" = "yes"; then + AC_PATH_PROG([DART], [dart]) + AC_PATH_PROG([DARTPUB], [pub]) + if test "x$DART" != "x" -a "x$DARTPUB" != "x"; then + have_dart="yes" + fi +fi +AM_CONDITIONAL(WITH_DART, [test "$have_dart" = "yes"]) + +AX_THRIFT_LIB(ruby, [Ruby], yes) +have_ruby=no +if test "$with_ruby" = "yes"; then + AC_PATH_PROG([RUBY], [ruby]) + AC_PATH_PROG([BUNDLER], [bundle]) + if test "x$RUBY" != "x" -a "x$BUNDLER" != "x"; then + have_ruby="yes" + fi +fi +AM_CONDITIONAL(WITH_RUBY, [test "$have_ruby" = "yes"]) +AM_CONDITIONAL(HAVE_BUNDLER, [test "x$BUNDLER" != "x"]) + +AX_THRIFT_LIB(haskell, [Haskell], yes) +have_haskell=no +RUNHASKELL=true +CABAL=true +if test "$with_haskell" = "yes"; then + AC_PATH_PROG([CABAL], [cabal]) + AC_PATH_PROG([RUNHASKELL], [runhaskell]) + if test "x$CABAL" != "x" -a "x$RUNHASKELL" != "x"; then + have_haskell="yes" + else + RUNHASKELL=true + CABAL=true + fi +fi +AC_SUBST(CABAL) +AC_SUBST(RUNHASKELL) +AM_CONDITIONAL(WITH_HASKELL, [test "$have_haskell" = "yes"]) + +AX_THRIFT_LIB(go, [Go], yes) +if test "$with_go" = "yes"; then + AC_PATH_PROG([GO], [go]) + if [[ -x "$GO" ]] ; then + AS_IF([test -n "$GO"],[ + ax_go_version="1.4" + ax_go17_version="1.7" + + AC_MSG_CHECKING([for Go version]) + golang_version=`$GO version 2>&1 | $SED -e 's/\(go \)\(version \)\(go\)\(@<:@0-9@:>@.@<:@0-9@:>@.@<:@0-9@:>@\)\(@<:@\*@:>@*\).*/\4/'` + AC_MSG_RESULT($golang_version) + AC_SUBST([golang_version],[$golang_version]) + AX_COMPARE_VERSION([$ax_go_version],[le],[$golang_version],[ + : + have_go="yes" + ],[ + : + have_go="no" + ]) + AX_COMPARE_VERSION([$golang_version],[lt],[$ax_go17_version],[ + : + go_version_lt_17="yes" + ],[ + : + go_version_lt_17="no" + ]) + ],[ + AC_MSG_WARN([could not find Go ]) + have_go="no" + ]) + fi +fi +AM_CONDITIONAL(WITH_GO, [test "$have_go" = "yes"]) +AM_CONDITIONAL([GOVERSION_LT_17], [test "$go_version_lt_17" = "yes"]) + +AX_THRIFT_LIB(rs, [Rust], yes) +have_rs="no" +if test "$with_rs" = "yes"; then + AC_PATH_PROG([CARGO], [cargo]) + AC_PATH_PROG([RUSTC], [rustc]) + if [[ -x "$CARGO" ]] && [[ -x "$RUSTC" ]]; then + min_rustc_version="1.13" + + AC_MSG_CHECKING([for rustc version]) + rustc_version=`$RUSTC --version 2>&1 | $SED -e 's/\(rustc \)\([0-9]\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\).*/\2.\3/'` + AC_MSG_RESULT($rustc_version) + AC_SUBST([rustc_version],[$rustc_version]) + + AX_COMPARE_VERSION([$min_rustc_version],[le],[$rustc_version],[ + : + have_rs="yes" + ],[ + : + have_rs="no" + ]) + fi +fi +AM_CONDITIONAL(WITH_RS, [test "$have_rs" = "yes"]) + +AX_THRIFT_LIB(haxe, [Haxe], yes) +if test "$with_haxe" = "yes"; then + AC_PATH_PROG([HAXE], [haxe]) + if [[ -x "$HAXE" ]] ; then + AX_PROG_HAXE_VERSION( [3.1.3], have_haxe="yes", have_haxe="no") + fi +fi +AM_CONDITIONAL(WITH_HAXE, [test "$have_haxe" = "yes"]) + + +AX_THRIFT_LIB(dotnetcore, [.NET Core], yes) +if test "$with_dotnetcore" = "yes"; then + AC_PATH_PROG([DOTNETCORE], [dotnet]) + if [[ -x "$DOTNETCORE" ]] ; then + AX_PROG_DOTNETCORE_VERSION( [2.0.0], have_dotnetcore="yes", have_dotnetcore="no") + fi +fi +AM_CONDITIONAL(WITH_DOTNETCORE, [test "$have_dotnetcore" = "yes"]) + + +AX_THRIFT_LIB(d, [D], yes) +if test "$with_d" = "yes"; then + AX_DMD + AC_SUBST(DMD) + if test "x$DMD" != "x"; then + have_d="yes" + fi +fi + +# Determine actual name of the generated D library for use in the command line +# when compiling tests. This is needed because the -l syntax doesn't work +# with OPTLINK (Windows). +lib_prefix=lib +lib_suffix=a +case "$host_os" in + cygwin* | mingw* | pw32* | cegcc*) + lib_prefix="" + lib_suffix=lib + ;; +esac +D_LIB_NAME="${lib_prefix}thriftd.${lib_suffix}" +AC_SUBST(D_LIB_NAME) +D_EVENT_LIB_NAME="${lib_prefix}thriftd-event.${lib_suffix}" +AC_SUBST(D_EVENT_LIB_NAME) +D_SSL_LIB_NAME="${lib_prefix}thriftd-ssl.${lib_suffix}" +AC_SUBST(D_SSL_LIB_NAME) + +if test "$have_d" = "yes"; then + AX_CHECK_D_MODULE(deimos.event2.event) + have_deimos_event2=$success + + with_d_event_tests="no" + if test "$have_deimos_event2" = "yes"; then + if test "x$DMD_LIBEVENT_FLAGS" = "x"; then + if test "$dmd_optlink" = "yes"; then + AC_MSG_WARN([D libevent interface found, but cannot auto-detect \ +linker flags for OPTLINK. Please set DMD_LIBEVENT_FLAGS manually.]) + else + AX_LIB_EVENT([2.0]) + if test "$success" = "yes"; then + DMD_LIBEVENT_FLAGS=$(echo "$LIBEVENT_LDFLAGS $LIBEVENT_LIBS" | \ + sed -e 's/^ *//g;s/ *$//g;s/^\(.\)/-L\1/g;s/ */ -L/g') + with_d_event_tests="yes" + else + AC_MSG_WARN([D libevent interface present, but libevent library not found.]) + fi + fi + else + with_d_event_tests="yes" + fi + fi + + AX_CHECK_D_MODULE(deimos.openssl.ssl) + have_deimos_openssl=$success + + with_d_ssl_tests="no" + if test "$have_deimos_openssl" = "yes"; then + if test "x$DMD_OPENSSL_FLAGS" = "x"; then + if test "$dmd_optlink" = "yes"; then + AC_MSG_WARN([D OpenSSL interface found, but cannot auto-detect \ +linker flags for OPTLINK. Please set DMD_OPENSSL_FLAGS manually.]) + else + AX_CHECK_OPENSSL([with_d_ssl_tests="yes"]) + if test "$with_d_ssl_tests" = "yes"; then + DMD_OPENSSL_FLAGS=$(echo "$OPENSSL_LDFLAGS $OPENSSL_LIBS" | \ + sed -e 's/^ *//g;s/ *$//g;s/^\(.\)/-L\1/g;s/ */ -L/g') + else + AC_MSG_WARN([D OpenSSL interface present, but OpenSSL library not found.]) + fi + fi + else + with_d_ssl_tests="yes" + fi + fi +fi + +AM_CONDITIONAL(WITH_D, [test "$have_d" = "yes"]) +AM_CONDITIONAL(DMD_OPTLINK, [test "$dmd_optlink" = "yes"]) +AC_SUBST(DMD_OF_DIRSEP, "$dmd_of_dirsep") +AM_CONDITIONAL(HAVE_DEIMOS_EVENT2, [test "$have_deimos_event2" = "yes"]) +AM_CONDITIONAL(WITH_D_EVENT_TESTS, [test "$with_d_event_tests" = "yes"]) +AC_SUBST(DMD_LIBEVENT_FLAGS) +AM_CONDITIONAL(HAVE_DEIMOS_OPENSSL, [test "$have_deimos_openssl" = "yes"]) +AM_CONDITIONAL(WITH_D_SSL_TESTS, [test "$with_d_ssl_tests" = "yes"]) +AC_SUBST(DMD_OPENSSL_FLAGS) + +AC_ARG_ENABLE([tests], + AS_HELP_STRING([--enable-tests], [build tests [default=yes]]), + [], enable_tests=yes +) +have_tests=yes +if test "$enable_tests" = "no"; then + have_tests="no" +fi +AM_CONDITIONAL(WITH_TESTS, [test "$have_tests" = "yes"]) + +AC_ARG_ENABLE([plugin], + AS_HELP_STRING([--enable-plugin], [build compiler plugin support [default=no]]), + [], enable_plugin=no +) +have_plugin=yes +if test "$have_cpp" = "no" ; then + have_plugin="no" +fi +if test "$enable_plugin" = "no"; then + have_plugin="no" +fi +AC_CONFIG_LINKS([compiler/cpp/test/plugin/t_cpp_generator.cc:compiler/cpp/src/thrift/generate/t_cpp_generator.cc]) +AM_CONDITIONAL(WITH_PLUGIN, [test "$have_plugin" = "yes"]) + +AC_ARG_ENABLE([tutorial], + AS_HELP_STRING([--enable-tutorial], [build tutorial [default=yes]]), + [], enable_tutorial=yes +) +have_tutorial=yes +if test "$enable_tutorial" = "no"; then + have_tutorial="no" +fi +AM_CONDITIONAL(WITH_TUTORIAL, [test "$have_tutorial" = "yes"]) + +AM_CONDITIONAL(MINGW, false) +case "${host_os}" in +*mingw*) + mingw32_support="yes" + AC_CHECK_HEADER(windows.h) + AM_CONDITIONAL(MINGW, true) + ;; +*) + AC_ISC_POSIX + ;; +esac + +AC_C_CONST +AC_C_INLINE +AC_C_VOLATILE + +AC_HEADER_STDBOOL +AC_HEADER_STDC +AC_HEADER_TIME +AC_HEADER_SYS_WAIT +AC_TYPE_SIGNAL +AC_CHECK_HEADERS([arpa/inet.h]) +AC_CHECK_HEADERS([sys/param.h]) +AC_CHECK_HEADERS([fcntl.h]) +AC_CHECK_HEADERS([inttypes.h]) +AC_CHECK_HEADERS([limits.h]) +AC_CHECK_HEADERS([netdb.h]) +AC_CHECK_HEADERS([netinet/in.h]) +AC_CHECK_HEADERS([pthread.h]) +AC_CHECK_HEADERS([stddef.h]) +AC_CHECK_HEADERS([stdlib.h]) +AC_CHECK_HEADERS([sys/socket.h]) +AC_CHECK_HEADERS([sys/time.h]) +AC_CHECK_HEADERS([sys/un.h]) +AC_CHECK_HEADERS([sys/poll.h]) +AC_CHECK_HEADERS([sys/resource.h]) +AC_CHECK_HEADERS([unistd.h]) +AC_CHECK_HEADERS([libintl.h]) +AC_CHECK_HEADERS([malloc.h]) +AC_CHECK_HEADERS([openssl/ssl.h]) +AC_CHECK_HEADERS([openssl/rand.h]) +AC_CHECK_HEADERS([openssl/x509v3.h]) +AC_CHECK_HEADERS([sched.h]) +AC_CHECK_HEADERS([wchar.h]) + +AC_CHECK_LIB(pthread, pthread_create) +dnl NOTE(dreiss): I haven't been able to find any really solid docs +dnl on what librt is and how it fits into various Unix systems. +dnl My best guess is that it is where glibc stashes its implementation +dnl of the POSIX Real-Time Extensions. This seems necessary on Linux, +dnl and we haven't yet found a system where this is a problem. +AC_CHECK_LIB(rt, clock_gettime) +AC_CHECK_LIB(socket, setsockopt) + +AC_TYPE_INT16_T +AC_TYPE_INT32_T +AC_TYPE_INT64_T +AC_TYPE_INT8_T +AC_TYPE_MODE_T +AC_TYPE_OFF_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_UINT8_T +AC_CHECK_TYPES([ptrdiff_t], [], [echo "ptrdiff_t not found or g++ not installed - cannot continue" && exit 1]) + +AC_STRUCT_TM + +dnl NOTE(dreiss): AI_ADDRCONFIG is not defined on OpenBSD. +AC_CHECK_DECL([AI_ADDRCONFIG], [], + [AC_DEFINE([AI_ADDRCONFIG], 0, + [Define if the AI_ADDRCONFIG symbol is unavailable])], + [ + #include + #include + #include +]) + +AC_FUNC_ALLOCA +AC_FUNC_FORK +AC_FUNC_MALLOC +AC_FUNC_MEMCMP +AC_FUNC_REALLOC +AC_FUNC_SELECT_ARGTYPES +AC_FUNC_STAT +AC_FUNC_STRERROR_R +AC_FUNC_STRFTIME +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([strtoul]) +AC_CHECK_FUNCS([bzero]) +AC_CHECK_FUNCS([ftruncate]) +AC_CHECK_FUNCS([gethostbyname]) +AC_CHECK_FUNCS([gethostbyname_r]) +AC_CHECK_FUNCS([gettimeofday]) +AC_CHECK_FUNCS([memmove]) +AC_CHECK_FUNCS([memset]) +AC_CHECK_FUNCS([mkdir]) +AC_CHECK_FUNCS([realpath]) +AC_CHECK_FUNCS([select]) +AC_CHECK_FUNCS([setlocale]) +AC_CHECK_FUNCS([socket]) +AC_CHECK_FUNCS([strchr]) +AC_CHECK_FUNCS([strdup]) +AC_CHECK_FUNCS([strerror]) +AC_CHECK_FUNCS([strstr]) +AC_CHECK_FUNCS([strtol]) +AC_CHECK_FUNCS([sqrt]) +dnl The following functions are optional. +AC_CHECK_FUNCS([alarm]) +AC_CHECK_FUNCS([clock_gettime]) +AC_CHECK_FUNCS([sched_get_priority_min]) +AC_CHECK_FUNCS([sched_get_priority_max]) +AC_CHECK_FUNCS([inet_ntoa]) +AC_CHECK_FUNCS([pow]) + +if test "$cross_compiling" = "no" ; then + AX_SIGNED_RIGHT_SHIFT +fi + +dnl autoscan thinks we need this macro because we have a member function +dnl called "error". Invoke the macro but don't run the check so autoscan +dnl thinks we are in the clear. It's highly unlikely that we will ever +dnl actually use the function that this checks for. +if false ; then + AC_FUNC_ERROR_AT_LINE +fi + +# --- Coverage hooks --- + +AC_ARG_ENABLE(coverage, + [ --enable-coverage turn on -fprofile-arcs -ftest-coverage], + [case "${enableval}" in + yes) ENABLE_COVERAGE=1 ;; + no) ENABLE_COVERAGE=0 ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-cov) ;; + esac], + [ENABLE_COVERAGE=2]) + +if test "x[$]ENABLE_COVERAGE" = "x1"; then + AC_MSG_WARN(enable coverage) + GCOV_CFLAGS="`echo \"[$]CFLAGS\" | perl -pe 's/-O\d+//g;'` -fprofile-arcs -ftest-coverage" + GCOV_CXXFLAGS="`echo \"[$]CXXFLAGS\" | perl -pe 's/-O\d+//g;'` -fprofile-arcs -ftest-coverage" + GCOV_LDFLAGS="-XCClinker -fprofile-arcs -XCClinker -ftest-coverage" +fi + +AC_SUBST(ENABLE_COVERAGE) +AC_SUBST(GCOV_CFLAGS) +AC_SUBST(GCOV_CXXFLAGS) +AC_SUBST(GCOV_LDFLAGS) + +AC_ARG_ENABLE(boostthreads, + [ --enable-boostthreads use boost threads, instead of POSIX pthread (experimental) ], + [case "${enableval}" in + yes) ENABLE_BOOSTTHREADS=1 ;; + no) ENABLE_BOOSTTHREADS=0 ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-cov) ;; + esac], + [ENABLE_BOOSTTHREADS=2]) + + +if test "x[$]ENABLE_BOOSTTHREADS" = "x1"; then + AC_MSG_WARN(enable boostthreads) + AC_DEFINE([USE_BOOST_THREAD], [1], [experimental --enable-boostthreads that replaces POSIX pthread by boost::thread]) + LIBS="-lboost_thread $LIBS" +fi + +AM_CONDITIONAL([WITH_BOOSTTHREADS], [test "x[$]ENABLE_BOOSTTHREADS" = "x1"]) + +AC_CONFIG_HEADERS(config.h:config.hin) +AC_CONFIG_HEADERS(lib/cpp/src/thrift/config.h:config.hin) +AC_CONFIG_HEADERS(lib/c_glib/src/thrift/config.h:config.hin) +# gruard against pre defined config.h +AH_TOP([ +#ifndef CONFIG_H +#define CONFIG_H +]) +AH_BOTTOM([ +#endif +]) + + +AC_CONFIG_FILES([ + Makefile + compiler/cpp/Makefile + compiler/cpp/src/Makefile + compiler/cpp/src/thrift/plugin/Makefile + compiler/cpp/test/Makefile + compiler/cpp/src/thrift/version.h + lib/Makefile + lib/cpp/Makefile + lib/cpp/test/Makefile + lib/cpp/thrift-nb.pc + lib/cpp/thrift-z.pc + lib/cpp/thrift-qt.pc + lib/cpp/thrift-qt5.pc + lib/cpp/thrift.pc + lib/c_glib/Makefile + lib/c_glib/thrift_c_glib.pc + lib/c_glib/test/Makefile + lib/csharp/Makefile + lib/csharp/test/Multiplex/Makefile + lib/d/Makefile + lib/d/test/Makefile + lib/erl/Makefile + lib/go/Makefile + lib/go/test/Makefile + lib/haxe/test/Makefile + lib/hs/Makefile + lib/java/Makefile + lib/js/Makefile + lib/js/test/Makefile + lib/json/Makefile + lib/json/test/Makefile + lib/netcore/Makefile + lib/nodejs/Makefile + lib/perl/Makefile + lib/perl/test/Makefile + lib/php/Makefile + lib/php/test/Makefile + lib/dart/Makefile + lib/py/Makefile + lib/rb/Makefile + lib/rs/Makefile + lib/rs/test/Makefile + lib/lua/Makefile + lib/xml/Makefile + lib/xml/test/Makefile + test/Makefile + test/features/Makefile + test/c_glib/Makefile + test/cpp/Makefile + test/csharp/Makefile + test/erl/Makefile + test/go/Makefile + test/haxe/Makefile + test/hs/Makefile + test/lua/Makefile + test/netcore/Makefile + test/php/Makefile + test/dart/Makefile + test/perl/Makefile + test/py/Makefile + test/py.twisted/Makefile + test/py.tornado/Makefile + test/rb/Makefile + test/rs/Makefile + tutorial/Makefile + tutorial/c_glib/Makefile + tutorial/cpp/Makefile + tutorial/d/Makefile + tutorial/go/Makefile + tutorial/haxe/Makefile + tutorial/hs/Makefile + tutorial/java/Makefile + tutorial/js/Makefile + tutorial/netcore/Makefile + tutorial/nodejs/Makefile + tutorial/dart/Makefile + tutorial/py/Makefile + tutorial/py.twisted/Makefile + tutorial/py.tornado/Makefile + tutorial/rb/Makefile + tutorial/rs/Makefile +]) + +if test "$have_cpp" = "yes" ; then MAYBE_CPP="cpp" ; else MAYBE_CPP="" ; fi +AC_SUBST([MAYBE_CPP]) +if test "$have_c_glib" = "yes" ; then MAYBE_C_GLIB="c_glib" ; else MAYBE_C_GLIB="" ; fi +AC_SUBST([MAYBE_C_GLIB]) +if test "$have_d" = "yes" -a "$have_deimos_event2" = "yes" -a "$have_deimos_openssl" = "yes"; then MAYBE_D="d" ; else MAYBE_D="" ; fi +AC_SUBST([MAYBE_D]) +if test "$have_java" = "yes" ; then MAYBE_JAVA="java" ; else MAYBE_JAVA="" ; fi +AC_SUBST([MAYBE_JAVA]) +if test "$have_csharp" = "yes" ; then MAYBE_CSHARP="csharp" ; else MAYBE_CSHARP="" ; fi +AC_SUBST([MAYBE_CSHARP]) +if test "$have_python" = "yes" ; then MAYBE_PYTHON="py" ; else MAYBE_PYTHON="" ; fi +AC_SUBST([MAYBE_PYTHON]) +if test "$have_py3" = "yes" ; then MAYBE_PY3="py3" ; else MAYBE_PY3="" ; fi +AC_SUBST([MAYBE_PY3]) +if test "$have_ruby" = "yes" ; then MAYBE_RUBY="rb" ; else MAYBE_RUBY="" ; fi +AC_SUBST([MAYBE_RUBY]) +if test "$have_haskell" = "yes" ; then MAYBE_HASKELL="hs" ; else MAYBE_HASKELL="" ; fi +AC_SUBST([MAYBE_HASKELL]) +if test "$have_perl" = "yes" ; then MAYBE_PERL="perl" ; else MAYBE_PERL="" ; fi +AC_SUBST([MAYBE_PERL]) +if test "$have_php" = "yes" ; then MAYBE_PHP="php" ; else MAYBE_PHP="" ; fi +AC_SUBST([MAYBE_PHP]) +if test "$have_dart" = "yes" ; then MAYBE_DART="dart" ; else MAYBE_DART="" ; fi +AC_SUBST([MAYBE_DART]) +if test "$have_go" = "yes" ; then MAYBE_GO="go" ; else MAYBE_GO="" ; fi +AC_SUBST([MAYBE_GO]) +if test "$have_nodejs" = "yes" ; then MAYBE_NODEJS="nodejs" ; else MAYBE_NODEJS="" ; fi +AC_SUBST([MAYBE_NODEJS]) +if test "$have_erlang" = "yes" ; then MAYBE_ERLANG="erl" ; else MAYBE_ERLANG="" ; fi +AC_SUBST([MAYBE_ERLANG]) +if test "$have_lua" = "yes" ; then MAYBE_LUA="lua" ; else MAYBE_LUA="" ; fi +AC_SUBST([MAYBE_LUA]) +if test "$have_rs" = "yes" ; then MAYBE_RS="rs" ; else MAYBE_RS="" ; fi +AC_SUBST([MAYBE_RS]) +if test "$have_dotnetcore" = "yes" ; then MAYBE_DOTNETCORE="netcore" ; else MAYBE_DOTNETCORE="" ; fi +AC_SUBST([MAYBE_DOTNETCORE]) + +AC_OUTPUT + + +echo +echo "$PACKAGE $VERSION" +echo +echo "Building C (GLib) Library .... : $have_c_glib" +echo "Building C# (Mono) Library ... : $have_csharp" +echo "Building C++ Library ......... : $have_cpp" +echo "Building D Library ........... : $have_d" +echo "Building Dart Library ........ : $have_dart" +echo "Building dotnetcore Library .. : $have_dotnetcore" +echo "Building Erlang Library ...... : $have_erlang" +echo "Building Go Library .......... : $have_go" +echo "Building Haskell Library ..... : $have_haskell" +echo "Building Haxe Library ........ : $have_haxe" +echo "Building Java Library ........ : $have_java" +echo "Building Lua Library ......... : $have_lua" +echo "Building NodeJS Library ...... : $have_nodejs" +echo "Building Perl Library ........ : $have_perl" +echo "Building PHP Library ......... : $have_php" +echo "Building Plugin Support ...... : $have_plugin" +echo "Building Python Library ...... : $have_python" +echo "Building Py3 Library ......... : $have_py3" +echo "Building Ruby Library ........ : $have_ruby" +echo "Building Rust Library ........ : $have_rs" + +if test "$have_csharp" = "yes" ; then + echo + echo "C# Library:" + echo " Using .NET 3.5 ............ : $net_3_5" + echo " Using mono version ........ : $($MCS --version | head -1)" +fi +if test "$have_cpp" = "yes" ; then + echo + echo "C++ Library:" + echo " C++ compiler .............. : $CXX" + echo " Build TZlibTransport ...... : $have_zlib" + echo " Build TNonblockingServer .. : $have_libevent" + echo " Build TQTcpServer (Qt4) ... : $have_qt" + echo " Build TQTcpServer (Qt5) ... : $have_qt5" + echo " C++ compiler version ...... : $($CXX --version | head -1)" +fi +if test "$have_d" = "yes" ; then + echo + echo "D Library:" + echo " Using D Compiler .......... : $DMD" + echo " Building D libevent tests . : $with_d_event_tests" + echo " Building D SSL tests ...... : $with_d_ssl_tests" + echo " Using D version ........... : $($DMD --version | head -1)" +fi +if test "$have_dart" = "yes" ; then + echo + echo "Dart Library:" + echo " Using Dart ................ : $DART" + echo " Using Pub ................. : $DARTPUB" + echo " Using Dart version ........ : $($DART --version 2>&1)" +fi +if test "$have_dotnetcore" = "yes" ; then + echo + echo ".NET Core Library:" + echo " Using .NET Core ........... : $DOTNETCORE" + echo " Using .NET Core version ... : $DOTNETCORE_VERSION" +fi +if test "$have_erlang" = "yes" ; then + echo + echo "Erlang Library:" + echo " Using erlc ................ : $ERLC" + echo " Using rebar ............... : $REBAR" + echo " Using erlc version ........ : $($ERL -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell | tr -d '\"')" +fi +if test "$have_go" = "yes" ; then + echo + echo "Go Library:" + echo " Using Go................... : $GO" + echo " Using Go version........... : $($GO version)" +fi +if test "$have_haskell" = "yes" ; then + echo + echo "Haskell Library:" + echo " Using Cabal ............... : $CABAL" + echo " Using Haskell ............. : $RUNHASKELL" + echo " Using Haskell version ..... : $($RUNHASKELL --version)" +fi +if test "$have_haxe" = "yes" ; then + echo + echo "Haxe Library:" + echo " Using Haxe ................ : $HAXE" + echo " Using Haxe version ........ : $HAXE_VERSION" +fi +if test "$have_java" = "yes" ; then + echo + echo "Java Library:" + echo " Using ant ................. : $ANT" + echo " Using java ................ : $JAVA" + echo " Using javac ............... : $JAVAC" + echo " Using ant version ......... : $($ANT -version 2>&1)" + echo " Using java version ........ : $($JAVA -version 2>&1 | grep 'version ')" +fi +if test "$have_lua" = "yes" ; then + echo + echo "Lua Library:" + echo " Using Lua ................. : $LUA" + echo " Using Lua version.......... : $($LUA -v)" +fi +if test "$have_nodejs" = "yes" ; then + echo + echo "NodeJS Library:" + echo " Using NodeJS .............. : $NODEJS" + echo " Using NodeJS version....... : $($NODEJS --version)" +fi +if test "$have_perl" = "yes" ; then + echo + echo "Perl Library:" + echo " Using Perl ................ : $PERL" + echo " Using Perl version ........ : $($PERL -v | grep 'version ')" +fi +if test "$have_php" = "yes" ; then + echo + echo "PHP Library:" + echo " Using php-config .......... : $PHP_CONFIG" + echo " Using php version ......... : $($PHP --version | head -1)" +fi +if test "$have_python" = "yes" ; then + echo + echo "Python Library:" + echo " Using Python .............. : $PYTHON" + echo " Using Python version ...... : $($PYTHON --version 2>&1)" + if test "$have_py3" = "yes" ; then + echo " Using Python3 ............. : $PYTHON3" + echo " Using Python3 version ..... : $($PYTHON3 --version)" + fi + if test "$have_trial" = "yes"; then + echo " Using trial ............... : $TRIAL" + fi +fi +if test "$have_ruby" = "yes" ; then + echo + echo "Ruby Library:" + echo " Using Ruby ................ : $RUBY" + echo " Using Ruby version ........ : $($RUBY --version)" +fi +if test "$have_rs" = "yes" ; then + echo + echo "Rust Library:" + echo " Using Cargo................ : $CARGO" + echo " Using rustc................ : $RUSTC" + echo " Using Rust version......... : $($RUSTC --version)" +fi +echo +echo "If something is missing that you think should be present," +echo "please skim the output of configure to find the missing" +echo "component. Details are present in config.log." +echo diff --git a/contrib/Rebus/App.config b/contrib/Rebus/App.config new file mode 100644 index 0000000..4208af6 --- /dev/null +++ b/contrib/Rebus/App.config @@ -0,0 +1,33 @@ + + + + + +
+ + + + + + + + + + diff --git a/contrib/Rebus/Program.cs b/contrib/Rebus/Program.cs new file mode 100644 index 0000000..563c62a --- /dev/null +++ b/contrib/Rebus/Program.cs @@ -0,0 +1,81 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +using Rebus.Configuration; +using Rebus.RabbitMQ; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using RebusSample.Client; +using RebusSample.Server; + +namespace RebusSample +{ + class Program + { + static BuiltinContainerAdapter StartRequestServer(string server) + { + // client Rebus configuration + var adapter = new BuiltinContainerAdapter(); + Configure.With(adapter) + .Transport(t => t.UseRabbitMq("amqp://" + server, "MathRequests", "MathRequestErrors")) + .MessageOwnership(o => o.FromRebusConfigurationSection()) + .CreateBus().Start(); + + // register all relevant message handlers + adapter.Register(typeof(MathRequestCallHandler)); + return adapter; + } + + + static BuiltinContainerAdapter StartResponseServer(string server) + { + // client Rebus configuration + var adapter = new BuiltinContainerAdapter(); + Configure.With(adapter) + .Transport(t => t.UseRabbitMq("amqp://" + server, "MathResponses", "MathResponseErrors")) + .MessageOwnership(o => o.FromRebusConfigurationSection()) + .CreateBus().Start(); + + // register all relevant message handlers + adapter.Register(typeof(MathResponseCallHandler)); + return adapter; + } + + static void Main(string[] args) + { + string server = "localhost"; + + // start all servers + var req = StartRequestServer(server); + var rsp = StartResponseServer(server); + + // send the first message + var random = new Random(); + var client = new MathRequestClient(server); + client.DoTheMath(random.Next(), random.Next()); + + // now what? + Console.Write("Hit to stop ... "); + Console.ReadLine(); + } + } +} diff --git a/contrib/Rebus/Properties/AssemblyInfo.cs b/contrib/Rebus/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9c4d7cc --- /dev/null +++ b/contrib/Rebus/Properties/AssemblyInfo.cs @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("RebusSample")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("RebusSample")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: Guid("0af10984-40d3-453d-b1e5-421529e8c7e2")] + +[assembly: AssemblyVersion("0.11.0.0")] +[assembly: AssemblyFileVersion("0.11.0.0")] diff --git a/contrib/Rebus/README.md b/contrib/Rebus/README.md new file mode 100644 index 0000000..bbb9c49 --- /dev/null +++ b/contrib/Rebus/README.md @@ -0,0 +1,21 @@ +Sample code for the combination of Thrift with Rebus. + +Rebus is a .NET service bus, similar to NServiceBus, but more lightweight. +It ihas been mainly written by Mogens Heller Grabe and is currently hosted +on GitHub (https://github.com/rebus-org/Rebus) + +As with all ServiceBus or MQ scenarios, due to the highly asynchronous +operations it is recommended to do all calls as "oneway void" calls. + +The configuration can be done via App.Config, via code or even mixed from +both locations. Refer to the Rebus documentation for further details. For +this example, since we are effectively implementing two queue listeners in +only one single process, we do configuration of incoming and error queues +in the code. + +If you want to communicate with non-NET languages, you may need a customized +serializer as well, in order to override Rebus' default wire format. Please +refer to the Rebus docs on how to do that (it's not that hard, really). + +Additional requirements: +- RabbitMQ .NET client (see nuget) diff --git a/contrib/Rebus/RebusSample.csproj b/contrib/Rebus/RebusSample.csproj new file mode 100644 index 0000000..4058a6d --- /dev/null +++ b/contrib/Rebus/RebusSample.csproj @@ -0,0 +1,102 @@ + + + + + + Debug + AnyCPU + {264E2126-EDE0-4B47-89C1-B397B25BB13D} + Exe + Properties + RebusSample + RebusSample + v4.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\..\..\Toolbox\ServiceBus\3rdparty\rabbitmq-dotnet-client-3.2.1-dotnet-3.0\bin\RabbitMQ.Client.dll + + + ..\..\..\..\..\Toolbox\ServiceBus\3rdparty\Rebus-master\deploy\NET40\Rebus.dll + + + ..\..\..\..\..\Toolbox\ServiceBus\3rdparty\Rebus-master\deploy\NET40\Rebus.RabbitMQ.dll + + + + + + + + + + + + + + + + + + + + + + + + + {499eb63c-d74c-47e8-ae48-a2fc94538e9d} + Thrift + + + + + cd $(ProjectDir) +if not exist gen-csharp\*.cs thrift -gen csharp sample.thrift + + + + \ No newline at end of file diff --git a/contrib/Rebus/RebusSample.sln b/contrib/Rebus/RebusSample.sln new file mode 100644 index 0000000..284ef36 --- /dev/null +++ b/contrib/Rebus/RebusSample.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30110.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RebusSample", "RebusSample.csproj", "{264E2126-EDE0-4B47-89C1-B397B25BB13D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\lib\csharp\src\Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {264E2126-EDE0-4B47-89C1-B397B25BB13D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {264E2126-EDE0-4B47-89C1-B397B25BB13D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {264E2126-EDE0-4B47-89C1-B397B25BB13D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {264E2126-EDE0-4B47-89C1-B397B25BB13D}.Release|Any CPU.Build.0 = Release|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/contrib/Rebus/ServiceImpl/Both.cs b/contrib/Rebus/ServiceImpl/Both.cs new file mode 100644 index 0000000..fba67ec --- /dev/null +++ b/contrib/Rebus/ServiceImpl/Both.cs @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +using System; + + +namespace RebusSample +{ + // generic data container for serialized Thrift calls + public class GenericThriftServiceCall + { + public byte[] rawBytes; + } + + // specific containers (one per Thrift service) to leverage Rebus' handler routing + public class MathRequestCall : GenericThriftServiceCall { } + public class MathResponseCall : GenericThriftServiceCall { } + +} \ No newline at end of file diff --git a/contrib/Rebus/ServiceImpl/Client.cs b/contrib/Rebus/ServiceImpl/Client.cs new file mode 100644 index 0000000..2408041 --- /dev/null +++ b/contrib/Rebus/ServiceImpl/Client.cs @@ -0,0 +1,157 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +using Rebus; +using Rebus.Configuration; +using Rebus.Messages; +using Rebus.RabbitMQ; +using System; +using System.Collections.Generic; +using System.IO; +using Thrift.Protocol; +using Thrift.Transport; + +/* + * The client emits calls to BasicMathServers + * + * The client implements the BasicMathClient service. + * If the server has processed our request, we get the results back through this service + */ + +namespace RebusSample.Client +{ + + // handler to be registered with Rebus + class MathResponseCallHandler : IHandleMessages + { + public void Handle(MathResponseCall message) + { + // Thrift protocol/transport stack + var stm = new MemoryStream(message.rawBytes); + var trns = new TStreamTransport(stm, null); + var prot = new TBinaryProtocol(trns); + + // create a processor and let him handle the call + var hndl = new MathResponsesHandler(); + var proc = new BasicMathClient.Processor(hndl); + proc.Process(prot, null); // oneway only + } + } + + + // serves incoming responses with calculation results + internal class MathResponsesHandler : BasicMathClient.Iface + { + public void FourResults(int added, int multiplied, int subtracted, int divided) + { + Console.WriteLine("added = {0}", added); + Console.WriteLine("multiplied= {0}", multiplied); + Console.WriteLine("subtracted = {0}", subtracted); + Console.WriteLine("divided = {0}", divided); + + PingAndDoAnotherCalculation(); + } + + + public void ThreeResults(int added, int multiplied, int subtracted) + { + Console.WriteLine("added = {0}", added); + Console.WriteLine("multiplied= {0}", multiplied); + Console.WriteLine("subtracted = {0}", subtracted); + Console.WriteLine("DIV/0 error during division"); + + PingAndDoAnotherCalculation(); + } + + + public void Pong(long value) + { + var latency = DateTime.Now.Ticks - value; + Console.WriteLine("Ping took {0} ms", new DateTime(latency).Millisecond); + } + + + private void PingAndDoAnotherCalculation() + { + var random = new Random(); + var client = new MathRequestClient("localhost"); + client.Ping(DateTime.Now.Ticks); + client.DoTheMath(random.Next(), random.Next()); + } + } + + + // provides the client-side interface for calculation requests + internal class MathRequestClient : BasicMathServer.Iface + { + private BuiltinContainerAdapter MQAdapter; + + + public MathRequestClient(string server) + { + MQAdapter = new BuiltinContainerAdapter(); + Configure.With(MQAdapter) + .Transport(t => t.UseRabbitMqInOneWayMode("amqp://" + server)) // we need send only + .MessageOwnership(o => o.FromRebusConfigurationSection()) + .CreateBus().Start(); + } + + + public void SerializeThriftCall(Action action) + { + // Thrift protocol/transport stack + var stm = new MemoryStream(); + var trns = new TStreamTransport(null, stm); + var prot = new TBinaryProtocol(trns); + + // serialize the call into a bunch of bytes + var client = new BasicMathServer.Client(prot); + if( action != null) + action(client); + else + throw new ArgumentException("action must not be null"); + + // make sure everything is written to the MemoryStream + trns.Flush(); + + // send the message + var msg = new MathRequestCall() { rawBytes = stm.ToArray() }; + MQAdapter.Bus.Send(msg); + } + + + public void Ping(long value) + { + SerializeThriftCall(client => + { + client.Ping(value); + }); + } + + + public void DoTheMath( int arg1, int arg2) + { + SerializeThriftCall(client => + { + client.DoTheMath(arg1, arg2); + }); + } + } +} + diff --git a/contrib/Rebus/ServiceImpl/Server.cs b/contrib/Rebus/ServiceImpl/Server.cs new file mode 100644 index 0000000..149d513 --- /dev/null +++ b/contrib/Rebus/ServiceImpl/Server.cs @@ -0,0 +1,143 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +using Rebus; +using Rebus.Configuration; +using Rebus.Messages; +using Rebus.RabbitMQ; +using System; +using System.Collections.Generic; +using System.IO; +using Thrift.Protocol; +using Thrift.Transport; + +/* + * The server implements the BasicMathServer service . + * All results are sent back to the client via the BasicMathClient service + */ + + +namespace RebusSample.Server +{ + // handler to be registered with Rebus + class MathRequestCallHandler : IHandleMessages + { + public void Handle(MathRequestCall message) + { + // Thrift protocol/transport stack + var stm = new MemoryStream(message.rawBytes); + var trns = new TStreamTransport(stm, null); + var prot = new TBinaryProtocol(trns); + + // create a processor and let him handle the call + var hndl = new MathRequestsHandler(); + var proc = new BasicMathServer.Processor(hndl); + proc.Process(prot, null); // oneway only + } + } + + + // serves incoming calculation requests + internal class MathRequestsHandler : BasicMathServer.Iface + { + public void Ping(long value) + { + var client = new MathResponseClient("localhost"); + client.Pong(value); + } + + + public void DoTheMath(int arg1, int arg2) + { + var client = new MathResponseClient("localhost"); + if( arg2 != 0) + client.FourResults( arg1+arg2, arg1*arg2, arg1-arg2, arg1/arg2); + else + client.ThreeResults( arg1+arg2, arg1*arg2, arg1-arg2); + } + } + + + // provides the client-side interface for calculation responses + internal class MathResponseClient : BasicMathClient.Iface + { + private BuiltinContainerAdapter MQAdapter; + + + public MathResponseClient(string server) + { + MQAdapter = new BuiltinContainerAdapter(); + Configure.With(MQAdapter) + .Transport(t => t.UseRabbitMqInOneWayMode("amqp://" + server)) // we need send only + .MessageOwnership(o => o.FromRebusConfigurationSection()) + .CreateBus().Start(); + } + + + public void SerializeThriftCall(Action action) + { + // Thrift protocol/transport stack + var stm = new MemoryStream(); + var trns = new TStreamTransport(null, stm); + var prot = new TBinaryProtocol(trns); + + // serialize the call into a bunch of bytes + var client = new BasicMathClient.Client(prot); + if (action != null) + action(client); + else + throw new ArgumentException("action must not be null"); + + // make sure everything is written to the MemoryStream + trns.Flush(); + + // send the message + var msg = new MathResponseCall() { rawBytes = stm.ToArray() }; + MQAdapter.Bus.Send(msg); + } + + + public void Pong(long value) + { + SerializeThriftCall(client => + { + client.Pong(value); + }); + } + + + public void ThreeResults(int added, int multiplied, int suctracted) + { + SerializeThriftCall(client => + { + client.ThreeResults(added, multiplied, suctracted); + }); + } + + + public void FourResults(int added, int multiplied, int suctracted, int divided) + { + SerializeThriftCall(client => + { + client.FourResults(added, multiplied, suctracted, divided); + }); + } + } +} + diff --git a/contrib/Rebus/sample.thrift b/contrib/Rebus/sample.thrift new file mode 100644 index 0000000..785e2d3 --- /dev/null +++ b/contrib/Rebus/sample.thrift @@ -0,0 +1,30 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +service BasicMathServer { + oneway void DoTheMath( 1: i32 arg1, 2: i32 arg2) + oneway void Ping(1: i64 value) +} + +service BasicMathClient { + oneway void ThreeResults( 1 : i32 added, 2 : i32 multiplied, 3 : i32 subtracted); + oneway void FourResults( 1 : i32 added, 2 : i32 multiplied, 3 : i32 subtracted, 4 : i32 divided); + oneway void Pong(1: i64 value) +} diff --git a/contrib/Stomp/README.md b/contrib/Stomp/README.md new file mode 100644 index 0000000..2e5f21c --- /dev/null +++ b/contrib/Stomp/README.md @@ -0,0 +1,18 @@ +Sample code for STOMP-based Thrift clients and/or servers. + +Although the sample Thrift STOMP Transport is written in +Delphi/Pascal, it can easily serve as a starting point for +similar implementations in other languages. + +STOMP is a protocol widely supported by many messaging systems, +such as Apache ActiveMQ, RabbitMQ and many others. In particular, +it can be used to communicate with Service-Bus products like Rebus +or NServiceBus, when running against a STOMP-capable MQ system. + +A prerequisite for this sample is the Delphi STOMP Adapter written +by Daniele Teti (http://www.danieleteti.it/stomp-client), currently +hosted at Google Code (http://code.google.com/p/delphistompclient). + +At the time of writing, the STOMP adapter does not fully support +binary data. Please check whether this has been fixed, otherwise +you have to use the JSON protocol (or to fix it on your own). diff --git a/contrib/Stomp/Thrift.Transport.STOMP.pas b/contrib/Stomp/Thrift.Transport.STOMP.pas new file mode 100644 index 0000000..7dfb376 --- /dev/null +++ b/contrib/Stomp/Thrift.Transport.STOMP.pas @@ -0,0 +1,200 @@ +(* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *) + +unit Thrift.Transport.STOMP; + +interface + +uses + Classes,Windows, SysUtils, + Thrift, + Thrift.Transport, + Thrift.Protocol, + Thrift.Stream, + StompClient, + StompTypes; + +type + TStompTransportImpl = class( TStreamTransportImpl) + strict private + FData : TStringStream; + FServer : string; + FOutQueue : string; + FStompCli : IStompClient; + protected + function GetIsOpen: Boolean; override; + function Peek: Boolean; override; + public + constructor Create( const aServerAndPort, aOutQueue : string); + destructor Destroy; override; + + procedure Open(); override; + procedure Close(); override; + procedure Flush; override; + end; + + + TStompServerTransportImpl = class( TServerTransportImpl) + strict private + FServer : string; + FInQueue : string; + FClient : IStompClient; + protected + procedure Listen; override; + procedure Close; override; + function Accept( const fnAccepting: TProc): ITransport; override; + public + constructor Create( const aServerAndPort, aInQueue : string); + destructor Destroy; override; + end; + + +const + QUEUE_PREFIX = '/queue/'; + TOPIC_PREFIX = '/topic/'; + EXCHANGE_PREFIX = '/exchange/'; + + +implementation + + + +constructor TStompTransportImpl.Create( const aServerAndPort, aOutQueue : string); +var adapter : IThriftStream; +begin + FData := TStringStream.Create; + FServer := aServerAndPort; + FOutQueue := aOutQueue; + + adapter := TThriftStreamAdapterDelphi.Create( FData, FALSE); + inherited Create( nil, adapter); // output only +end; + + +destructor TStompTransportImpl.Destroy; +begin + inherited Destroy; + FreeAndNil( FData); + FStompCli := nil; +end; + + +function TStompTransportImpl.GetIsOpen: Boolean; +begin + result := (FStompCli <> nil); +end; + + +function TStompTransportImpl.Peek: Boolean; +begin + result := FALSE; // output only +end; + + +procedure TStompTransportImpl.Open; +begin + if FStompCli <> nil + then raise TTransportException.Create( TTransportException.TExceptionType.AlreadyOpen, 'already open') + else FStompCli := StompUtils.NewStomp( FServer); +end; + + +procedure TStompTransportImpl.Close; +begin + FStompCli := nil; + FData.Clear; +end; + + +procedure TStompTransportImpl.Flush; +begin + if FStompCli = nil + then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen, 'not open'); + + FStompCli.Send( FOutQueue, FData.DataString); + FData.Clear; +end; + + +//--- TStompServerTransportImpl -------------------------------------------- + + +constructor TStompServerTransportImpl.Create( const aServerAndPort, aInQueue : string); +begin + inherited Create; + FServer := aServerAndPort; + FInQueue := aInQueue; +end; + + +destructor TStompServerTransportImpl.Destroy; +begin + try + Close; + finally + inherited Destroy; + end; +end; + + +procedure TStompServerTransportImpl.Listen; +begin + FClient := StompUtils.NewStomp(FServer); + FClient.Subscribe( FInQueue); +end; + + +procedure TStompServerTransportImpl.Close; +begin + if FClient <> nil then begin + FClient.Unsubscribe( FInQueue); + FClient := nil; + end; +end; + + +function TStompServerTransportImpl.Accept( const fnAccepting: TProc): ITransport; +var frame : IStompFrame; + adapter : IThriftStream; + stream : TStringStream; +begin + if FClient = nil + then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen, + 'Not connected.'); + + if Assigned(fnAccepting) + then fnAccepting(); + + try + frame := FClient.Receive(MAXINT); + if frame = nil then Exit(nil); + + stream := TStringStream.Create( frame.GetBody); + adapter := TThriftStreamAdapterDelphi.Create( stream, TRUE); + result := TStreamTransportImpl.Create( adapter, nil); + + except + on E: Exception + do raise TTransportException.Create( E.ToString ); + end; +end; + + +end. + diff --git a/contrib/Vagrantfile b/contrib/Vagrantfile new file mode 100644 index 0000000..3bcc46a --- /dev/null +++ b/contrib/Vagrantfile @@ -0,0 +1,133 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +$build_and_test = < + + + + + +### hello.js - Node Server + var thrift = require('thrift'); + var hello_svc = require('./gen-nodejs/hello_svc.js'); + + var hello_handler = { + get_message: function(name, result) { + var msg = "Hello " + name + "!"; + result(null, msg); + } + } + + var hello_svc_opt = { + transport: thrift.TBufferedTransport, + protocol: thrift.TJSONProtocol, + processor: hello_svc, + handler: hello_handler + }; + + var server_opt = { + staticFilePath: ".", + services: { + "/hello": hello_svc_opt + } + } + + var server = Thrift.createWebServer(server_opt); + var port = 9099; + server.listen(port); + console.log("Http/Thrift Server running on port: " + port); + + +TypeScript +------------------------------------ +TypeScript definition files can also be generated by running: + + thrift --gen js:ts file.thrift + diff --git a/lib/js/coding_standards.md b/lib/js/coding_standards.md new file mode 100644 index 0000000..fa0390b --- /dev/null +++ b/lib/js/coding_standards.md @@ -0,0 +1 @@ +Please follow [General Coding Standards](/doc/coding_standards.md) diff --git a/lib/js/package.json b/lib/js/package.json new file mode 100644 index 0000000..421de93 --- /dev/null +++ b/lib/js/package.json @@ -0,0 +1,19 @@ +{ + "name": "thrift", + "version": "0.11.0", + "devDependencies": { + "grunt": "^0.4.5", + "grunt-cli": "^1.2.0", + "grunt-contrib-concat": "^1.0.1", + "grunt-contrib-jshint": "^1.0.0", + "grunt-contrib-qunit": "^1.2.0", + "grunt-contrib-uglify": "^1.0.1", + "grunt-external-daemon": "^1.1.0", + "grunt-jsdoc": "^2.2.0", + "grunt-shell": "^1.3.0" + }, + "dependencies": { + "jsdoc": "^3.5.5", + "nopt": "^4.0.1" + } +} diff --git a/lib/js/src/thrift.js b/lib/js/src/thrift.js new file mode 100644 index 0000000..d308c46 --- /dev/null +++ b/lib/js/src/thrift.js @@ -0,0 +1,1564 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*jshint evil:true*/ + +/** + * The Thrift namespace houses the Apache Thrift JavaScript library + * elements providing JavaScript bindings for the Apache Thrift RPC + * system. End users will typically only directly make use of the + * Transport (TXHRTransport/TWebSocketTransport) and Protocol + * (TJSONPRotocol/TBinaryProtocol) constructors. + * + * Object methods beginning with a __ (e.g. __onOpen()) are internal + * and should not be called outside of the object's own methods. + * + * This library creates one global object: Thrift + * Code in this library must never create additional global identifiers, + * all features must be scoped within the Thrift namespace. + * @namespace + * @example + * var transport = new Thrift.Transport('http://localhost:8585'); + * var protocol = new Thrift.Protocol(transport); + * var client = new MyThriftSvcClient(protocol); + * var result = client.MyMethod(); + */ +var Thrift = { + /** + * Thrift JavaScript library version. + * @readonly + * @const {string} Version + * @memberof Thrift + */ + Version: '0.11.0', + + /** + * Thrift IDL type string to Id mapping. + * @readonly + * @property {number} STOP - End of a set of fields. + * @property {number} VOID - No value (only legal for return types). + * @property {number} BOOL - True/False integer. + * @property {number} BYTE - Signed 8 bit integer. + * @property {number} I08 - Signed 8 bit integer. + * @property {number} DOUBLE - 64 bit IEEE 854 floating point. + * @property {number} I16 - Signed 16 bit integer. + * @property {number} I32 - Signed 32 bit integer. + * @property {number} I64 - Signed 64 bit integer. + * @property {number} STRING - Array of bytes representing a string of characters. + * @property {number} UTF7 - Array of bytes representing a string of UTF7 encoded characters. + * @property {number} STRUCT - A multifield type. + * @property {number} MAP - A collection type (map/associative-array/dictionary). + * @property {number} SET - A collection type (unordered and without repeated values). + * @property {number} LIST - A collection type (unordered). + * @property {number} UTF8 - Array of bytes representing a string of UTF8 encoded characters. + * @property {number} UTF16 - Array of bytes representing a string of UTF16 encoded characters. + */ + Type: { + STOP: 0, + VOID: 1, + BOOL: 2, + BYTE: 3, + I08: 3, + DOUBLE: 4, + I16: 6, + I32: 8, + I64: 10, + STRING: 11, + UTF7: 11, + STRUCT: 12, + MAP: 13, + SET: 14, + LIST: 15, + UTF8: 16, + UTF16: 17 + }, + + /** + * Thrift RPC message type string to Id mapping. + * @readonly + * @property {number} CALL - RPC call sent from client to server. + * @property {number} REPLY - RPC call normal response from server to client. + * @property {number} EXCEPTION - RPC call exception response from server to client. + * @property {number} ONEWAY - Oneway RPC call from client to server with no response. + */ + MessageType: { + CALL: 1, + REPLY: 2, + EXCEPTION: 3, + ONEWAY: 4 + }, + + /** + * Utility function returning the count of an object's own properties. + * @param {object} obj - Object to test. + * @returns {number} number of object's own properties + */ + objectLength: function(obj) { + var length = 0; + for (var k in obj) { + if (obj.hasOwnProperty(k)) { + length++; + } + } + return length; + }, + + /** + * Utility function to establish prototype inheritance. + * @see {@link http://javascript.crockford.com/prototypal.html|Prototypal Inheritance} + * @param {function} constructor - Contstructor function to set as derived. + * @param {function} superConstructor - Contstructor function to set as base. + * @param {string} [name] - Type name to set as name property in derived prototype. + */ + inherits: function(constructor, superConstructor, name) { + function F() {} + F.prototype = superConstructor.prototype; + constructor.prototype = new F(); + constructor.prototype.name = name || ''; + } +}; + +/** + * Initializes a Thrift TException instance. + * @constructor + * @augments Error + * @param {string} message - The TException message (distinct from the Error message). + * @classdesc TException is the base class for all Thrift exceptions types. + */ +Thrift.TException = function(message) { + this.message = message; +}; +Thrift.inherits(Thrift.TException, Error, 'TException'); + +/** + * Returns the message set on the exception. + * @readonly + * @returns {string} exception message + */ +Thrift.TException.prototype.getMessage = function() { + return this.message; +}; + +/** + * Thrift Application Exception type string to Id mapping. + * @readonly + * @property {number} UNKNOWN - Unknown/undefined. + * @property {number} UNKNOWN_METHOD - Client attempted to call a method unknown to the server. + * @property {number} INVALID_MESSAGE_TYPE - Client passed an unknown/unsupported MessageType. + * @property {number} WRONG_METHOD_NAME - Unused. + * @property {number} BAD_SEQUENCE_ID - Unused in Thrift RPC, used to flag proprietary sequence number errors. + * @property {number} MISSING_RESULT - Raised by a server processor if a handler fails to supply the required return result. + * @property {number} INTERNAL_ERROR - Something bad happened. + * @property {number} PROTOCOL_ERROR - The protocol layer failed to serialize or deserialize data. + * @property {number} INVALID_TRANSFORM - Unused. + * @property {number} INVALID_PROTOCOL - The protocol (or version) is not supported. + * @property {number} UNSUPPORTED_CLIENT_TYPE - Unused. + */ +Thrift.TApplicationExceptionType = { + UNKNOWN: 0, + UNKNOWN_METHOD: 1, + INVALID_MESSAGE_TYPE: 2, + WRONG_METHOD_NAME: 3, + BAD_SEQUENCE_ID: 4, + MISSING_RESULT: 5, + INTERNAL_ERROR: 6, + PROTOCOL_ERROR: 7, + INVALID_TRANSFORM: 8, + INVALID_PROTOCOL: 9, + UNSUPPORTED_CLIENT_TYPE: 10 +}; + +/** + * Initializes a Thrift TApplicationException instance. + * @constructor + * @augments Thrift.TException + * @param {string} message - The TApplicationException message (distinct from the Error message). + * @param {Thrift.TApplicationExceptionType} [code] - The TApplicationExceptionType code. + * @classdesc TApplicationException is the exception class used to propagate exceptions from an RPC server back to a calling client. +*/ +Thrift.TApplicationException = function(message, code) { + this.message = message; + this.code = typeof code === 'number' ? code : 0; +}; +Thrift.inherits(Thrift.TApplicationException, Thrift.TException, 'TApplicationException'); + +/** + * Read a TApplicationException from the supplied protocol. + * @param {object} input - The input protocol to read from. + */ +Thrift.TApplicationException.prototype.read = function(input) { + while (1) { + var ret = input.readFieldBegin(); + + if (ret.ftype == Thrift.Type.STOP) { + break; + } + + var fid = ret.fid; + + switch (fid) { + case 1: + if (ret.ftype == Thrift.Type.STRING) { + ret = input.readString(); + this.message = ret.value; + } else { + ret = input.skip(ret.ftype); + } + break; + case 2: + if (ret.ftype == Thrift.Type.I32) { + ret = input.readI32(); + this.code = ret.value; + } else { + ret = input.skip(ret.ftype); + } + break; + default: + ret = input.skip(ret.ftype); + break; + } + + input.readFieldEnd(); + } + + input.readStructEnd(); +}; + +/** + * Wite a TApplicationException to the supplied protocol. + * @param {object} output - The output protocol to write to. + */ +Thrift.TApplicationException.prototype.write = function(output) { + output.writeStructBegin('TApplicationException'); + + if (this.message) { + output.writeFieldBegin('message', Thrift.Type.STRING, 1); + output.writeString(this.getMessage()); + output.writeFieldEnd(); + } + + if (this.code) { + output.writeFieldBegin('type', Thrift.Type.I32, 2); + output.writeI32(this.code); + output.writeFieldEnd(); + } + + output.writeFieldStop(); + output.writeStructEnd(); +}; + +/** + * Returns the application exception code set on the exception. + * @readonly + * @returns {Thrift.TApplicationExceptionType} exception code + */ +Thrift.TApplicationException.prototype.getCode = function() { + return this.code; +}; + +Thrift.TProtocolExceptionType = { + UNKNOWN: 0, + INVALID_DATA: 1, + NEGATIVE_SIZE: 2, + SIZE_LIMIT: 3, + BAD_VERSION: 4, + NOT_IMPLEMENTED: 5, + DEPTH_LIMIT: 6 +}; + +Thrift.TProtocolException = function TProtocolException(type, message) { + Error.call(this); + Error.captureStackTrace(this, this.constructor); + this.name = this.constructor.name; + this.type = type; + this.message = message; +}; +Thrift.inherits(Thrift.TProtocolException, Thrift.TException, 'TProtocolException'); + +/** + * Constructor Function for the XHR transport. + * If you do not specify a url then you must handle XHR operations on + * your own. This type can also be constructed using the Transport alias + * for backward compatibility. + * @constructor + * @param {string} [url] - The URL to connect to. + * @classdesc The Apache Thrift Transport layer performs byte level I/O + * between RPC clients and servers. The JavaScript TXHRTransport object + * uses Http[s]/XHR. Target servers must implement the http[s] transport + * (see: node.js example server_http.js). + * @example + * var transport = new Thrift.TXHRTransport("http://localhost:8585"); + */ +Thrift.Transport = Thrift.TXHRTransport = function(url, options) { + this.url = url; + this.wpos = 0; + this.rpos = 0; + this.useCORS = (options && options.useCORS); + this.customHeaders = options ? (options.customHeaders ? options.customHeaders : {}): {}; + this.send_buf = ''; + this.recv_buf = ''; +}; + +Thrift.TXHRTransport.prototype = { + /** + * Gets the browser specific XmlHttpRequest Object. + * @returns {object} the browser XHR interface object + */ + getXmlHttpRequestObject: function() { + try { return new XMLHttpRequest(); } catch (e1) { } + try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { } + try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { } + + throw "Your browser doesn't support XHR."; + }, + + /** + * Sends the current XRH request if the transport was created with a URL + * and the async parameter is false. If the transport was not created with + * a URL, or the async parameter is True and no callback is provided, or + * the URL is an empty string, the current send buffer is returned. + * @param {object} async - If true the current send buffer is returned. + * @param {object} callback - Optional async completion callback + * @returns {undefined|string} Nothing or the current send buffer. + * @throws {string} If XHR fails. + */ + flush: function(async, callback) { + var self = this; + if ((async && !callback) || this.url === undefined || this.url === '') { + return this.send_buf; + } + + var xreq = this.getXmlHttpRequestObject(); + + if (xreq.overrideMimeType) { + xreq.overrideMimeType('application/vnd.apache.thrift.json; charset=utf-8'); + } + + if (callback) { + //Ignore XHR callbacks until the data arrives, then call the + // client's callback + xreq.onreadystatechange = + (function() { + var clientCallback = callback; + return function() { + if (this.readyState == 4 && this.status == 200) { + self.setRecvBuffer(this.responseText); + clientCallback(); + } + }; + }()); + + // detect net::ERR_CONNECTION_REFUSED and call the callback. + xreq.onerror = + (function() { + var clientCallback = callback; + return function() { + clientCallback(); + }; + }()); + + } + + xreq.open('POST', this.url, !!async); + + // add custom headers + Object.keys(self.customHeaders).forEach(function(prop) { + xreq.setRequestHeader(prop, self.customHeaders[prop]); + }); + + if (xreq.setRequestHeader) { + xreq.setRequestHeader('Accept', 'application/vnd.apache.thrift.json; charset=utf-8'); + xreq.setRequestHeader('Content-Type', 'application/vnd.apache.thrift.json; charset=utf-8'); + } + + xreq.send(this.send_buf); + if (async && callback) { + return; + } + + if (xreq.readyState != 4) { + throw 'encountered an unknown ajax ready state: ' + xreq.readyState; + } + + if (xreq.status != 200) { + throw 'encountered a unknown request status: ' + xreq.status; + } + + this.recv_buf = xreq.responseText; + this.recv_buf_sz = this.recv_buf.length; + this.wpos = this.recv_buf.length; + this.rpos = 0; + }, + + /** + * Creates a jQuery XHR object to be used for a Thrift server call. + * @param {object} client - The Thrift Service client object generated by the IDL compiler. + * @param {object} postData - The message to send to the server. + * @param {function} args - The original call arguments with the success call back at the end. + * @param {function} recv_method - The Thrift Service Client receive method for the call. + * @returns {object} A new jQuery XHR object. + * @throws {string} If the jQuery version is prior to 1.5 or if jQuery is not found. + */ + jqRequest: function(client, postData, args, recv_method) { + if (typeof jQuery === 'undefined' || + typeof jQuery.Deferred === 'undefined') { + throw 'Thrift.js requires jQuery 1.5+ to use asynchronous requests'; + } + + var thriftTransport = this; + + var jqXHR = jQuery.ajax({ + url: this.url, + data: postData, + type: 'POST', + cache: false, + contentType: 'application/vnd.apache.thrift.json; charset=utf-8', + dataType: 'text thrift', + converters: { + 'text thrift' : function(responseData) { + thriftTransport.setRecvBuffer(responseData); + var value = recv_method.call(client); + return value; + } + }, + context: client, + success: jQuery.makeArray(args).pop() + }); + + return jqXHR; + }, + + /** + * Sets the buffer to provide the protocol when deserializing. + * @param {string} buf - The buffer to supply the protocol. + */ + setRecvBuffer: function(buf) { + this.recv_buf = buf; + this.recv_buf_sz = this.recv_buf.length; + this.wpos = this.recv_buf.length; + this.rpos = 0; + }, + + /** + * Returns true if the transport is open, XHR always returns true. + * @readonly + * @returns {boolean} Always True. + */ + isOpen: function() { + return true; + }, + + /** + * Opens the transport connection, with XHR this is a nop. + */ + open: function() {}, + + /** + * Closes the transport connection, with XHR this is a nop. + */ + close: function() {}, + + /** + * Returns the specified number of characters from the response + * buffer. + * @param {number} len - The number of characters to return. + * @returns {string} Characters sent by the server. + */ + read: function(len) { + var avail = this.wpos - this.rpos; + + if (avail === 0) { + return ''; + } + + var give = len; + + if (avail < len) { + give = avail; + } + + var ret = this.read_buf.substr(this.rpos, give); + this.rpos += give; + + //clear buf when complete? + return ret; + }, + + /** + * Returns the entire response buffer. + * @returns {string} Characters sent by the server. + */ + readAll: function() { + return this.recv_buf; + }, + + /** + * Sets the send buffer to buf. + * @param {string} buf - The buffer to send. + */ + write: function(buf) { + this.send_buf = buf; + }, + + /** + * Returns the send buffer. + * @readonly + * @returns {string} The send buffer. + */ + getSendBuffer: function() { + return this.send_buf; + } + +}; + + +/** + * Constructor Function for the WebSocket transport. + * @constructor + * @param {string} [url] - The URL to connect to. + * @classdesc The Apache Thrift Transport layer performs byte level I/O + * between RPC clients and servers. The JavaScript TWebSocketTransport object + * uses the WebSocket protocol. Target servers must implement WebSocket. + * (see: node.js example server_http.js). + * @example + * var transport = new Thrift.TWebSocketTransport("http://localhost:8585"); + */ +Thrift.TWebSocketTransport = function(url) { + this.__reset(url); +}; + +Thrift.TWebSocketTransport.prototype = { + __reset: function(url) { + this.url = url; //Where to connect + this.socket = null; //The web socket + this.callbacks = []; //Pending callbacks + this.send_pending = []; //Buffers/Callback pairs waiting to be sent + this.send_buf = ''; //Outbound data, immutable until sent + this.recv_buf = ''; //Inbound data + this.rb_wpos = 0; //Network write position in receive buffer + this.rb_rpos = 0; //Client read position in receive buffer + }, + + /** + * Sends the current WS request and registers callback. The async + * parameter is ignored (WS flush is always async) and the callback + * function parameter is required. + * @param {object} async - Ignored. + * @param {object} callback - The client completion callback. + * @returns {undefined|string} Nothing (undefined) + */ + flush: function(async, callback) { + var self = this; + if (this.isOpen()) { + //Send data and register a callback to invoke the client callback + this.socket.send(this.send_buf); + this.callbacks.push((function() { + var clientCallback = callback; + return function(msg) { + self.setRecvBuffer(msg); + clientCallback(); + }; + }())); + if(callback) { + this.callbacks.push((function() { + var clientCallback = callback; + return function(msg) { + self.setRecvBuffer(msg); + clientCallback(); + }; + }())); + } + } else { + //Queue the send to go out __onOpen + this.send_pending.push({ + buf: this.send_buf, + cb: callback + }); + } + }, + + __onOpen: function() { + var self = this; + if (this.send_pending.length > 0) { + //If the user made calls before the connection was fully + //open, send them now + this.send_pending.forEach(function(elem) { + this.socket.send(elem.buf); + this.callbacks.push((function() { + var clientCallback = elem.cb; + return function(msg) { + self.setRecvBuffer(msg); + clientCallback(); + }; + }())); + }); + this.send_pending = []; + } + }, + + __onClose: function(evt) { + this.__reset(this.url); + }, + + __onMessage: function(evt) { + if (this.callbacks.length) { + this.callbacks.shift()(evt.data); + } + }, + + __onError: function(evt) { + console.log('Thrift WebSocket Error: ' + evt.toString()); + this.socket.close(); + }, + + /** + * Sets the buffer to use when receiving server responses. + * @param {string} buf - The buffer to receive server responses. + */ + setRecvBuffer: function(buf) { + this.recv_buf = buf; + this.recv_buf_sz = this.recv_buf.length; + this.wpos = this.recv_buf.length; + this.rpos = 0; + }, + + /** + * Returns true if the transport is open + * @readonly + * @returns {boolean} + */ + isOpen: function() { + return this.socket && this.socket.readyState == this.socket.OPEN; + }, + + /** + * Opens the transport connection + */ + open: function() { + //If OPEN/CONNECTING/CLOSING ignore additional opens + if (this.socket && this.socket.readyState != this.socket.CLOSED) { + return; + } + //If there is no socket or the socket is closed: + this.socket = new WebSocket(this.url); + this.socket.onopen = this.__onOpen.bind(this); + this.socket.onmessage = this.__onMessage.bind(this); + this.socket.onerror = this.__onError.bind(this); + this.socket.onclose = this.__onClose.bind(this); + }, + + /** + * Closes the transport connection + */ + close: function() { + this.socket.close(); + }, + + /** + * Returns the specified number of characters from the response + * buffer. + * @param {number} len - The number of characters to return. + * @returns {string} Characters sent by the server. + */ + read: function(len) { + var avail = this.wpos - this.rpos; + + if (avail === 0) { + return ''; + } + + var give = len; + + if (avail < len) { + give = avail; + } + + var ret = this.read_buf.substr(this.rpos, give); + this.rpos += give; + + //clear buf when complete? + return ret; + }, + + /** + * Returns the entire response buffer. + * @returns {string} Characters sent by the server. + */ + readAll: function() { + return this.recv_buf; + }, + + /** + * Sets the send buffer to buf. + * @param {string} buf - The buffer to send. + */ + write: function(buf) { + this.send_buf = buf; + }, + + /** + * Returns the send buffer. + * @readonly + * @returns {string} The send buffer. + */ + getSendBuffer: function() { + return this.send_buf; + } + +}; + +/** + * Initializes a Thrift JSON protocol instance. + * @constructor + * @param {Thrift.Transport} transport - The transport to serialize to/from. + * @classdesc Apache Thrift Protocols perform serialization which enables cross + * language RPC. The Protocol type is the JavaScript browser implementation + * of the Apache Thrift TJSONProtocol. + * @example + * var protocol = new Thrift.Protocol(transport); + */ +Thrift.TJSONProtocol = Thrift.Protocol = function(transport) { + this.tstack = []; + this.tpos = []; + this.transport = transport; +}; + +/** + * Thrift IDL type Id to string mapping. + * @readonly + * @see {@link Thrift.Type} + */ +Thrift.Protocol.Type = {}; +Thrift.Protocol.Type[Thrift.Type.BOOL] = '"tf"'; +Thrift.Protocol.Type[Thrift.Type.BYTE] = '"i8"'; +Thrift.Protocol.Type[Thrift.Type.I16] = '"i16"'; +Thrift.Protocol.Type[Thrift.Type.I32] = '"i32"'; +Thrift.Protocol.Type[Thrift.Type.I64] = '"i64"'; +Thrift.Protocol.Type[Thrift.Type.DOUBLE] = '"dbl"'; +Thrift.Protocol.Type[Thrift.Type.STRUCT] = '"rec"'; +Thrift.Protocol.Type[Thrift.Type.STRING] = '"str"'; +Thrift.Protocol.Type[Thrift.Type.MAP] = '"map"'; +Thrift.Protocol.Type[Thrift.Type.LIST] = '"lst"'; +Thrift.Protocol.Type[Thrift.Type.SET] = '"set"'; + +/** + * Thrift IDL type string to Id mapping. + * @readonly + * @see {@link Thrift.Type} + */ +Thrift.Protocol.RType = {}; +Thrift.Protocol.RType.tf = Thrift.Type.BOOL; +Thrift.Protocol.RType.i8 = Thrift.Type.BYTE; +Thrift.Protocol.RType.i16 = Thrift.Type.I16; +Thrift.Protocol.RType.i32 = Thrift.Type.I32; +Thrift.Protocol.RType.i64 = Thrift.Type.I64; +Thrift.Protocol.RType.dbl = Thrift.Type.DOUBLE; +Thrift.Protocol.RType.rec = Thrift.Type.STRUCT; +Thrift.Protocol.RType.str = Thrift.Type.STRING; +Thrift.Protocol.RType.map = Thrift.Type.MAP; +Thrift.Protocol.RType.lst = Thrift.Type.LIST; +Thrift.Protocol.RType.set = Thrift.Type.SET; + +/** + * The TJSONProtocol version number. + * @readonly + * @const {number} Version + * @memberof Thrift.Protocol + */ + Thrift.Protocol.Version = 1; + +Thrift.Protocol.prototype = { + /** + * Returns the underlying transport. + * @readonly + * @returns {Thrift.Transport} The underlying transport. + */ + getTransport: function() { + return this.transport; + }, + + /** + * Serializes the beginning of a Thrift RPC message. + * @param {string} name - The service method to call. + * @param {Thrift.MessageType} messageType - The type of method call. + * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift). + */ + writeMessageBegin: function(name, messageType, seqid) { + this.tstack = []; + this.tpos = []; + + this.tstack.push([Thrift.Protocol.Version, '"' + + name + '"', messageType, seqid]); + }, + + /** + * Serializes the end of a Thrift RPC message. + */ + writeMessageEnd: function() { + var obj = this.tstack.pop(); + + this.wobj = this.tstack.pop(); + this.wobj.push(obj); + + this.wbuf = '[' + this.wobj.join(',') + ']'; + + this.transport.write(this.wbuf); + }, + + + /** + * Serializes the beginning of a struct. + * @param {string} name - The name of the struct. + */ + writeStructBegin: function(name) { + this.tpos.push(this.tstack.length); + this.tstack.push({}); + }, + + /** + * Serializes the end of a struct. + */ + writeStructEnd: function() { + + var p = this.tpos.pop(); + var struct = this.tstack[p]; + var str = '{'; + var first = true; + for (var key in struct) { + if (first) { + first = false; + } else { + str += ','; + } + + str += key + ':' + struct[key]; + } + + str += '}'; + this.tstack[p] = str; + }, + + /** + * Serializes the beginning of a struct field. + * @param {string} name - The name of the field. + * @param {Thrift.Protocol.Type} fieldType - The data type of the field. + * @param {number} fieldId - The field's unique identifier. + */ + writeFieldBegin: function(name, fieldType, fieldId) { + this.tpos.push(this.tstack.length); + this.tstack.push({ 'fieldId': '"' + + fieldId + '"', 'fieldType': Thrift.Protocol.Type[fieldType] + }); + + }, + + /** + * Serializes the end of a field. + */ + writeFieldEnd: function() { + var value = this.tstack.pop(); + var fieldInfo = this.tstack.pop(); + + this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' + + fieldInfo.fieldType + ':' + value + '}'; + this.tpos.pop(); + }, + + /** + * Serializes the end of the set of fields for a struct. + */ + writeFieldStop: function() { + //na + }, + + /** + * Serializes the beginning of a map collection. + * @param {Thrift.Type} keyType - The data type of the key. + * @param {Thrift.Type} valType - The data type of the value. + * @param {number} [size] - The number of elements in the map (ignored). + */ + writeMapBegin: function(keyType, valType, size) { + this.tpos.push(this.tstack.length); + this.tstack.push([Thrift.Protocol.Type[keyType], + Thrift.Protocol.Type[valType], 0]); + }, + + /** + * Serializes the end of a map. + */ + writeMapEnd: function() { + var p = this.tpos.pop(); + + if (p == this.tstack.length) { + return; + } + + if ((this.tstack.length - p - 1) % 2 !== 0) { + this.tstack.push(''); + } + + var size = (this.tstack.length - p - 1) / 2; + + this.tstack[p][this.tstack[p].length - 1] = size; + + var map = '}'; + var first = true; + while (this.tstack.length > p + 1) { + var v = this.tstack.pop(); + var k = this.tstack.pop(); + if (first) { + first = false; + } else { + map = ',' + map; + } + + if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings + map = k + ':' + v + map; + } + map = '{' + map; + + this.tstack[p].push(map); + this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; + }, + + /** + * Serializes the beginning of a list collection. + * @param {Thrift.Type} elemType - The data type of the elements. + * @param {number} size - The number of elements in the list. + */ + writeListBegin: function(elemType, size) { + this.tpos.push(this.tstack.length); + this.tstack.push([Thrift.Protocol.Type[elemType], size]); + }, + + /** + * Serializes the end of a list. + */ + writeListEnd: function() { + var p = this.tpos.pop(); + + while (this.tstack.length > p + 1) { + var tmpVal = this.tstack[p + 1]; + this.tstack.splice(p + 1, 1); + this.tstack[p].push(tmpVal); + } + + this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; + }, + + /** + * Serializes the beginning of a set collection. + * @param {Thrift.Type} elemType - The data type of the elements. + * @param {number} size - The number of elements in the list. + */ + writeSetBegin: function(elemType, size) { + this.tpos.push(this.tstack.length); + this.tstack.push([Thrift.Protocol.Type[elemType], size]); + }, + + /** + * Serializes the end of a set. + */ + writeSetEnd: function() { + var p = this.tpos.pop(); + + while (this.tstack.length > p + 1) { + var tmpVal = this.tstack[p + 1]; + this.tstack.splice(p + 1, 1); + this.tstack[p].push(tmpVal); + } + + this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; + }, + + /** Serializes a boolean */ + writeBool: function(value) { + this.tstack.push(value ? 1 : 0); + }, + + /** Serializes a number */ + writeByte: function(i8) { + this.tstack.push(i8); + }, + + /** Serializes a number */ + writeI16: function(i16) { + this.tstack.push(i16); + }, + + /** Serializes a number */ + writeI32: function(i32) { + this.tstack.push(i32); + }, + + /** Serializes a number */ + writeI64: function(i64) { + this.tstack.push(i64); + }, + + /** Serializes a number */ + writeDouble: function(dbl) { + this.tstack.push(dbl); + }, + + /** Serializes a string */ + writeString: function(str) { + // We do not encode uri components for wire transfer: + if (str === null) { + this.tstack.push(null); + } else { + // concat may be slower than building a byte buffer + var escapedString = ''; + for (var i = 0; i < str.length; i++) { + var ch = str.charAt(i); // a single double quote: " + if (ch === '\"') { + escapedString += '\\\"'; // write out as: \" + } else if (ch === '\\') { // a single backslash + escapedString += '\\\\'; // write out as double backslash + } else if (ch === '\b') { // a single backspace: invisible + escapedString += '\\b'; // write out as: \b" + } else if (ch === '\f') { // a single formfeed: invisible + escapedString += '\\f'; // write out as: \f" + } else if (ch === '\n') { // a single newline: invisible + escapedString += '\\n'; // write out as: \n" + } else if (ch === '\r') { // a single return: invisible + escapedString += '\\r'; // write out as: \r" + } else if (ch === '\t') { // a single tab: invisible + escapedString += '\\t'; // write out as: \t" + } else { + escapedString += ch; // Else it need not be escaped + } + } + this.tstack.push('"' + escapedString + '"'); + } + }, + + /** Serializes a string */ + writeBinary: function(binary) { + var str = ''; + if (typeof binary == 'string') { + str = binary; + } else if (binary instanceof Uint8Array) { + var arr = binary; + for (var i = 0; i < arr.length; ++i) { + str += String.fromCharCode(arr[i]); + } + } else { + throw new TypeError('writeBinary only accepts String or Uint8Array.'); + } + this.tstack.push('"' + btoa(str) + '"'); + }, + + /** + @class + @name AnonReadMessageBeginReturn + @property {string} fname - The name of the service method. + @property {Thrift.MessageType} mtype - The type of message call. + @property {number} rseqid - The sequence number of the message (0 in Thrift RPC). + */ + /** + * Deserializes the beginning of a message. + * @returns {AnonReadMessageBeginReturn} + */ + readMessageBegin: function() { + this.rstack = []; + this.rpos = []; + + if (typeof JSON !== 'undefined' && typeof JSON.parse === 'function') { + this.robj = JSON.parse(this.transport.readAll()); + } else if (typeof jQuery !== 'undefined') { + this.robj = jQuery.parseJSON(this.transport.readAll()); + } else { + this.robj = eval(this.transport.readAll()); + } + + var r = {}; + var version = this.robj.shift(); + + if (version != Thrift.Protocol.Version) { + throw 'Wrong thrift protocol version: ' + version; + } + + r.fname = this.robj.shift(); + r.mtype = this.robj.shift(); + r.rseqid = this.robj.shift(); + + + //get to the main obj + this.rstack.push(this.robj.shift()); + + return r; + }, + + /** Deserializes the end of a message. */ + readMessageEnd: function() { + }, + + /** + * Deserializes the beginning of a struct. + * @param {string} [name] - The name of the struct (ignored) + * @returns {object} - An object with an empty string fname property + */ + readStructBegin: function(name) { + var r = {}; + r.fname = ''; + + //incase this is an array of structs + if (this.rstack[this.rstack.length - 1] instanceof Array) { + this.rstack.push(this.rstack[this.rstack.length - 1].shift()); + } + + return r; + }, + + /** Deserializes the end of a struct. */ + readStructEnd: function() { + if (this.rstack[this.rstack.length - 2] instanceof Array) { + this.rstack.pop(); + } + }, + + /** + @class + @name AnonReadFieldBeginReturn + @property {string} fname - The name of the field (always ''). + @property {Thrift.Type} ftype - The data type of the field. + @property {number} fid - The unique identifier of the field. + */ + /** + * Deserializes the beginning of a field. + * @returns {AnonReadFieldBeginReturn} + */ + readFieldBegin: function() { + var r = {}; + + var fid = -1; + var ftype = Thrift.Type.STOP; + + //get a fieldId + for (var f in (this.rstack[this.rstack.length - 1])) { + if (f === null) { + continue; + } + + fid = parseInt(f, 10); + this.rpos.push(this.rstack.length); + + var field = this.rstack[this.rstack.length - 1][fid]; + + //remove so we don't see it again + delete this.rstack[this.rstack.length - 1][fid]; + + this.rstack.push(field); + + break; + } + + if (fid != -1) { + + //should only be 1 of these but this is the only + //way to match a key + for (var i in (this.rstack[this.rstack.length - 1])) { + if (Thrift.Protocol.RType[i] === null) { + continue; + } + + ftype = Thrift.Protocol.RType[i]; + this.rstack[this.rstack.length - 1] = + this.rstack[this.rstack.length - 1][i]; + } + } + + r.fname = ''; + r.ftype = ftype; + r.fid = fid; + + return r; + }, + + /** Deserializes the end of a field. */ + readFieldEnd: function() { + var pos = this.rpos.pop(); + + //get back to the right place in the stack + while (this.rstack.length > pos) { + this.rstack.pop(); + } + + }, + + /** + @class + @name AnonReadMapBeginReturn + @property {Thrift.Type} ktype - The data type of the key. + @property {Thrift.Type} vtype - The data type of the value. + @property {number} size - The number of elements in the map. + */ + /** + * Deserializes the beginning of a map. + * @returns {AnonReadMapBeginReturn} + */ + readMapBegin: function() { + var map = this.rstack.pop(); + var first = map.shift(); + if (first instanceof Array) { + this.rstack.push(map); + map = first; + first = map.shift(); + } + + var r = {}; + r.ktype = Thrift.Protocol.RType[first]; + r.vtype = Thrift.Protocol.RType[map.shift()]; + r.size = map.shift(); + + + this.rpos.push(this.rstack.length); + this.rstack.push(map.shift()); + + return r; + }, + + /** Deserializes the end of a map. */ + readMapEnd: function() { + this.readFieldEnd(); + }, + + /** + @class + @name AnonReadColBeginReturn + @property {Thrift.Type} etype - The data type of the element. + @property {number} size - The number of elements in the collection. + */ + /** + * Deserializes the beginning of a list. + * @returns {AnonReadColBeginReturn} + */ + readListBegin: function() { + var list = this.rstack[this.rstack.length - 1]; + + var r = {}; + r.etype = Thrift.Protocol.RType[list.shift()]; + r.size = list.shift(); + + this.rpos.push(this.rstack.length); + this.rstack.push(list.shift()); + + return r; + }, + + /** Deserializes the end of a list. */ + readListEnd: function() { + this.readFieldEnd(); + }, + + /** + * Deserializes the beginning of a set. + * @returns {AnonReadColBeginReturn} + */ + readSetBegin: function(elemType, size) { + return this.readListBegin(elemType, size); + }, + + /** Deserializes the end of a set. */ + readSetEnd: function() { + return this.readListEnd(); + }, + + /** Returns an object with a value property set to + * False unless the next number in the protocol buffer + * is 1, in which case the value property is True */ + readBool: function() { + var r = this.readI32(); + + if (r !== null && r.value == '1') { + r.value = true; + } else { + r.value = false; + } + + return r; + }, + + /** Returns the an object with a value property set to the + next value found in the protocol buffer */ + readByte: function() { + return this.readI32(); + }, + + /** Returns the an object with a value property set to the + next value found in the protocol buffer */ + readI16: function() { + return this.readI32(); + }, + + /** Returns the an object with a value property set to the + next value found in the protocol buffer */ + readI32: function(f) { + if (f === undefined) { + f = this.rstack[this.rstack.length - 1]; + } + + var r = {}; + + if (f instanceof Array) { + if (f.length === 0) { + r.value = undefined; + } else { + r.value = f.shift(); + } + } else if (f instanceof Object) { + for (var i in f) { + if (i === null) { + continue; + } + this.rstack.push(f[i]); + delete f[i]; + + r.value = i; + break; + } + } else { + r.value = f; + this.rstack.pop(); + } + + return r; + }, + + /** Returns the an object with a value property set to the + next value found in the protocol buffer */ + readI64: function() { + return this.readI32(); + }, + + /** Returns the an object with a value property set to the + next value found in the protocol buffer */ + readDouble: function() { + return this.readI32(); + }, + + /** Returns the an object with a value property set to the + next value found in the protocol buffer */ + readString: function() { + var r = this.readI32(); + return r; + }, + + /** Returns the an object with a value property set to the + next value found in the protocol buffer */ + readBinary: function() { + var r = this.readI32(); + r.value = atob(r.value); + return r; + }, + + /** + * Method to arbitrarily skip over data */ + skip: function(type) { + var ret, i; + switch (type) { + case Thrift.Type.STOP: + return null; + + case Thrift.Type.BOOL: + return this.readBool(); + + case Thrift.Type.BYTE: + return this.readByte(); + + case Thrift.Type.I16: + return this.readI16(); + + case Thrift.Type.I32: + return this.readI32(); + + case Thrift.Type.I64: + return this.readI64(); + + case Thrift.Type.DOUBLE: + return this.readDouble(); + + case Thrift.Type.STRING: + return this.readString(); + + case Thrift.Type.STRUCT: + this.readStructBegin(); + while (true) { + ret = this.readFieldBegin(); + if (ret.ftype == Thrift.Type.STOP) { + break; + } + this.skip(ret.ftype); + this.readFieldEnd(); + } + this.readStructEnd(); + return null; + + case Thrift.Type.MAP: + ret = this.readMapBegin(); + for (i = 0; i < ret.size; i++) { + if (i > 0) { + if (this.rstack.length > this.rpos[this.rpos.length - 1] + 1) { + this.rstack.pop(); + } + } + this.skip(ret.ktype); + this.skip(ret.vtype); + } + this.readMapEnd(); + return null; + + case Thrift.Type.SET: + ret = this.readSetBegin(); + for (i = 0; i < ret.size; i++) { + this.skip(ret.etype); + } + this.readSetEnd(); + return null; + + case Thrift.Type.LIST: + ret = this.readListBegin(); + for (i = 0; i < ret.size; i++) { + this.skip(ret.etype); + } + this.readListEnd(); + return null; + } + } +}; + + +/** + * Initializes a MutilplexProtocol Implementation as a Wrapper for Thrift.Protocol + * @constructor + */ +Thrift.MultiplexProtocol = function(srvName, trans, strictRead, strictWrite) { + Thrift.Protocol.call(this, trans, strictRead, strictWrite); + this.serviceName = srvName; +}; +Thrift.inherits(Thrift.MultiplexProtocol, Thrift.Protocol, 'multiplexProtocol'); + +/** Override writeMessageBegin method of prototype*/ +Thrift.MultiplexProtocol.prototype.writeMessageBegin = function(name, type, seqid) { + + if (type === Thrift.MessageType.CALL || type === Thrift.MessageType.ONEWAY) { + Thrift.Protocol.prototype.writeMessageBegin.call(this, this.serviceName + ':' + name, type, seqid); + } else { + Thrift.Protocol.prototype.writeMessageBegin.call(this, name, type, seqid); + } +}; + +Thrift.Multiplexer = function() { + this.seqid = 0; +}; + +/** Instantiates a multiplexed client for a specific service + * @constructor + * @param {String} serviceName - The transport to serialize to/from. + * @param {Thrift.ServiceClient} SCl - The Service Client Class + * @param {Thrift.Transport} transport - Thrift.Transport instance which provides remote host:port + * @example + * var mp = new Thrift.Multiplexer(); + * var transport = new Thrift.Transport("http://localhost:9090/foo.thrift"); + * var protocol = new Thrift.Protocol(transport); + * var client = mp.createClient('AuthService', AuthServiceClient, transport); +*/ +Thrift.Multiplexer.prototype.createClient = function(serviceName, SCl, transport) { + if (SCl.Client) { + SCl = SCl.Client; + } + var self = this; + SCl.prototype.new_seqid = function() { + self.seqid += 1; + return self.seqid; + }; + var client = new SCl(new Thrift.MultiplexProtocol(serviceName, transport)); + + return client; +}; + + + +var copyList, copyMap; + +copyList = function(lst, types) { + + if (!lst) {return lst; } + + var type; + + if (types.shift === undefined) { + type = types; + } + else { + type = types[0]; + } + var Type = type; + + var len = lst.length, result = [], i, val; + for (i = 0; i < len; i++) { + val = lst[i]; + if (type === null) { + result.push(val); + } + else if (type === copyMap || type === copyList) { + result.push(type(val, types.slice(1))); + } + else { + result.push(new Type(val)); + } + } + return result; +}; + +copyMap = function(obj, types) { + + if (!obj) {return obj; } + + var type; + + if (types.shift === undefined) { + type = types; + } + else { + type = types[0]; + } + var Type = type; + + var result = {}, val; + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + val = obj[prop]; + if (type === null) { + result[prop] = val; + } + else if (type === copyMap || type === copyList) { + result[prop] = type(val, types.slice(1)); + } + else { + result[prop] = new Type(val); + } + } + } + return result; +}; + +Thrift.copyMap = copyMap; +Thrift.copyList = copyList; diff --git a/lib/js/test/Makefile b/lib/js/test/Makefile new file mode 100644 index 0000000..49381a8 --- /dev/null +++ b/lib/js/test/Makefile @@ -0,0 +1,634 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# lib/js/test/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/thrift +pkgincludedir = $(includedir)/thrift +pkglibdir = $(libdir)/thrift +pkglibexecdir = $(libexecdir)/thrift +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-pc-linux-gnu +host_triplet = x86_64-pc-linux-gnu +subdir = lib/js/test +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_$(V)) +am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15 +ALLOCA = +AMTAR = $${TAR-tar} +AM_DEFAULT_VERBOSITY = 1 +ANT = /usr/bin/ant +ANT_FLAGS = +AR = ar +AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf +AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader +AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15 +AWK = gawk +BISON = bison +BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a +BOOST_CPPFLAGS = -I/usr/include +BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a +BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu +BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu +BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a +BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a +BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a +BUNDLER = /usr/bin/bundle +CABAL = /usr/bin/cabal +CABAL_CONFIGURE_FLAGS = +CARGO = /usr/bin/cargo +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 +CLASSPATH = +CPP = gcc -E +CPPFLAGS = +CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \; +CXX = g++ -std=c++11 +CXXCPP = g++ -E -std=c++11 +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -g -O2 +CYGPATH_W = echo +DART = /usr/lib/dart/bin/dart +DARTPUB = /usr/lib/dart/bin/pub +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +DLLTOOL = false +DMD = dmd +DMD_LIBEVENT_FLAGS = +DMD_OF_DIRSEP = / +DMD_OPENSSL_FLAGS = +DOTNETCORE = /usr/bin/dotnet +DOTNETCORE_VERSION = 2.0.3 +DSYMUTIL = +DUMPBIN = +D_EVENT_LIB_NAME = libthriftd-event.a +D_IMPORT_PREFIX = ${prefix}/include/d2 +D_LIB_NAME = libthriftd.a +D_SSL_LIB_NAME = libthriftd-ssl.a +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +ENABLE_COVERAGE = 2 +ERL = /usr/bin/erl +ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib +ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0 +ERLANG_LIB_DIR = /usr/lib/erlang/lib +ERLC = /usr/bin/erlc +ERLCFLAGS = +EXEEXT = +FGREP = /bin/grep -F +GCOV_CFLAGS = +GCOV_CXXFLAGS = +GCOV_LDFLAGS = +GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GLIB_LIBS = -lglib-2.0 +GO = /usr/bin/go +GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0 +GREP = /bin/grep +HAVE_CXX11 = 1 +HAXE = /usr/bin/haxe +HAXE_VERSION = 3.2.1 +INSTALL = /usr/bin/install -c +INSTALLDIRS = vendor +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +JAVA_PREFIX = /usr/local/lib +LD = /usr/bin/ld -m elf_x86_64 +LDFLAGS = +LEX = flex +LEXLIB = -lfl +LEX_OUTPUT_ROOT = lex.yy +LIBEVENT_CPPFLAGS = +LIBEVENT_LDFLAGS = +LIBEVENT_LIBS = -levent +LIBOBJS = +LIBS = -lrt -lpthread +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LIPO = +LN_S = ln -s +LTLIBOBJS = +LT_SYS_LIBRARY_PATH = +LUA = /usr/bin/lua5.3 +LUA_EXEC_PREFIX = ${exec_prefix} +LUA_INCLUDE = -I/usr/include/lua5.3 +LUA_LIB = -llua5.3 -ldl +LUA_PLATFORM = unknown +LUA_PREFIX = ${prefix} +LUA_SHORT_VERSION = 53 +LUA_VERSION = 5.3 +MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo +MANIFEST_TOOL = : +MAYBE_CPP = cpp +MAYBE_CSHARP = csharp +MAYBE_C_GLIB = c_glib +MAYBE_D = +MAYBE_DART = dart +MAYBE_DOTNETCORE = netcore +MAYBE_ERLANG = erl +MAYBE_GO = go +MAYBE_HASKELL = hs +MAYBE_JAVA = java +MAYBE_LUA = lua +MAYBE_NODEJS = nodejs +MAYBE_PERL = perl +MAYBE_PHP = php +MAYBE_PY3 = py3 +MAYBE_PYTHON = py +MAYBE_RS = rs +MAYBE_RUBY = rb +MCS = /usr/bin/mcs +MKDIR_P = /bin/mkdir -p +MONO_CFLAGS = +MONO_LIBS = +NM = /usr/bin/nm -B +NMEDIT = +NODEJS = /usr/bin/nodejs +NPM = /usr/bin/npm +OBJDUMP = objdump +OBJEXT = o +OPENSSL_INCLUDES = +OPENSSL_LDFLAGS = +OPENSSL_LIBS = -lssl -lcrypto +OTOOL = +OTOOL64 = +PACKAGE = thrift +PACKAGE_BUGREPORT = +PACKAGE_NAME = thrift +PACKAGE_STRING = thrift 0.11.0 +PACKAGE_TARNAME = thrift +PACKAGE_URL = +PACKAGE_VERSION = 0.11.0 +PATH_SEPARATOR = : +PERL = /usr/bin/perl +PERL_PREFIX = /usr/local +PHP = /usr/bin/php +PHPUNIT = /usr/bin/phpunit +PHP_CONFIG = /usr/bin/php-config +PHP_CONFIG_PREFIX = /etc/php.d +PHP_PREFIX = /usr/lib/php +PKG_CONFIG = /usr/bin/pkg-config +PKG_CONFIG_LIBDIR = +PKG_CONFIG_PATH = +PYTHON = /usr/bin/python +PYTHON3 = /usr/bin/python3 +PYTHON_EXEC_PREFIX = ${exec_prefix} +PYTHON_PLATFORM = linux2 +PYTHON_PREFIX = ${prefix} +PYTHON_VERSION = 2.7 +PY_PREFIX = /usr +QT5_CFLAGS = +QT5_LIBS = +QT5_MOC = +QT_CFLAGS = +QT_LIBS = +QT_MOC = +RANLIB = ranlib +REBAR = /usr/bin/rebar +RUBY = /usr/bin/ruby +RUBY_PREFIX = +RUNHASKELL = /usr/bin/runhaskell +RUSTC = /usr/bin/rustc +SED = /bin/sed +SET_MAKE = +SHELL = /bin/bash +STRIP = strip +THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift +TRIAL = /usr/bin/trial +VERSION = 0.11.0 +YACC = bison -y +YFLAGS = +ZLIB_CPPFLAGS = +ZLIB_LDFLAGS = +ZLIB_LIBS = -lz +abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/lib/js/test +abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/lib/js/test +abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift +abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift +ac_ct_AR = ar +ac_ct_CC = gcc +ac_ct_CXX = g++ +ac_ct_DUMPBIN = +am__include = include +am__leading_dot = . +am__quote = +am__tar = tar --format=ustar -chf - "$$tardir" +am__untar = tar -xf - +bindir = ${exec_prefix}/bin +build = x86_64-pc-linux-gnu +build_alias = +build_cpu = x86_64 +build_os = linux-gnu +build_vendor = pc +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +golang_version = 1.6.2 +have_prog_bison = yes +host = x86_64-pc-linux-gnu +host_alias = +host_cpu = x86_64 +host_os = linux-gnu +host_vendor = pc +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +luadir = ${prefix}/share/lua/5.3 +luaexecdir = ${exec_prefix}/lib/lua/5.3 +mandir = ${datarootdir}/man +mkdir_p = $(MKDIR_P) +oldincludedir = /usr/include +pdfdir = ${docdir} +pkgluadir = ${luadir}/thrift +pkgluaexecdir = ${luaexecdir}/thrift +pkgpyexecdir = ${pyexecdir}/thrift +pkgpythondir = ${pythondir}/thrift +prefix = /usr/local +program_transform_name = s,x,x, +psdir = ${docdir} +pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages +pythondir = ${prefix}/lib/python2.7/dist-packages +runstatedir = ${localstatedir}/run +rustc_version = rustc 1.17.0 +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +subdirs = lib/php/src/ext/thrift_protocol +sysconfdir = ${prefix}/etc +target_alias = +top_build_prefix = ../../../ +top_builddir = ../../.. +top_srcdir = ../../.. +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/js/test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/js/test/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: all all-am check check-am check-local clean clean-generic \ + clean-libtool clean-local cscopelist-am ctags-am distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +export CLASSPATH + +# Make sure this doesn't fail if ant is not configured. +clean-local: + ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ + $$ANT $(ANT_FLAGS) clean + +check-local: all + $(ANT) $(ANT_FLAGS) test + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/js/test/Makefile.am b/lib/js/test/Makefile.am new file mode 100755 index 0000000..14927c4 --- /dev/null +++ b/lib/js/test/Makefile.am @@ -0,0 +1,29 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +export CLASSPATH + +# Make sure this doesn't fail if ant is not configured. +clean-local: + ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ + $$ANT $(ANT_FLAGS) clean + +check-local: all + $(ANT) $(ANT_FLAGS) test + diff --git a/lib/js/test/Makefile.in b/lib/js/test/Makefile.in new file mode 100644 index 0000000..ce68f2f --- /dev/null +++ b/lib/js/test/Makefile.in @@ -0,0 +1,634 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/js/test +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/js/test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/js/test/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: all all-am check check-am check-local clean clean-generic \ + clean-libtool clean-local cscopelist-am ctags-am distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +export CLASSPATH + +# Make sure this doesn't fail if ant is not configured. +clean-local: + ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ + $$ANT $(ANT_FLAGS) clean + +check-local: all + $(ANT) $(ANT_FLAGS) test + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/js/test/README.md b/lib/js/test/README.md new file mode 100644 index 0000000..9ad140e --- /dev/null +++ b/lib/js/test/README.md @@ -0,0 +1,68 @@ +Thrift Javascript Library +========================= +This browser based Apache Thrift implementation supports +RPC clients using the JSON protocol over Http[s] with XHR +and WebSocket. + +License +------- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + +Test Servers +------------ +drwxr-xr-x 2 randy randy 4096 Feb 8 15:44 sec +-rw-r--r-- 1 randy randy 2183 Feb 9 04:01 server_http.js +-rw-r--r-- 1 randy randy 2386 Feb 9 05:39 server_https.js + +server_http.js is a Node.js web server which support the +standard Apache Thrift test suite (thrift/test/ThriftTest.thrift). +The server supports Apache Thrift XHR and WebSocket clients. + +server_https.js is the same but uses SSL/TLS. The server key +and cert are pulled from the thrift/test/keys folder. + +Both of these servers support WebSocket (the http: supports ws:, +and the https: support wss:). + +To run the client test with the Java test server use: +$ make check (requires the Apache Thrift Java branch +and make check must have been run in thrift/lib/java +previously). + +To run the client tests with the Node servers run the grunt + build in the parent js directory (see README there). + +Test Clients +------------ +-rw-r--r-- 1 randy randy 13558 Feb 9 07:18 test-async.js +-rw-r--r-- 1 randy randy 5724 Feb 9 03:45 test_handler.js +-rwxr-xr-x 1 randy randy 2719 Feb 9 06:04 test.html +-rw-r--r-- 1 randy randy 4611 Feb 9 06:05 test-jq.js +-rwxr-xr-x 1 randy randy 12153 Feb 9 06:04 test.js +-rw-r--r-- 1 randy randy 2593 Feb 9 06:16 test-nojq.html +-rw-r--r-- 1 randy randy 1450 Feb 9 06:14 test-nojq.js +-rw-r--r-- 1 randy randy 2847 Feb 9 06:31 testws.html + +There are three html test driver files, all of which are +QUnit based. test.html tests the Apache Thrift jQuery +generated code (thrift -gen js:jquery). The test-nojq.html +runs almost identical tests against normal JavaScript builds +(thrift -gen js). Both of the previous tests use the XHR +transport. The testws.html runs similar tests using the +WebSocket transport. The test*.js files are loaded by the +html drivers and contain the actual Apache Thrift tests. diff --git a/lib/js/test/build.xml b/lib/js/test/build.xml new file mode 100755 index 0000000..a905fde --- /dev/null +++ b/lib/js/test/build.xml @@ -0,0 +1,227 @@ + + + + Java Script Test based on Thrift Java Library + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + You need libthrift*.jar and libthrift*test.jar located at + ${thrift.java.dir}/build + Did you compile Thrift Java library and its test suite by "ant compile-test"? + + + + + + + + + + Thrift compiler is missing ! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + check if Xvfb is available: + + + + + + + check if phantomjs is available: + + + + + + + + + + + + + + + + Running Unit Tests with headless browser! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + check if gjslint is available: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/js/test/deep-constructor.test.js b/lib/js/test/deep-constructor.test.js new file mode 100644 index 0000000..336fc15 --- /dev/null +++ b/lib/js/test/deep-constructor.test.js @@ -0,0 +1,195 @@ +function serialize(data) { + var transport = new Thrift.Transport('/service'); + var protocol = new Thrift.Protocol(transport); + protocol.writeMessageBegin('', 0, 0); + data.write(protocol); + protocol.writeMessageEnd(); + return transport.send_buf; +} + +function deserialize(serialized, type) { + var transport = new Thrift.Transport('/service'); + transport.setRecvBuffer(serialized); + var protocol = new Thrift.Protocol(transport); + protocol.readMessageBegin(); + var data = new type(); + data.read(protocol); + protocol.readMessageEnd(); + return data; +} + + +function createThriftObj() { + + return new Complex({ + + struct_field: new Simple({value: 'a'}), + + struct_list_field: [ + new Simple({value: 'b'}), + new Simple({value: 'c'}) + ], + + struct_set_field: [ + new Simple({value: 'd'}), + new Simple({value: 'e'}) + ], + + struct_map_field: { + A: new Simple({value: 'f'}), + B: new Simple({value: 'g'}) + }, + + struct_nested_containers_field: [ + [ + { + C: [ + new Simple({value: 'h'}), + new Simple({value: 'i'}) + ] + } + ] + ], + + + struct_nested_containers_field2: { + D: [ + { + DA: new Simple({value: 'j'}) + }, + { + DB: new Simple({value: 'k'}) + } + ] + } + } + ); +} + + +function createJsObj() { + + return { + + struct_field: {value: 'a'}, + + struct_list_field: [ + {value: 'b'}, + {value: 'c'} + ], + + struct_set_field: [ + {value: 'd'}, + {value: 'e'} + ], + + struct_map_field: { + A: {value: 'f'}, + B: {value: 'g'} + }, + + struct_nested_containers_field: [ + [ + { + C: [ + {value: 'h'}, + {value: 'i'} + ] + } + ] + ], + + struct_nested_containers_field2: { + D: [ + { + DA: {value: 'j'} + }, + { + DB: {value: 'k'} + } + ] + } + }; +} + + +function assertValues(obj, assert) { + assert.equal(obj.struct_field.value, 'a'); + assert.equal(obj.struct_list_field[0].value, 'b'); + assert.equal(obj.struct_list_field[1].value, 'c'); + assert.equal(obj.struct_set_field[0].value, 'd'); + assert.equal(obj.struct_set_field[1].value, 'e'); + assert.equal(obj.struct_map_field.A.value, 'f'); + assert.equal(obj.struct_map_field.B.value, 'g'); + assert.equal(obj.struct_nested_containers_field[0][0].C[0].value, 'h'); + assert.equal(obj.struct_nested_containers_field[0][0].C[1].value, 'i'); + assert.equal(obj.struct_nested_containers_field2.D[0].DA.value, 'j'); + assert.equal(obj.struct_nested_containers_field2.D[1].DB.value, 'k'); +} + +var cases = { + + 'Serialize/deserialize simple struct should return equal object': function(assert) { + var tObj = new Simple({value: 'a'}); + var received = deserialize(serialize(tObj), Simple); + assert.ok(tObj !== received); + assert.deepEqual(received, tObj); + }, + + + 'Serialize/deserialize should return equal object': function(assert) { + var tObj = createThriftObj(); + var received = deserialize(serialize(tObj), Complex); + assert.ok(tObj !== received); + assert.deepEqual(received, tObj); + }, + + 'Nested structs and containers initialized from plain js objects should serialize same as if initialized from thrift objects': function(assert) { + var tObj1 = createThriftObj(); + var tObj2 = new Complex(createJsObj()); + assertValues(tObj2, assert); + assert.equal(serialize(tObj2), serialize(tObj1)); + }, + + 'Modifications to args object should not affect constructed Thrift object': function(assert) { + + var args = createJsObj(); + assertValues(args, assert); + + var tObj = new Complex(args); + assertValues(tObj, assert); + + args.struct_field.value = 'ZZZ'; + args.struct_list_field[0].value = 'ZZZ'; + args.struct_list_field[1].value = 'ZZZ'; + args.struct_set_field[0].value = 'ZZZ'; + args.struct_set_field[1].value = 'ZZZ'; + args.struct_map_field.A.value = 'ZZZ'; + args.struct_map_field.B.value = 'ZZZ'; + args.struct_nested_containers_field[0][0].C[0] = 'ZZZ'; + args.struct_nested_containers_field[0][0].C[1] = 'ZZZ'; + args.struct_nested_containers_field2.D[0].DA = 'ZZZ'; + args.struct_nested_containers_field2.D[0].DB = 'ZZZ'; + + assertValues(tObj, assert); + }, + + 'nulls are ok': function(assert) { + var tObj = new Complex({ + struct_field: null, + struct_list_field: null, + struct_set_field: null, + struct_map_field: null, + struct_nested_containers_field: null, + struct_nested_containers_field2: null + }); + var received = deserialize(serialize(tObj), Complex); + assert.ok(tObj !== received); + assert.deepEqual(tObj, received); + } + +}; + +Object.keys(cases).forEach(function(caseName) { + test(caseName, cases[caseName]); +}); diff --git a/lib/js/test/jsTestDriver.conf b/lib/js/test/jsTestDriver.conf new file mode 100755 index 0000000..b9702cd --- /dev/null +++ b/lib/js/test/jsTestDriver.conf @@ -0,0 +1,17 @@ +server: http://localhost:9876 + +load: +# Qunit adapter + - build/js/lib/equiv.js + - build/js/lib/QUnitAdapter.js +# dependencies + - build/js/lib/jquery.js + - build/js/thrift.js + - gen-js/ThriftTest_types.js + - gen-js/ThriftTest.js +# the test suite + - test.js + +# redirect to the Java based Thrift testserver +proxy: + - {matcher: "*", server: " http://localhost:8088"} diff --git a/lib/js/test/phantom-client.js b/lib/js/test/phantom-client.js new file mode 100644 index 0000000..d517e71 --- /dev/null +++ b/lib/js/test/phantom-client.js @@ -0,0 +1,382 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + /* jshint -W100 */ + +(function() { + 'use strict'; + + // Rudimentary test helper functions + // TODO: Return error code based on kind of errors rather than throw + var ok = function(t, msg) { + if (!t) { + console.log('*** FAILED ***'); + throw new Error(msg); + } + }; + var equal = function(a, b) { + if (a !== b) { + console.log('*** FAILED ***'); + throw new Error(); + } + }; + var test = function(name, f) { + console.log('TEST : ' + name); + f(); + console.log('OK\n'); + }; + + var parseArgs = function(args) { + var skips = [ + '--transport=http', + '--protocol=json' + ]; + var opts = { + port: '9090' + // protocol: 'json', + }; + var keys = {}; + for (var key in opts) { + keys['--' + key + '='] = key; + } + for (var i in args) { + var arg = args[i]; + if (skips.indexOf(arg) != -1) { + continue; + } + var hit = false; + for (var k in keys) { + if (arg.slice(0, k.length) === k) { + opts[keys[k]] = arg.slice(k.length); + hit = true; + break; + } + } + if (!hit) { + throw new Error('Unknown argument: ' + arg); + } + } + opts.port = parseInt(opts.port, 10); + if (!opts.port || opts.port < 1 || opts.port > 65535) { + throw new Error('Invalid port number'); + } + return opts; + }; + + var execute = function() { + console.log('### Apache Thrift Javascript standalone test client'); + console.log('------------------------------------------------------------'); + + phantom.page.injectJs('src/thrift.js'); + phantom.page.injectJs('test/gen-js/ThriftTest_types.js'); + phantom.page.injectJs('test/gen-js/ThriftTest.js'); + + var system = require('system'); + var opts = parseArgs(system.args.slice(1)); + var port = opts.port; + var transport = new Thrift.Transport('http://localhost:' + port + '/service'); + var protocol = new Thrift.Protocol(transport); + var client = new ThriftTest.ThriftTestClient(protocol); + + + // TODO: Remove duplicate code with test.js. + // all Languages in UTF-8 + var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"; + + function checkRecursively(map1, map2) { + if (typeof map1 !== 'function' && typeof map2 !== 'function') { + if (!map1 || typeof map1 !== 'object') { + equal(map1, map2); + } else { + for (var key in map1) { + checkRecursively(map1[key], map2[key]); + } + } + } + } + + test('Void', function() { + equal(client.testVoid(), undefined); + }); + test('Binary (String)', function() { + var binary = ''; + for (var v = 255; v >= 0; --v) { + binary += String.fromCharCode(v); + } + equal(client.testBinary(binary), binary); + }); + test('Binary (Uint8Array)', function() { + var binary = ''; + for (var v = 255; v >= 0; --v) { + binary += String.fromCharCode(v); + } + var arr = new Uint8Array(binary.length); + for (var i = 0; i < binary.length; ++i) { + arr[i] = binary[i].charCodeAt(); + } + equal(client.testBinary(arr), binary); + }); + test('String', function() { + equal(client.testString(''), ''); + equal(client.testString(stringTest), stringTest); + + var specialCharacters = 'quote: \" backslash:' + + ' forwardslash-escaped: \/ ' + + ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + + ' now-all-of-them-together: "\\\/\b\n\r\t' + + ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><'; + equal(client.testString(specialCharacters), specialCharacters); + }); + test('Double', function() { + equal(client.testDouble(0), 0); + equal(client.testDouble(-1), -1); + equal(client.testDouble(3.14), 3.14); + equal(client.testDouble(Math.pow(2, 60)), Math.pow(2, 60)); + }); + test('Bool', function() { + equal(client.testBool(true), true); + equal(client.testBool(false), false); + }); + test('I8', function() { + equal(client.testByte(0), 0); + equal(client.testByte(0x01), 0x01); + }); + test('I32', function() { + equal(client.testI32(0), 0); + equal(client.testI32(Math.pow(2, 30)), Math.pow(2, 30)); + equal(client.testI32(-Math.pow(2, 30)), -Math.pow(2, 30)); + }); + test('I64', function() { + equal(client.testI64(0), 0); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + equal(client.testI64(Math.pow(2, 52)), Math.pow(2, 52)); + equal(client.testI64(-Math.pow(2, 52)), -Math.pow(2, 52)); + }); + + test('Struct', function() { + var structTestInput = new ThriftTest.Xtruct(); + structTestInput.string_thing = 'worked'; + structTestInput.byte_thing = 0x01; + structTestInput.i32_thing = Math.pow(2, 30); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + structTestInput.i64_thing = Math.pow(2, 52); + + var structTestOutput = client.testStruct(structTestInput); + + equal(structTestOutput.string_thing, structTestInput.string_thing); + equal(structTestOutput.byte_thing, structTestInput.byte_thing); + equal(structTestOutput.i32_thing, structTestInput.i32_thing); + equal(structTestOutput.i64_thing, structTestInput.i64_thing); + + equal(JSON.stringify(structTestOutput), JSON.stringify(structTestInput)); + }); + + test('Nest', function() { + var xtrTestInput = new ThriftTest.Xtruct(); + xtrTestInput.string_thing = 'worked'; + xtrTestInput.byte_thing = 0x01; + xtrTestInput.i32_thing = Math.pow(2, 30); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + xtrTestInput.i64_thing = Math.pow(2, 52); + + var nestTestInput = new ThriftTest.Xtruct2(); + nestTestInput.byte_thing = 0x02; + nestTestInput.struct_thing = xtrTestInput; + nestTestInput.i32_thing = Math.pow(2, 15); + + var nestTestOutput = client.testNest(nestTestInput); + + equal(nestTestOutput.byte_thing, nestTestInput.byte_thing); + equal(nestTestOutput.struct_thing.string_thing, nestTestInput.struct_thing.string_thing); + equal(nestTestOutput.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing); + equal(nestTestOutput.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing); + equal(nestTestOutput.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing); + equal(nestTestOutput.i32_thing, nestTestInput.i32_thing); + + equal(JSON.stringify(nestTestOutput), JSON.stringify(nestTestInput)); + }); + + test('Map', function() { + var mapTestInput = {7: 77, 8: 88, 9: 99}; + + var mapTestOutput = client.testMap(mapTestInput); + + for (var key in mapTestOutput) { + equal(mapTestOutput[key], mapTestInput[key]); + } + }); + + test('StringMap', function() { + var mapTestInput = { + 'a': '123', 'a b': 'with spaces ', 'same': 'same', '0': 'numeric key', + 'longValue': stringTest, stringTest: 'long key' + }; + + var mapTestOutput = client.testStringMap(mapTestInput); + + for (var key in mapTestOutput) { + equal(mapTestOutput[key], mapTestInput[key]); + } + }); + + test('Set', function() { + var setTestInput = [1, 2, 3]; + ok(client.testSet(setTestInput), setTestInput); + }); + + test('List', function() { + var listTestInput = [1, 2, 3]; + ok(client.testList(listTestInput), listTestInput); + }); + + test('Enum', function() { + equal(client.testEnum(ThriftTest.Numberz.ONE), ThriftTest.Numberz.ONE); + }); + + test('TypeDef', function() { + equal(client.testTypedef(69), 69); + }); + + test('Skip', function() { + var structTestInput = new ThriftTest.Xtruct(); + var modifiedClient = new ThriftTest.ThriftTestClient(protocol); + + modifiedClient.recv_testStruct = function() { + var input = modifiedClient.input; + var xtruct3 = new ThriftTest.Xtruct3(); + + input.readMessageBegin(); + input.readStructBegin(); + + // read Xtruct data with Xtruct3 + input.readFieldBegin(); + xtruct3.read(input); + input.readFieldEnd(); + // read Thrift.Type.STOP message + input.readFieldBegin(); + input.readFieldEnd(); + + input.readStructEnd(); + input.readMessageEnd(); + + return xtruct3; + }; + + structTestInput.string_thing = 'worked'; + structTestInput.byte_thing = 0x01; + structTestInput.i32_thing = Math.pow(2, 30); + structTestInput.i64_thing = Math.pow(2, 52); + + var structTestOutput = modifiedClient.testStruct(structTestInput); + + equal(structTestOutput instanceof ThriftTest.Xtruct3, true); + equal(structTestOutput.string_thing, structTestInput.string_thing); + equal(structTestOutput.changed, null); + equal(structTestOutput.i32_thing, structTestInput.i32_thing); + equal(structTestOutput.i64_thing, structTestInput.i64_thing); + }); + + test('MapMap', function() { + var mapMapTestExpectedResult = { + '4': {'1': 1, '2': 2, '3': 3, '4': 4}, + '-4': {'-4': -4, '-3': -3, '-2': -2, '-1': -1} + }; + + var mapMapTestOutput = client.testMapMap(1); + + + for (var key in mapMapTestOutput) { + for (var key2 in mapMapTestOutput[key]) { + equal(mapMapTestOutput[key][key2], mapMapTestExpectedResult[key][key2]); + } + } + + checkRecursively(mapMapTestOutput, mapMapTestExpectedResult); + }); + + test('Xception', function() { + try { + client.testException('Xception'); + ok(false); + } catch (e) { + equal(e.errorCode, 1001); + equal(e.message, 'Xception'); + } + }); + + test('no Exception', function() { + try { + client.testException('no Exception'); + } catch (e) { + ok(false); + } + }); + + test('TException', function() { + try { + client.testException('TException'); + ok(false); + } catch (e) { + ok(ok); + } + }); + + var crazy = { + 'userMap': { '5': 5, '8': 8 }, + 'xtructs': [{ + 'string_thing': 'Goodbye4', + 'byte_thing': 4, + 'i32_thing': 4, + 'i64_thing': 4 + }, + { + 'string_thing': 'Hello2', + 'byte_thing': 2, + 'i32_thing': 2, + 'i64_thing': 2 + }] + }; + test('Insanity', function() { + var insanity = { + '1': { + '2': crazy, + '3': crazy + }, + '2': { '6': { 'userMap': null, 'xtructs': null } } + }; + var res = client.testInsanity(new ThriftTest.Insanity(crazy)); + ok(res, JSON.stringify(res)); + ok(insanity, JSON.stringify(insanity)); + + checkRecursively(res, insanity); + }); + + console.log('------------------------------------------------------------'); + console.log('### All tests succeeded.'); + return 0; + }; + + try { + var ret = execute(); + phantom.exit(ret); + } catch (err) { + // Catch all and exit to avoid hang. + console.error(err); + phantom.exit(1); + } +})(); diff --git a/lib/js/test/phantomjs-qunit.js b/lib/js/test/phantomjs-qunit.js new file mode 100755 index 0000000..c1d7a5b --- /dev/null +++ b/lib/js/test/phantomjs-qunit.js @@ -0,0 +1,91 @@ +/*jshint evil:true*/ + +/* This file is only used by the test suite. + * + * Origin: https://github.com/ariya/phantomjs/blob/master/examples/run-qunit.js + * License: https://github.com/ariya/phantomjs/blob/master/LICENSE.BSD + * + * Inclusion into Apache products is allowed according to http://www.apache.org/legal/3party.html + */ + +var system = require('system'); + + +/** + * Wait until the test condition is true or a timeout occurs. Useful for waiting + * on a server response or for a ui change (fadeIn, etc.) to occur. + * + * @param testFx javascript condition that evaluates to a boolean, + * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or + * as a callback function. + * @param onReady what to do when testFx condition is fulfilled, + * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or + * as a callback function. + * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used. + */ +function waitFor(testFx, onReady, timeOutMillis) { + var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3001, //< Default Max Timout is 3s + start = new Date().getTime(), + condition = false, + interval = setInterval(function() { + if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) { + // If not time-out yet and condition not yet fulfilled + condition = (typeof(testFx) === 'string' ? eval(testFx) : testFx()); //< defensive code + } else { + if (!condition) { + // If condition still not fulfilled (timeout but condition is 'false') + console.log("'waitFor()' timeout"); + phantom.exit(1); + } else { + // Condition fulfilled (timeout and/or condition is 'true') + console.log("'waitFor()' finished in " + (new Date().getTime() - start) + 'ms.'); + if (typeof(onReady) === 'string') { + eval(onReady); + } else { + onReady(); //< Do what it's supposed to do once the condition is fulfilled + } + clearInterval(interval); //< Stop this interval + } + } + }, 100); //< repeat check every 250ms +} + + +if (system.args.length === 1 || system.args.length > 3) { + console.log('Usage: phantomjs phantomjs-qunit.js URL'); + phantom.exit(1); +} + +var page = new WebPage(); + +// Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this") +page.onConsoleMessage = function(msg) { + console.log(msg); +}; + +page.open(system.args[1], function(status) { + if (status !== 'success') { + console.log('Unable to access network'); + phantom.exit(1); + } else { + waitFor(function() { + return page.evaluate(function() { + var el = document.getElementById('qunit-testresult'); + if (el && el.innerText.match('completed')) { + return true; + } + return false; + }); + }, function() { + var failedNum = page.evaluate(function() { + var el = document.getElementById('qunit-testresult'); + console.log(el.innerText); + try { + return el.getElementsByClassName('failed')[0].innerHTML; + } catch (e) { } + return 10000; + }); + phantom.exit((parseInt(failedNum, 10) > 0) ? 1 : 0); + }); + } +}); diff --git a/lib/js/test/server_http.js b/lib/js/test/server_http.js new file mode 100644 index 0000000..1115474 --- /dev/null +++ b/lib/js/test/server_http.js @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//This HTTP server is designed to serve the test.html browser +// based JavaScript test page (which must be in the current directory). +// This server also supplies the Thrift based test service, which depends +// on the standard ThriftTest.thrift IDL service (which must be compiled +// for Node and browser based JavaScript in ./gen-nodejs and ./gen-js +// respectively). + +var thrift = require('../../nodejs/lib/thrift'); +var ThriftTestSvc = require('./gen-nodejs/ThriftTest.js'); +var ThriftTestHandler = require('./test_handler').ThriftTestHandler; + +var ThriftTestSvcOpt = { + transport: thrift.TBufferedTransport, + protocol: thrift.TJSONProtocol, + processor: ThriftTestSvc, + handler: ThriftTestHandler +}; + +var ThriftWebServerOptions = { + files: '.', + services: { + '/service': ThriftTestSvcOpt + } +}; + +var server = thrift.createWebServer(ThriftWebServerOptions); +var port = 8088; +server.listen(port); +console.log('Serving files from: ' + __dirname); +console.log('Http/Thrift Server running on port: ' + port); diff --git a/lib/js/test/server_https.js b/lib/js/test/server_https.js new file mode 100644 index 0000000..7e78d9e --- /dev/null +++ b/lib/js/test/server_https.js @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//This HTTP server is designed to server the test.html browser +// based JavaScript test page (which must be in the current directory). +// This server also supplies the Thrift based test service, which depends +// on the standard ThriftTest.thrift IDL service (which must be compiled +// for Node and browser based JavaScript in ./gen-nodejs and ./gen-js +// respectively). The current directory must also include the browser +// support libraries for test.html (jquery.js, qunit.js and qunit.css +// in ./build/js/lib). + +var fs = require('fs'); +var thrift = require('../../nodejs/lib/thrift'); +var ThriftTestSvc = require('./gen-nodejs/ThriftTest.js'); +var ThriftTestHandler = require('./test_handler').ThriftTestHandler; + +//Setup the I/O stack options for the ThriftTest service +var ThriftTestSvcOpt = { + transport: thrift.TBufferedTransport, + protocol: thrift.TJSONProtocol, + processor: ThriftTestSvc, + handler: ThriftTestHandler +}; + +var ThriftWebServerOptions = { + files: '.', + tls: { + key: fs.readFileSync('../../../test/keys/server.key'), + cert: fs.readFileSync('../../../test/keys/server.crt') + }, + services: { + '/service': ThriftTestSvcOpt + } +}; + +var server = thrift.createWebServer(ThriftWebServerOptions); +var port = 8089; +server.listen(port); +console.log('Serving files from: ' + __dirname); +console.log('Http/Thrift Server running on port: ' + port); diff --git a/lib/js/test/src/test/Httpd.java b/lib/js/test/src/test/Httpd.java new file mode 100644 index 0000000..e4fc0cc --- /dev/null +++ b/lib/js/test/src/test/Httpd.java @@ -0,0 +1,323 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package test; + +import java.io.File; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URLDecoder; +import java.util.Locale; + +import org.apache.http.ConnectionClosedException; +import org.apache.http.HttpEntity; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.HttpServerConnection; +import org.apache.http.HttpStatus; +import org.apache.http.MethodNotSupportedException; +import org.apache.http.entity.ContentProducer; +import org.apache.http.entity.EntityTemplate; +import org.apache.http.entity.FileEntity; +import org.apache.http.impl.DefaultHttpResponseFactory; +import org.apache.http.impl.DefaultHttpServerConnection; +import org.apache.http.impl.NoConnectionReuseStrategy; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.params.CoreProtocolPNames; +import org.apache.http.params.HttpParams; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.BasicHttpProcessor; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpProcessor; +import org.apache.http.protocol.HttpRequestHandler; +import org.apache.http.protocol.HttpRequestHandlerRegistry; +import org.apache.http.protocol.HttpService; +import org.apache.http.util.EntityUtils; +import org.apache.thrift.TProcessor; +import org.apache.thrift.protocol.TJSONProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.transport.TMemoryBuffer; + +import thrift.test.ThriftTest; +import org.apache.thrift.server.ServerTestBase.TestHandler; + +import eu.medsea.mimeutil.detector.ExtensionMimeDetector; +import eu.medsea.mimeutil.MimeUtil2; +import eu.medsea.mimeutil.MimeType; +import java.util.Collection; +import java.util.Iterator; + +/** + * Basic, yet fully functional and spec compliant, HTTP/1.1 file server. + *

+ * Please note the purpose of this application is demonstrate the usage of + * HttpCore APIs. It is NOT intended to demonstrate the most efficient way of + * building an HTTP file server. + * + * + */ +public class Httpd { + + public static void main(String[] args) throws Exception { + if (args.length < 1) { + System.err.println("Please specify document root directory"); + System.exit(1); + } + Thread t = new RequestListenerThread(8088, args[0]); + t.setDaemon(false); + t.start(); + } + + static class HttpFileHandler implements HttpRequestHandler { + + private final String docRoot; + + public HttpFileHandler(final String docRoot) { + super(); + this.docRoot = docRoot; + } + + public void handle(final HttpRequest request, final HttpResponse response, final HttpContext context) throws HttpException, IOException { + + String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH); + if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST")) { + throw new MethodNotSupportedException(method + " method not supported"); + } + String target = request.getRequestLine().getUri(); + + if (request instanceof HttpEntityEnclosingRequest && target.equals("/service")) { + HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); + byte[] entityContent = EntityUtils.toByteArray(entity); + System.out.println("Incoming content: " + new String(entityContent)); + + final String output = this.thriftRequest(entityContent); + + System.out.println("Outgoing content: "+output); + + EntityTemplate body = new EntityTemplate(new ContentProducer() { + + public void writeTo(final OutputStream outstream) throws IOException { + OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8"); + writer.write(output); + writer.flush(); + } + + }); + body.setContentType("text/html; charset=UTF-8"); + response.setEntity(body); + } else { + if(target.indexOf("?") != -1) { + target = target.substring(1, target.indexOf("?")); + } + + final File file = new File(this.docRoot, URLDecoder.decode(target, "UTF-8")); + + if (!file.exists()) { + + response.setStatusCode(HttpStatus.SC_NOT_FOUND); + EntityTemplate body = new EntityTemplate(new ContentProducer() { + + public void writeTo(final OutputStream outstream) throws IOException { + OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8"); + writer.write("

"); + writer.write("File "); + writer.write(file.getPath()); + writer.write(" not found"); + writer.write("

"); + writer.flush(); + } + + }); + body.setContentType("text/html; charset=UTF-8"); + response.setEntity(body); + System.out.println("File " + file.getPath() + " not found"); + + } else if (!file.canRead() || file.isDirectory()) { + + response.setStatusCode(HttpStatus.SC_FORBIDDEN); + EntityTemplate body = new EntityTemplate(new ContentProducer() { + + public void writeTo(final OutputStream outstream) throws IOException { + OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8"); + writer.write("

"); + writer.write("Access denied"); + writer.write("

"); + writer.flush(); + } + + }); + body.setContentType("text/html; charset=UTF-8"); + response.setEntity(body); + System.out.println("Cannot read file " + file.getPath()); + + } else { + + String mimeType = "application/octet-stream"; + MimeUtil2 mimeUtil = new MimeUtil2(); + synchronized (this) { + mimeUtil.registerMimeDetector(ExtensionMimeDetector.class.getName()); + } + Collection collection = mimeUtil.getMimeTypes(file); + Iterator iterator = collection.iterator(); + while(iterator.hasNext()) { + MimeType mt = iterator.next(); + mimeType = mt.getMediaType() + "/" + mt.getSubType(); + break; + } + + response.setStatusCode(HttpStatus.SC_OK); + FileEntity body = new FileEntity(file, mimeType); + response.addHeader("Content-Type", mimeType); + response.setEntity(body); + System.out.println("Serving file " + file.getPath()); + + } + } + } + + private String thriftRequest(byte[] input){ + try{ + + //Input + TMemoryBuffer inbuffer = new TMemoryBuffer(input.length); + inbuffer.write(input); + TProtocol inprotocol = new TJSONProtocol(inbuffer); + + //Output + TMemoryBuffer outbuffer = new TMemoryBuffer(100); + TProtocol outprotocol = new TJSONProtocol(outbuffer); + + TProcessor processor = new ThriftTest.Processor(new TestHandler()); + processor.process(inprotocol, outprotocol); + + byte[] output = new byte[outbuffer.length()]; + outbuffer.readAll(output, 0, output.length); + + return new String(output,"UTF-8"); + }catch(Throwable t){ + return "Error:"+t.getMessage(); + } + + + } + + } + + static class RequestListenerThread extends Thread { + + private final ServerSocket serversocket; + private final HttpParams params; + private final HttpService httpService; + + public RequestListenerThread(int port, final String docroot) throws IOException { + this.serversocket = new ServerSocket(port); + this.params = new BasicHttpParams(); + this.params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 1000).setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) + .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false).setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) + .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); + + // Set up the HTTP protocol processor + HttpProcessor httpproc = new BasicHttpProcessor(); + + // Set up request handlers + HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry(); + reqistry.register("*", new HttpFileHandler(docroot)); + + // Set up the HTTP service + this.httpService = new HttpService(httpproc, new NoConnectionReuseStrategy(), new DefaultHttpResponseFactory()); + this.httpService.setParams(this.params); + this.httpService.setHandlerResolver(reqistry); + } + + public void run() { + System.out.println("Listening on port " + this.serversocket.getLocalPort()); + System.out.println("Point your browser to http://localhost:8088/test/test.html"); + + while (!Thread.interrupted()) { + try { + // Set up HTTP connection + Socket socket = this.serversocket.accept(); + DefaultHttpServerConnection conn = new DefaultHttpServerConnection(); + System.out.println("Incoming connection from " + socket.getInetAddress()); + conn.bind(socket, this.params); + + // Start worker thread + Thread t = new WorkerThread(this.httpService, conn); + t.setDaemon(true); + t.start(); + } catch (InterruptedIOException ex) { + break; + } catch (IOException e) { + System.err.println("I/O error initialising connection thread: " + e.getMessage()); + break; + } + } + } + } + + static class WorkerThread extends Thread { + + private final HttpService httpservice; + private final HttpServerConnection conn; + + public WorkerThread(final HttpService httpservice, final HttpServerConnection conn) { + super(); + this.httpservice = httpservice; + this.conn = conn; + } + + public void run() { + System.out.println("New connection thread"); + HttpContext context = new BasicHttpContext(null); + try { + while (!Thread.interrupted() && this.conn.isOpen()) { + this.httpservice.handleRequest(this.conn, context); + } + } catch (ConnectionClosedException ex) { + System.err.println("Client closed connection"); + } catch (IOException ex) { + System.err.println("I/O error: " + ex.getMessage()); + } catch (HttpException ex) { + System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage()); + } finally { + try { + this.conn.shutdown(); + } catch (IOException ignore) { + } + } + } + + } + +} diff --git a/lib/js/test/test-async.js b/lib/js/test/test-async.js new file mode 100644 index 0000000..b56f2a2 --- /dev/null +++ b/lib/js/test/test-async.js @@ -0,0 +1,348 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + /* jshint -W100 */ + +/* + * Fully Async JavaScript test suite for ThriftTest.thrift. + * These tests are designed to exercise the WebSocket transport + * (which is exclusively async). + * + * To compile client code for this test use: + * $ thrift -gen js ThriftTest.thrift + */ + + + +// all Languages in UTF-8 +var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"; + +function checkRecursively(map1, map2) { + if (typeof map1 !== 'function' && typeof map2 !== 'function') { + if (!map1 || typeof map1 !== 'object') { + equal(map1, map2); + } else { + for (var key in map1) { + checkRecursively(map1[key], map2[key]); + } + } + } +} + +module('Base Types'); + + asyncTest('Void', function() { + expect(1); + client.testVoid(function(result) { + equal(result, undefined); + QUnit.start(); + }); + }); + + + asyncTest('String', function() { + expect(3); + QUnit.stop(2); + client.testString('', function(result) { + equal(result, ''); + QUnit.start(); + }); + client.testString(stringTest, function(result) { + equal(result, stringTest); + QUnit.start(); + }); + + var specialCharacters = 'quote: \" backslash:' + + ' forwardslash-escaped: \/ ' + + ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + + ' now-all-of-them-together: "\\\/\b\n\r\t' + + ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><'; + client.testString(specialCharacters, function(result) { + equal(result, specialCharacters); + QUnit.start(); + }); + }); + asyncTest('Double', function() { + expect(4); + QUnit.stop(3); + client.testDouble(0, function(result) { + equal(result, 0); + QUnit.start(); + }); + client.testDouble(-1, function(result) { + equal(result, -1); + QUnit.start(); + }); + client.testDouble(3.14, function(result) { + equal(result, 3.14); + QUnit.start(); + }); + client.testDouble(Math.pow(2, 60), function(result) { + equal(result, Math.pow(2, 60)); + QUnit.start(); + }); + }); + // TODO: add testBinary() + asyncTest('Byte', function() { + expect(2); + QUnit.stop(); + client.testByte(0, function(result) { + equal(result, 0); + QUnit.start(); + }); + client.testByte(0x01, function(result) { + equal(result, 0x01); + QUnit.start(); + }); + }); + asyncTest('I32', function() { + expect(3); + QUnit.stop(2); + client.testI32(0, function(result) { + equal(result, 0); + QUnit.start(); + }); + client.testI32(Math.pow(2, 30), function(result) { + equal(result, Math.pow(2, 30)); + QUnit.start(); + }); + client.testI32(-Math.pow(2, 30), function(result) { + equal(result, -Math.pow(2, 30)); + QUnit.start(); + }); + }); + asyncTest('I64', function() { + expect(3); + QUnit.stop(2); + client.testI64(0, function(result) { + equal(result, 0); + QUnit.start(); + }); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + client.testI64(Math.pow(2, 52), function(result) { + equal(result, Math.pow(2, 52)); + QUnit.start(); + }); + client.testI64(-Math.pow(2, 52), function(result) { + equal(result, -Math.pow(2, 52)); + QUnit.start(); + }); + }); + + + + +module('Structured Types'); + + asyncTest('Struct', function() { + expect(5); + var structTestInput = new ThriftTest.Xtruct(); + structTestInput.string_thing = 'worked'; + structTestInput.byte_thing = 0x01; + structTestInput.i32_thing = Math.pow(2, 30); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + structTestInput.i64_thing = Math.pow(2, 52); + + client.testStruct(structTestInput, function(result) { + equal(result.string_thing, structTestInput.string_thing); + equal(result.byte_thing, structTestInput.byte_thing); + equal(result.i32_thing, structTestInput.i32_thing); + equal(result.i64_thing, structTestInput.i64_thing); + equal(JSON.stringify(result), JSON.stringify(structTestInput)); + QUnit.start(); + }); + }); + + asyncTest('Nest', function() { + expect(7); + var xtrTestInput = new ThriftTest.Xtruct(); + xtrTestInput.string_thing = 'worked'; + xtrTestInput.byte_thing = 0x01; + xtrTestInput.i32_thing = Math.pow(2, 30); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + xtrTestInput.i64_thing = Math.pow(2, 52); + + var nestTestInput = new ThriftTest.Xtruct2(); + nestTestInput.byte_thing = 0x02; + nestTestInput.struct_thing = xtrTestInput; + nestTestInput.i32_thing = Math.pow(2, 15); + + client.testNest(nestTestInput, function(result) { + equal(result.byte_thing, nestTestInput.byte_thing); + equal(result.struct_thing.string_thing, nestTestInput.struct_thing.string_thing); + equal(result.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing); + equal(result.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing); + equal(result.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing); + equal(result.i32_thing, nestTestInput.i32_thing); + equal(JSON.stringify(result), JSON.stringify(nestTestInput)); + QUnit.start(); + }); + }); + + asyncTest('Map', function() { + expect(3); + var mapTestInput = {7: 77, 8: 88, 9: 99}; + + client.testMap(mapTestInput, function(result) { + for (var key in result) { + equal(result[key], mapTestInput[key]); + } + QUnit.start(); + }); + }); + + asyncTest('StringMap', function() { + expect(6); + var mapTestInput = { + 'a': '123', 'a b': 'with spaces ', 'same': 'same', '0': 'numeric key', + 'longValue': stringTest, stringTest: 'long key' + }; + + client.testStringMap(mapTestInput, function(result) { + for (var key in result) { + equal(result[key], mapTestInput[key]); + } + QUnit.start(); + }); + }); + + asyncTest('Set', function() { + expect(1); + var setTestInput = [1, 2, 3]; + client.testSet(setTestInput, function(result) { + ok(result, setTestInput); + QUnit.start(); + }); + }); + + asyncTest('List', function() { + expect(1); + var listTestInput = [1, 2, 3]; + client.testList(listTestInput, function(result) { + ok(result, listTestInput); + QUnit.start(); + }); + }); + + asyncTest('Enum', function() { + expect(1); + client.testEnum(ThriftTest.Numberz.ONE, function(result) { + equal(result, ThriftTest.Numberz.ONE); + QUnit.start(); + }); + }); + + asyncTest('TypeDef', function() { + expect(1); + client.testTypedef(69, function(result) { + equal(result, 69); + QUnit.start(); + }); + }); + + +module('deeper!'); + + asyncTest('MapMap', function() { + expect(16); + var mapMapTestExpectedResult = { + '4': {'1': 1, '2': 2, '3': 3, '4': 4}, + '-4': {'-4': -4, '-3': -3, '-2': -2, '-1': -1} + }; + + client.testMapMap(1, function(result) { + for (var key in result) { + for (var key2 in result[key]) { + equal(result[key][key2], mapMapTestExpectedResult[key][key2]); + } + } + checkRecursively(result, mapMapTestExpectedResult); + QUnit.start(); + }); + }); + + +module('Exception'); + + asyncTest('Xception', function() { + expect(2); + client.testException('Xception', function(e) { + equal(e.errorCode, 1001); + equal(e.message, 'Xception'); + QUnit.start(); + }); + }); + + asyncTest('no Exception', 0, function() { + expect(1); + client.testException('no Exception', function(e) { + ok(!e); + QUnit.start(); + }); + }); + +module('Insanity'); + + asyncTest('testInsanity', function() { + expect(24); + var insanity = { + '1': { + '2': { + 'userMap': { '5': 5, '8': 8 }, + 'xtructs': [{ + 'string_thing': 'Goodbye4', + 'byte_thing': 4, + 'i32_thing': 4, + 'i64_thing': 4 + }, + { + 'string_thing': 'Hello2', + 'byte_thing': 2, + 'i32_thing': 2, + 'i64_thing': 2 + } + ] + }, + '3': { + 'userMap': { '5': 5, '8': 8 }, + 'xtructs': [{ + 'string_thing': 'Goodbye4', + 'byte_thing': 4, + 'i32_thing': 4, + 'i64_thing': 4 + }, + { + 'string_thing': 'Hello2', + 'byte_thing': 2, + 'i32_thing': 2, + 'i64_thing': 2 + } + ] + } + }, + '2': { '6': { 'userMap': null, 'xtructs': null } } + }; + client.testInsanity(new ThriftTest.Insanity(), function(res) { + ok(res, JSON.stringify(res)); + ok(insanity, JSON.stringify(insanity)); + checkRecursively(res, insanity); + QUnit.start(); + }); + }); + + diff --git a/lib/js/test/test-deep-constructor.html b/lib/js/test/test-deep-constructor.html new file mode 100755 index 0000000..5835dc8 --- /dev/null +++ b/lib/js/test/test-deep-constructor.html @@ -0,0 +1,49 @@ + + + + + + Thrift Javascript Bindings: Unit Test + + + + + + + + + + + + + + +

Thrift Javascript Bindings: Deep Constructor Test (JsDeepConstructorTest.thrift)

+

+
+

+
+

+ Valid XHTML 1.0! +

+ + diff --git a/lib/js/test/test-jq.js b/lib/js/test/test-jq.js new file mode 100644 index 0000000..d8649a0 --- /dev/null +++ b/lib/js/test/test-jq.js @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + /* jshint -W100 */ + +/* + * JavaScript test suite for ThriftTest.thrift. These tests + * will run only with jQuery (-gen js:jquery) Apache Thrift + * interfaces. To create client code: + * $ thrift -gen js:jquery ThriftTest.thrift + * + * See also: + * ++ test.js for generic tests + * ++ test-nojq.js for "-gen js" only tests + */ + + +////////////////////////////////// +//jQuery asynchronous tests +jQuery.ajaxSetup({ timeout: 0 }); +$(document).ajaxError(function() { QUnit.start(); }); + +module('jQ Async Manual'); + + test('testI32', function() { + expect(2); + QUnit.stop(); + + var transport = new Thrift.Transport(); + var protocol = new Thrift.Protocol(transport); + var client = new ThriftTest.ThriftTestClient(protocol); + + var jqxhr = jQuery.ajax({ + url: '/service', + data: client.send_testI32(Math.pow(-2, 31)), + type: 'POST', + cache: false, + dataType: 'text', + success: function(res) { + transport.setRecvBuffer(res); + equal(client.recv_testI32(), Math.pow(-2, 31)); + }, + error: function() { ok(false); }, + complete: function() { + ok(true); + QUnit.start(); + } + }); + }); + + test('testI64', function() { + expect(2); + QUnit.stop(); + + var transport = new Thrift.Transport(); + var protocol = new Thrift.Protocol(transport); + var client = new ThriftTest.ThriftTestClient(protocol); + + jQuery.ajax({ + url: '/service', + //This is usually 2^61 but JS cannot represent anything over 2^52 accurately + data: client.send_testI64(Math.pow(-2, 52)), + type: 'POST', + cache: false, + dataType: 'text', + success: function(res) { + transport.setRecvBuffer(res); + //This is usually 2^61 but JS cannot represent anything over 2^52 accurately + equal(client.recv_testI64(), Math.pow(-2, 52)); + }, + error: function() { ok(false); }, + complete: function() { + ok(true); + QUnit.start(); + } + }); + }); + + +module('jQ Async'); + test('I32', function() { + expect(3); + + QUnit.stop(); + client.testI32(Math.pow(2, 30), function(result) { + equal(result, Math.pow(2, 30)); + QUnit.start(); + }); + + QUnit.stop(); + var jqxhr = client.testI32(Math.pow(-2, 31), function(result) { + equal(result, Math.pow(-2, 31)); + }); + + jqxhr.success(function(result) { + equal(result, Math.pow(-2, 31)); + QUnit.start(); + }); + }); + + test('I64', function() { + expect(4); + + QUnit.stop(); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + client.testI64(Math.pow(2, 52), function(result) { + equal(result, Math.pow(2, 52)); + QUnit.start(); + }); + + QUnit.stop(); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + client.testI64(Math.pow(-2, 52), function(result) { + equal(result, Math.pow(-2, 52)); + }) + .error(function(xhr, status, e) { ok(false, e.message); }) + .success(function(result) { + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + equal(result, Math.pow(-2, 52)); + }) + .complete(function() { + ok(true); + QUnit.start(); + }); + }); + + test('Xception', function() { + expect(2); + + QUnit.stop(); + + var dfd = client.testException('Xception', function(result) { + ok(false); + QUnit.start(); + }) + .error(function(xhr, status, e) { + equal(e.errorCode, 1001); + equal(e.message, 'Xception'); + //QUnit.start(); + //Note start is not required here because: + //$(document).ajaxError( function() { QUnit.start(); } ); + }); + }); diff --git a/lib/js/test/test-nojq.html b/lib/js/test/test-nojq.html new file mode 100644 index 0000000..541bffe --- /dev/null +++ b/lib/js/test/test-nojq.html @@ -0,0 +1,52 @@ + + + + + + Thrift Javascript Bindings: Unit Test + + + + + + + + + + + + + + +

Thrift Javascript Bindings: Unit Test (ThriftTest.thrift)

+

+
+

+
+ + + + diff --git a/lib/js/test/test-nojq.js b/lib/js/test/test-nojq.js new file mode 100644 index 0000000..c4f3cf7 --- /dev/null +++ b/lib/js/test/test-nojq.js @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + /* jshint -W100 */ + +/* + * JavaScript test suite for ThriftTest.thrift. These tests + * will run only with normal "-gen js" Apache Thrift interfaces. + * To create client code: + * $ thrift -gen js ThriftTest.thrift + * + * See also: + * ++ test.js for generic tests + * ++ test-jq.js for "-gen js:jquery" only tests + */ + + +////////////////////////////////// +//Async exception tests + +module('NojQ Async'); + + test('Xception', function() { + expect(2); + + QUnit.stop(); + + client.testException('Xception', function(result) { + equal(result.errorCode, 1001); + equal(result.message, 'Xception'); + QUnit.start(); + }); + }); + diff --git a/lib/js/test/test.html b/lib/js/test/test.html new file mode 100755 index 0000000..edec3a3 --- /dev/null +++ b/lib/js/test/test.html @@ -0,0 +1,59 @@ + + + + + + Thrift Javascript Bindings: Unit Test + + + + + + + + + + + + + + + + + + +

Thrift Javascript Bindings: Unit Test (ThriftTest.thrift)

+

+
+

+
+ + + diff --git a/lib/js/test/test.js b/lib/js/test/test.js new file mode 100755 index 0000000..e3b8d51 --- /dev/null +++ b/lib/js/test/test.js @@ -0,0 +1,412 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + /* jshint -W100 */ + +/* + * JavaScript test suite for ThriftTest.thrift. These tests + * will run against Normal (-gen js) and jQuery (-gen js:jquery) + * Apache Thrift interfaces. + * + * Synchronous blocking calls should be identical in both + * Normal and jQuery interfaces. All synchronous tests belong + * here. + * + * Asynchronous success callbacks passed as the last parameter + * of an RPC call should be identical in both Normal and jQuery + * interfaces. Async success tests belong here. + * + * Asynchronous exception processing is different in Normal + * and jQuery interfaces. Such tests belong in the test-nojq.js + * or test-jq.js files respectively. jQuery specific XHR object + * tests also belong in test-jq.js. Do not create any jQuery + * dependencies in this file or in test-nojq.js + * + * To compile client code for this test use: + * $ thrift -gen js ThriftTest.thrift + * -- or -- + * $ thrift -gen js:jquery ThriftTest.thrift + * + * See also: + * ++ test-nojq.js for "-gen js" only tests + * ++ test-jq.js for "-gen js:jquery" only tests + */ + +var transport = new Thrift.Transport('/service'); +var protocol = new Thrift.Protocol(transport); +var client = new ThriftTest.ThriftTestClient(protocol); + +// Work around for old API used by QUnitAdapter of jsTestDriver +if (typeof QUnit.log == 'function') { + // When using real QUnit (fron PhantomJS) log failures to console + QUnit.log(function(details) { + if (!details.result) { + console.log('======== FAIL ========'); + console.log('TestName: ' + details.name); + if (details.message) console.log(details.message); + console.log('Expected: ' + details.expected); + console.log('Actual : ' + details.actual); + console.log('======================'); + } + }); +} + +// all Languages in UTF-8 +var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"; + +function checkRecursively(map1, map2) { + if (typeof map1 !== 'function' && typeof map2 !== 'function') { + if (!map1 || typeof map1 !== 'object') { + equal(map1, map2); + } else { + for (var key in map1) { + checkRecursively(map1[key], map2[key]); + } + } + } +} + +module('Base Types'); + + test('Void', function() { + equal(client.testVoid(), undefined); + }); + test('Binary (String)', function() { + var binary = ''; + for (var v = 255; v >= 0; --v) { + binary += String.fromCharCode(v); + } + equal(client.testBinary(binary), binary); + }); + test('Binary (Uint8Array)', function() { + var binary = ''; + for (var v = 255; v >= 0; --v) { + binary += String.fromCharCode(v); + } + var arr = new Uint8Array(binary.length); + for (var i = 0; i < binary.length; ++i) { + arr[i] = binary[i].charCodeAt(); + } + equal(client.testBinary(arr), binary); + }); + test('String', function() { + equal(client.testString(''), ''); + equal(client.testString(stringTest), stringTest); + + var specialCharacters = 'quote: \" backslash:' + + ' forwardslash-escaped: \/ ' + + ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + + ' now-all-of-them-together: "\\\/\b\n\r\t' + + ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><'; + equal(client.testString(specialCharacters), specialCharacters); + }); + test('Double', function() { + equal(client.testDouble(0), 0); + equal(client.testDouble(-1), -1); + equal(client.testDouble(3.14), 3.14); + equal(client.testDouble(Math.pow(2, 60)), Math.pow(2, 60)); + }); + test('Byte', function() { + equal(client.testByte(0), 0); + equal(client.testByte(0x01), 0x01); + }); + test('I32', function() { + equal(client.testI32(0), 0); + equal(client.testI32(Math.pow(2, 30)), Math.pow(2, 30)); + equal(client.testI32(-Math.pow(2, 30)), -Math.pow(2, 30)); + }); + test('I64', function() { + equal(client.testI64(0), 0); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + equal(client.testI64(Math.pow(2, 52)), Math.pow(2, 52)); + equal(client.testI64(-Math.pow(2, 52)), -Math.pow(2, 52)); + }); + + +module('Structured Types'); + + test('Struct', function() { + var structTestInput = new ThriftTest.Xtruct(); + structTestInput.string_thing = 'worked'; + structTestInput.byte_thing = 0x01; + structTestInput.i32_thing = Math.pow(2, 30); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + structTestInput.i64_thing = Math.pow(2, 52); + + var structTestOutput = client.testStruct(structTestInput); + + equal(structTestOutput.string_thing, structTestInput.string_thing); + equal(structTestOutput.byte_thing, structTestInput.byte_thing); + equal(structTestOutput.i32_thing, structTestInput.i32_thing); + equal(structTestOutput.i64_thing, structTestInput.i64_thing); + + equal(JSON.stringify(structTestOutput), JSON.stringify(structTestInput)); + }); + + test('Nest', function() { + var xtrTestInput = new ThriftTest.Xtruct(); + xtrTestInput.string_thing = 'worked'; + xtrTestInput.byte_thing = 0x01; + xtrTestInput.i32_thing = Math.pow(2, 30); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + xtrTestInput.i64_thing = Math.pow(2, 52); + + var nestTestInput = new ThriftTest.Xtruct2(); + nestTestInput.byte_thing = 0x02; + nestTestInput.struct_thing = xtrTestInput; + nestTestInput.i32_thing = Math.pow(2, 15); + + var nestTestOutput = client.testNest(nestTestInput); + + equal(nestTestOutput.byte_thing, nestTestInput.byte_thing); + equal(nestTestOutput.struct_thing.string_thing, nestTestInput.struct_thing.string_thing); + equal(nestTestOutput.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing); + equal(nestTestOutput.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing); + equal(nestTestOutput.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing); + equal(nestTestOutput.i32_thing, nestTestInput.i32_thing); + + equal(JSON.stringify(nestTestOutput), JSON.stringify(nestTestInput)); + }); + + test('Map', function() { + var mapTestInput = {7: 77, 8: 88, 9: 99}; + + var mapTestOutput = client.testMap(mapTestInput); + + for (var key in mapTestOutput) { + equal(mapTestOutput[key], mapTestInput[key]); + } + }); + + test('StringMap', function() { + var mapTestInput = { + 'a': '123', 'a b': 'with spaces ', 'same': 'same', '0': 'numeric key', + 'longValue': stringTest, stringTest: 'long key' + }; + + var mapTestOutput = client.testStringMap(mapTestInput); + + for (var key in mapTestOutput) { + equal(mapTestOutput[key], mapTestInput[key]); + } + }); + + test('Set', function() { + var setTestInput = [1, 2, 3]; + ok(client.testSet(setTestInput), setTestInput); + }); + + test('List', function() { + var listTestInput = [1, 2, 3]; + ok(client.testList(listTestInput), listTestInput); + }); + + test('Enum', function() { + equal(client.testEnum(ThriftTest.Numberz.ONE), ThriftTest.Numberz.ONE); + }); + + test('TypeDef', function() { + equal(client.testTypedef(69), 69); + }); + + test('Skip', function() { + var structTestInput = new ThriftTest.Xtruct(); + var modifiedClient = new ThriftTest.ThriftTestClient(protocol); + + modifiedClient.recv_testStruct = function() { + var input = modifiedClient.input; + var xtruct3 = new ThriftTest.Xtruct3(); + + input.readMessageBegin(); + input.readStructBegin(); + + // read Xtruct data with Xtruct3 + input.readFieldBegin(); + xtruct3.read(input); + input.readFieldEnd(); + // read Thrift.Type.STOP message + input.readFieldBegin(); + input.readFieldEnd(); + + input.readStructEnd(); + input.readMessageEnd(); + + return xtruct3; + }; + + structTestInput.string_thing = 'worked'; + structTestInput.byte_thing = 0x01; + structTestInput.i32_thing = Math.pow(2, 30); + structTestInput.i64_thing = Math.pow(2, 52); + + var structTestOutput = modifiedClient.testStruct(structTestInput); + + equal(structTestOutput instanceof ThriftTest.Xtruct3, true); + equal(structTestOutput.string_thing, structTestInput.string_thing); + equal(structTestOutput.changed, null); + equal(structTestOutput.i32_thing, structTestInput.i32_thing); + equal(structTestOutput.i64_thing, structTestInput.i64_thing); + }); + + +module('deeper!'); + + test('MapMap', function() { + var mapMapTestExpectedResult = { + '4': {'1': 1, '2': 2, '3': 3, '4': 4}, + '-4': {'-4': -4, '-3': -3, '-2': -2, '-1': -1} + }; + + var mapMapTestOutput = client.testMapMap(1); + + + for (var key in mapMapTestOutput) { + for (var key2 in mapMapTestOutput[key]) { + equal(mapMapTestOutput[key][key2], mapMapTestExpectedResult[key][key2]); + } + } + + checkRecursively(mapMapTestOutput, mapMapTestExpectedResult); + }); + + +module('Exception'); + + test('Xception', function() { + expect(2); + try { + client.testException('Xception'); + }catch (e) { + equal(e.errorCode, 1001); + equal(e.message, 'Xception'); + } + }); + + test('no Exception', 0, function() { + try { + client.testException('no Exception'); + }catch (e) { + ok(false); + } + }); + + test('TException', function() { + //ThriftTest does not list TException as a legal exception so it will + // generate an exception on the server that does not propagate back to + // the client. This test has been modified to equate to "no exception" + expect(1); + try { + client.testException('TException'); + } catch (e) { + //ok(false); + } + ok(true); + }); + + +module('Insanity'); + + var crazy = { + 'userMap': { '5': 5, '8': 8 }, + 'xtructs': [{ + 'string_thing': 'Goodbye4', + 'byte_thing': 4, + 'i32_thing': 4, + 'i64_thing': 4 + }, + { + 'string_thing': 'Hello2', + 'byte_thing': 2, + 'i32_thing': 2, + 'i64_thing': 2 + }] + }; + test('testInsanity', function() { + var insanity = { + '1': { + '2': crazy, + '3': crazy + }, + '2': { '6': { 'userMap': null, 'xtructs': null } } + }; + var res = client.testInsanity(new ThriftTest.Insanity(crazy)); + ok(res, JSON.stringify(res)); + ok(insanity, JSON.stringify(insanity)); + + checkRecursively(res, insanity); + }); + + +////////////////////////////////// +//Run same tests asynchronously + +module('Async'); + + test('Double', function() { + expect(1); + + QUnit.stop(); + client.testDouble(3.14159265, function(result) { + equal(result, 3.14159265); + QUnit.start(); + }); + }); + + test('Byte', function() { + expect(1); + + QUnit.stop(); + client.testByte(0x01, function(result) { + equal(result, 0x01); + QUnit.start(); + }); + }); + + test('I32', function() { + expect(2); + + QUnit.stop(); + client.testI32(Math.pow(2, 30), function(result) { + equal(result, Math.pow(2, 30)); + QUnit.start(); + }); + + QUnit.stop(); + client.testI32(Math.pow(-2, 31), function(result) { + equal(result, Math.pow(-2, 31)); + QUnit.start(); + }); + }); + + test('I64', function() { + expect(2); + + QUnit.stop(); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + client.testI64(Math.pow(2, 52), function(result) { + equal(result, Math.pow(2, 52)); + QUnit.start(); + }); + + QUnit.stop(); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + client.testI64(Math.pow(-2, 52), function(result) { + equal(result, Math.pow(-2, 52)); + QUnit.start(); + }); + }); diff --git a/lib/js/test/test_handler.js b/lib/js/test/test_handler.js new file mode 100644 index 0000000..496b5e0 --- /dev/null +++ b/lib/js/test/test_handler.js @@ -0,0 +1,199 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * 'License'); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//This is the server side Node test handler for the standard +// Apache Thrift test service. + +var ttypes = require('./gen-nodejs/ThriftTest_types'); +var TException = require('../../nodejs/lib/thrift').TException; + +var ThriftTestHandler = exports.ThriftTestHandler = { + testVoid: function(result) { + console.log('testVoid()'); + result(null); + }, + testString: function(thing, result) { + console.log('testString(\'' + thing + '\')'); + result(null, thing); + }, + testByte: function(thing, result) { + console.log('testByte(' + thing + ')'); + result(null, thing); + }, + testI32: function(thing, result) { + console.log('testI32(' + thing + ')'); + result(null, thing); + }, + testI64: function(thing, result) { + console.log('testI64(' + thing + ')'); + result(null, thing); + }, + testDouble: function(thing, result) { + console.log('testDouble(' + thing + ')'); + result(null, thing); + }, + testBinary: function(thing, result) { + console.log('testBinary(\'' + thing + '\')'); + result(null, thing); + }, + testStruct: function(thing, result) { + console.log('testStruct('); + console.log(thing); + console.log(')'); + result(null, thing); + }, + testNest: function(nest, result) { + console.log('testNest('); + console.log(nest); + console.log(')'); + result(null, nest); + }, + testMap: function(thing, result) { + console.log('testMap('); + console.log(thing); + console.log(')'); + result(null, thing); + }, + testStringMap: function(thing, result) { + console.log('testStringMap('); + console.log(thing); + console.log(')'); + result(null, thing); + }, + testSet: function(thing, result) { + console.log('testSet('); + console.log(thing); + console.log(')'); + result(null, thing); + }, + testList: function(thing, result) { + console.log('testList('); + console.log(thing); + console.log(')'); + result(null, thing); + }, + testEnum: function(thing, result) { + console.log('testEnum(' + thing + ')'); + result(null, thing); + }, + testTypedef: function(thing, result) { + console.log('testTypedef(' + thing + ')'); + result(null, thing); + }, + testMapMap: function(hello, result) { + console.log('testMapMap(' + hello + ')'); + + var mapmap = []; + var pos = []; + var neg = []; + for (var i = 1; i < 5; i++) { + pos[i] = i; + neg[-i] = -i; + } + mapmap[4] = pos; + mapmap[-4] = neg; + + result(null, mapmap); + }, + testInsanity: function(argument, result) { + console.log('testInsanity('); + console.log(argument); + console.log(')'); + + var hello = new ttypes.Xtruct(); + hello.string_thing = 'Hello2'; + hello.byte_thing = 2; + hello.i32_thing = 2; + hello.i64_thing = 2; + + var goodbye = new ttypes.Xtruct(); + goodbye.string_thing = 'Goodbye4'; + goodbye.byte_thing = 4; + goodbye.i32_thing = 4; + goodbye.i64_thing = 4; + + var crazy = new ttypes.Insanity(); + crazy.userMap = []; + crazy.userMap[ttypes.Numberz.EIGHT] = 8; + crazy.userMap[ttypes.Numberz.FIVE] = 5; + crazy.xtructs = [goodbye, hello]; + + var first_map = []; + var second_map = []; + + first_map[ttypes.Numberz.TWO] = crazy; + first_map[ttypes.Numberz.THREE] = crazy; + + var looney = new ttypes.Insanity(); + second_map[ttypes.Numberz.SIX] = looney; + + var insane = []; + insane[1] = first_map; + insane[2] = second_map; + + console.log('insane result:'); + console.log(insane); + result(null, insane); + }, + testMulti: function(arg0, arg1, arg2, arg3, arg4, arg5, result) { + console.log('testMulti()'); + + var hello = new ttypes.Xtruct(); + hello.string_thing = 'Hello2'; + hello.byte_thing = arg0; + hello.i32_thing = arg1; + hello.i64_thing = arg2; + result(null, hello); + }, + testException: function(arg, result) { + console.log('testException(' + arg + ')'); + if (arg === 'Xception') { + var x = new ttypes.Xception(); + x.errorCode = 1001; + x.message = arg; + result(x); + } else if (arg === 'TException') { + result(new TException(arg)); + } else { + result(null); + } + }, + testMultiException: function(arg0, arg1, result) { + console.log('testMultiException(' + arg0 + ', ' + arg1 + ')'); + if (arg0 === ('Xception')) { + var x = new ttypes.Xception(); + x.errorCode = 1001; + x.message = 'This is an Xception'; + result(x); + } else if (arg0 === ('Xception2')) { + var x2 = new ttypes.Xception2(); + x2.errorCode = 2002; + x2.struct_thing = new ttypes.Xtruct(); + x2.struct_thing.string_thing = 'This is an Xception2'; + result(x2); + } + + var res = new ttypes.Xtruct(); + res.string_thing = arg1; + result(null, res); + }, + testOneway: function(sleepFor, result) { + console.log('testOneway(' + sleepFor + ') => JavaScript (like Rust) never sleeps!'); + } +}; //ThriftTestSvcHandler diff --git a/lib/js/test/testws.html b/lib/js/test/testws.html new file mode 100644 index 0000000..f99a146 --- /dev/null +++ b/lib/js/test/testws.html @@ -0,0 +1,62 @@ + + + + + + Thrift Javascript Bindings: Unit Test + + + + + + + + + + + + + + + + + +

Thrift Javascript Bindings: Unit Test (ThriftTest.thrift)

+

+
+

+
+ + + diff --git a/lib/json/Makefile.am b/lib/json/Makefile.am new file mode 100644 index 0000000..1051b9b --- /dev/null +++ b/lib/json/Makefile.am @@ -0,0 +1,29 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +SUBDIRS = + +if WITH_JAVA +# Schema validation test depends on java +SUBDIRS += test +endif + +EXTRA_DIST = \ + schema.json \ + test diff --git a/lib/json/Makefile.in b/lib/json/Makefile.in new file mode 100644 index 0000000..08e9f4b --- /dev/null +++ b/lib/json/Makefile.in @@ -0,0 +1,811 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ + +# Schema validation test depends on java +@WITH_JAVA_TRUE@am__append_1 = test +subdir = lib/json +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = test +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = $(am__append_1) +EXTRA_DIST = \ + schema.json \ + test + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/json/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/json/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +style: style-recursive + +style-am: style-local + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am style-am style-local tags tags-am uninstall \ + uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/json/schema.json b/lib/json/schema.json new file mode 100644 index 0000000..d058a7c --- /dev/null +++ b/lib/json/schema.json @@ -0,0 +1,344 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + + "id": "http://thrift.apache.org/schema.json#", + "description": "Schema for Apache Thrift protocol descriptors", + + "definitions": { + "type-id": { + "title": "Any type id (name)", + "enum": [ + "void", + "string", + "bool", + "byte", + "i8", + "i16", + "i32", + "i64", + "double", + "list", + "set", + "map", + "union", + "struct", + "binary" + ] + }, + "base-type": { + "title": "Base type schema", + "type": "object", + "properties": { + "typeId": { + "enum": ["void", "string", "bool", "byte", "i8", "i16", "i32", "i64", "double", "binary" ] + } + }, + "required": [ "typeId" ] + }, + "list-type": { + "title": "List and set schema", + "type": "object", + "properties": { + "typeId": { + "enum": [ "list", "set" ] + }, + "elemTypeId": { "$ref": "#/definitions/type-id" }, + "elemType": { "$ref": "#/definitions/type-desc" } + }, + "required": [ "typeId", "elemTypeId" ] + }, + "map-type": { + "title": "Map schema", + "type": "object", + "properties": { + "typeId": { + "enum": [ "map" ] + }, + "keyTypeId": { "$ref": "#/definitions/type-id" }, + "keyType": { "$ref": "#/definitions/type-desc" }, + "valueTypeId": { "$ref": "#/definitions/type-id" }, + "valueType": { "$ref": "#/definitions/type-desc" } + }, + "required": [ "typeId", "keyTypeId", "valueTypeId" ] + }, + "struct-type": { + "title": "Struct, union and exception schema", + "type": "object", + "properties": { + "typeId": { + "enum": [ "union", "struct", "exception" ] + } + }, + "required": [ "typeId", "class" ] + }, + "type-desc": { + "title": "Type descriptor schema", + "allOf": [ + { + "type": "object", + "properties": { + "typeId": { "type": "string" }, + "class": { "type": "string" } + } + }, + { + "oneOf": + [ + { "$ref": "#/definitions/base-type" }, + { "$ref": "#/definitions/list-type" }, + { "$ref": "#/definitions/map-type" }, + { "$ref": "#/definitions/struct-type" } + ] + } + ] + }, + "name-and-doc": { + "title": "Name and documentation sub-schema", + "type": "object", + "properties": { + "name": { "type": "string" }, + "doc": { "type": "string" } + }, + "required": [ "name" ] + }, + "enum": { + "title": "Thrift 'enum' definition schema", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/name-and-doc" }, + { + "required": [ "members" ], + "properties": { + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "value": { "type": "integer" } + }, + "required": [ "name", "value" ] + } + } + } + } + ] + }, + "typedef": { + "title": "Thrift typedef definition schema", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/name-and-doc" }, + { + "properties": { + "typeId": { "$ref": "#/definitions/type-id" }, + "type": { "$ref": "#/definitions/type-desc" } + }, + "required": [ "typeId" ] + } + ] + }, + "constant": { + "title": "Thrift constant definition schema", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/name-and-doc" }, + { "$ref": "#/definitions/type-desc" }, + { + "properties": { + "value": { + "oneOf": [ + { "type": "string" }, + { "type": "number" }, + { "type": "array" }, + { "type": "object" } + ] + } + }, + "required": [ "value" ] + } + ] + }, + "field": { + "title": "Thrift struct field definition schema", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/name-and-doc" }, + { + "properties": { + "key": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "required": { + "enum": [ "required", "optional", "req_out" ] + }, + "typeId": { "$ref": "#/definitions/type-id" }, + "type": { "$ref": "#/definitions/type-desc" }, + "default": { + "oneOf": [ + { "type": "string" }, + { "type": "number" }, + { "type": "array" }, + { "type": "object" } + ] + } + }, + "required": [ "key", "required" ] + } + ] + }, + "struct": { + "title": "Thrift struct definition schema", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/name-and-doc" }, + { + "properties": { + "isException": { "type": "boolean" }, + "isUnion": { "type": "boolean" }, + "fields": { + "type": "array", + "items": { + "$ref": "#/definitions/field" + } + } + }, + "required": [ "isException", "isUnion", "fields" ] + } + ] + }, + "union": { + "title": "Thrift union definition schema", + "$ref": "#/definitions/struct" + }, + "exception": { + "title": "Thrift exception definition schema", + "type": "object", + "properties": { + "key": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "name": { "type": "string" }, + "typeId": { "enum": [ "exception" ] }, + "type": { "$ref": "#/definitions/struct-type" } + }, + "required": [ "key", "name", "typeId" ] + }, + "function": { + "title": "Thrift service function definition schema", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/name-and-doc" }, + { + "properties": { + "oneway": { + "type": "boolean" + }, + "returnType": { + "$ref": "#/definitions/type-desc" + }, + "arguments": { + "type": "array", + "items": { + "$ref": "#/definitions/field" + } + }, + "exceptions": { + "type": "array", + "items": { "$ref": "#/definitions/exception" } + } + }, + "required": [ "oneway", "arguments", "exceptions" ] + } + ] + }, + "service": { + "title": "Thrift service definition schema", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/name-and-doc" }, + { + "properties": { + "functions": { + "type": "array", + "items": { + "$ref": "#/definitions/function" + } + } + }, + "required": [ "functions" ] + } + ] + }, + "annotations": { + "title": "Map of annotation names to values", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + + "type": "object", + "required": [ + "name", + "enums", + "typedefs", + "structs", + "constants", + "services" + ], + "properties": { + "name": { + "type": "string" + }, + "includes": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "namespaces": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "enums": { + "type": "array", + "items": { + "$ref": "#/definitions/enum" + } + }, + "typedefs": { + "type": "array", + "items": { + "$ref": "#/definitions/typedef" + } + }, + "structs": { + "type": "array", + "items": { + "$ref": "#/definitions/struct" + } + }, + "constants": { + "type": "array", + "items": { + "$ref": "#/definitions/constant" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/definitions/service" + } + } + }, + "additionalProperties": false +} diff --git a/lib/json/test/Makefile b/lib/json/test/Makefile new file mode 100644 index 0000000..a23fdd6 --- /dev/null +++ b/lib/json/test/Makefile @@ -0,0 +1,630 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# lib/json/test/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/thrift +pkgincludedir = $(includedir)/thrift +pkglibdir = $(libdir)/thrift +pkglibexecdir = $(libexecdir)/thrift +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-pc-linux-gnu +host_triplet = x86_64-pc-linux-gnu +subdir = lib/json/test +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_$(V)) +am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15 +ALLOCA = +AMTAR = $${TAR-tar} +AM_DEFAULT_VERBOSITY = 1 +ANT = /usr/bin/ant +ANT_FLAGS = +AR = ar +AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf +AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader +AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15 +AWK = gawk +BISON = bison +BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a +BOOST_CPPFLAGS = -I/usr/include +BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a +BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu +BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu +BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a +BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a +BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a +BUNDLER = /usr/bin/bundle +CABAL = /usr/bin/cabal +CABAL_CONFIGURE_FLAGS = +CARGO = /usr/bin/cargo +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 +CLASSPATH = +CPP = gcc -E +CPPFLAGS = +CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \; +CXX = g++ -std=c++11 +CXXCPP = g++ -E -std=c++11 +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -g -O2 +CYGPATH_W = echo +DART = /usr/lib/dart/bin/dart +DARTPUB = /usr/lib/dart/bin/pub +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +DLLTOOL = false +DMD = dmd +DMD_LIBEVENT_FLAGS = +DMD_OF_DIRSEP = / +DMD_OPENSSL_FLAGS = +DOTNETCORE = /usr/bin/dotnet +DOTNETCORE_VERSION = 2.0.3 +DSYMUTIL = +DUMPBIN = +D_EVENT_LIB_NAME = libthriftd-event.a +D_IMPORT_PREFIX = ${prefix}/include/d2 +D_LIB_NAME = libthriftd.a +D_SSL_LIB_NAME = libthriftd-ssl.a +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +ENABLE_COVERAGE = 2 +ERL = /usr/bin/erl +ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib +ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0 +ERLANG_LIB_DIR = /usr/lib/erlang/lib +ERLC = /usr/bin/erlc +ERLCFLAGS = +EXEEXT = +FGREP = /bin/grep -F +GCOV_CFLAGS = +GCOV_CXXFLAGS = +GCOV_LDFLAGS = +GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GLIB_LIBS = -lglib-2.0 +GO = /usr/bin/go +GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0 +GREP = /bin/grep +HAVE_CXX11 = 1 +HAXE = /usr/bin/haxe +HAXE_VERSION = 3.2.1 +INSTALL = /usr/bin/install -c +INSTALLDIRS = vendor +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +JAVA_PREFIX = /usr/local/lib +LD = /usr/bin/ld -m elf_x86_64 +LDFLAGS = +LEX = flex +LEXLIB = -lfl +LEX_OUTPUT_ROOT = lex.yy +LIBEVENT_CPPFLAGS = +LIBEVENT_LDFLAGS = +LIBEVENT_LIBS = -levent +LIBOBJS = +LIBS = -lrt -lpthread +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LIPO = +LN_S = ln -s +LTLIBOBJS = +LT_SYS_LIBRARY_PATH = +LUA = /usr/bin/lua5.3 +LUA_EXEC_PREFIX = ${exec_prefix} +LUA_INCLUDE = -I/usr/include/lua5.3 +LUA_LIB = -llua5.3 -ldl +LUA_PLATFORM = unknown +LUA_PREFIX = ${prefix} +LUA_SHORT_VERSION = 53 +LUA_VERSION = 5.3 +MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo +MANIFEST_TOOL = : +MAYBE_CPP = cpp +MAYBE_CSHARP = csharp +MAYBE_C_GLIB = c_glib +MAYBE_D = +MAYBE_DART = dart +MAYBE_DOTNETCORE = netcore +MAYBE_ERLANG = erl +MAYBE_GO = go +MAYBE_HASKELL = hs +MAYBE_JAVA = java +MAYBE_LUA = lua +MAYBE_NODEJS = nodejs +MAYBE_PERL = perl +MAYBE_PHP = php +MAYBE_PY3 = py3 +MAYBE_PYTHON = py +MAYBE_RS = rs +MAYBE_RUBY = rb +MCS = /usr/bin/mcs +MKDIR_P = /bin/mkdir -p +MONO_CFLAGS = +MONO_LIBS = +NM = /usr/bin/nm -B +NMEDIT = +NODEJS = /usr/bin/nodejs +NPM = /usr/bin/npm +OBJDUMP = objdump +OBJEXT = o +OPENSSL_INCLUDES = +OPENSSL_LDFLAGS = +OPENSSL_LIBS = -lssl -lcrypto +OTOOL = +OTOOL64 = +PACKAGE = thrift +PACKAGE_BUGREPORT = +PACKAGE_NAME = thrift +PACKAGE_STRING = thrift 0.11.0 +PACKAGE_TARNAME = thrift +PACKAGE_URL = +PACKAGE_VERSION = 0.11.0 +PATH_SEPARATOR = : +PERL = /usr/bin/perl +PERL_PREFIX = /usr/local +PHP = /usr/bin/php +PHPUNIT = /usr/bin/phpunit +PHP_CONFIG = /usr/bin/php-config +PHP_CONFIG_PREFIX = /etc/php.d +PHP_PREFIX = /usr/lib/php +PKG_CONFIG = /usr/bin/pkg-config +PKG_CONFIG_LIBDIR = +PKG_CONFIG_PATH = +PYTHON = /usr/bin/python +PYTHON3 = /usr/bin/python3 +PYTHON_EXEC_PREFIX = ${exec_prefix} +PYTHON_PLATFORM = linux2 +PYTHON_PREFIX = ${prefix} +PYTHON_VERSION = 2.7 +PY_PREFIX = /usr +QT5_CFLAGS = +QT5_LIBS = +QT5_MOC = +QT_CFLAGS = +QT_LIBS = +QT_MOC = +RANLIB = ranlib +REBAR = /usr/bin/rebar +RUBY = /usr/bin/ruby +RUBY_PREFIX = +RUNHASKELL = /usr/bin/runhaskell +RUSTC = /usr/bin/rustc +SED = /bin/sed +SET_MAKE = +SHELL = /bin/bash +STRIP = strip +THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift +TRIAL = /usr/bin/trial +VERSION = 0.11.0 +YACC = bison -y +YFLAGS = +ZLIB_CPPFLAGS = +ZLIB_LDFLAGS = +ZLIB_LIBS = -lz +abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/lib/json/test +abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/lib/json/test +abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift +abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift +ac_ct_AR = ar +ac_ct_CC = gcc +ac_ct_CXX = g++ +ac_ct_DUMPBIN = +am__include = include +am__leading_dot = . +am__quote = +am__tar = tar --format=ustar -chf - "$$tardir" +am__untar = tar -xf - +bindir = ${exec_prefix}/bin +build = x86_64-pc-linux-gnu +build_alias = +build_cpu = x86_64 +build_os = linux-gnu +build_vendor = pc +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +golang_version = 1.6.2 +have_prog_bison = yes +host = x86_64-pc-linux-gnu +host_alias = +host_cpu = x86_64 +host_os = linux-gnu +host_vendor = pc +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +luadir = ${prefix}/share/lua/5.3 +luaexecdir = ${exec_prefix}/lib/lua/5.3 +mandir = ${datarootdir}/man +mkdir_p = $(MKDIR_P) +oldincludedir = /usr/include +pdfdir = ${docdir} +pkgluadir = ${luadir}/thrift +pkgluaexecdir = ${luaexecdir}/thrift +pkgpyexecdir = ${pyexecdir}/thrift +pkgpythondir = ${pythondir}/thrift +prefix = /usr/local +program_transform_name = s,x,x, +psdir = ${docdir} +pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages +pythondir = ${prefix}/lib/python2.7/dist-packages +runstatedir = ${localstatedir}/run +rustc_version = rustc 1.17.0 +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +subdirs = lib/php/src/ext/thrift_protocol +sysconfdir = ${prefix}/etc +target_alias = +top_build_prefix = ../../../ +top_builddir = ../../.. +top_srcdir = ../../.. +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/json/test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/json/test/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +check: + $(ANT) $(ANT_FLAGS) test + +# Make sure this doesn't fail if ant is not configured. +clean-local: + ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ + $$ANT $(ANT_FLAGS) clean + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/json/test/Makefile.am b/lib/json/test/Makefile.am new file mode 100644 index 0000000..bb87a52 --- /dev/null +++ b/lib/json/test/Makefile.am @@ -0,0 +1,26 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +check: + $(ANT) $(ANT_FLAGS) test + +# Make sure this doesn't fail if ant is not configured. +clean-local: + ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ + $$ANT $(ANT_FLAGS) clean diff --git a/lib/json/test/Makefile.in b/lib/json/test/Makefile.in new file mode 100644 index 0000000..4a00a08 --- /dev/null +++ b/lib/json/test/Makefile.in @@ -0,0 +1,630 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/json/test +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/json/test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/json/test/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +check: + $(ANT) $(ANT_FLAGS) test + +# Make sure this doesn't fail if ant is not configured. +clean-local: + ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ + $$ANT $(ANT_FLAGS) clean + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/json/test/build.properties b/lib/json/test/build.properties new file mode 100644 index 0000000..075f640 --- /dev/null +++ b/lib/json/test/build.properties @@ -0,0 +1,10 @@ +# Jar versions +mvn.ant.task.version=2.1.3 + +# Dependency versions +json-schema-validator.version=2.2.6 + +# Maven dependency download locations +mvn.repo=http://repo1.maven.org/maven2 +mvn.ant.task.url=${mvn.repo}/org/apache/maven/maven-ant-tasks/${mvn.ant.task.version} +mvn.ant.task.jar=maven-ant-tasks-${mvn.ant.task.version}.jar diff --git a/lib/json/test/build.xml b/lib/json/test/build.xml new file mode 100644 index 0000000..956a238 --- /dev/null +++ b/lib/json/test/build.xml @@ -0,0 +1,144 @@ + + + + JSON Schema Validation Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Thrift compiler is missing ! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/lua/Makefile.am b/lib/lua/Makefile.am new file mode 100644 index 0000000..3dfc27c --- /dev/null +++ b/lib/lua/Makefile.am @@ -0,0 +1,73 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +AUTOMAKE_OPTIONS = subdir-objects + +SUBDIRS = . + +lib_LTLIBRARIES = \ + libluasocket.la \ + libluabpack.la \ + libluabitwise.la \ + liblualongnumber.la + +libluasocket_la_SOURCES = \ + src/luasocket.c \ + src/usocket.c + +nobase_include_HEADERS = src/socket.h + +libluasocket_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE +libluasocket_la_LDFLAGS = $(AM_LDFLAGS) +libluasocket_la_LIBADD = $(LUA_LIB) -lm + +libluabpack_la_SOURCES = src/luabpack.c + +libluabpack_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE +libluabpack_la_LDFLAGS = $(AM_LDFLAGS) +libluabpack_la_LIBADD = liblualongnumber.la $(LUA_LIB) -lm + +libluabitwise_la_SOURCES = src/luabitwise.c + +libluabitwise_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE +libluabitwise_la_LDFLAGS = $(AM_LDFLAGS) +libluabitwise_la_LIBADD = $(LUA_LIB) -lm + +liblualongnumber_la_SOURCES = \ + src/lualongnumber.c \ + src/longnumberutils.c + +liblualongnumber_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE +liblualongnumber_la_LDFLAGS = $(AM_LDFLAGS) +liblualongnumber_la_LIBADD = $(LUA_LIB) -lm + +EXTRA_DIST = \ + coding_standards.md \ + TBinaryProtocol.lua \ + TBufferedTransport.lua \ + TCompactProtocol.lua \ + TFramedTransport.lua \ + Thrift.lua \ + THttpTransport.lua \ + TJsonProtocol.lua \ + TMemoryBuffer.lua \ + TProtocol.lua \ + TServer.lua \ + TSocket.lua \ + TTransport.lua diff --git a/lib/lua/Makefile.in b/lib/lua/Makefile.in new file mode 100644 index 0000000..76e68ba --- /dev/null +++ b/lib/lua/Makefile.in @@ -0,0 +1,1129 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/lua +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(nobase_include_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libluabitwise_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__dirstamp = $(am__leading_dot)dirstamp +am_libluabitwise_la_OBJECTS = src/libluabitwise_la-luabitwise.lo +libluabitwise_la_OBJECTS = $(am_libluabitwise_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libluabitwise_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libluabitwise_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +libluabpack_la_DEPENDENCIES = liblualongnumber.la \ + $(am__DEPENDENCIES_1) +am_libluabpack_la_OBJECTS = src/libluabpack_la-luabpack.lo +libluabpack_la_OBJECTS = $(am_libluabpack_la_OBJECTS) +libluabpack_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libluabpack_la_LDFLAGS) $(LDFLAGS) -o \ + $@ +liblualongnumber_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_liblualongnumber_la_OBJECTS = \ + src/liblualongnumber_la-lualongnumber.lo \ + src/liblualongnumber_la-longnumberutils.lo +liblualongnumber_la_OBJECTS = $(am_liblualongnumber_la_OBJECTS) +liblualongnumber_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(liblualongnumber_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +libluasocket_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_libluasocket_la_OBJECTS = src/libluasocket_la-luasocket.lo \ + src/libluasocket_la-usocket.lo +libluasocket_la_OBJECTS = $(am_libluasocket_la_OBJECTS) +libluasocket_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libluasocket_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/lib/cpp/src/thrift -I$(top_builddir)/lib/c_glib/src/thrift +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libluabitwise_la_SOURCES) $(libluabpack_la_SOURCES) \ + $(liblualongnumber_la_SOURCES) $(libluasocket_la_SOURCES) +DIST_SOURCES = $(libluabitwise_la_SOURCES) $(libluabpack_la_SOURCES) \ + $(liblualongnumber_la_SOURCES) $(libluasocket_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(nobase_include_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = subdir-objects +SUBDIRS = . +lib_LTLIBRARIES = \ + libluasocket.la \ + libluabpack.la \ + libluabitwise.la \ + liblualongnumber.la + +libluasocket_la_SOURCES = \ + src/luasocket.c \ + src/usocket.c + +nobase_include_HEADERS = src/socket.h +libluasocket_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE +libluasocket_la_LDFLAGS = $(AM_LDFLAGS) +libluasocket_la_LIBADD = $(LUA_LIB) -lm +libluabpack_la_SOURCES = src/luabpack.c +libluabpack_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE +libluabpack_la_LDFLAGS = $(AM_LDFLAGS) +libluabpack_la_LIBADD = liblualongnumber.la $(LUA_LIB) -lm +libluabitwise_la_SOURCES = src/luabitwise.c +libluabitwise_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE +libluabitwise_la_LDFLAGS = $(AM_LDFLAGS) +libluabitwise_la_LIBADD = $(LUA_LIB) -lm +liblualongnumber_la_SOURCES = \ + src/lualongnumber.c \ + src/longnumberutils.c + +liblualongnumber_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE +liblualongnumber_la_LDFLAGS = $(AM_LDFLAGS) +liblualongnumber_la_LIBADD = $(LUA_LIB) -lm +EXTRA_DIST = \ + coding_standards.md \ + TBinaryProtocol.lua \ + TBufferedTransport.lua \ + TCompactProtocol.lua \ + TFramedTransport.lua \ + Thrift.lua \ + THttpTransport.lua \ + TJsonProtocol.lua \ + TMemoryBuffer.lua \ + TProtocol.lua \ + TServer.lua \ + TSocket.lua \ + TTransport.lua + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/lua/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/lua/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } +src/$(am__dirstamp): + @$(MKDIR_P) src + @: > src/$(am__dirstamp) +src/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/$(DEPDIR) + @: > src/$(DEPDIR)/$(am__dirstamp) +src/libluabitwise_la-luabitwise.lo: src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +libluabitwise.la: $(libluabitwise_la_OBJECTS) $(libluabitwise_la_DEPENDENCIES) $(EXTRA_libluabitwise_la_DEPENDENCIES) + $(AM_V_CCLD)$(libluabitwise_la_LINK) -rpath $(libdir) $(libluabitwise_la_OBJECTS) $(libluabitwise_la_LIBADD) $(LIBS) +src/libluabpack_la-luabpack.lo: src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +libluabpack.la: $(libluabpack_la_OBJECTS) $(libluabpack_la_DEPENDENCIES) $(EXTRA_libluabpack_la_DEPENDENCIES) + $(AM_V_CCLD)$(libluabpack_la_LINK) -rpath $(libdir) $(libluabpack_la_OBJECTS) $(libluabpack_la_LIBADD) $(LIBS) +src/liblualongnumber_la-lualongnumber.lo: src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/liblualongnumber_la-longnumberutils.lo: src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +liblualongnumber.la: $(liblualongnumber_la_OBJECTS) $(liblualongnumber_la_DEPENDENCIES) $(EXTRA_liblualongnumber_la_DEPENDENCIES) + $(AM_V_CCLD)$(liblualongnumber_la_LINK) -rpath $(libdir) $(liblualongnumber_la_OBJECTS) $(liblualongnumber_la_LIBADD) $(LIBS) +src/libluasocket_la-luasocket.lo: src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/libluasocket_la-usocket.lo: src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +libluasocket.la: $(libluasocket_la_OBJECTS) $(libluasocket_la_DEPENDENCIES) $(EXTRA_libluasocket_la_DEPENDENCIES) + $(AM_V_CCLD)$(libluasocket_la_LINK) -rpath $(libdir) $(libluasocket_la_OBJECTS) $(libluasocket_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f src/*.$(OBJEXT) + -rm -f src/*.lo + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/libluabitwise_la-luabitwise.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/libluabpack_la-luabpack.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/liblualongnumber_la-longnumberutils.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/liblualongnumber_la-lualongnumber.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/libluasocket_la-luasocket.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/libluasocket_la-usocket.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +src/libluabitwise_la-luabitwise.lo: src/luabitwise.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluabitwise_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/libluabitwise_la-luabitwise.lo -MD -MP -MF src/$(DEPDIR)/libluabitwise_la-luabitwise.Tpo -c -o src/libluabitwise_la-luabitwise.lo `test -f 'src/luabitwise.c' || echo '$(srcdir)/'`src/luabitwise.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/libluabitwise_la-luabitwise.Tpo src/$(DEPDIR)/libluabitwise_la-luabitwise.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/luabitwise.c' object='src/libluabitwise_la-luabitwise.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluabitwise_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/libluabitwise_la-luabitwise.lo `test -f 'src/luabitwise.c' || echo '$(srcdir)/'`src/luabitwise.c + +src/libluabpack_la-luabpack.lo: src/luabpack.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluabpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/libluabpack_la-luabpack.lo -MD -MP -MF src/$(DEPDIR)/libluabpack_la-luabpack.Tpo -c -o src/libluabpack_la-luabpack.lo `test -f 'src/luabpack.c' || echo '$(srcdir)/'`src/luabpack.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/libluabpack_la-luabpack.Tpo src/$(DEPDIR)/libluabpack_la-luabpack.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/luabpack.c' object='src/libluabpack_la-luabpack.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluabpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/libluabpack_la-luabpack.lo `test -f 'src/luabpack.c' || echo '$(srcdir)/'`src/luabpack.c + +src/liblualongnumber_la-lualongnumber.lo: src/lualongnumber.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblualongnumber_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/liblualongnumber_la-lualongnumber.lo -MD -MP -MF src/$(DEPDIR)/liblualongnumber_la-lualongnumber.Tpo -c -o src/liblualongnumber_la-lualongnumber.lo `test -f 'src/lualongnumber.c' || echo '$(srcdir)/'`src/lualongnumber.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/liblualongnumber_la-lualongnumber.Tpo src/$(DEPDIR)/liblualongnumber_la-lualongnumber.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/lualongnumber.c' object='src/liblualongnumber_la-lualongnumber.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblualongnumber_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/liblualongnumber_la-lualongnumber.lo `test -f 'src/lualongnumber.c' || echo '$(srcdir)/'`src/lualongnumber.c + +src/liblualongnumber_la-longnumberutils.lo: src/longnumberutils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblualongnumber_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/liblualongnumber_la-longnumberutils.lo -MD -MP -MF src/$(DEPDIR)/liblualongnumber_la-longnumberutils.Tpo -c -o src/liblualongnumber_la-longnumberutils.lo `test -f 'src/longnumberutils.c' || echo '$(srcdir)/'`src/longnumberutils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/liblualongnumber_la-longnumberutils.Tpo src/$(DEPDIR)/liblualongnumber_la-longnumberutils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/longnumberutils.c' object='src/liblualongnumber_la-longnumberutils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblualongnumber_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/liblualongnumber_la-longnumberutils.lo `test -f 'src/longnumberutils.c' || echo '$(srcdir)/'`src/longnumberutils.c + +src/libluasocket_la-luasocket.lo: src/luasocket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluasocket_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/libluasocket_la-luasocket.lo -MD -MP -MF src/$(DEPDIR)/libluasocket_la-luasocket.Tpo -c -o src/libluasocket_la-luasocket.lo `test -f 'src/luasocket.c' || echo '$(srcdir)/'`src/luasocket.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/libluasocket_la-luasocket.Tpo src/$(DEPDIR)/libluasocket_la-luasocket.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/luasocket.c' object='src/libluasocket_la-luasocket.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluasocket_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/libluasocket_la-luasocket.lo `test -f 'src/luasocket.c' || echo '$(srcdir)/'`src/luasocket.c + +src/libluasocket_la-usocket.lo: src/usocket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluasocket_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/libluasocket_la-usocket.lo -MD -MP -MF src/$(DEPDIR)/libluasocket_la-usocket.Tpo -c -o src/libluasocket_la-usocket.lo `test -f 'src/usocket.c' || echo '$(srcdir)/'`src/usocket.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/libluasocket_la-usocket.Tpo src/$(DEPDIR)/libluasocket_la-usocket.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/usocket.c' object='src/libluasocket_la-usocket.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libluasocket_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/libluasocket_la-usocket.lo `test -f 'src/usocket.c' || echo '$(srcdir)/'`src/usocket.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf src/.libs src/_libs +install-nobase_includeHEADERS: $(nobase_include_HEADERS) + @$(NORMAL_INSTALL) + @list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ + fi; \ + $(am__nobase_list) | while read dir files; do \ + xfiles=; for file in $$files; do \ + if test -f "$$file"; then xfiles="$$xfiles $$file"; \ + else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ + test -z "$$xfiles" || { \ + test "x$$dir" = x. || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(includedir)/$$dir'"; \ + $(MKDIR_P) "$(DESTDIR)$(includedir)/$$dir"; }; \ + echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(includedir)/$$dir'"; \ + $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(includedir)/$$dir" || exit $$?; }; \ + done + +uninstall-nobase_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \ + $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ + dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f src/$(DEPDIR)/$(am__dirstamp) + -rm -f src/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf src/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-nobase_includeHEADERS + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf src/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +style: style-recursive + +style-am: style-local + +uninstall-am: uninstall-libLTLIBRARIES uninstall-nobase_includeHEADERS + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libLTLIBRARIES \ + clean-libtool cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man \ + install-nobase_includeHEADERS install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags tags-am uninstall uninstall-am \ + uninstall-libLTLIBRARIES uninstall-nobase_includeHEADERS + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/lua/TBinaryProtocol.lua b/lib/lua/TBinaryProtocol.lua new file mode 100644 index 0000000..4b8e98a --- /dev/null +++ b/lib/lua/TBinaryProtocol.lua @@ -0,0 +1,264 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +require 'TProtocol' +require 'libluabpack' +require 'libluabitwise' + +TBinaryProtocol = __TObject.new(TProtocolBase, { + __type = 'TBinaryProtocol', + VERSION_MASK = -65536, -- 0xffff0000 + VERSION_1 = -2147418112, -- 0x80010000 + TYPE_MASK = 0x000000ff, + strictRead = false, + strictWrite = true +}) + +function TBinaryProtocol:writeMessageBegin(name, ttype, seqid) + if self.strictWrite then + self:writeI32(libluabitwise.bor(TBinaryProtocol.VERSION_1, ttype)) + self:writeString(name) + self:writeI32(seqid) + else + self:writeString(name) + self:writeByte(ttype) + self:writeI32(seqid) + end +end + +function TBinaryProtocol:writeMessageEnd() +end + +function TBinaryProtocol:writeStructBegin(name) +end + +function TBinaryProtocol:writeStructEnd() +end + +function TBinaryProtocol:writeFieldBegin(name, ttype, id) + self:writeByte(ttype) + self:writeI16(id) +end + +function TBinaryProtocol:writeFieldEnd() +end + +function TBinaryProtocol:writeFieldStop() + self:writeByte(TType.STOP); +end + +function TBinaryProtocol:writeMapBegin(ktype, vtype, size) + self:writeByte(ktype) + self:writeByte(vtype) + self:writeI32(size) +end + +function TBinaryProtocol:writeMapEnd() +end + +function TBinaryProtocol:writeListBegin(etype, size) + self:writeByte(etype) + self:writeI32(size) +end + +function TBinaryProtocol:writeListEnd() +end + +function TBinaryProtocol:writeSetBegin(etype, size) + self:writeByte(etype) + self:writeI32(size) +end + +function TBinaryProtocol:writeSetEnd() +end + +function TBinaryProtocol:writeBool(bool) + if bool then + self:writeByte(1) + else + self:writeByte(0) + end +end + +function TBinaryProtocol:writeByte(byte) + local buff = libluabpack.bpack('c', byte) + self.trans:write(buff) +end + +function TBinaryProtocol:writeI16(i16) + local buff = libluabpack.bpack('s', i16) + self.trans:write(buff) +end + +function TBinaryProtocol:writeI32(i32) + local buff = libluabpack.bpack('i', i32) + self.trans:write(buff) +end + +function TBinaryProtocol:writeI64(i64) + local buff = libluabpack.bpack('l', i64) + self.trans:write(buff) +end + +function TBinaryProtocol:writeDouble(dub) + local buff = libluabpack.bpack('d', dub) + self.trans:write(buff) +end + +function TBinaryProtocol:writeString(str) + -- Should be utf-8 + self:writeI32(string.len(str)) + self.trans:write(str) +end + +function TBinaryProtocol:readMessageBegin() + local sz, ttype, name, seqid = self:readI32() + if sz < 0 then + local version = libluabitwise.band(sz, TBinaryProtocol.VERSION_MASK) + if version ~= TBinaryProtocol.VERSION_1 then + terror(TProtocolException:new{ + message = 'Bad version in readMessageBegin: ' .. sz + }) + end + ttype = libluabitwise.band(sz, TBinaryProtocol.TYPE_MASK) + name = self:readString() + seqid = self:readI32() + else + if self.strictRead then + terror(TProtocolException:new{message = 'No protocol version header'}) + end + name = self.trans:readAll(sz) + ttype = self:readByte() + seqid = self:readI32() + end + return name, ttype, seqid +end + +function TBinaryProtocol:readMessageEnd() +end + +function TBinaryProtocol:readStructBegin() + return nil +end + +function TBinaryProtocol:readStructEnd() +end + +function TBinaryProtocol:readFieldBegin() + local ttype = self:readByte() + if ttype == TType.STOP then + return nil, ttype, 0 + end + local id = self:readI16() + return nil, ttype, id +end + +function TBinaryProtocol:readFieldEnd() +end + +function TBinaryProtocol:readMapBegin() + local ktype = self:readByte() + local vtype = self:readByte() + local size = self:readI32() + return ktype, vtype, size +end + +function TBinaryProtocol:readMapEnd() +end + +function TBinaryProtocol:readListBegin() + local etype = self:readByte() + local size = self:readI32() + return etype, size +end + +function TBinaryProtocol:readListEnd() +end + +function TBinaryProtocol:readSetBegin() + local etype = self:readByte() + local size = self:readI32() + return etype, size +end + +function TBinaryProtocol:readSetEnd() +end + +function TBinaryProtocol:readBool() + local byte = self:readByte() + if byte == 0 then + return false + end + return true +end + +function TBinaryProtocol:readByte() + local buff = self.trans:readAll(1) + local val = libluabpack.bunpack('c', buff) + return val +end + +function TBinaryProtocol:readI16() + local buff = self.trans:readAll(2) + local val = libluabpack.bunpack('s', buff) + return val +end + +function TBinaryProtocol:readI32() + local buff = self.trans:readAll(4) + local val = libluabpack.bunpack('i', buff) + return val +end + +function TBinaryProtocol:readI64() + local buff = self.trans:readAll(8) + local val = libluabpack.bunpack('l', buff) + return val +end + +function TBinaryProtocol:readDouble() + local buff = self.trans:readAll(8) + local val = libluabpack.bunpack('d', buff) + return val +end + +function TBinaryProtocol:readString() + local len = self:readI32() + local str = self.trans:readAll(len) + return str +end + +TBinaryProtocolFactory = TProtocolFactory:new{ + __type = 'TBinaryProtocolFactory', + strictRead = false +} + +function TBinaryProtocolFactory:getProtocol(trans) + -- TODO Enforce that this must be a transport class (ie not a bool) + if not trans then + terror(TProtocolException:new{ + message = 'Must supply a transport to ' .. ttype(self) + }) + end + return TBinaryProtocol:new{ + trans = trans, + strictRead = self.strictRead, + strictWrite = true + } +end diff --git a/lib/lua/TBufferedTransport.lua b/lib/lua/TBufferedTransport.lua new file mode 100644 index 0000000..45ef4b1 --- /dev/null +++ b/lib/lua/TBufferedTransport.lua @@ -0,0 +1,91 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +require 'TTransport' + +TBufferedTransport = TTransportBase:new{ + __type = 'TBufferedTransport', + rBufSize = 2048, + wBufSize = 2048, + wBuf = '', + rBuf = '' +} + +function TBufferedTransport:new(obj) + if ttype(obj) ~= 'table' then + error(ttype(self) .. 'must be initialized with a table') + end + + -- Ensure a transport is provided + if not obj.trans then + error('You must provide ' .. ttype(self) .. ' with a trans') + end + + return TTransportBase.new(self, obj) +end + +function TBufferedTransport:isOpen() + return self.trans:isOpen() +end + +function TBufferedTransport:open() + return self.trans:open() +end + +function TBufferedTransport:close() + return self.trans:close() +end + +function TBufferedTransport:read(len) + return self.trans:read(len) +end + +function TBufferedTransport:readAll(len) + return self.trans:readAll(len) +end + +function TBufferedTransport:write(buf) + self.wBuf = self.wBuf .. buf + if string.len(self.wBuf) >= self.wBufSize then + self.trans:write(self.wBuf) + self.wBuf = '' + end +end + +function TBufferedTransport:flush() + if string.len(self.wBuf) > 0 then + self.trans:write(self.wBuf) + self.wBuf = '' + end +end + +TBufferedTransportFactory = TTransportFactoryBase:new{ + __type = 'TBufferedTransportFactory' +} + +function TBufferedTransportFactory:getTransport(trans) + if not trans then + terror(TTransportException:new{ + message = 'Must supply a transport to ' .. ttype(self) + }) + end + return TBufferedTransport:new{ + trans = trans + } +end diff --git a/lib/lua/TCompactProtocol.lua b/lib/lua/TCompactProtocol.lua new file mode 100644 index 0000000..877595a --- /dev/null +++ b/lib/lua/TCompactProtocol.lua @@ -0,0 +1,457 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +require 'TProtocol' +require 'libluabpack' +require 'libluabitwise' +require 'liblualongnumber' + +TCompactProtocol = __TObject.new(TProtocolBase, { + __type = 'TCompactProtocol', + COMPACT_PROTOCOL_ID = 0x82, + COMPACT_VERSION = 1, + COMPACT_VERSION_MASK = 0x1f, + COMPACT_TYPE_MASK = 0xE0, + COMPACT_TYPE_BITS = 0x07, + COMPACT_TYPE_SHIFT_AMOUNT = 5, + + -- Used to keep track of the last field for the current and previous structs, + -- so we can do the delta stuff. + lastField = {}, + lastFieldId = 0, + lastFieldIndex = 1, + + -- If we encounter a boolean field begin, save the TField here so it can + -- have the value incorporated. + booleanFieldName = "", + booleanFieldId = 0, + booleanFieldPending = false, + + -- If we read a field header, and it's a boolean field, save the boolean + -- value here so that readBool can use it. + boolValue = false, + boolValueIsNotNull = false, +}) + +TCompactType = { + COMPACT_BOOLEAN_TRUE = 0x01, + COMPACT_BOOLEAN_FALSE = 0x02, + COMPACT_BYTE = 0x03, + COMPACT_I16 = 0x04, + COMPACT_I32 = 0x05, + COMPACT_I64 = 0x06, + COMPACT_DOUBLE = 0x07, + COMPACT_BINARY = 0x08, + COMPACT_LIST = 0x09, + COMPACT_SET = 0x0A, + COMPACT_MAP = 0x0B, + COMPACT_STRUCT = 0x0C +} + +TTypeToCompactType = {} +TTypeToCompactType[TType.STOP] = TType.STOP +TTypeToCompactType[TType.BOOL] = TCompactType.COMPACT_BOOLEAN_TRUE +TTypeToCompactType[TType.BYTE] = TCompactType.COMPACT_BYTE +TTypeToCompactType[TType.I16] = TCompactType.COMPACT_I16 +TTypeToCompactType[TType.I32] = TCompactType.COMPACT_I32 +TTypeToCompactType[TType.I64] = TCompactType.COMPACT_I64 +TTypeToCompactType[TType.DOUBLE] = TCompactType.COMPACT_DOUBLE +TTypeToCompactType[TType.STRING] = TCompactType.COMPACT_BINARY +TTypeToCompactType[TType.LIST] = TCompactType.COMPACT_LIST +TTypeToCompactType[TType.SET] = TCompactType.COMPACT_SET +TTypeToCompactType[TType.MAP] = TCompactType.COMPACT_MAP +TTypeToCompactType[TType.STRUCT] = TCompactType.COMPACT_STRUCT + +CompactTypeToTType = {} +CompactTypeToTType[TType.STOP] = TType.STOP +CompactTypeToTType[TCompactType.COMPACT_BOOLEAN_TRUE] = TType.BOOL +CompactTypeToTType[TCompactType.COMPACT_BOOLEAN_FALSE] = TType.BOOL +CompactTypeToTType[TCompactType.COMPACT_BYTE] = TType.BYTE +CompactTypeToTType[TCompactType.COMPACT_I16] = TType.I16 +CompactTypeToTType[TCompactType.COMPACT_I32] = TType.I32 +CompactTypeToTType[TCompactType.COMPACT_I64] = TType.I64 +CompactTypeToTType[TCompactType.COMPACT_DOUBLE] = TType.DOUBLE +CompactTypeToTType[TCompactType.COMPACT_BINARY] = TType.STRING +CompactTypeToTType[TCompactType.COMPACT_LIST] = TType.LIST +CompactTypeToTType[TCompactType.COMPACT_SET] = TType.SET +CompactTypeToTType[TCompactType.COMPACT_MAP] = TType.MAP +CompactTypeToTType[TCompactType.COMPACT_STRUCT] = TType.STRUCT + +function TCompactProtocol:resetLastField() + self.lastField = {} + self.lastFieldId = 0 + self.lastFieldIndex = 1 +end + +function TCompactProtocol:packCompactType(ktype, vtype) + return libluabitwise.bor(libluabitwise.shiftl(ktype, 4), vtype) +end + +function TCompactProtocol:writeMessageBegin(name, ttype, seqid) + self:writeByte(TCompactProtocol.COMPACT_PROTOCOL_ID) + self:writeByte(libluabpack.packMesgType(TCompactProtocol.COMPACT_VERSION, + TCompactProtocol.COMPACT_VERSION_MASK,ttype, + TCompactProtocol.COMPACT_TYPE_SHIFT_AMOUNT, + TCompactProtocol.COMPACT_TYPE_MASK)) + self:writeVarint32(seqid) + self:writeString(name) + self:resetLastField() +end + +function TCompactProtocol:writeMessageEnd() +end + +function TCompactProtocol:writeStructBegin(name) + self.lastFieldIndex = self.lastFieldIndex + 1 + self.lastField[self.lastFieldIndex] = self.lastFieldId + self.lastFieldId = 0 +end + +function TCompactProtocol:writeStructEnd() + self.lastFieldIndex = self.lastFieldIndex - 1 + self.lastFieldId = self.lastField[self.lastFieldIndex] +end + +function TCompactProtocol:writeFieldBegin(name, ttype, id) + if ttype == TType.BOOL then + self.booleanFieldName = name + self.booleanFieldId = id + self.booleanFieldPending = true + else + self:writeFieldBeginInternal(name, ttype, id, -1) + end +end + +function TCompactProtocol:writeFieldEnd() +end + +function TCompactProtocol:writeFieldStop() + self:writeByte(TType.STOP); +end + +function TCompactProtocol:writeMapBegin(ktype, vtype, size) + if size == 0 then + self:writeByte(0) + else + self:writeVarint32(size) + self:writeByte(self:packCompactType(TTypeToCompactType[ktype], TTypeToCompactType[vtype])) + end +end + +function TCompactProtocol:writeMapEnd() +end + +function TCompactProtocol:writeListBegin(etype, size) + self:writeCollectionBegin(etype, size) +end + +function TCompactProtocol:writeListEnd() +end + +function TCompactProtocol:writeSetBegin(etype, size) + self:writeCollectionBegin(etype, size) +end + +function TCompactProtocol:writeSetEnd() +end + +function TCompactProtocol:writeBool(bool) + local value = TCompactType.COMPACT_BOOLEAN_FALSE + if bool then + value = TCompactType.COMPACT_BOOLEAN_TRUE + end + print(value,self.booleanFieldPending,self.booleanFieldId) + if self.booleanFieldPending then + self:writeFieldBeginInternal(self.booleanFieldName, TType.BOOL, self.booleanFieldId, value) + self.booleanFieldPending = false + else + self:writeByte(value) + end +end + +function TCompactProtocol:writeByte(byte) + local buff = libluabpack.bpack('c', byte) + self.trans:write(buff) +end + +function TCompactProtocol:writeI16(i16) + self:writeVarint32(libluabpack.i32ToZigzag(i16)) +end + +function TCompactProtocol:writeI32(i32) + self:writeVarint32(libluabpack.i32ToZigzag(i32)) +end + +function TCompactProtocol:writeI64(i64) + self:writeVarint64(libluabpack.i64ToZigzag(i64)) +end + +function TCompactProtocol:writeDouble(dub) + local buff = libluabpack.bpack('d', dub) + self.trans:write(buff) +end + +function TCompactProtocol:writeString(str) + -- Should be utf-8 + self:writeBinary(str) +end + +function TCompactProtocol:writeBinary(str) + -- Should be utf-8 + self:writeVarint32(string.len(str)) + self.trans:write(str) +end + +function TCompactProtocol:writeFieldBeginInternal(name, ttype, id, typeOverride) + if typeOverride == -1 then + typeOverride = TTypeToCompactType[ttype] + end + local offset = id - self.lastFieldId + if id > self.lastFieldId and offset <= 15 then + self:writeByte(libluabitwise.bor(libluabitwise.shiftl(offset, 4), typeOverride)) + else + self:writeByte(typeOverride) + self:writeI16(id) + end + self.lastFieldId = id +end + +function TCompactProtocol:writeCollectionBegin(etype, size) + if size <= 14 then + self:writeByte(libluabitwise.bor(libluabitwise.shiftl(size, 4), TTypeToCompactType[etype])) + else + self:writeByte(libluabitwise.bor(0xf0, TTypeToCompactType[etype])) + self:writeVarint32(size) + end +end + +function TCompactProtocol:writeVarint32(i32) + -- Should be utf-8 + local str = libluabpack.toVarint32(i32) + self.trans:write(str) +end + +function TCompactProtocol:writeVarint64(i64) + -- Should be utf-8 + local str = libluabpack.toVarint64(i64) + self.trans:write(str) +end + +function TCompactProtocol:readMessageBegin() + local protocolId = self:readSignByte() + if protocolId ~= self.COMPACT_PROTOCOL_ID then + terror(TProtocolException:new{ + message = "Expected protocol id " .. self.COMPACT_PROTOCOL_ID .. " but got " .. protocolId}) + end + local versionAndType = self:readSignByte() + local version = libluabitwise.band(versionAndType, self.COMPACT_VERSION_MASK) + local ttype = libluabitwise.band(libluabitwise.shiftr(versionAndType, + self.COMPACT_TYPE_SHIFT_AMOUNT), self.COMPACT_TYPE_BITS) + if version ~= self.COMPACT_VERSION then + terror(TProtocolException:new{ + message = "Expected version " .. self.COMPACT_VERSION .. " but got " .. version}) + end + local seqid = self:readVarint32() + local name = self:readString() + return name, ttype, seqid +end + +function TCompactProtocol:readMessageEnd() +end + +function TCompactProtocol:readStructBegin() + self.lastField[self.lastFieldIndex] = self.lastFieldId + self.lastFieldIndex = self.lastFieldIndex + 1 + self.lastFieldId = 0 + return nil +end + +function TCompactProtocol:readStructEnd() + self.lastFieldIndex = self.lastFieldIndex - 1 + self.lastFieldId = self.lastField[self.lastFieldIndex] +end + +function TCompactProtocol:readFieldBegin() + local field_and_ttype = self:readSignByte() + local ttype = self:getTType(field_and_ttype) + if ttype == TType.STOP then + return nil, ttype, 0 + end + -- mask off the 4 MSB of the type header. it could contain a field id delta. + local modifier = libluabitwise.shiftr(libluabitwise.band(field_and_ttype, 0xf0), 4) + local id = 0 + if modifier == 0 then + id = self:readI16() + else + id = self.lastFieldId + modifier + end + if ttype == TType.BOOL then + boolValue = libluabitwise.band(field_and_ttype, 0x0f) == TCompactType.COMPACT_BOOLEAN_TRUE + boolValueIsNotNull = true + end + self.lastFieldId = id + return nil, ttype, id +end + +function TCompactProtocol:readFieldEnd() +end + +function TCompactProtocol:readMapBegin() + local size = self:readVarint32() + if size < 0 then + return nil,nil,nil + end + local kvtype = self:readSignByte() + local ktype = self:getTType(libluabitwise.shiftr(kvtype, 4)) + local vtype = self:getTType(kvtype) + return ktype, vtype, size +end + +function TCompactProtocol:readMapEnd() +end + +function TCompactProtocol:readListBegin() + local size_and_type = self:readSignByte() + local size = libluabitwise.band(libluabitwise.shiftr(size_and_type, 4), 0x0f) + if size == 15 then + size = self:readVarint32() + end + if size < 0 then + return nil,nil + end + local etype = self:getTType(libluabitwise.band(size_and_type, 0x0f)) + return etype, size +end + +function TCompactProtocol:readListEnd() +end + +function TCompactProtocol:readSetBegin() + return self:readListBegin() +end + +function TCompactProtocol:readSetEnd() +end + +function TCompactProtocol:readBool() + if boolValueIsNotNull then + boolValueIsNotNull = true + return boolValue + end + local val = self:readSignByte() + if val == TCompactType.COMPACT_BOOLEAN_TRUE then + return true + end + return false +end + +function TCompactProtocol:readByte() + local buff = self.trans:readAll(1) + local val = libluabpack.bunpack('c', buff) + return val +end + +function TCompactProtocol:readSignByte() + local buff = self.trans:readAll(1) + local val = libluabpack.bunpack('C', buff) + return val +end + +function TCompactProtocol:readI16() + return self:readI32() +end + +function TCompactProtocol:readI32() + local v = self:readVarint32() + local value = libluabpack.zigzagToI32(v) + return value +end + +function TCompactProtocol:readI64() + local value = self:readVarint64() + return value +end + +function TCompactProtocol:readDouble() + local buff = self.trans:readAll(8) + local val = libluabpack.bunpack('d', buff) + return val +end + +function TCompactProtocol:readString() + return self:readBinary() +end + +function TCompactProtocol:readBinary() + local size = self:readVarint32() + if size <= 0 then + return "" + end + return self.trans:readAll(size) +end + +function TCompactProtocol:readVarint32() + local shiftl = 0 + local result = 0 + while true do + b = self:readByte() + result = libluabitwise.bor(result, + libluabitwise.shiftl(libluabitwise.band(b, 0x7f), shiftl)) + if libluabitwise.band(b, 0x80) ~= 0x80 then + break + end + shiftl = shiftl + 7 + end + return result +end + +function TCompactProtocol:readVarint64() + local result = liblualongnumber.new + local data = result(0) + local shiftl = 0 + while true do + b = self:readByte() + endFlag, data = libluabpack.fromVarint64(b, shiftl, data) + shiftl = shiftl + 7 + if endFlag == 0 then + break + end + end + return data +end + +function TCompactProtocol:getTType(ctype) + return CompactTypeToTType[libluabitwise.band(ctype, 0x0f)] +end + +TCompactProtocolFactory = TProtocolFactory:new{ + __type = 'TCompactProtocolFactory', +} + +function TCompactProtocolFactory:getProtocol(trans) + -- TODO Enforce that this must be a transport class (ie not a bool) + if not trans then + terror(TProtocolException:new{ + message = 'Must supply a transport to ' .. ttype(self) + }) + end + return TCompactProtocol:new{ + trans = trans + } +end diff --git a/lib/lua/TFramedTransport.lua b/lib/lua/TFramedTransport.lua new file mode 100644 index 0000000..437b701 --- /dev/null +++ b/lib/lua/TFramedTransport.lua @@ -0,0 +1,118 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +require 'TTransport' +require 'libluabpack' + +TFramedTransport = TTransportBase:new{ + __type = 'TFramedTransport', + doRead = true, + doWrite = true, + wBuf = '', + rBuf = '' +} + +function TFramedTransport:new(obj) + if ttype(obj) ~= 'table' then + error(ttype(self) .. 'must be initialized with a table') + end + + -- Ensure a transport is provided + if not obj.trans then + error('You must provide ' .. ttype(self) .. ' with a trans') + end + + return TTransportBase.new(self, obj) +end + +function TFramedTransport:isOpen() + return self.trans:isOpen() +end + +function TFramedTransport:open() + return self.trans:open() +end + +function TFramedTransport:close() + return self.trans:close() +end + +function TFramedTransport:read(len) + if string.len(self.rBuf) == 0 then + self:__readFrame() + end + + if self.doRead == false then + return self.trans:read(len) + end + + if len > string.len(self.rBuf) then + local val = self.rBuf + self.rBuf = '' + return val + end + + local val = string.sub(self.rBuf, 0, len) + self.rBuf = string.sub(self.rBuf, len+1) + return val +end + +function TFramedTransport:__readFrame() + local buf = self.trans:readAll(4) + local frame_len = libluabpack.bunpack('i', buf) + self.rBuf = self.trans:readAll(frame_len) +end + + +function TFramedTransport:write(buf, len) + if self.doWrite == false then + return self.trans:write(buf, len) + end + + if len and len < string.len(buf) then + buf = string.sub(buf, 0, len) + end + self.wBuf = self.wBuf .. buf +end + +function TFramedTransport:flush() + if self.doWrite == false then + return self.trans:flush() + end + + -- If the write fails we still want wBuf to be clear + local tmp = self.wBuf + self.wBuf = '' + local frame_len_buf = libluabpack.bpack("i", string.len(tmp)) + self.trans:write(frame_len_buf) + self.trans:write(tmp) + self.trans:flush() +end + +TFramedTransportFactory = TTransportFactoryBase:new{ + __type = 'TFramedTransportFactory' +} +function TFramedTransportFactory:getTransport(trans) + if not trans then + terror(TProtocolException:new{ + message = 'Must supply a transport to ' .. ttype(self) + }) + end + return TFramedTransport:new{trans = trans} +end diff --git a/lib/lua/THttpTransport.lua b/lib/lua/THttpTransport.lua new file mode 100644 index 0000000..041e421 --- /dev/null +++ b/lib/lua/THttpTransport.lua @@ -0,0 +1,182 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +require 'TTransport' + +THttpTransport = TTransportBase:new{ + __type = 'THttpTransport', + path = '/', + wBuf = '', + rBuf = '', + CRLF = '\r\n', + VERSION = '0.11.0', + isServer = true +} + +function THttpTransport:new(obj) + if ttype(obj) ~= 'table' then + error(ttype(self) .. 'must be initialized with a table') + end + + -- Ensure a transport is provided + if not obj.trans then + error('You must provide ' .. ttype(self) .. ' with a trans') + end + + return TTransportBase.new(self, obj) +end + +function THttpTransport:isOpen() + return self.trans:isOpen() +end + +function THttpTransport:open() + return self.trans:open() +end + +function THttpTransport:close() + return self.trans:close() +end + +function THttpTransport:readAll(len) + return self:read(len) +end + +function THttpTransport:read(len) + if string.len(self.rBuf) == 0 then + self:_readMsg() + end + if len > string.len(self.rBuf) then + local val = self.rBuf + self.rBuf = '' + return val + end + + local val = string.sub(self.rBuf, 0, len) + self.rBuf = string.sub(self.rBuf, len+1) + return val +end + +function THttpTransport:_readMsg() + while true do + self.rBuf = self.rBuf .. self.trans:read(4) + if string.find(self.rBuf, self.CRLF .. self.CRLF) then + break + end + end + if not self.rBuf then + self.rBuf = "" + return + end + self:getLine() + local headers = self:_parseHeaders() + if not headers then + self.rBuf = "" + return + end + + local length = tonumber(headers["Content-Length"]) + if length then + length = length - string.len(self.rBuf) + self.rBuf = self.rBuf .. self.trans:readAll(length) + end + if self.rBuf == nil then + self.rBuf = "" + end +end + +function THttpTransport:getLine() + local a,b = string.find(self.rBuf, self.CRLF) + local line = "" + if a and b then + line = string.sub(self.rBuf, 0, a-1) + self.rBuf = string.sub(self.rBuf, b+1) + end + return line +end + +function THttpTransport:_parseHeaders() + local headers = {} + + repeat + local line = self:getLine() + for key, val in string.gmatch(line, "([%w%-]+)%s*:%s*(.+)") do + if headers[key] then + local delimiter = ", " + if key == "Set-Cookie" then + delimiter = "; " + end + headers[key] = headers[key] .. delimiter .. tostring(val) + else + headers[key] = tostring(val) + end + end + until string.find(line, "^%s*$") + + return headers +end + +function THttpTransport:write(buf, len) + if len and len < string.len(buf) then + buf = string.sub(buf, 0, len) + end + self.wBuf = self.wBuf .. buf +end + +function THttpTransport:writeHttpHeader(content_len) + if self.isServer then + local header = "HTTP/1.1 200 OK" .. self.CRLF + .. "Server: Thrift/" .. self.VERSION .. self.CRLF + .. "Access-Control-Allow-Origin: *" .. self.CRLF + .. "Content-Type: application/x-thrift" .. self.CRLF + .. "Content-Length: " .. content_len .. self.CRLF + .. "Connection: Keep-Alive" .. self.CRLF .. self.CRLF + self.trans:write(header) + else + local header = "POST " .. self.path .. " HTTP/1.1" .. self.CRLF + .. "Host: " .. self.trans.host .. self.CRLF + .. "Content-Type: application/x-thrift" .. self.CRLF + .. "Content-Length: " .. content_len .. self.CRLF + .. "Accept: application/x-thrift " .. self.CRLF + .. "User-Agent: Thrift/" .. self.VERSION .. " (Lua/THttpClient)" + .. self.CRLF .. self.CRLF + self.trans:write(header) + end +end + +function THttpTransport:flush() + -- If the write fails we still want wBuf to be clear + local tmp = self.wBuf + self.wBuf = '' + self:writeHttpHeader(string.len(tmp)) + self.trans:write(tmp) + self.trans:flush() +end + +THttpTransportFactory = TTransportFactoryBase:new{ + __type = 'THttpTransportFactory' +} +function THttpTransportFactory:getTransport(trans) + if not trans then + terror(TProtocolException:new{ + message = 'Must supply a transport to ' .. ttype(self) + }) + end + return THttpTransport:new{trans = trans} +end diff --git a/lib/lua/TJsonProtocol.lua b/lib/lua/TJsonProtocol.lua new file mode 100644 index 0000000..db08eec --- /dev/null +++ b/lib/lua/TJsonProtocol.lua @@ -0,0 +1,727 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"), you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +require 'TProtocol' +require 'libluabpack' +require 'libluabitwise' + +TJSONProtocol = __TObject.new(TProtocolBase, { + __type = 'TJSONProtocol', + THRIFT_JSON_PROTOCOL_VERSION = 1, + jsonContext = {}, + jsonContextVal = {first = true, colon = true, ttype = 2, null = true}, + jsonContextIndex = 1, + hasReadByte = "" +}) + +TTypeToString = {} +TTypeToString[TType.BOOL] = "tf" +TTypeToString[TType.BYTE] = "i8" +TTypeToString[TType.I16] = "i16" +TTypeToString[TType.I32] = "i32" +TTypeToString[TType.I64] = "i64" +TTypeToString[TType.DOUBLE] = "dbl" +TTypeToString[TType.STRING] = "str" +TTypeToString[TType.STRUCT] = "rec" +TTypeToString[TType.LIST] = "lst" +TTypeToString[TType.SET] = "set" +TTypeToString[TType.MAP] = "map" + +StringToTType = { + tf = TType.BOOL, + i8 = TType.BYTE, + i16 = TType.I16, + i32 = TType.I32, + i64 = TType.I64, + dbl = TType.DOUBLE, + str = TType.STRING, + rec = TType.STRUCT, + map = TType.MAP, + set = TType.SET, + lst = TType.LIST +} + +JSONNode = { + ObjectBegin = '{', + ObjectEnd = '}', + ArrayBegin = '[', + ArrayEnd = ']', + PairSeparator = ':', + ElemSeparator = ',', + Backslash = '\\', + StringDelimiter = '"', + ZeroChar = '0', + EscapeChar = 'u', + Nan = 'NaN', + Infinity = 'Infinity', + NegativeInfinity = '-Infinity', + EscapeChars = "\"\\bfnrt", + EscapePrefix = "\\u00" +} + +EscapeCharVals = { + '"', '\\', '\b', '\f', '\n', '\r', '\t' +} + +JSONCharTable = { + --0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0, 98,116,110, 0,102,114, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1,34, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +} + +-- character table string +local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + +-- encoding +function base64_encode(data) + return ((data:gsub('.', function(x) + local r,b='',x:byte() + for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end + return r; + end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x) + if (#x < 6) then return '' end + local c=0 + for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end + return b:sub(c+1,c+1) + end)..({ '', '==', '=' })[#data%3+1]) +end + +-- decoding +function base64_decode(data) + data = string.gsub(data, '[^'..b..'=]', '') + return (data:gsub('.', function(x) + if (x == '=') then return '' end + local r,f='',(b:find(x)-1) + for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end + return r; + end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x) + if (#x ~= 8) then return '' end + local c=0 + for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end + return string.char(c) + end)) +end + +function TJSONProtocol:resetContext() + self.jsonContext = {} + self.jsonContextVal = {first = true, colon = true, ttype = 2, null = true} + self.jsonContextIndex = 1 +end + +function TJSONProtocol:contextPush(context) + self.jsonContextIndex = self.jsonContextIndex + 1 + self.jsonContext[self.jsonContextIndex] = self.jsonContextVal + self.jsonContextVal = context +end + +function TJSONProtocol:contextPop() + self.jsonContextVal = self.jsonContext[self.jsonContextIndex] + self.jsonContextIndex = self.jsonContextIndex - 1 +end + +function TJSONProtocol:escapeNum() + if self.jsonContextVal.ttype == 1 then + return self.jsonContextVal.colon + else + return false + end +end + +function TJSONProtocol:writeElemSeparator() + if self.jsonContextVal.null then + return + end + if self.jsonContextVal.first then + self.jsonContextVal.first = false + else + if self.jsonContextVal.ttype == 1 then + if self.jsonContextVal.colon then + self.trans:write(JSONNode.PairSeparator) + self.jsonContextVal.colon = false + else + self.trans:write(JSONNode.ElemSeparator) + self.jsonContextVal.colon = true + end + else + self.trans:write(JSONNode.ElemSeparator) + end + end +end + +function TJSONProtocol:hexChar(val) + val = libluabitwise.band(val, 0x0f) + if val < 10 then + return val + 48 + else + return val + 87 + end +end + +function TJSONProtocol:writeJSONEscapeChar(ch) + self.trans:write(JSONNode.EscapePrefix) + local outCh = hexChar(libluabitwise.shiftr(ch, 4)) + local buff = libluabpack.bpack('c', outCh) + self.trans:write(buff) + outCh = hexChar(ch) + buff = libluabpack.bpack('c', outCh) + self.trans:write(buff) +end + +function TJSONProtocol:writeJSONChar(byte) + ch = string.byte(byte) + if ch >= 0x30 then + if ch == JSONNode.Backslash then + self.trans:write(JSONNode.Backslash) + self.trans:write(JSONNode.Backslash) + else + self.trans:write(byte) + end + else + local outCh = JSONCharTable[ch+1] + if outCh == 1 then + self.trans:write(byte) + elseif outCh > 1 then + self.trans:write(JSONNode.Backslash) + local buff = libluabpack.bpack('c', outCh) + self.trans:write(buff) + else + self:writeJSONEscapeChar(ch) + end + end +end + +function TJSONProtocol:writeJSONString(str) + self:writeElemSeparator() + self.trans:write(JSONNode.StringDelimiter) + -- TODO escape special characters + local length = string.len(str) + local ii = 1 + while ii <= length do + self:writeJSONChar(string.sub(str, ii, ii)) + ii = ii + 1 + end + self.trans:write(JSONNode.StringDelimiter) +end + +function TJSONProtocol:writeJSONBase64(str) + self:writeElemSeparator() + self.trans:write(JSONNode.StringDelimiter) + local length = string.len(str) + local offset = 1 + while length >= 3 do + -- Encode 3 bytes at a time + local bytes = base64_encode(string.sub(str, offset, offset+3)) + self.trans:write(bytes) + length = length - 3 + offset = offset + 3 + end + if length > 0 then + local bytes = base64_encode(string.sub(str, offset, offset+length)) + self.trans:write(bytes) + end + self.trans:write(JSONNode.StringDelimiter) +end + +function TJSONProtocol:writeJSONInteger(num) + self:writeElemSeparator() + if self:escapeNum() then + self.trans:write(JSONNode.StringDelimiter) + end + local numstr = "" .. num + numstr = string.sub(numstr, string.find(numstr, "^[+-]?%d+")) + self.trans:write(numstr) + if self:escapeNum() then + self.trans:write(JSONNode.StringDelimiter) + end +end + +function TJSONProtocol:writeJSONDouble(dub) + self:writeElemSeparator() + local val = "" .. dub + local prefix = string.sub(val, 1, 1) + local special = false + if prefix == 'N' or prefix == 'n' then + val = JSONNode.Nan + special = true + elseif prefix == 'I' or prefix == 'i' then + val = JSONNode.Infinity + special = true + elseif prefix == '-' then + local secondByte = string.sub(val, 2, 2) + if secondByte == 'I' or secondByte == 'i' then + val = JSONNode.NegativeInfinity + special = true + end + end + + if special or self:escapeNum() then + self.trans:write(JSONNode.StringDelimiter) + end + self.trans:write(val) + if special or self:escapeNum() then + self.trans:write(JSONNode.StringDelimiter) + end +end + +function TJSONProtocol:writeJSONObjectBegin() + self:writeElemSeparator() + self.trans:write(JSONNode.ObjectBegin) + self:contextPush({first = true, colon = true, ttype = 1, null = false}) +end + +function TJSONProtocol:writeJSONObjectEnd() + self:contextPop() + self.trans:write(JSONNode.ObjectEnd) +end + +function TJSONProtocol:writeJSONArrayBegin() + self:writeElemSeparator() + self.trans:write(JSONNode.ArrayBegin) + self:contextPush({first = true, colon = true, ttype = 2, null = false}) +end + +function TJSONProtocol:writeJSONArrayEnd() + self:contextPop() + self.trans:write(JSONNode.ArrayEnd) +end + +function TJSONProtocol:writeMessageBegin(name, ttype, seqid) + self:resetContext() + self:writeJSONArrayBegin() + self:writeJSONInteger(TJSONProtocol.THRIFT_JSON_PROTOCOL_VERSION) + self:writeJSONString(name) + self:writeJSONInteger(ttype) + self:writeJSONInteger(seqid) +end + +function TJSONProtocol:writeMessageEnd() + self:writeJSONArrayEnd() +end + +function TJSONProtocol:writeStructBegin(name) + self:writeJSONObjectBegin() +end + +function TJSONProtocol:writeStructEnd() + self:writeJSONObjectEnd() +end + +function TJSONProtocol:writeFieldBegin(name, ttype, id) + self:writeJSONInteger(id) + self:writeJSONObjectBegin() + self:writeJSONString(TTypeToString[ttype]) +end + +function TJSONProtocol:writeFieldEnd() + self:writeJSONObjectEnd() +end + +function TJSONProtocol:writeFieldStop() +end + +function TJSONProtocol:writeMapBegin(ktype, vtype, size) + self:writeJSONArrayBegin() + self:writeJSONString(TTypeToString[ktype]) + self:writeJSONString(TTypeToString[vtype]) + self:writeJSONInteger(size) + return self:writeJSONObjectBegin() +end + +function TJSONProtocol:writeMapEnd() + self:writeJSONObjectEnd() + self:writeJSONArrayEnd() +end + +function TJSONProtocol:writeListBegin(etype, size) + self:writeJSONArrayBegin() + self:writeJSONString(TTypeToString[etype]) + self:writeJSONInteger(size) +end + +function TJSONProtocol:writeListEnd() + self:writeJSONArrayEnd() +end + +function TJSONProtocol:writeSetBegin(etype, size) + self:writeJSONArrayBegin() + self:writeJSONString(TTypeToString[etype]) + self:writeJSONInteger(size) +end + +function TJSONProtocol:writeSetEnd() + self:writeJSONArrayEnd() +end + +function TJSONProtocol:writeBool(bool) + if bool then + self:writeJSONInteger(1) + else + self:writeJSONInteger(0) + end +end + +function TJSONProtocol:writeByte(byte) + local buff = libluabpack.bpack('c', byte) + local val = libluabpack.bunpack('c', buff) + self:writeJSONInteger(val) +end + +function TJSONProtocol:writeI16(i16) + local buff = libluabpack.bpack('s', i16) + local val = libluabpack.bunpack('s', buff) + self:writeJSONInteger(val) +end + +function TJSONProtocol:writeI32(i32) + local buff = libluabpack.bpack('i', i32) + local val = libluabpack.bunpack('i', buff) + self:writeJSONInteger(val) +end + +function TJSONProtocol:writeI64(i64) + local buff = libluabpack.bpack('l', i64) + local val = libluabpack.bunpack('l', buff) + self:writeJSONInteger(tostring(val)) +end + +function TJSONProtocol:writeDouble(dub) + self:writeJSONDouble(string.format("%.16f", dub)) +end + +function TJSONProtocol:writeString(str) + self:writeJSONString(str) +end + +function TJSONProtocol:writeBinary(str) + -- Should be utf-8 + self:writeJSONBase64(str) +end + +function TJSONProtocol:readJSONSyntaxChar(ch) + local ch2 = "" + if self.hasReadByte ~= "" then + ch2 = self.hasReadByte + self.hasReadByte = "" + else + ch2 = self.trans:readAll(1) + end + if ch2 ~= ch then + terror(TProtocolException:new{message = "Expected ".. ch .. ", got " .. ch2}) + end +end + +function TJSONProtocol:readElemSeparator() + if self.jsonContextVal.null then + return + end + if self.jsonContextVal.first then + self.jsonContextVal.first = false + else + if self.jsonContextVal.ttype == 1 then + if self.jsonContextVal.colon then + self:readJSONSyntaxChar(JSONNode.PairSeparator) + self.jsonContextVal.colon = false + else + self:readJSONSyntaxChar(JSONNode.ElemSeparator) + self.jsonContextVal.colon = true + end + else + self:readJSONSyntaxChar(JSONNode.ElemSeparator) + end + end +end + +function TJSONProtocol:hexVal(ch) + local val = string.byte(ch) + if val >= 48 and val <= 57 then + return val - 48 + elseif val >= 97 and val <= 102 then + return val - 87 + else + terror(TProtocolException:new{message = "Expected hex val ([0-9a-f]); got " .. ch}) + end +end + +function TJSONProtocol:readJSONEscapeChar(ch) + self:readJSONSyntaxChar(JSONNode.ZeroChar) + self:readJSONSyntaxChar(JSONNode.ZeroChar) + local b1 = self.trans:readAll(1) + local b2 = self.trans:readAll(1) + return libluabitwise.shiftl(self:hexVal(b1), 4) + self:hexVal(b2) +end + + +function TJSONProtocol:readJSONString() + self:readElemSeparator() + self:readJSONSyntaxChar(JSONNode.StringDelimiter) + local result = "" + while true do + local ch = self.trans:readAll(1) + if ch == JSONNode.StringDelimiter then + break + end + if ch == JSONNode.Backslash then + ch = self.trans:readAll(1) + if ch == JSONNode.EscapeChar then + self:readJSONEscapeChar(ch) + else + local pos, _ = string.find(JSONNode.EscapeChars, ch) + if pos == nil then + terror(TProtocolException:new{message = "Expected control char, got " .. ch}) + end + ch = EscapeCharVals[pos] + end + end + result = result .. ch + end + return result +end + +function TJSONProtocol:readJSONBase64() + local result = self:readJSONString() + local length = string.len(result) + local str = "" + local offset = 1 + while length >= 4 do + local bytes = string.sub(result, offset, offset+4) + str = str .. base64_decode(bytes) + offset = offset + 4 + length = length - 4 + end + if length >= 0 then + str = str .. base64_decode(string.sub(result, offset, offset + length)) + end + return str +end + +function TJSONProtocol:readJSONNumericChars() + local result = "" + while true do + local ch = self.trans:readAll(1) + if string.find(ch, '[-+0-9.Ee]') then + result = result .. ch + else + self.hasReadByte = ch + break + end + end + return result +end + +function TJSONProtocol:readJSONLongInteger() + self:readElemSeparator() + if self:escapeNum() then + self:readJSONSyntaxChar(JSONNode.StringDelimiter) + end + local result = self:readJSONNumericChars() + if self:escapeNum() then + self:readJSONSyntaxChar(JSONNode.StringDelimiter) + end + return result +end + +function TJSONProtocol:readJSONInteger() + return tonumber(self:readJSONLongInteger()) +end + +function TJSONProtocol:readJSONDouble() + self:readElemSeparator() + local delimiter = self.trans:readAll(1) + local num = 0.0 + if delimiter == JSONNode.StringDelimiter then + local str = self:readJSONString() + if str == JSONNode.Nan then + num = 1.0 + elseif str == JSONNode.Infinity then + num = math.maxinteger + elseif str == JSONNode.NegativeInfinity then + num = math.mininteger + else + num = tonumber(str) + end + else + if self:escapeNum() then + self:readJSONSyntaxChar(JSONNode.StringDelimiter) + end + local result = self:readJSONNumericChars() + num = tonumber(delimiter.. result) + end + return num +end + +function TJSONProtocol:readJSONObjectBegin() + self:readElemSeparator() + self:readJSONSyntaxChar(JSONNode.ObjectBegin) + self:contextPush({first = true, colon = true, ttype = 1, null = false}) +end + +function TJSONProtocol:readJSONObjectEnd() + self:readJSONSyntaxChar(JSONNode.ObjectEnd) + self:contextPop() +end + +function TJSONProtocol:readJSONArrayBegin() + self:readElemSeparator() + self:readJSONSyntaxChar(JSONNode.ArrayBegin) + self:contextPush({first = true, colon = true, ttype = 2, null = false}) +end + +function TJSONProtocol:readJSONArrayEnd() + self:readJSONSyntaxChar(JSONNode.ArrayEnd) + self:contextPop() +end + +function TJSONProtocol:readMessageBegin() + self:resetContext() + self:readJSONArrayBegin() + local version = self:readJSONInteger() + if version ~= self.THRIFT_JSON_PROTOCOL_VERSION then + terror(TProtocolException:new{message = "Message contained bad version."}) + end + local name = self:readJSONString() + local ttype = self:readJSONInteger() + local seqid = self:readJSONInteger() + return name, ttype, seqid +end + +function TJSONProtocol:readMessageEnd() + self:readJSONArrayEnd() +end + +function TJSONProtocol:readStructBegin() + self:readJSONObjectBegin() + return nil +end + +function TJSONProtocol:readStructEnd() + self:readJSONObjectEnd() +end + +function TJSONProtocol:readFieldBegin() + local ttype = TType.STOP + local id = 0 + local ch = self.trans:readAll(1) + self.hasReadByte = ch + if ch ~= JSONNode.ObjectEnd then + id = self:readJSONInteger() + self:readJSONObjectBegin() + local typeName = self:readJSONString() + ttype = StringToTType[typeName] + end + return nil, ttype, id +end + +function TJSONProtocol:readFieldEnd() + self:readJSONObjectEnd() +end + +function TJSONProtocol:readMapBegin() + self:readJSONArrayBegin() + local typeName = self:readJSONString() + local ktype = StringToTType[typeName] + typeName = self:readJSONString() + local vtype = StringToTType[typeName] + local size = self:readJSONInteger() + self:readJSONObjectBegin() + return ktype, vtype, size +end + +function TJSONProtocol:readMapEnd() + self:readJSONObjectEnd() + self:readJSONArrayEnd() +end + +function TJSONProtocol:readListBegin() + self:readJSONArrayBegin() + local typeName = self:readJSONString() + local etype = StringToTType[typeName] + local size = self:readJSONInteger() + return etype, size +end + +function TJSONProtocol:readListEnd() + return self:readJSONArrayEnd() +end + +function TJSONProtocol:readSetBegin() + return self:readListBegin() +end + +function TJSONProtocol:readSetEnd() + return self:readJSONArrayEnd() +end + +function TJSONProtocol:readBool() + local result = self:readJSONInteger() + if result == 1 then + return true + else + return false + end +end + +function TJSONProtocol:readByte() + local result = self:readJSONInteger() + if result >= 256 then + terror(TProtocolException:new{message = "UnExpected Byte " .. result}) + end + return result +end + +function TJSONProtocol:readI16() + return self:readJSONInteger() +end + +function TJSONProtocol:readI32() + return self:readJSONInteger() +end + +function TJSONProtocol:readI64() + local long = liblualongnumber.new + return long(self:readJSONLongInteger()) +end + +function TJSONProtocol:readDouble() + return self:readJSONDouble() +end + +function TJSONProtocol:readString() + return self:readJSONString() +end + +function TJSONProtocol:readBinary() + return self:readJSONBase64() +end + +TJSONProtocolFactory = TProtocolFactory:new{ + __type = 'TJSONProtocolFactory', +} + +function TJSONProtocolFactory:getProtocol(trans) + -- TODO Enforce that this must be a transport class (ie not a bool) + if not trans then + terror(TProtocolException:new{ + message = 'Must supply a transport to ' .. ttype(self) + }) + end + return TJSONProtocol:new{ + trans = trans + } +end diff --git a/lib/lua/TMemoryBuffer.lua b/lib/lua/TMemoryBuffer.lua new file mode 100644 index 0000000..78b2f5c --- /dev/null +++ b/lib/lua/TMemoryBuffer.lua @@ -0,0 +1,91 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +require 'TTransport' + +TMemoryBuffer = TTransportBase:new{ + __type = 'TMemoryBuffer', + buffer = '', + bufferSize = 1024, + wPos = 0, + rPos = 0 +} +function TMemoryBuffer:isOpen() + return 1 +end +function TMemoryBuffer:open() end +function TMemoryBuffer:close() end + +function TMemoryBuffer:peak() + return self.rPos < self.wPos +end + +function TMemoryBuffer:getBuffer() + return self.buffer +end + +function TMemoryBuffer:resetBuffer(buf) + if buf then + self.buffer = buf + self.bufferSize = string.len(buf) + else + self.buffer = '' + self.bufferSize = 1024 + end + self.wPos = string.len(buf) + self.rPos = 0 +end + +function TMemoryBuffer:available() + return self.wPos - self.rPos +end + +function TMemoryBuffer:read(len) + local avail = self:available() + if avail == 0 then + return '' + end + + if avail < len then + len = avail + end + + local val = string.sub(self.buffer, self.rPos + 1, self.rPos + len) + self.rPos = self.rPos + len + return val +end + +function TMemoryBuffer:readAll(len) + local avail = self:available() + + if avail < len then + local msg = string.format('Attempt to readAll(%d) found only %d available', + len, avail) + terror(TTransportException:new{message = msg}) + end + -- read should block so we don't need a loop here + return self:read(len) +end + +function TMemoryBuffer:write(buf) + self.buffer = self.buffer .. buf + self.wPos = self.wPos + string.len(buf) +end + +function TMemoryBuffer:flush() end diff --git a/lib/lua/TProtocol.lua b/lib/lua/TProtocol.lua new file mode 100644 index 0000000..616e167 --- /dev/null +++ b/lib/lua/TProtocol.lua @@ -0,0 +1,162 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +require 'Thrift' + +TProtocolException = TException:new { + UNKNOWN = 0, + INVALID_DATA = 1, + NEGATIVE_SIZE = 2, + SIZE_LIMIT = 3, + BAD_VERSION = 4, + INVALID_PROTOCOL = 5, + DEPTH_LIMIT = 6, + errorCode = 0, + __type = 'TProtocolException' +} +function TProtocolException:__errorCodeToString() + if self.errorCode == self.INVALID_DATA then + return 'Invalid data' + elseif self.errorCode == self.NEGATIVE_SIZE then + return 'Negative size' + elseif self.errorCode == self.SIZE_LIMIT then + return 'Size limit' + elseif self.errorCode == self.BAD_VERSION then + return 'Bad version' + elseif self.errorCode == self.INVALID_PROTOCOL then + return 'Invalid protocol' + elseif self.errorCode == self.DEPTH_LIMIT then + return 'Exceeded size limit' + else + return 'Default (unknown)' + end +end + +TProtocolBase = __TObject:new{ + __type = 'TProtocolBase', + trans +} + +function TProtocolBase:new(obj) + if ttype(obj) ~= 'table' then + error(ttype(self) .. 'must be initialized with a table') + end + + -- Ensure a transport is provided + if not obj.trans then + error('You must provide ' .. ttype(self) .. ' with a trans') + end + + return __TObject.new(self, obj) +end + +function TProtocolBase:writeMessageBegin(name, ttype, seqid) end +function TProtocolBase:writeMessageEnd() end +function TProtocolBase:writeStructBegin(name) end +function TProtocolBase:writeStructEnd() end +function TProtocolBase:writeFieldBegin(name, ttype, id) end +function TProtocolBase:writeFieldEnd() end +function TProtocolBase:writeFieldStop() end +function TProtocolBase:writeMapBegin(ktype, vtype, size) end +function TProtocolBase:writeMapEnd() end +function TProtocolBase:writeListBegin(ttype, size) end +function TProtocolBase:writeListEnd() end +function TProtocolBase:writeSetBegin(ttype, size) end +function TProtocolBase:writeSetEnd() end +function TProtocolBase:writeBool(bool) end +function TProtocolBase:writeByte(byte) end +function TProtocolBase:writeI16(i16) end +function TProtocolBase:writeI32(i32) end +function TProtocolBase:writeI64(i64) end +function TProtocolBase:writeDouble(dub) end +function TProtocolBase:writeString(str) end +function TProtocolBase:readMessageBegin() end +function TProtocolBase:readMessageEnd() end +function TProtocolBase:readStructBegin() end +function TProtocolBase:readStructEnd() end +function TProtocolBase:readFieldBegin() end +function TProtocolBase:readFieldEnd() end +function TProtocolBase:readMapBegin() end +function TProtocolBase:readMapEnd() end +function TProtocolBase:readListBegin() end +function TProtocolBase:readListEnd() end +function TProtocolBase:readSetBegin() end +function TProtocolBase:readSetEnd() end +function TProtocolBase:readBool() end +function TProtocolBase:readByte() end +function TProtocolBase:readI16() end +function TProtocolBase:readI32() end +function TProtocolBase:readI64() end +function TProtocolBase:readDouble() end +function TProtocolBase:readString() end + +function TProtocolBase:skip(ttype) + if type == TType.STOP then + return + elseif ttype == TType.BOOL then + self:readBool() + elseif ttype == TType.BYTE then + self:readByte() + elseif ttype == TType.I16 then + self:readI16() + elseif ttype == TType.I32 then + self:readI32() + elseif ttype == TType.I64 then + self:readI64() + elseif ttype == TType.DOUBLE then + self:readDouble() + elseif ttype == TType.STRING then + self:readString() + elseif ttype == TType.STRUCT then + local name = self:readStructBegin() + while true do + local name, ttype, id = self:readFieldBegin() + if ttype == TType.STOP then + break + end + self:skip(ttype) + self:readFieldEnd() + end + self:readStructEnd() + elseif ttype == TType.MAP then + local kttype, vttype, size = self:readMapBegin() + for i = 1, size, 1 do + self:skip(kttype) + self:skip(vttype) + end + self:readMapEnd() + elseif ttype == TType.SET then + local ettype, size = self:readSetBegin() + for i = 1, size, 1 do + self:skip(ettype) + end + self:readSetEnd() + elseif ttype == TType.LIST then + local ettype, size = self:readListBegin() + for i = 1, size, 1 do + self:skip(ettype) + end + self:readListEnd() + end +end + +TProtocolFactory = __TObject:new{ + __type = 'TProtocolFactory', +} +function TProtocolFactory:getProtocol(trans) end diff --git a/lib/lua/TServer.lua b/lib/lua/TServer.lua new file mode 100644 index 0000000..4e37d58 --- /dev/null +++ b/lib/lua/TServer.lua @@ -0,0 +1,140 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +require 'Thrift' +require 'TFramedTransport' +require 'TBinaryProtocol' + +-- TServer +TServer = __TObject:new{ + __type = 'TServer' +} + +-- 2 possible constructors +-- 1. {processor, serverTransport} +-- 2. {processor, serverTransport, transportFactory, protocolFactory} +function TServer:new(args) + if ttype(args) ~= 'table' then + error('TServer must be initialized with a table') + end + if args.processor == nil then + terror('You must provide ' .. ttype(self) .. ' with a processor') + end + if args.serverTransport == nil then + terror('You must provide ' .. ttype(self) .. ' with a serverTransport') + end + + -- Create the object + local obj = __TObject.new(self, args) + + if obj.transportFactory then + obj.inputTransportFactory = obj.transportFactory + obj.outputTransportFactory = obj.transportFactory + obj.transportFactory = nil + else + obj.inputTransportFactory = TFramedTransportFactory:new{} + obj.outputTransportFactory = obj.inputTransportFactory + end + + if obj.protocolFactory then + obj.inputProtocolFactory = obj.protocolFactory + obj.outputProtocolFactory = obj.protocolFactory + obj.protocolFactory = nil + else + obj.inputProtocolFactory = TBinaryProtocolFactory:new{} + obj.outputProtocolFactory = obj.inputProtocolFactory + end + + -- Set the __server variable in the handler so we can stop the server + obj.processor.handler.__server = self + + return obj +end + +function TServer:setServerEventHandler(handler) + self.serverEventHandler = handler +end + +function TServer:_clientBegin(content, iprot, oprot) + if self.serverEventHandler and + type(self.serverEventHandler.clientBegin) == 'function' then + self.serverEventHandler:clientBegin(iprot, oprot) + end +end + +function TServer:_preServe() + if self.serverEventHandler and + type(self.serverEventHandler.preServe) == 'function' then + self.serverEventHandler:preServe(self.serverTransport:getSocketInfo()) + end +end + +function TServer:_handleException(err) + if string.find(err, 'TTransportException') == nil then + print(err) + end +end + +function TServer:serve() end +function TServer:handle(client) + local itrans, otrans = + self.inputTransportFactory:getTransport(client), + self.outputTransportFactory:getTransport(client) + local iprot, oprot = + self.inputProtocolFactory:getProtocol(itrans), + self.outputProtocolFactory:getProtocol(otrans) + + self:_clientBegin(iprot, oprot) + while true do + local ret, err = pcall(self.processor.process, self.processor, iprot, oprot) + if ret == false and err then + if not string.find(err, "TTransportException") then + self:_handleException(err) + end + break + end + end + itrans:close() + otrans:close() +end + +function TServer:close() + self.serverTransport:close() +end + +-- TSimpleServer +-- Single threaded server that handles one transport (connection) +TSimpleServer = __TObject:new(TServer, { + __type = 'TSimpleServer', + __stop = false +}) + +function TSimpleServer:serve() + self.serverTransport:listen() + self:_preServe() + while not self.__stop do + client = self.serverTransport:accept() + self:handle(client) + end + self:close() +end + +function TSimpleServer:stop() + self.__stop = true +end diff --git a/lib/lua/TSocket.lua b/lib/lua/TSocket.lua new file mode 100644 index 0000000..d71fc1f --- /dev/null +++ b/lib/lua/TSocket.lua @@ -0,0 +1,132 @@ +---- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +require 'TTransport' +require 'libluasocket' + +-- TSocketBase +TSocketBase = TTransportBase:new{ + __type = 'TSocketBase', + timeout = 1000, + host = 'localhost', + port = 9090, + handle +} + +function TSocketBase:close() + if self.handle then + self.handle:destroy() + self.handle = nil + end +end + +-- Returns a table with the fields host and port +function TSocketBase:getSocketInfo() + if self.handle then + return self.handle:getsockinfo() + end + terror(TTransportException:new{errorCode = TTransportException.NOT_OPEN}) +end + +function TSocketBase:setTimeout(timeout) + if timeout and ttype(timeout) == 'number' then + if self.handle then + self.handle:settimeout(timeout) + end + self.timeout = timeout + end +end + +-- TSocket +TSocket = TSocketBase:new{ + __type = 'TSocket', + host = 'localhost', + port = 9090 +} + +function TSocket:isOpen() + if self.handle then + return true + end + return false +end + +function TSocket:open() + if self.handle then + self:close() + end + + -- Create local handle + local sock, err = luasocket.create_and_connect( + self.host, self.port, self.timeout) + if err == nil then + self.handle = sock + end + + if err then + terror(TTransportException:new{ + message = 'Could not connect to ' .. self.host .. ':' .. self.port + .. ' (' .. err .. ')' + }) + end +end + +function TSocket:read(len) + local buf = self.handle:receive(self.handle, len) + if not buf or string.len(buf) ~= len then + terror(TTransportException:new{errorCode = TTransportException.UNKNOWN}) + end + return buf +end + +function TSocket:write(buf) + self.handle:send(self.handle, buf) +end + +function TSocket:flush() +end + +-- TServerSocket +TServerSocket = TSocketBase:new{ + __type = 'TServerSocket', + host = 'localhost', + port = 9090 +} + +function TServerSocket:listen() + if self.handle then + self:close() + end + + local sock, err = luasocket.create(self.host, self.port) + if not err then + self.handle = sock + else + terror(err) + end + self.handle:settimeout(self.timeout) + self.handle:listen() +end + +function TServerSocket:accept() + local client, err = self.handle:accept() + if err then + terror(err) + end + return TSocket:new({handle = client}) +end diff --git a/lib/lua/TTransport.lua b/lib/lua/TTransport.lua new file mode 100644 index 0000000..01c7e59 --- /dev/null +++ b/lib/lua/TTransport.lua @@ -0,0 +1,93 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +require 'Thrift' + +TTransportException = TException:new { + UNKNOWN = 0, + NOT_OPEN = 1, + ALREADY_OPEN = 2, + TIMED_OUT = 3, + END_OF_FILE = 4, + INVALID_FRAME_SIZE = 5, + INVALID_TRANSFORM = 6, + INVALID_CLIENT_TYPE = 7, + errorCode = 0, + __type = 'TTransportException' +} + +function TTransportException:__errorCodeToString() + if self.errorCode == self.NOT_OPEN then + return 'Transport not open' + elseif self.errorCode == self.ALREADY_OPEN then + return 'Transport already open' + elseif self.errorCode == self.TIMED_OUT then + return 'Transport timed out' + elseif self.errorCode == self.END_OF_FILE then + return 'End of file' + elseif self.errorCode == self.INVALID_FRAME_SIZE then + return 'Invalid frame size' + elseif self.errorCode == self.INVALID_TRANSFORM then + return 'Invalid transform' + elseif self.errorCode == self.INVALID_CLIENT_TYPE then + return 'Invalid client type' + else + return 'Default (unknown)' + end +end + +TTransportBase = __TObject:new{ + __type = 'TTransportBase' +} + +function TTransportBase:isOpen() end +function TTransportBase:open() end +function TTransportBase:close() end +function TTransportBase:read(len) end +function TTransportBase:readAll(len) + local buf, have, chunk = '', 0 + while have < len do + chunk = self:read(len - have) + have = have + string.len(chunk) + buf = buf .. chunk + + if string.len(chunk) == 0 then + terror(TTransportException:new{ + errorCode = TTransportException.END_OF_FILE + }) + end + end + return buf +end +function TTransportBase:write(buf) end +function TTransportBase:flush() end + +TServerTransportBase = __TObject:new{ + __type = 'TServerTransportBase' +} +function TServerTransportBase:listen() end +function TServerTransportBase:accept() end +function TServerTransportBase:close() end + +TTransportFactoryBase = __TObject:new{ + __type = 'TTransportFactoryBase' +} +function TTransportFactoryBase:getTransport(trans) + return trans +end diff --git a/lib/lua/Thrift.lua b/lib/lua/Thrift.lua new file mode 100644 index 0000000..a9a9078 --- /dev/null +++ b/lib/lua/Thrift.lua @@ -0,0 +1,281 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +---- namespace thrift +--thrift = {} +--setmetatable(thrift, {__index = _G}) --> perf hit for accessing global methods +--setfenv(1, thrift) + +package.cpath = package.cpath .. ';bin/?.so' -- TODO FIX +function ttype(obj) + if type(obj) == 'table' and + obj.__type and + type(obj.__type) == 'string' then + return obj.__type + end + return type(obj) +end + +function terror(e) + if e and e.__tostring then + error(e:__tostring()) + return + end + error(e) +end + +function ttable_size(t) + local count = 0 + for k, v in pairs(t) do + count = count + 1 + end + return count +end + +version = 1.0 + +TType = { + STOP = 0, + VOID = 1, + BOOL = 2, + BYTE = 3, + I08 = 3, + DOUBLE = 4, + I16 = 6, + I32 = 8, + I64 = 10, + STRING = 11, + UTF7 = 11, + STRUCT = 12, + MAP = 13, + SET = 14, + LIST = 15, + UTF8 = 16, + UTF16 = 17 +} + +TMessageType = { + CALL = 1, + REPLY = 2, + EXCEPTION = 3, + ONEWAY = 4 +} + +-- Recursive __index function to achieve inheritance +function __tobj_index(self, key) + local v = rawget(self, key) + if v ~= nil then + return v + end + + local p = rawget(self, '__parent') + if p then + return __tobj_index(p, key) + end + + return nil +end + +-- Basic Thrift-Lua Object +__TObject = { + __type = '__TObject', + __mt = { + __index = __tobj_index + } +} +function __TObject:new(init_obj) + local obj = {} + if ttype(obj) == 'table' then + obj = init_obj + end + + -- Use the __parent key and the __index function to achieve inheritance + obj.__parent = self + setmetatable(obj, __TObject.__mt) + return obj +end + +-- Return a string representation of any lua variable +function thrift_print_r(t) + local ret = '' + local ltype = type(t) + if (ltype == 'table') then + ret = ret .. '{ ' + for key,value in pairs(t) do + ret = ret .. tostring(key) .. '=' .. thrift_print_r(value) .. ' ' + end + ret = ret .. '}' + elseif ltype == 'string' then + ret = ret .. "'" .. tostring(t) .. "'" + else + ret = ret .. tostring(t) + end + return ret +end + +-- Basic Exception +TException = __TObject:new{ + message, + errorCode, + __type = 'TException' +} +function TException:__tostring() + if self.message then + return string.format('%s: %s', self.__type, self.message) + else + local message + if self.errorCode and self.__errorCodeToString then + message = string.format('%d: %s', self.errorCode, self:__errorCodeToString()) + else + message = thrift_print_r(self) + end + return string.format('%s:%s', self.__type, message) + end +end + +TApplicationException = TException:new{ + UNKNOWN = 0, + UNKNOWN_METHOD = 1, + INVALID_MESSAGE_TYPE = 2, + WRONG_METHOD_NAME = 3, + BAD_SEQUENCE_ID = 4, + MISSING_RESULT = 5, + INTERNAL_ERROR = 6, + PROTOCOL_ERROR = 7, + INVALID_TRANSFORM = 8, + INVALID_PROTOCOL = 9, + UNSUPPORTED_CLIENT_TYPE = 10, + errorCode = 0, + __type = 'TApplicationException' +} + +function TApplicationException:__errorCodeToString() + if self.errorCode == self.UNKNOWN_METHOD then + return 'Unknown method' + elseif self.errorCode == self.INVALID_MESSAGE_TYPE then + return 'Invalid message type' + elseif self.errorCode == self.WRONG_METHOD_NAME then + return 'Wrong method name' + elseif self.errorCode == self.BAD_SEQUENCE_ID then + return 'Bad sequence ID' + elseif self.errorCode == self.MISSING_RESULT then + return 'Missing result' + elseif self.errorCode == self.INTERNAL_ERROR then + return 'Internal error' + elseif self.errorCode == self.PROTOCOL_ERROR then + return 'Protocol error' + elseif self.errorCode == self.INVALID_TRANSFORM then + return 'Invalid transform' + elseif self.errorCode == self.INVALID_PROTOCOL then + return 'Invalid protocol' + elseif self.errorCode == self.UNSUPPORTED_CLIENT_TYPE then + return 'Unsupported client type' + else + return 'Default (unknown)' + end +end + +function TException:read(iprot) + iprot:readStructBegin() + while true do + local fname, ftype, fid = iprot:readFieldBegin() + if ftype == TType.STOP then + break + elseif fid == 1 then + if ftype == TType.STRING then + self.message = iprot:readString() + else + iprot:skip(ftype) + end + elseif fid == 2 then + if ftype == TType.I32 then + self.errorCode = iprot:readI32() + else + iprot:skip(ftype) + end + else + iprot:skip(ftype) + end + iprot:readFieldEnd() + end + iprot:readStructEnd() +end + +function TException:write(oprot) + oprot:writeStructBegin('TApplicationException') + if self.message then + oprot:writeFieldBegin('message', TType.STRING, 1) + oprot:writeString(self.message) + oprot:writeFieldEnd() + end + if self.errorCode then + oprot:writeFieldBegin('type', TType.I32, 2) + oprot:writeI32(self.errorCode) + oprot:writeFieldEnd() + end + oprot:writeFieldStop() + oprot:writeStructEnd() +end + +-- Basic Client (used in generated lua code) +__TClient = __TObject:new{ + __type = '__TClient', + _seqid = 0 +} +function __TClient:new(obj) + if ttype(obj) ~= 'table' then + error('TClient must be initialized with a table') + end + + -- Set iprot & oprot + if obj.protocol then + obj.iprot = obj.protocol + obj.oprot = obj.protocol + obj.protocol = nil + elseif not obj.iprot then + error('You must provide ' .. ttype(self) .. ' with an iprot') + end + if not obj.oprot then + obj.oprot = obj.iprot + end + + return __TObject.new(self, obj) +end + +function __TClient:close() + self.iprot.trans:close() + self.oprot.trans:close() +end + +-- Basic Processor (used in generated lua code) +__TProcessor = __TObject:new{ + __type = '__TProcessor' +} +function __TProcessor:new(obj) + if ttype(obj) ~= 'table' then + error('TProcessor must be initialized with a table') + end + + -- Ensure a handler is provided + if not obj.handler then + error('You must provide ' .. ttype(self) .. ' with a handler') + end + + return __TObject.new(self, obj) +end diff --git a/lib/lua/coding_standards.md b/lib/lua/coding_standards.md new file mode 100644 index 0000000..fa0390b --- /dev/null +++ b/lib/lua/coding_standards.md @@ -0,0 +1 @@ +Please follow [General Coding Standards](/doc/coding_standards.md) diff --git a/lib/lua/src/longnumberutils.c b/lib/lua/src/longnumberutils.c new file mode 100644 index 0000000..fbc6789 --- /dev/null +++ b/lib/lua/src/longnumberutils.c @@ -0,0 +1,47 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +#include +#include +#include +#include + +const char * LONG_NUM_TYPE = "__thrift_longnumber"; +int64_t lualongnumber_checklong(lua_State *L, int index) { + switch (lua_type(L, index)) { + case LUA_TNUMBER: + return (int64_t)lua_tonumber(L, index); + case LUA_TSTRING: + return atoll(lua_tostring(L, index)); + default: + return *((int64_t *)luaL_checkudata(L, index, LONG_NUM_TYPE)); + } +} + +// Creates a new longnumber and pushes it onto the statck +int64_t * lualongnumber_pushlong(lua_State *L, int64_t *val) { + int64_t *data = (int64_t *)lua_newuserdata(L, sizeof(int64_t)); // longnum + luaL_getmetatable(L, LONG_NUM_TYPE); // longnum, mt + lua_setmetatable(L, -2); // longnum + if (val) { + *data = *val; + } + return data; +} + diff --git a/lib/lua/src/luabitwise.c b/lib/lua/src/luabitwise.c new file mode 100644 index 0000000..2e07e17 --- /dev/null +++ b/lib/lua/src/luabitwise.c @@ -0,0 +1,83 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +#include +#include + +static int l_not(lua_State *L) { + int a = luaL_checkinteger(L, 1); + a = ~a; + lua_pushnumber(L, a); + return 1; +} + +static int l_xor(lua_State *L) { + int a = luaL_checkinteger(L, 1); + int b = luaL_checkinteger(L, 2); + a ^= b; + lua_pushnumber(L, a); + return 1; +} + +static int l_and(lua_State *L) { + int a = luaL_checkinteger(L, 1); + int b = luaL_checkinteger(L, 2); + a &= b; + lua_pushnumber(L, a); + return 1; +} + +static int l_or(lua_State *L) { + int a = luaL_checkinteger(L, 1); + int b = luaL_checkinteger(L, 2); + a |= b; + lua_pushnumber(L, a); + return 1; +} + +static int l_shiftr(lua_State *L) { + int a = luaL_checkinteger(L, 1); + int b = luaL_checkinteger(L, 2); + a = a >> b; + lua_pushnumber(L, a); + return 1; +} + +static int l_shiftl(lua_State *L) { + int a = luaL_checkinteger(L, 1); + int b = luaL_checkinteger(L, 2); + a = a << b; + lua_pushnumber(L, a); + return 1; +} + +static const struct luaL_Reg funcs[] = { + {"band", l_and}, + {"bor", l_or}, + {"bxor", l_xor}, + {"bnot", l_not}, + {"shiftl", l_shiftl}, + {"shiftr", l_shiftr}, + {NULL, NULL} +}; + +int luaopen_libluabitwise(lua_State *L) { + luaL_register(L, "libluabitwise", funcs); + return 1; +} diff --git a/lib/lua/src/luabpack.c b/lib/lua/src/luabpack.c new file mode 100644 index 0000000..077b6aa --- /dev/null +++ b/lib/lua/src/luabpack.c @@ -0,0 +1,308 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +#include +#include +#include +#include +#include + +extern int64_t lualongnumber_checklong(lua_State *L, int index); +extern int64_t lualongnumber_pushlong(lua_State *L, int64_t *val); + +// host order to network order (64-bit) +static int64_t T_htonll(uint64_t data) { + uint32_t d1 = htonl((uint32_t)data); + uint32_t d2 = htonl((uint32_t)(data >> 32)); + return ((uint64_t)d1 << 32) + (uint64_t)d2; +} + +// network order to host order (64-bit) +static int64_t T_ntohll(uint64_t data) { + uint32_t d1 = ntohl((uint32_t)data); + uint32_t d2 = ntohl((uint32_t)(data >> 32)); + return ((uint64_t)d1 << 32) + (uint64_t)d2; +} + +/** + * bpack(type, data) + * c - Signed Byte + * s - Signed Short + * i - Signed Int + * l - Signed Long + * d - Double + */ +static int l_bpack(lua_State *L) { + const char *code = luaL_checkstring(L, 1); + luaL_argcheck(L, code[1] == '\0', 0, "Format code must be one character."); + luaL_Buffer buf; + luaL_buffinit(L, &buf); + + switch (code[0]) { + case 'c': { + int8_t data = luaL_checknumber(L, 2); + luaL_addlstring(&buf, (void*)&data, sizeof(data)); + break; + } + case 's': { + int16_t data = luaL_checknumber(L, 2); + data = (int16_t)htons(data); + luaL_addlstring(&buf, (void*)&data, sizeof(data)); + break; + } + case 'i': { + int32_t data = luaL_checkinteger(L, 2); + data = (int32_t)htonl(data); + luaL_addlstring(&buf, (void*)&data, sizeof(data)); + break; + } + case 'l': { + int64_t data = lualongnumber_checklong(L, 2); + data = (int64_t)T_htonll(data); + luaL_addlstring(&buf, (void*)&data, sizeof(data)); + break; + } + case 'd': { + double data = luaL_checknumber(L, 2); + luaL_addlstring(&buf, (void*)&data, sizeof(data)); + break; + } + default: + luaL_argcheck(L, 0, 0, "Invalid format code."); + } + + luaL_pushresult(&buf); + return 1; +} + +/** + * bunpack(type, data) + * c - Signed Byte + * C - Unsigned Byte + * s - Signed Short + * i - Signed Int + * l - Signed Long + * d - Double + */ +static int l_bunpack(lua_State *L) { + const char *code = luaL_checkstring(L, 1); + luaL_argcheck(L, code[1] == '\0', 0, "Format code must be one character."); + const char *data = luaL_checkstring(L, 2); +#if LUA_VERSION_NUM >= 502 + size_t len = lua_rawlen(L, 2); +#else + size_t len = lua_objlen(L, 2); +#endif + + switch (code[0]) { + case 'c': { + int8_t val; + luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); + memcpy(&val, data, sizeof(val)); + lua_pushnumber(L, val); + break; + } + /** + * unpack unsigned Byte. + */ + case 'C': { + uint8_t val; + luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); + memcpy(&val, data, sizeof(val)); + lua_pushnumber(L, val); + break; + } + case 's': { + int16_t val; + luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); + memcpy(&val, data, sizeof(val)); + val = (int16_t)ntohs(val); + lua_pushnumber(L, val); + break; + } + case 'i': { + int32_t val; + luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); + memcpy(&val, data, sizeof(val)); + val = (int32_t)ntohl(val); + lua_pushnumber(L, val); + break; + } + case 'l': { + int64_t val; + luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); + memcpy(&val, data, sizeof(val)); + val = (int64_t)T_ntohll(val); + lualongnumber_pushlong(L, &val); + break; + } + case 'd': { + double val; + luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); + memcpy(&val, data, sizeof(val)); + lua_pushnumber(L, val); + break; + } + default: + luaL_argcheck(L, 0, 0, "Invalid format code."); + } + return 1; +} + +/** + * Convert l into a zigzag long. This allows negative numbers to be + * represented compactly as a varint. + */ +static int l_i64ToZigzag(lua_State *L) { + int64_t n = lualongnumber_checklong(L, 1); + int64_t result = (n << 1) ^ (n >> 63); + lualongnumber_pushlong(L, &result); + return 1; +} +/** + * Convert n into a zigzag int. This allows negative numbers to be + * represented compactly as a varint. + */ +static int l_i32ToZigzag(lua_State *L) { + int32_t n = luaL_checkinteger(L, 1); + uint32_t result = (uint32_t)(n << 1) ^ (n >> 31); + lua_pushnumber(L, result); + return 1; +} + +/** + * Convert from zigzag int to int. + */ +static int l_zigzagToI32(lua_State *L) { + uint32_t n = luaL_checkinteger(L, 1); + int32_t result = (int32_t)(n >> 1) ^ (uint32_t)(-(int32_t)(n & 1)); + lua_pushnumber(L, result); + return 1; +} + +/** + * Convert from zigzag long to long. + */ +static int l_zigzagToI64(lua_State *L) { + int64_t n = lualongnumber_checklong(L, 1); + int64_t result = (int64_t)(n >> 1) ^ (uint64_t)(-(int64_t)(n & 1)); + lualongnumber_pushlong(L, &result); + return 1; +} + +/** + * Convert an i32 to a varint. Results in 1-5 bytes on the buffer. + */ +static int l_toVarint32(lua_State *L) { + uint8_t buf[5]; + uint32_t n = luaL_checkinteger(L, 1); + uint32_t wsize = 0; + + while (1) { + if ((n & ~0x7F) == 0) { + buf[wsize++] = (int8_t)n; + break; + } else { + buf[wsize++] = (int8_t)((n & 0x7F) | 0x80); + n >>= 7; + } + } + lua_pushlstring(L, buf, wsize); + return 1; +} + +/** + * Convert an i64 to a varint. Results in 1-10 bytes on the buffer. + */ +static int l_toVarint64(lua_State *L) { + uint8_t data[10]; + uint64_t n = lualongnumber_checklong(L, 1); + uint32_t wsize = 0; + luaL_Buffer buf; + luaL_buffinit(L, &buf); + + while (1) { + if ((n & ~0x7FL) == 0) { + data[wsize++] = (int8_t)n; + break; + } else { + data[wsize++] = (int8_t)((n & 0x7F) | 0x80); + n >>= 7; + } + } + + luaL_addlstring(&buf, (void*)&data, wsize); + luaL_pushresult(&buf); + return 1; +} + +/** + * Convert a varint to i64. + */ +static int l_fromVarint64(lua_State *L) { + int64_t result; + uint8_t byte = luaL_checknumber(L, 1); + int32_t shift = luaL_checknumber(L, 2); + uint64_t n = (uint64_t)lualongnumber_checklong(L, 3); + n |= (uint64_t)(byte & 0x7f) << shift; + + if (!(byte & 0x80)) { + result = (int64_t)(n >> 1) ^ (uint64_t)(-(int64_t)(n & 1)); + lua_pushnumber(L, 0); + } else { + result = n; + lua_pushnumber(L, 1); + } + lualongnumber_pushlong(L, &result); + return 2; +} + +/** + * To pack message type of compact protocol. + */ +static int l_packMesgType(lua_State *L) { + int32_t version_n = luaL_checkinteger(L, 1); + int32_t version_mask = luaL_checkinteger(L, 2); + int32_t messagetype = luaL_checkinteger(L, 3); + int32_t type_shift_amount = luaL_checkinteger(L, 4); + int32_t type_mask = luaL_checkinteger(L, 5); + int32_t to_mesg_type = (version_n & version_mask) | + (((int32_t)messagetype << type_shift_amount) & type_mask); + lua_pushnumber(L, to_mesg_type); + return 1; +} + +static const struct luaL_Reg lua_bpack[] = { + {"bpack", l_bpack}, + {"bunpack", l_bunpack}, + {"i32ToZigzag", l_i32ToZigzag}, + {"i64ToZigzag", l_i64ToZigzag}, + {"zigzagToI32", l_zigzagToI32}, + {"zigzagToI64", l_zigzagToI64}, + {"toVarint32", l_toVarint32}, + {"toVarint64", l_toVarint64}, + {"fromVarint64", l_fromVarint64}, + {"packMesgType", l_packMesgType}, + {NULL, NULL} +}; + +int luaopen_libluabpack(lua_State *L) { + luaL_register(L, "libluabpack", lua_bpack); + return 1; +} diff --git a/lib/lua/src/lualongnumber.c b/lib/lua/src/lualongnumber.c new file mode 100644 index 0000000..9001e4a --- /dev/null +++ b/lib/lua/src/lualongnumber.c @@ -0,0 +1,228 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +#include +#include +#include +#include +#include +#include + +extern const char * LONG_NUM_TYPE; +extern int64_t lualongnumber_checklong(lua_State *L, int index); +extern int64_t lualongnumber_pushlong(lua_State *L, int64_t *val); + +//////////////////////////////////////////////////////////////////////////////// + +static void l_serialize(char *buf, int len, int64_t val) { + snprintf(buf, len, "%"PRId64, val); +} + +static int64_t l_deserialize(const char *buf) { + int64_t data; + int rv; + // Support hex prefixed with '0x' + if (strstr(buf, "0x") == buf) { + rv = sscanf(buf, "%"PRIx64, &data); + } else { + rv = sscanf(buf, "%"PRId64, &data); + } + if (rv == 1) { + return data; + } + return 0; // Failed +} + +//////////////////////////////////////////////////////////////////////////////// + +static int l_new(lua_State *L) { + int64_t val; + const char *str = NULL; + if (lua_type(L, 1) == LUA_TSTRING) { + str = lua_tostring(L, 1); + val = l_deserialize(str); + } else if (lua_type(L, 1) == LUA_TNUMBER) { + val = (int64_t)lua_tonumber(L, 1); + str = (const char *)1; + } + lualongnumber_pushlong(L, (str ? &val : NULL)); + return 1; +} + +//////////////////////////////////////////////////////////////////////////////// + +// a + b +static int l_add(lua_State *L) { + int64_t a, b, c; + a = lualongnumber_checklong(L, 1); + b = lualongnumber_checklong(L, 2); + c = a + b; + lualongnumber_pushlong(L, &c); + return 1; +} + +// a / b +static int l_div(lua_State *L) { + int64_t a, b, c; + a = lualongnumber_checklong(L, 1); + b = lualongnumber_checklong(L, 2); + c = a / b; + lualongnumber_pushlong(L, &c); + return 1; +} + +// a == b (both a and b are lualongnumber's) +static int l_eq(lua_State *L) { + int64_t a, b; + a = lualongnumber_checklong(L, 1); + b = lualongnumber_checklong(L, 2); + lua_pushboolean(L, (a == b ? 1 : 0)); + return 1; +} + +// garbage collection +static int l_gc(lua_State *L) { + lua_pushnil(L); + lua_setmetatable(L, 1); + return 0; +} + +// a < b +static int l_lt(lua_State *L) { + int64_t a, b; + a = lualongnumber_checklong(L, 1); + b = lualongnumber_checklong(L, 2); + lua_pushboolean(L, (a < b ? 1 : 0)); + return 1; +} + +// a <= b +static int l_le(lua_State *L) { + int64_t a, b; + a = lualongnumber_checklong(L, 1); + b = lualongnumber_checklong(L, 2); + lua_pushboolean(L, (a <= b ? 1 : 0)); + return 1; +} + +// a % b +static int l_mod(lua_State *L) { + int64_t a, b, c; + a = lualongnumber_checklong(L, 1); + b = lualongnumber_checklong(L, 2); + c = a % b; + lualongnumber_pushlong(L, &c); + return 1; +} + +// a * b +static int l_mul(lua_State *L) { + int64_t a, b, c; + a = lualongnumber_checklong(L, 1); + b = lualongnumber_checklong(L, 2); + c = a * b; + lualongnumber_pushlong(L, &c); + return 1; +} + +// a ^ b +static int l_pow(lua_State *L) { + long double a, b; + int64_t c; + a = (long double)lualongnumber_checklong(L, 1); + b = (long double)lualongnumber_checklong(L, 2); + c = (int64_t)pow(a, b); + lualongnumber_pushlong(L, &c); + return 1; +} + +// a - b +static int l_sub(lua_State *L) { + int64_t a, b, c; + a = lualongnumber_checklong(L, 1); + b = lualongnumber_checklong(L, 2); + c = a - b; + lualongnumber_pushlong(L, &c); + return 1; +} + +// tostring() +static int l_tostring(lua_State *L) { + int64_t a; + char str[256]; + l_serialize(str, 256, lualongnumber_checklong(L, 1)); + lua_pushstring(L, str); + return 1; +} + +// -a +static int l_unm(lua_State *L) { + int64_t a, c; + a = lualongnumber_checklong(L, 1); + c = -a; + lualongnumber_pushlong(L, &c); + return 1; +} + +//////////////////////////////////////////////////////////////////////////////// + +static const luaL_Reg methods[] = { + {"__add", l_add}, + {"__div", l_div}, + {"__eq", l_eq}, + {"__gc", l_gc}, + {"__lt", l_lt}, + {"__le", l_le}, + {"__mod", l_mod}, + {"__mul", l_mul}, + {"__pow", l_pow}, + {"__sub", l_sub}, + {"__tostring", l_tostring}, + {"__unm", l_unm}, + {NULL, NULL}, +}; + +static const luaL_Reg funcs[] = { + {"new", l_new}, + {NULL, NULL} +}; + +//////////////////////////////////////////////////////////////////////////////// + +static void set_methods(lua_State *L, + const char *metatablename, + const struct luaL_Reg *methods) { + luaL_getmetatable(L, metatablename); // mt + // No need for a __index table since everything is __* + for (; methods->name; methods++) { + lua_pushstring(L, methods->name); // mt, "name" + lua_pushcfunction(L, methods->func); // mt, "name", func + lua_rawset(L, -3); // mt + } + lua_pop(L, 1); +} + +LUALIB_API int luaopen_liblualongnumber(lua_State *L) { + luaL_newmetatable(L, LONG_NUM_TYPE); + lua_pop(L, 1); + set_methods(L, LONG_NUM_TYPE, methods); + + luaL_register(L, "liblualongnumber", funcs); + return 1; +} diff --git a/lib/lua/src/luasocket.c b/lib/lua/src/luasocket.c new file mode 100644 index 0000000..d483510 --- /dev/null +++ b/lib/lua/src/luasocket.c @@ -0,0 +1,380 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +#include +#include + +#include +#include "string.h" +#include "socket.h" + +//////////////////////////////////////////////////////////////////////////////// + +static const char *SOCKET_ANY = "__thrift_socket_any"; +static const char *SOCKET_CONN = "__thrift_socket_connected"; + +static const char *SOCKET_GENERIC = "__thrift_socket_generic"; +static const char *SOCKET_CLIENT = "__thrift_socket_client"; +static const char *SOCKET_SERVER = "__thrift_socket_server"; + +static const char *DEFAULT_HOST = "localhost"; + +typedef struct __t_tcp { + t_socket sock; + int timeout; // Milliseconds +} t_tcp; +typedef t_tcp *p_tcp; + +//////////////////////////////////////////////////////////////////////////////// +// Util + +static void throw_argerror(lua_State *L, int index, const char *expected) { + char msg[256]; + sprintf(msg, "%s expected, got %s", expected, luaL_typename(L, index)); + luaL_argerror(L, index, msg); +} + +static void *checkgroup(lua_State *L, int index, const char *groupname) { + if (!lua_getmetatable(L, index)) { + throw_argerror(L, index, groupname); + } + + lua_pushstring(L, groupname); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { + lua_pop(L, 2); + throw_argerror(L, index, groupname); + } else { + lua_pop(L, 2); + return lua_touserdata(L, index); + } + return NULL; // Not reachable +} + +static void *checktype(lua_State *L, int index, const char *typename) { + if (strcmp(typename, SOCKET_ANY) == 0 || + strcmp(typename, SOCKET_CONN) == 0) { + return checkgroup(L, index, typename); + } else { + return luaL_checkudata(L, index, typename); + } +} + +static void settype(lua_State *L, int index, const char *typename) { + luaL_getmetatable(L, typename); + lua_setmetatable(L, index); +} + +#define LUA_SUCCESS_RETURN(L) \ + lua_pushnumber(L, 1); \ + return 1 + +#define LUA_CHECK_RETURN(L, err) \ + if (err) { \ + lua_pushnil(L); \ + lua_pushstring(L, err); \ + return 2; \ + } \ + LUA_SUCCESS_RETURN(L) + +//////////////////////////////////////////////////////////////////////////////// + +static int l_socket_create(lua_State *L); +static int l_socket_destroy(lua_State *L); +static int l_socket_settimeout(lua_State *L); +static int l_socket_getsockinfo(lua_State *L); + +static int l_socket_accept(lua_State *L); +static int l_socket_listen(lua_State *L); + +static int l_socket_create_and_connect(lua_State *L); +static int l_socket_connect(lua_State *L); +static int l_socket_send(lua_State *L); +static int l_socket_receive(lua_State *L); + +//////////////////////////////////////////////////////////////////////////////// + +static const struct luaL_Reg methods_generic[] = { + {"destroy", l_socket_destroy}, + {"settimeout", l_socket_settimeout}, + {"getsockinfo", l_socket_getsockinfo}, + {"listen", l_socket_listen}, + {"connect", l_socket_connect}, + {NULL, NULL} +}; + +static const struct luaL_Reg methods_server[] = { + {"destroy", l_socket_destroy}, + {"getsockinfo", l_socket_getsockinfo}, + {"accept", l_socket_accept}, + {"send", l_socket_send}, + {"receive", l_socket_receive}, + {NULL, NULL} +}; + +static const struct luaL_Reg methods_client[] = { + {"destroy", l_socket_destroy}, + {"settimeout", l_socket_settimeout}, + {"getsockinfo", l_socket_getsockinfo}, + {"send", l_socket_send}, + {"receive", l_socket_receive}, + {NULL, NULL} +}; + +static const struct luaL_Reg funcs_luasocket[] = { + {"create", l_socket_create}, + {"create_and_connect", l_socket_create_and_connect}, + {NULL, NULL} +}; + +//////////////////////////////////////////////////////////////////////////////// + +// Check/enforce inheritance +static void add_to_group(lua_State *L, + const char *metatablename, + const char *groupname) { + luaL_getmetatable(L, metatablename); // mt + lua_pushstring(L, groupname); // mt, "name" + lua_pushboolean(L, 1); // mt, "name", true + lua_rawset(L, -3); // mt + lua_pop(L, 1); +} + +static void set_methods(lua_State *L, + const char *metatablename, + const struct luaL_Reg *methods) { + luaL_getmetatable(L, metatablename); // mt + // Create the __index table + lua_pushstring(L, "__index"); // mt, "__index" + lua_newtable(L); // mt, "__index", t + for (; methods->name; methods++) { + lua_pushstring(L, methods->name); // mt, "__index", t, "name" + lua_pushcfunction(L, methods->func); // mt, "__index", t, "name", func + lua_rawset(L, -3); // mt, "__index", t + } + lua_rawset(L, -3); // mt + lua_pop(L, 1); +} + +int luaopen_libluasocket(lua_State *L) { + luaL_newmetatable(L, SOCKET_GENERIC); + luaL_newmetatable(L, SOCKET_CLIENT); + luaL_newmetatable(L, SOCKET_SERVER); + lua_pop(L, 3); + add_to_group(L, SOCKET_GENERIC, SOCKET_ANY); + add_to_group(L, SOCKET_CLIENT, SOCKET_ANY); + add_to_group(L, SOCKET_SERVER, SOCKET_ANY); + add_to_group(L, SOCKET_CLIENT, SOCKET_CONN); + add_to_group(L, SOCKET_SERVER, SOCKET_CONN); + set_methods(L, SOCKET_GENERIC, methods_generic); + set_methods(L, SOCKET_CLIENT, methods_client); + set_methods(L, SOCKET_SERVER, methods_server); + + luaL_register(L, "luasocket", funcs_luasocket); + return 1; +} + +//////////////////////////////////////////////////////////////////////////////// +// General + +// sock,err create(bind_host, bind_port) +// sock,err create(bind_host) -> any port +// sock,err create() -> any port on localhost +static int l_socket_create(lua_State *L) { + const char *err; + t_socket sock; + const char *addr = lua_tostring(L, 1); + if (!addr) { + addr = DEFAULT_HOST; + } + unsigned short port = lua_tonumber(L, 2); + err = tcp_create(&sock); + if (!err) { + err = tcp_bind(&sock, addr, port); // bind on create + if (err) { + tcp_destroy(&sock); + } else { + p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); + settype(L, -2, SOCKET_GENERIC); + socket_setnonblocking(&sock); + tcp->sock = sock; + tcp->timeout = 0; + return 1; // Return userdata + } + } + LUA_CHECK_RETURN(L, err); +} + +// destroy() +static int l_socket_destroy(lua_State *L) { + p_tcp tcp = (p_tcp) checktype(L, 1, SOCKET_ANY); + const char *err = tcp_destroy(&tcp->sock); + LUA_CHECK_RETURN(L, err); +} + +// send(socket, data) +static int l_socket_send(lua_State *L) { + p_tcp self = (p_tcp) checktype(L, 1, SOCKET_CONN); + p_tcp tcp = (p_tcp) checktype(L, 2, SOCKET_CONN); + size_t len; + const char *data = luaL_checklstring(L, 3, &len); + const char *err = + tcp_send(&tcp->sock, data, len, tcp->timeout); + LUA_CHECK_RETURN(L, err); +} + +#define LUA_READ_STEP 8192 +static int l_socket_receive(lua_State *L) { + p_tcp self = (p_tcp) checktype(L, 1, SOCKET_CONN); + p_tcp handle = (p_tcp) checktype(L, 2, SOCKET_CONN); + size_t len = luaL_checknumber(L, 3); + char buf[LUA_READ_STEP]; + const char *err = NULL; + int received; + size_t got = 0, step = 0; + luaL_Buffer b; + + luaL_buffinit(L, &b); + do { + step = (LUA_READ_STEP < len - got ? LUA_READ_STEP : len - got); + err = tcp_raw_receive(&handle->sock, buf, step, self->timeout, &received); + if (err == NULL) { + luaL_addlstring(&b, buf, received); + got += received; + } + } while (err == NULL && got < len); + + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + luaL_pushresult(&b); + return 1; +} + +// settimeout(timeout) +static int l_socket_settimeout(lua_State *L) { + p_tcp self = (p_tcp) checktype(L, 1, SOCKET_ANY); + int timeout = luaL_checknumber(L, 2); + self->timeout = timeout; + LUA_SUCCESS_RETURN(L); +} + +// table getsockinfo() +static int l_socket_getsockinfo(lua_State *L) { + char buf[256]; + short port = 0; + p_tcp tcp = (p_tcp) checktype(L, 1, SOCKET_ANY); + if (socket_get_info(&tcp->sock, &port, buf, 256) == SUCCESS) { + lua_newtable(L); // t + lua_pushstring(L, "host"); // t, "host" + lua_pushstring(L, buf); // t, "host", buf + lua_rawset(L, -3); // t + lua_pushstring(L, "port"); // t, "port" + lua_pushnumber(L, port); // t, "port", port + lua_rawset(L, -3); // t + return 1; + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// Server + +// accept() +static int l_socket_accept(lua_State *L) { + const char *err; + p_tcp self = (p_tcp) checktype(L, 1, SOCKET_SERVER); + t_socket sock; + err = tcp_accept(&self->sock, &sock, self->timeout); + if (!err) { // Success + // Create a reference to the client + p_tcp client = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); + settype(L, 2, SOCKET_CLIENT); + socket_setnonblocking(&sock); + client->sock = sock; + client->timeout = self->timeout; + return 1; + } + LUA_CHECK_RETURN(L, err); +} + +static int l_socket_listen(lua_State *L) { + const char* err; + p_tcp tcp = (p_tcp) checktype(L, 1, SOCKET_GENERIC); + int backlog = 10; + err = tcp_listen(&tcp->sock, backlog); + if (!err) { + // Set the current as a server + settype(L, 1, SOCKET_SERVER); // Now a server + } + LUA_CHECK_RETURN(L, err); +} + +//////////////////////////////////////////////////////////////////////////////// +// Client + +// create_and_connect(host, port, timeout) +extern double __gettime(); +static int l_socket_create_and_connect(lua_State *L) { + const char* err = NULL; + double end; + t_socket sock; + const char *host = luaL_checkstring(L, 1); + unsigned short port = luaL_checknumber(L, 2); + int timeout = luaL_checknumber(L, 3); + + // Create and connect loop for timeout milliseconds + end = __gettime() + timeout/1000; + do { + // Create the socket + err = tcp_create(&sock); + if (!err) { + // Connect + err = tcp_connect(&sock, host, port, timeout); + if (err) { + tcp_destroy(&sock); + usleep(100000); // sleep for 100ms + } else { + p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); + settype(L, -2, SOCKET_CLIENT); + socket_setnonblocking(&sock); + tcp->sock = sock; + tcp->timeout = timeout; + return 1; // Return userdata + } + } + } while (err && __gettime() < end); + + LUA_CHECK_RETURN(L, err); +} + +// connect(host, port) +static int l_socket_connect(lua_State *L) { + const char *err; + p_tcp tcp = (p_tcp) checktype(L, 1, SOCKET_GENERIC); + const char *host = luaL_checkstring(L, 2); + unsigned short port = luaL_checknumber(L, 3); + err = tcp_connect(&tcp->sock, host, port, tcp->timeout); + if (!err) { + settype(L, 1, SOCKET_CLIENT); // Now a client + } + LUA_CHECK_RETURN(L, err); +} diff --git a/lib/lua/src/socket.h b/lib/lua/src/socket.h new file mode 100644 index 0000000..afb827e --- /dev/null +++ b/lib/lua/src/socket.h @@ -0,0 +1,78 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +#ifndef LUA_THRIFT_SOCKET_H +#define LUA_THRIFT_SOCKET_H + +#include + +#ifdef _WIN32 +// SOL +#else +typedef int t_socket; +typedef t_socket* p_socket; +#endif + +// Error Codes +enum { + SUCCESS = 0, + TIMEOUT = -1, + CLOSED = -2, +}; +typedef int T_ERRCODE; + +static const char * TIMEOUT_MSG = "Timeout"; +static const char * CLOSED_MSG = "Connection Closed"; + +typedef struct sockaddr t_sa; +typedef t_sa * p_sa; + +T_ERRCODE socket_create(p_socket sock, int domain, int type, int protocol); +T_ERRCODE socket_destroy(p_socket sock); +T_ERRCODE socket_bind(p_socket sock, p_sa addr, int addr_len); +T_ERRCODE socket_get_info(p_socket sock, short *port, char *buf, size_t len); +T_ERRCODE socket_send(p_socket sock, const char *data, size_t len, int timeout); +T_ERRCODE socket_recv(p_socket sock, char *data, size_t len, int timeout, + int *received); + +T_ERRCODE socket_setblocking(p_socket sock); +T_ERRCODE socket_setnonblocking(p_socket sock); + +T_ERRCODE socket_accept(p_socket sock, p_socket sibling, + p_sa addr, socklen_t *addr_len, int timeout); +T_ERRCODE socket_listen(p_socket sock, int backlog); + +T_ERRCODE socket_connect(p_socket sock, p_sa addr, int addr_len, int timeout); + +const char * tcp_create(p_socket sock); +const char * tcp_destroy(p_socket sock); +const char * tcp_bind(p_socket sock, const char *host, unsigned short port); +const char * tcp_send(p_socket sock, const char *data, size_t w_len, + int timeout); +const char * tcp_receive(p_socket sock, char *data, size_t r_len, int timeout); +const char * tcp_raw_receive(p_socket sock, char * data, size_t r_len, + int timeout, int *received); + +const char * tcp_listen(p_socket sock, int backlog); +const char * tcp_accept(p_socket sock, p_socket client, int timeout); + +const char * tcp_connect(p_socket sock, const char *host, unsigned short port, + int timeout); + +#endif diff --git a/lib/lua/src/usocket.c b/lib/lua/src/usocket.c new file mode 100644 index 0000000..1a1b549 --- /dev/null +++ b/lib/lua/src/usocket.c @@ -0,0 +1,376 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include // TODO REMOVE + +#include "socket.h" + +//////////////////////////////////////////////////////////////////////////////// +// Private + +// Num seconds since Jan 1 1970 (UTC) +#ifdef _WIN32 +// SOL +#else + double __gettime() { + struct timeval v; + gettimeofday(&v, (struct timezone*) NULL); + return v.tv_sec + v.tv_usec/1.0e6; + } +#endif + +#define WAIT_MODE_R 1 +#define WAIT_MODE_W 2 +#define WAIT_MODE_C (WAIT_MODE_R|WAIT_MODE_W) +T_ERRCODE socket_wait(p_socket sock, int mode, int timeout) { + int ret = 0; + fd_set rfds, wfds; + struct timeval tv; + double end, t; + if (!timeout) { + return TIMEOUT; + } + + end = __gettime() + timeout/1000; + do { + FD_ZERO(&rfds); + FD_ZERO(&wfds); + + // Specify what I/O operations we care about + if (mode & WAIT_MODE_R) { + FD_SET(*sock, &rfds); + } + if (mode & WAIT_MODE_W) { + FD_SET(*sock, &wfds); + } + + // Check for timeout + t = end - __gettime(); + if (t < 0.0) { + break; + } + + // Wait + tv.tv_sec = (int)t; + tv.tv_usec = (int)((t - tv.tv_sec) * 1.0e6); + ret = select(*sock+1, &rfds, &wfds, NULL, &tv); + } while (ret == -1 && errno == EINTR); + if (ret == -1) { + return errno; + } + + // Check for timeout + if (ret == 0) { + return TIMEOUT; + } + + // Verify that we can actually read from the remote host + if (mode & WAIT_MODE_C && FD_ISSET(*sock, &rfds) && + recv(*sock, (char*) &rfds, 0, 0) != 0) { + return errno; + } + + return SUCCESS; +} + +//////////////////////////////////////////////////////////////////////////////// +// General + +T_ERRCODE socket_create(p_socket sock, int domain, int type, int protocol) { + *sock = socket(domain, type, protocol); + if (*sock > 0) { + return SUCCESS; + } else { + return errno; + } +} + +T_ERRCODE socket_destroy(p_socket sock) { + // TODO Figure out if I should be free-ing this + if (*sock > 0) { + (void)socket_setblocking(sock); + close(*sock); + *sock = -1; + } + return SUCCESS; +} + +T_ERRCODE socket_bind(p_socket sock, p_sa addr, int addr_len) { + int ret = socket_setblocking(sock); + if (ret != SUCCESS) { + return ret; + } + if (bind(*sock, addr, addr_len)) { + ret = errno; + } + int ret2 = socket_setnonblocking(sock); + return ret == SUCCESS ? ret2 : ret; +} + +T_ERRCODE socket_get_info(p_socket sock, short *port, char *buf, size_t len) { + struct sockaddr_storage sa; + memset(&sa, 0, sizeof(sa)); + socklen_t addrlen = sizeof(sa); + int rc = getsockname(*sock, (struct sockaddr*)&sa, &addrlen); + if (!rc) { + if (sa.ss_family == AF_INET6) { + struct sockaddr_in6* sin = (struct sockaddr_in6*)(&sa); + if (!inet_ntop(AF_INET6, &sin->sin6_addr, buf, len)) { + return errno; + } + *port = ntohs(sin->sin6_port); + } else { + struct sockaddr_in* sin = (struct sockaddr_in*)(&sa); + if (!inet_ntop(AF_INET, &sin->sin_addr, buf, len)) { + return errno; + } + *port = ntohs(sin->sin_port); + } + return SUCCESS; + } + return errno; +} + +//////////////////////////////////////////////////////////////////////////////// +// Server + +T_ERRCODE socket_accept(p_socket sock, p_socket client, + p_sa addr, socklen_t *addrlen, int timeout) { + int err; + if (*sock < 0) { + return CLOSED; + } + do { + *client = accept(*sock, addr, addrlen); + if (*client > 0) { + return SUCCESS; + } + } while ((err = errno) == EINTR); + + if (err == EAGAIN || err == ECONNABORTED) { + return socket_wait(sock, WAIT_MODE_R, timeout); + } + + return err; +} + +T_ERRCODE socket_listen(p_socket sock, int backlog) { + int ret = socket_setblocking(sock); + if (ret != SUCCESS) { + return ret; + } + if (listen(*sock, backlog)) { + ret = errno; + } + int ret2 = socket_setnonblocking(sock); + return ret == SUCCESS ? ret2 : ret; +} + +//////////////////////////////////////////////////////////////////////////////// +// Client + +T_ERRCODE socket_connect(p_socket sock, p_sa addr, int addr_len, int timeout) { + int err; + if (*sock < 0) { + return CLOSED; + } + + do { + if (connect(*sock, addr, addr_len) == 0) { + return SUCCESS; + } + } while ((err = errno) == EINTR); + if (err != EINPROGRESS && err != EAGAIN) { + return err; + } + return socket_wait(sock, WAIT_MODE_C, timeout); +} + +T_ERRCODE socket_send( + p_socket sock, const char *data, size_t len, int timeout) { + int err, put = 0; + if (*sock < 0) { + return CLOSED; + } + do { + put = send(*sock, data, len, 0); + if (put > 0) { + return SUCCESS; + } + } while ((err = errno) == EINTR); + + if (err == EAGAIN) { + return socket_wait(sock, WAIT_MODE_W, timeout); + } + + return err; +} + +T_ERRCODE socket_recv( + p_socket sock, char *data, size_t len, int timeout, int *received) { + int err, got = 0; + if (*sock < 0) { + return CLOSED; + } + *received = 0; + + do { + got = recv(*sock, data, len, 0); + if (got > 0) { + *received = got; + return SUCCESS; + } + err = errno; + + // Connection has been closed by peer + if (got == 0) { + return CLOSED; + } + } while (err == EINTR); + + if (err == EAGAIN) { + return socket_wait(sock, WAIT_MODE_R, timeout); + } + + return err; +} + +//////////////////////////////////////////////////////////////////////////////// +// Util + +T_ERRCODE socket_setnonblocking(p_socket sock) { + int flags = fcntl(*sock, F_GETFL, 0); + flags |= O_NONBLOCK; + return fcntl(*sock, F_SETFL, flags) != -1 ? SUCCESS : errno; +} + +T_ERRCODE socket_setblocking(p_socket sock) { + int flags = fcntl(*sock, F_GETFL, 0); + flags &= (~(O_NONBLOCK)); + return fcntl(*sock, F_SETFL, flags) != -1 ? SUCCESS : errno; +} + +//////////////////////////////////////////////////////////////////////////////// +// TCP + +#define ERRORSTR_RETURN(err) \ + if (err == SUCCESS) { \ + return NULL; \ + } else if (err == TIMEOUT) { \ + return TIMEOUT_MSG; \ + } else if (err == CLOSED) { \ + return CLOSED_MSG; \ + } \ + return strerror(err) + +const char * tcp_create(p_socket sock) { + int err = socket_create(sock, AF_INET, SOCK_STREAM, 0); + ERRORSTR_RETURN(err); +} + +const char * tcp_destroy(p_socket sock) { + int err = socket_destroy(sock); + ERRORSTR_RETURN(err); +} + +const char * tcp_bind(p_socket sock, const char *host, unsigned short port) { + int err; + struct hostent *h; + struct sockaddr_in local; + memset(&local, 0, sizeof(local)); + local.sin_family = AF_INET; + local.sin_addr.s_addr = htonl(INADDR_ANY); + local.sin_port = htons(port); + if (strcmp(host, "*") && !inet_aton(host, &local.sin_addr)) { + h = gethostbyname(host); + if (!h) { + return hstrerror(h_errno); + } + memcpy(&local.sin_addr, + (struct in_addr *)h->h_addr_list[0], + sizeof(struct in_addr)); + } + err = socket_bind(sock, (p_sa) &local, sizeof(local)); + ERRORSTR_RETURN(err); +} + +const char * tcp_listen(p_socket sock, int backlog) { + int err = socket_listen(sock, backlog); + ERRORSTR_RETURN(err); +} + +const char * tcp_accept(p_socket sock, p_socket client, int timeout) { + int err = socket_accept(sock, client, NULL, NULL, timeout); + ERRORSTR_RETURN(err); +} + +const char * tcp_connect(p_socket sock, + const char *host, + unsigned short port, + int timeout) { + int err; + struct hostent *h; + struct sockaddr_in remote; + memset(&remote, 0, sizeof(remote)); + remote.sin_family = AF_INET; + remote.sin_port = htons(port); + if (strcmp(host, "*") && !inet_aton(host, &remote.sin_addr)) { + h = gethostbyname(host); + if (!h) { + return hstrerror(h_errno); + } + memcpy(&remote.sin_addr, + (struct in_addr *)h->h_addr_list[0], + sizeof(struct in_addr)); + } + err = socket_connect(sock, (p_sa) &remote, sizeof(remote), timeout); + ERRORSTR_RETURN(err); +} + +#define WRITE_STEP 8192 +const char * tcp_send( + p_socket sock, const char * data, size_t w_len, int timeout) { + int err; + size_t put = 0, step; + if (!w_len) { + return NULL; + } + + do { + step = (WRITE_STEP < w_len - put ? WRITE_STEP : w_len - put); + err = socket_send(sock, data + put, step, timeout); + put += step; + } while (err == SUCCESS && put < w_len); + ERRORSTR_RETURN(err); +} + +const char * tcp_raw_receive( + p_socket sock, char * data, size_t r_len, int timeout, int *received) { + int err = socket_recv(sock, data, r_len, timeout, received); + ERRORSTR_RETURN(err); +} diff --git a/lib/netcore/Makefile.am b/lib/netcore/Makefile.am new file mode 100644 index 0000000..facee11 --- /dev/null +++ b/lib/netcore/Makefile.am @@ -0,0 +1,105 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +SUBDIRS = . + +THRIFT = $(top_builddir)/compiler/cpp/thrift + +TESTDIR = Tests/Thrift.PublicInterfaces.Compile.Tests +GENDIR = $(TESTDIR)/gen-netcore + +THRIFTCODE = \ + Thrift/Thrift.csproj \ + Thrift/ITAsyncProcessor.cs \ + Thrift/ITProcessorFactory.cs \ + Thrift/SingletonTProcessorFactory.cs \ + Thrift/TApplicationException.cs \ + Thrift/TBaseClient.cs \ + Thrift/TException.cs \ + Thrift/TMultiplexedProcessor.cs \ + Thrift/Collections/TCollections.cs \ + Thrift/Collections/THashSet.cs \ + Thrift/Properties/AssemblyInfo.cs \ + Thrift/Protocols/ITProtocolFactory.cs \ + Thrift/Protocols/TAbstractBase.cs \ + Thrift/Protocols/TBase.cs \ + Thrift/Protocols/TBinaryProtocol.cs \ + Thrift/Protocols/TCompactProtocol.cs \ + Thrift/Protocols/TJSONProtocol.cs \ + Thrift/Protocols/TMultiplexedProtocol.cs \ + Thrift/Protocols/TProtocol.cs \ + Thrift/Protocols/TProtocolDecorator.cs \ + Thrift/Protocols/TProtocolException.cs \ + Thrift/Protocols/Entities/TField.cs \ + Thrift/Protocols/Entities/TList.cs \ + Thrift/Protocols/Entities/TMap.cs \ + Thrift/Protocols/Entities/TMessage.cs \ + Thrift/Protocols/Entities/TMessageType.cs \ + Thrift/Protocols/Entities/TSet.cs \ + Thrift/Protocols/Entities/TStruct.cs \ + Thrift/Protocols/Entities/TType.cs \ + Thrift/Protocols/Utilities/TBase64Utils.cs \ + Thrift/Protocols/Utilities/TProtocolUtil.cs \ + Thrift/Server/AsyncBaseServer.cs \ + Thrift/Server/TBaseServer.cs \ + Thrift/Server/TServerEventHandler.cs \ + Thrift/Transports/TClientTransport.cs \ + Thrift/Transports/TServerTransport.cs \ + Thrift/Transports/TTransportException.cs \ + Thrift/Transports/TTransportFactory.cs \ + Thrift/Transports/Client/TBufferedClientTransport.cs \ + Thrift/Transports/Client/TFramedClientTransport.cs \ + Thrift/Transports/Client/THttpClientTransport.cs \ + Thrift/Transports/Client/TMemoryBufferClientTransport.cs \ + Thrift/Transports/Client/TNamedPipeClientTransport.cs \ + Thrift/Transports/Client/TSocketClientTransport.cs \ + Thrift/Transports/Client/TStreamClientTransport.cs \ + Thrift/Transports/Client/TTlsSocketClientTransport.cs \ + Thrift/Transports/Server/THttpServerTransport.cs \ + Thrift/Transports/Server/TNamedPipeServerTransport.cs \ + Thrift/Transports/Server/TServerFramedTransport.cs \ + Thrift/Transports/Server/TServerSocketTransport.cs \ + Thrift/Transports/Server/TTlsServerSocketTransport.cs + +all-local: \ + Thrift.dll + +Thrift.dll: $(THRIFTCODE) + $(MKDIR_P) $(GENDIR) + $(THRIFT) -gen netcore:wcf -r -out $(GENDIR) $(TESTDIR)/CassandraTest.thrift + $(THRIFT) -gen netcore:wcf -r -out $(GENDIR) $(top_srcdir)/test/ThriftTest.thrift + $(THRIFT) -gen netcore:wcf -r -out $(GENDIR) $(top_srcdir)/contrib/fb303/if/fb303.thrift + $(DOTNETCORE) --info + $(DOTNETCORE) restore + $(DOTNETCORE) build + +clean-local: + $(RM) Thrift.dll + $(RM) -r $(GENDIR) + $(RM) -r Thrift/bin + $(RM) -r Thrift/obj + $(RM) -r Tests/Thrift.PublicInterfaces.Compile.Tests/bin + $(RM) -r Tests/Thrift.PublicInterfaces.Compile.Tests/obj + +EXTRA_DIST = \ + $(THRIFTCODE) \ + Thrift.sln \ + Tests \ + README.md + diff --git a/lib/netcore/Makefile.in b/lib/netcore/Makefile.in new file mode 100644 index 0000000..f999c98 --- /dev/null +++ b/lib/netcore/Makefile.in @@ -0,0 +1,885 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/netcore +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = $(top_builddir)/compiler/cpp/thrift +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . +TESTDIR = Tests/Thrift.PublicInterfaces.Compile.Tests +GENDIR = $(TESTDIR)/gen-netcore +THRIFTCODE = \ + Thrift/Thrift.csproj \ + Thrift/ITAsyncProcessor.cs \ + Thrift/ITProcessorFactory.cs \ + Thrift/SingletonTProcessorFactory.cs \ + Thrift/TApplicationException.cs \ + Thrift/TBaseClient.cs \ + Thrift/TException.cs \ + Thrift/TMultiplexedProcessor.cs \ + Thrift/Collections/TCollections.cs \ + Thrift/Collections/THashSet.cs \ + Thrift/Properties/AssemblyInfo.cs \ + Thrift/Protocols/ITProtocolFactory.cs \ + Thrift/Protocols/TAbstractBase.cs \ + Thrift/Protocols/TBase.cs \ + Thrift/Protocols/TBinaryProtocol.cs \ + Thrift/Protocols/TCompactProtocol.cs \ + Thrift/Protocols/TJSONProtocol.cs \ + Thrift/Protocols/TMultiplexedProtocol.cs \ + Thrift/Protocols/TProtocol.cs \ + Thrift/Protocols/TProtocolDecorator.cs \ + Thrift/Protocols/TProtocolException.cs \ + Thrift/Protocols/Entities/TField.cs \ + Thrift/Protocols/Entities/TList.cs \ + Thrift/Protocols/Entities/TMap.cs \ + Thrift/Protocols/Entities/TMessage.cs \ + Thrift/Protocols/Entities/TMessageType.cs \ + Thrift/Protocols/Entities/TSet.cs \ + Thrift/Protocols/Entities/TStruct.cs \ + Thrift/Protocols/Entities/TType.cs \ + Thrift/Protocols/Utilities/TBase64Utils.cs \ + Thrift/Protocols/Utilities/TProtocolUtil.cs \ + Thrift/Server/AsyncBaseServer.cs \ + Thrift/Server/TBaseServer.cs \ + Thrift/Server/TServerEventHandler.cs \ + Thrift/Transports/TClientTransport.cs \ + Thrift/Transports/TServerTransport.cs \ + Thrift/Transports/TTransportException.cs \ + Thrift/Transports/TTransportFactory.cs \ + Thrift/Transports/Client/TBufferedClientTransport.cs \ + Thrift/Transports/Client/TFramedClientTransport.cs \ + Thrift/Transports/Client/THttpClientTransport.cs \ + Thrift/Transports/Client/TMemoryBufferClientTransport.cs \ + Thrift/Transports/Client/TNamedPipeClientTransport.cs \ + Thrift/Transports/Client/TSocketClientTransport.cs \ + Thrift/Transports/Client/TStreamClientTransport.cs \ + Thrift/Transports/Client/TTlsSocketClientTransport.cs \ + Thrift/Transports/Server/THttpServerTransport.cs \ + Thrift/Transports/Server/TNamedPipeServerTransport.cs \ + Thrift/Transports/Server/TServerFramedTransport.cs \ + Thrift/Transports/Server/TServerSocketTransport.cs \ + Thrift/Transports/Server/TTlsServerSocketTransport.cs + +EXTRA_DIST = \ + $(THRIFTCODE) \ + Thrift.sln \ + Tests \ + README.md + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/netcore/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/netcore/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile all-local +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +style: style-recursive + +style-am: style-local + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \ + check check-am clean clean-generic clean-libtool clean-local \ + cscopelist-am ctags ctags-am distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +all-local: \ + Thrift.dll + +Thrift.dll: $(THRIFTCODE) + $(MKDIR_P) $(GENDIR) + $(THRIFT) -gen netcore:wcf -r -out $(GENDIR) $(TESTDIR)/CassandraTest.thrift + $(THRIFT) -gen netcore:wcf -r -out $(GENDIR) $(top_srcdir)/test/ThriftTest.thrift + $(THRIFT) -gen netcore:wcf -r -out $(GENDIR) $(top_srcdir)/contrib/fb303/if/fb303.thrift + $(DOTNETCORE) --info + $(DOTNETCORE) restore + $(DOTNETCORE) build + +clean-local: + $(RM) Thrift.dll + $(RM) -r $(GENDIR) + $(RM) -r Thrift/bin + $(RM) -r Thrift/obj + $(RM) -r Tests/Thrift.PublicInterfaces.Compile.Tests/bin + $(RM) -r Tests/Thrift.PublicInterfaces.Compile.Tests/obj + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/netcore/README.md b/lib/netcore/README.md new file mode 100644 index 0000000..39492f3 --- /dev/null +++ b/lib/netcore/README.md @@ -0,0 +1,21 @@ +# Apache Thrift netcore + +Thrift client library ported to Microsoft .Net Core + +# Content +- Tests/Thrift.PublicInterfaces.Compile.Tests - project for checking public interfaces during adding changes to Thrift library +- Thrift - Thrift library + +# Reused components +- .NET Standard 1.6 (SDK 2.0.0) + +# How to build on Windows +- Open the Thrift.sln project with Visual Studio and build. + +# How to build on Unix +- Ensure you have .NET Core 2.0.0 SDK installed or use the Ubuntu Xenial docker image +- Follow common build practice for Thrift: bootstrap, configure, and make + +# Known issues +- In trace logging mode you can see some not important internal exceptions + diff --git a/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/CassandraTest.thrift b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/CassandraTest.thrift new file mode 100644 index 0000000..4b92720 --- /dev/null +++ b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/CassandraTest.thrift @@ -0,0 +1,705 @@ +#!/usr/local/bin/thrift --java --php --py +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# *** PLEASE REMEMBER TO EDIT THE VERSION CONSTANT WHEN MAKING CHANGES *** +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# +# Interface definition for Cassandra Service +# + +namespace netcore Apache.Cassandra.Test + +# Thrift.rb has a bug where top-level modules that include modules +# with the same name are not properly referenced, so we can't do +# Cassandra::Cassandra::Client. +namespace rb CassandraThrift + +# The API version (NOT the product version), composed as a dot delimited +# string with major, minor, and patch level components. +# +# - Major: Incremented for backward incompatible changes. An example would +# be changes to the number or disposition of method arguments. +# - Minor: Incremented for backward compatible changes. An example would +# be the addition of a new (optional) method. +# - Patch: Incremented for bug fixes. The patch level should be increased +# for every edit that doesn't result in a change to major/minor. +# +# See the Semantic Versioning Specification (SemVer) http://semver.org. +const string VERSION = "19.24.0" + + +# +# data structures +# + +/** Basic unit of data within a ColumnFamily. + * @param name, the name by which this column is set and retrieved. Maximum 64KB long. + * @param value. The data associated with the name. Maximum 2GB long, but in practice you should limit it to small numbers of MB (since Thrift must read the full value into memory to operate on it). + * @param timestamp. The timestamp is used for conflict detection/resolution when two columns with same name need to be compared. + * @param ttl. An optional, positive delay (in seconds) after which the column will be automatically deleted. + */ +struct Column { + 1: required binary name, + 2: optional binary value, + 3: optional i64 timestamp, + 4: optional i32 ttl, +} + +/** A named list of columns. + * @param name. see Column.name. + * @param columns. A collection of standard Columns. The columns within a super column are defined in an adhoc manner. + * Columns within a super column do not have to have matching structures (similarly named child columns). + */ +struct SuperColumn { + 1: required binary name, + 2: required list columns, +} + +struct CounterColumn { + 1: required binary name, + 2: required i64 value +} + +struct CounterSuperColumn { + 1: required binary name, + 2: required list columns +} + +/** + Methods for fetching rows/records from Cassandra will return either a single instance of ColumnOrSuperColumn or a list + of ColumnOrSuperColumns (get_slice()). If you're looking up a SuperColumn (or list of SuperColumns) then the resulting + instances of ColumnOrSuperColumn will have the requested SuperColumn in the attribute super_column. For queries resulting + in Columns, those values will be in the attribute column. This change was made between 0.3 and 0.4 to standardize on + single query methods that may return either a SuperColumn or Column. + + If the query was on a counter column family, you will either get a counter_column (instead of a column) or a + counter_super_column (instead of a super_column) + + @param column. The Column returned by get() or get_slice(). + @param super_column. The SuperColumn returned by get() or get_slice(). + @param counter_column. The Counterolumn returned by get() or get_slice(). + @param counter_super_column. The CounterSuperColumn returned by get() or get_slice(). + */ +struct ColumnOrSuperColumn { + 1: optional Column column, + 2: optional SuperColumn super_column, + 3: optional CounterColumn counter_column, + 4: optional CounterSuperColumn counter_super_column +} + + +# +# Exceptions +# (note that internal server errors will raise a TApplicationException, courtesy of Thrift) +# + +/** A specific column was requested that does not exist. */ +exception NotFoundException { +} + +/** Invalid request could mean keyspace or column family does not exist, required parameters are missing, or a parameter is malformed. + why contains an associated error message. +*/ +exception InvalidRequestException { + 1: required string why +} + +/** Not all the replicas required could be created and/or read. */ +exception UnavailableException { +} + +/** RPC timeout was exceeded. either a node failed mid-operation, or load was too high, or the requested op was too large. */ +exception TimedOutException { +} + +/** invalid authentication request (invalid keyspace, user does not exist, or credentials invalid) */ +exception AuthenticationException { + 1: required string why +} + +/** invalid authorization request (user does not have access to keyspace) */ +exception AuthorizationException { + 1: required string why +} + +/** schemas are not in agreement across all nodes */ +exception SchemaDisagreementException { +} + + +# +# service api +# +/** + * The ConsistencyLevel is an enum that controls both read and write + * behavior based on the ReplicationFactor of the keyspace. The + * different consistency levels have different meanings, depending on + * if you're doing a write or read operation. + * + * If W + R > ReplicationFactor, where W is the number of nodes to + * block for on write, and R the number to block for on reads, you + * will have strongly consistent behavior; that is, readers will + * always see the most recent write. Of these, the most interesting is + * to do QUORUM reads and writes, which gives you consistency while + * still allowing availability in the face of node failures up to half + * of . Of course if latency is more important than + * consistency then you can use lower values for either or both. + * + * Some ConsistencyLevels (ONE, TWO, THREE) refer to a specific number + * of replicas rather than a logical concept that adjusts + * automatically with the replication factor. Of these, only ONE is + * commonly used; TWO and (even more rarely) THREE are only useful + * when you care more about guaranteeing a certain level of + * durability, than consistency. + * + * Write consistency levels make the following guarantees before reporting success to the client: + * ANY Ensure that the write has been written once somewhere, including possibly being hinted in a non-target node. + * ONE Ensure that the write has been written to at least 1 node's commit log and memory table + * TWO Ensure that the write has been written to at least 2 node's commit log and memory table + * THREE Ensure that the write has been written to at least 3 node's commit log and memory table + * QUORUM Ensure that the write has been written to / 2 + 1 nodes + * LOCAL_QUORUM Ensure that the write has been written to / 2 + 1 nodes, within the local datacenter (requires NetworkTopologyStrategy) + * EACH_QUORUM Ensure that the write has been written to / 2 + 1 nodes in each datacenter (requires NetworkTopologyStrategy) + * ALL Ensure that the write is written to <ReplicationFactor> nodes before responding to the client. + * + * Read consistency levels make the following guarantees before returning successful results to the client: + * ANY Not supported. You probably want ONE instead. + * ONE Returns the record obtained from a single replica. + * TWO Returns the record with the most recent timestamp once two replicas have replied. + * THREE Returns the record with the most recent timestamp once three replicas have replied. + * QUORUM Returns the record with the most recent timestamp once a majority of replicas have replied. + * LOCAL_QUORUM Returns the record with the most recent timestamp once a majority of replicas within the local datacenter have replied. + * EACH_QUORUM Returns the record with the most recent timestamp once a majority of replicas within each datacenter have replied. + * ALL Returns the record with the most recent timestamp once all replicas have replied (implies no replica may be down).. +*/ +enum ConsistencyLevel { + ONE = 1, + QUORUM = 2, + LOCAL_QUORUM = 3, + EACH_QUORUM = 4, + ALL = 5, + ANY = 6, + TWO = 7, + THREE = 8, +} + +/** + ColumnParent is used when selecting groups of columns from the same ColumnFamily. In directory structure terms, imagine + ColumnParent as ColumnPath + '/../'. + + See also ColumnPath + */ +struct ColumnParent { + 3: required string column_family, + 4: optional binary super_column, +} + +/** The ColumnPath is the path to a single column in Cassandra. It might make sense to think of ColumnPath and + * ColumnParent in terms of a directory structure. + * + * ColumnPath is used to looking up a single column. + * + * @param column_family. The name of the CF of the column being looked up. + * @param super_column. The super column name. + * @param column. The column name. + */ +struct ColumnPath { + 3: required string column_family, + 4: optional binary super_column, + 5: optional binary column, +} + +/** + A slice range is a structure that stores basic range, ordering and limit information for a query that will return + multiple columns. It could be thought of as Cassandra's version of LIMIT and ORDER BY + + @param start. The column name to start the slice with. This attribute is not required, though there is no default value, + and can be safely set to '', i.e., an empty byte array, to start with the first column name. Otherwise, it + must a valid value under the rules of the Comparator defined for the given ColumnFamily. + @param finish. The column name to stop the slice at. This attribute is not required, though there is no default value, + and can be safely set to an empty byte array to not stop until 'count' results are seen. Otherwise, it + must also be a valid value to the ColumnFamily Comparator. + @param reversed. Whether the results should be ordered in reversed order. Similar to ORDER BY blah DESC in SQL. + @param count. How many columns to return. Similar to LIMIT in SQL. May be arbitrarily large, but Thrift will + materialize the whole result into memory before returning it to the client, so be aware that you may + be better served by iterating through slices by passing the last value of one call in as the 'start' + of the next instead of increasing 'count' arbitrarily large. + */ +struct SliceRange { + 1: required binary start, + 2: required binary finish, + 3: required bool reversed=0, + 4: required i32 count=100, +} + +/** + A SlicePredicate is similar to a mathematic predicate (see http://en.wikipedia.org/wiki/Predicate_(mathematical_logic)), + which is described as "a property that the elements of a set have in common." + + SlicePredicate's in Cassandra are described with either a list of column_names or a SliceRange. If column_names is + specified, slice_range is ignored. + + @param column_name. A list of column names to retrieve. This can be used similar to Memcached's "multi-get" feature + to fetch N known column names. For instance, if you know you wish to fetch columns 'Joe', 'Jack', + and 'Jim' you can pass those column names as a list to fetch all three at once. + @param slice_range. A SliceRange describing how to range, order, and/or limit the slice. + */ +struct SlicePredicate { + 1: optional list column_names, + 2: optional SliceRange slice_range, +} + +enum IndexOperator { + EQ, + GTE, + GT, + LTE, + LT +} + +struct IndexExpression { + 1: required binary column_name, + 2: required IndexOperator op, + 3: required binary value, +} + +struct IndexClause { + 1: required list expressions + 2: required binary start_key, + 3: required i32 count=100, +} + +/** +The semantics of start keys and tokens are slightly different. +Keys are start-inclusive; tokens are start-exclusive. Token +ranges may also wrap -- that is, the end token may be less +than the start one. Thus, a range from keyX to keyX is a +one-element range, but a range from tokenY to tokenY is the +full ring. +*/ +struct KeyRange { + 1: optional binary start_key, + 2: optional binary end_key, + 3: optional string start_token, + 4: optional string end_token, + 5: required i32 count=100 +} + +/** + A KeySlice is key followed by the data it maps to. A collection of KeySlice is returned by the get_range_slice operation. + + @param key. a row key + @param columns. List of data represented by the key. Typically, the list is pared down to only the columns specified by + a SlicePredicate. + */ +struct KeySlice { + 1: required binary key, + 2: required list columns, +} + +struct KeyCount { + 1: required binary key, + 2: required i32 count +} + +/** + * Note that the timestamp is only optional in case of counter deletion. + */ +struct Deletion { + 1: optional i64 timestamp, + 2: optional binary super_column, + 3: optional SlicePredicate predicate, +} + +/** + A Mutation is either an insert (represented by filling column_or_supercolumn) or a deletion (represented by filling the deletion attribute). + @param column_or_supercolumn. An insert to a column or supercolumn (possibly counter column or supercolumn) + @param deletion. A deletion of a column or supercolumn +*/ +struct Mutation { + 1: optional ColumnOrSuperColumn column_or_supercolumn, + 2: optional Deletion deletion, +} + +struct EndpointDetails { + 1: string host, + 2: string datacenter, + 3: optional string rack +} + +/** + A TokenRange describes part of the Cassandra ring, it is a mapping from a range to + endpoints responsible for that range. + @param start_token The first token in the range + @param end_token The last token in the range + @param endpoints The endpoints responsible for the range (listed by their configured listen_address) + @param rpc_endpoints The endpoints responsible for the range (listed by their configured rpc_address) +*/ +struct TokenRange { + 1: required string start_token, + 2: required string end_token, + 3: required list endpoints, + 4: optional list rpc_endpoints + 5: optional list endpoint_details, +} + +/** + Authentication requests can contain any data, dependent on the IAuthenticator used +*/ +struct AuthenticationRequest { + 1: required map credentials +} + +enum IndexType { + KEYS, + CUSTOM +} + +/* describes a column in a column family. */ +struct ColumnDef { + 1: required binary name, + 2: required string validation_class, + 3: optional IndexType index_type, + 4: optional string index_name, + 5: optional map index_options +} + + +/* describes a column family. */ +struct CfDef { + 1: required string keyspace, + 2: required string name, + 3: optional string column_type="Standard", + 5: optional string comparator_type="BytesType", + 6: optional string subcomparator_type, + 8: optional string comment, + 12: optional double read_repair_chance=1.0, + 13: optional list column_metadata, + 14: optional i32 gc_grace_seconds, + 15: optional string default_validation_class, + 16: optional i32 id, + 17: optional i32 min_compaction_threshold, + 18: optional i32 max_compaction_threshold, + 24: optional bool replicate_on_write, + 25: optional double merge_shards_chance, + 26: optional string key_validation_class, + 28: optional binary key_alias, + 29: optional string compaction_strategy, + 30: optional map compaction_strategy_options, + 32: optional map compression_options, + 33: optional double bloom_filter_fp_chance, +} + +/* describes a keyspace. */ +struct KsDef { + 1: required string name, + 2: required string strategy_class, + 3: optional map strategy_options, + + /** @deprecated */ + 4: optional i32 replication_factor, + + 5: required list cf_defs, + 6: optional bool durable_writes=1, +} + +/** CQL query compression */ +enum Compression { + GZIP = 1, + NONE = 2 +} + +enum CqlResultType { + ROWS = 1, + VOID = 2, + INT = 3 +} + +/** Row returned from a CQL query */ +struct CqlRow { + 1: required binary key, + 2: required list columns +} + +struct CqlMetadata { + 1: required map name_types, + 2: required map value_types, + 3: required string default_name_type, + 4: required string default_value_type +} + +struct CqlResult { + 1: required CqlResultType type, + 2: optional list rows, + 3: optional i32 num, + 4: optional CqlMetadata schema +} + +struct CqlPreparedResult { + 1: required i32 itemId, + 2: required i32 count +} + + +service Cassandra { + # auth methods + void login(1: required AuthenticationRequest auth_request) throws (1:AuthenticationException authnx, 2:AuthorizationException authzx), + + # set keyspace + void set_keyspace(1: required string keyspace) throws (1:InvalidRequestException ire), + + # retrieval methods + + /** + Get the Column or SuperColumn at the given column_path. If no value is present, NotFoundException is thrown. (This is + the only method that can throw an exception under non-failure conditions.) + */ + ColumnOrSuperColumn get(1:required binary key, + 2:required ColumnPath column_path, + 3:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) + throws (1:InvalidRequestException ire, 2:NotFoundException nfe, 3:UnavailableException ue, 4:TimedOutException te), + + /** + Get the group of columns contained by column_parent (either a ColumnFamily name or a ColumnFamily/SuperColumn name + pair) specified by the given SlicePredicate. If no matching values are found, an empty list is returned. + */ + list get_slice(1:required binary key, + 2:required ColumnParent column_parent, + 3:required SlicePredicate predicate, + 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) + throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), + + /** + returns the number of columns matching predicate for a particular key, + ColumnFamily and optionally SuperColumn. + */ + i32 get_count(1:required binary key, + 2:required ColumnParent column_parent, + 3:required SlicePredicate predicate, + 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) + throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), + + /** + Performs a get_slice for column_parent and predicate for the given keys in parallel. + */ + map> multiget_slice(1:required list keys, + 2:required ColumnParent column_parent, + 3:required SlicePredicate predicate, + 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) + throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), + + /** + Perform a get_count in parallel on the given list keys. The return value maps keys to the count found. + */ + map multiget_count(1:required list keys, + 2:required ColumnParent column_parent, + 3:required SlicePredicate predicate, + 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) + throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), + + /** + returns a subset of columns for a contiguous range of keys. + */ + list get_range_slices(1:required ColumnParent column_parent, + 2:required SlicePredicate predicate, + 3:required KeyRange range, + 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) + throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), + + /** Returns the subset of columns specified in SlicePredicate for the rows matching the IndexClause */ + list get_indexed_slices(1:required ColumnParent column_parent, + 2:required IndexClause index_clause, + 3:required SlicePredicate column_predicate, + 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) + throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), + + # modification methods + + /** + * Insert a Column at the given column_parent.column_family and optional column_parent.super_column. + */ + void insert(1:required binary key, + 2:required ColumnParent column_parent, + 3:required Column column, + 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) + throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), + + /** + * Increment or decrement a counter. + */ + void add(1:required binary key, + 2:required ColumnParent column_parent, + 3:required CounterColumn column, + 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) + throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), + + /** + Remove data from the row specified by key at the granularity specified by column_path, and the given timestamp. Note + that all the values in column_path besides column_path.column_family are truly optional: you can remove the entire + row by just specifying the ColumnFamily, or you can remove a SuperColumn or a single Column by specifying those levels too. + */ + void remove(1:required binary key, + 2:required ColumnPath column_path, + 3:required i64 timestamp, + 4:ConsistencyLevel consistency_level=ConsistencyLevel.ONE) + throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), + + /** + * Remove a counter at the specified location. + * Note that counters have limited support for deletes: if you remove a counter, you must wait to issue any following update + * until the delete has reached all the nodes and all of them have been fully compacted. + */ + void remove_counter(1:required binary key, + 2:required ColumnPath path, + 3:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) + throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), + + + /** + Mutate many columns or super columns for many row keys. See also: Mutation. + + mutation_map maps key to column family to a list of Mutation objects to take place at that scope. + **/ + void batch_mutate(1:required map>> mutation_map, + 2:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) + throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), + + /** + Truncate will mark and entire column family as deleted. + From the user's perspective a successful call to truncate will result complete data deletion from cfname. + Internally, however, disk space will not be immediatily released, as with all deletes in cassandra, this one + only marks the data as deleted. + The operation succeeds only if all hosts in the cluster at available and will throw an UnavailableException if + some hosts are down. + */ + void truncate(1:required string cfname) + throws (1: InvalidRequestException ire, 2: UnavailableException ue, 3: TimedOutException te), + + + + // Meta-APIs -- APIs to get information about the node or cluster, + // rather than user data. The nodeprobe program provides usage examples. + + /** + * for each schema version present in the cluster, returns a list of nodes at that version. + * hosts that do not respond will be under the key DatabaseDescriptor.INITIAL_VERSION. + * the cluster is all on the same version if the size of the map is 1. + */ + map> describe_schema_versions() + throws (1: InvalidRequestException ire), + + /** list the defined keyspaces in this cluster */ + list describe_keyspaces() + throws (1:InvalidRequestException ire), + + /** get the cluster name */ + string describe_cluster_name(), + + /** get the thrift api version */ + string describe_version(), + + /** get the token ring: a map of ranges to host addresses, + represented as a set of TokenRange instead of a map from range + to list of endpoints, because you can't use Thrift structs as + map keys: + https://issues.apache.org/jira/browse/THRIFT-162 + + for the same reason, we can't return a set here, even though + order is neither important nor predictable. */ + list describe_ring(1:required string keyspace) + throws (1:InvalidRequestException ire), + + /** returns the partitioner used by this cluster */ + string describe_partitioner(), + + /** returns the snitch used by this cluster */ + string describe_snitch(), + + /** describe specified keyspace */ + KsDef describe_keyspace(1:required string keyspace) + throws (1:NotFoundException nfe, 2:InvalidRequestException ire), + + /** experimental API for hadoop/parallel query support. + may change violently and without warning. + + returns list of token strings such that first subrange is (list[0], list[1]], + next is (list[1], list[2]], etc. */ + list describe_splits(1:required string cfName, + 2:required string start_token, + 3:required string end_token, + 4:required i32 keys_per_split) + throws (1:InvalidRequestException ire), + + /** adds a column family. returns the new schema id. */ + string system_add_column_family(1:required CfDef cf_def) + throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde), + + /** drops a column family. returns the new schema id. */ + string system_drop_column_family(1:required string column_family) + throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde), + + /** adds a keyspace and any column families that are part of it. returns the new schema id. */ + string system_add_keyspace(1:required KsDef ks_def) + throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde), + + /** drops a keyspace and any column families that are part of it. returns the new schema id. */ + string system_drop_keyspace(1:required string keyspace) + throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde), + + /** updates properties of a keyspace. returns the new schema id. */ + string system_update_keyspace(1:required KsDef ks_def) + throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde), + + /** updates properties of a column family. returns the new schema id. */ + string system_update_column_family(1:required CfDef cf_def) + throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde), + + /** + * Executes a CQL (Cassandra Query Language) statement and returns a + * CqlResult containing the results. + */ + CqlResult execute_cql_query(1:required binary query, 2:required Compression compression) + throws (1:InvalidRequestException ire, + 2:UnavailableException ue, + 3:TimedOutException te, + 4:SchemaDisagreementException sde) + + + /** + * Prepare a CQL (Cassandra Query Language) statement by compiling and returning + * - the type of CQL statement + * - an id token of the compiled CQL stored on the server side. + * - a count of the discovered bound markers in the statement + */ + CqlPreparedResult prepare_cql_query(1:required binary query, 2:required Compression compression) + throws (1:InvalidRequestException ire) + + + /** + * Executes a prepared CQL (Cassandra Query Language) statement by passing an id token and a list of variables + * to bind and returns a CqlResult containing the results. + */ + CqlResult execute_prepared_cql_query(1:required i32 itemId, 2:required list values) + throws (1:InvalidRequestException ire, + 2:UnavailableException ue, + 3:TimedOutException te, + 4:SchemaDisagreementException sde) + + +} diff --git a/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Properties/AssemblyInfo.cs b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0bb460f --- /dev/null +++ b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("The Apache Software Foundation")] +[assembly: AssemblyProduct("Thrift")] +[assembly: AssemblyCopyright("The Apache Software Foundation")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. + +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM + +[assembly: Guid("d0d3706b-fed5-4cf5-b984-04f448de9d7b")] \ No newline at end of file diff --git a/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj new file mode 100644 index 0000000..f551116 --- /dev/null +++ b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj @@ -0,0 +1,21 @@ + + + + netcoreapp2.0 + Thrift.PublicInterfaces.Compile.Tests + Thrift.PublicInterfaces.Compile.Tests + false + false + false + false + + + + + + + + + + + diff --git a/lib/netcore/Thrift.sln b/lib/netcore/Thrift.sln new file mode 100644 index 0000000..a730269 --- /dev/null +++ b/lib/netcore/Thrift.sln @@ -0,0 +1,55 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26730.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{F51FC4DA-CAC0-48B1-A069-B1712BCAA5BE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.PublicInterfaces.Compile.Tests", "Tests\Thrift.PublicInterfaces.Compile.Tests\Thrift.PublicInterfaces.Compile.Tests.csproj", "{0676962B-98C2-49EC-B4C4-7A0451D0640B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift", "Thrift\Thrift.csproj", "{D85F572F-7D80-40A4-9A9B-2731ED187C24}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0676962B-98C2-49EC-B4C4-7A0451D0640B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0676962B-98C2-49EC-B4C4-7A0451D0640B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0676962B-98C2-49EC-B4C4-7A0451D0640B}.Debug|x64.ActiveCfg = Debug|Any CPU + {0676962B-98C2-49EC-B4C4-7A0451D0640B}.Debug|x64.Build.0 = Debug|Any CPU + {0676962B-98C2-49EC-B4C4-7A0451D0640B}.Debug|x86.ActiveCfg = Debug|Any CPU + {0676962B-98C2-49EC-B4C4-7A0451D0640B}.Debug|x86.Build.0 = Debug|Any CPU + {0676962B-98C2-49EC-B4C4-7A0451D0640B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0676962B-98C2-49EC-B4C4-7A0451D0640B}.Release|Any CPU.Build.0 = Release|Any CPU + {0676962B-98C2-49EC-B4C4-7A0451D0640B}.Release|x64.ActiveCfg = Release|Any CPU + {0676962B-98C2-49EC-B4C4-7A0451D0640B}.Release|x64.Build.0 = Release|Any CPU + {0676962B-98C2-49EC-B4C4-7A0451D0640B}.Release|x86.ActiveCfg = Release|Any CPU + {0676962B-98C2-49EC-B4C4-7A0451D0640B}.Release|x86.Build.0 = Release|Any CPU + {D85F572F-7D80-40A4-9A9B-2731ED187C24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D85F572F-7D80-40A4-9A9B-2731ED187C24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D85F572F-7D80-40A4-9A9B-2731ED187C24}.Debug|x64.ActiveCfg = Debug|Any CPU + {D85F572F-7D80-40A4-9A9B-2731ED187C24}.Debug|x64.Build.0 = Debug|Any CPU + {D85F572F-7D80-40A4-9A9B-2731ED187C24}.Debug|x86.ActiveCfg = Debug|Any CPU + {D85F572F-7D80-40A4-9A9B-2731ED187C24}.Debug|x86.Build.0 = Debug|Any CPU + {D85F572F-7D80-40A4-9A9B-2731ED187C24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D85F572F-7D80-40A4-9A9B-2731ED187C24}.Release|Any CPU.Build.0 = Release|Any CPU + {D85F572F-7D80-40A4-9A9B-2731ED187C24}.Release|x64.ActiveCfg = Release|Any CPU + {D85F572F-7D80-40A4-9A9B-2731ED187C24}.Release|x64.Build.0 = Release|Any CPU + {D85F572F-7D80-40A4-9A9B-2731ED187C24}.Release|x86.ActiveCfg = Release|Any CPU + {D85F572F-7D80-40A4-9A9B-2731ED187C24}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {0676962B-98C2-49EC-B4C4-7A0451D0640B} = {F51FC4DA-CAC0-48B1-A069-B1712BCAA5BE} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FD20BC4A-0109-41D8-8C0C-893E784D7EF9} + EndGlobalSection +EndGlobal diff --git a/lib/netcore/Thrift/Collections/TCollections.cs b/lib/netcore/Thrift/Collections/TCollections.cs new file mode 100644 index 0000000..147bfc7 --- /dev/null +++ b/lib/netcore/Thrift/Collections/TCollections.cs @@ -0,0 +1,101 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Collections; + +namespace Thrift.Collections +{ + // ReSharper disable once InconsistentNaming + public class TCollections + { + /// + /// This will return true if the two collections are value-wise the same. + /// If the collection contains a collection, the collections will be compared using this method. + /// + public static bool Equals(IEnumerable first, IEnumerable second) + { + if (first == null && second == null) + { + return true; + } + + if (first == null || second == null) + { + return false; + } + + var fiter = first.GetEnumerator(); + var siter = second.GetEnumerator(); + + var fnext = fiter.MoveNext(); + var snext = siter.MoveNext(); + + while (fnext && snext) + { + var fenum = fiter.Current as IEnumerable; + var senum = siter.Current as IEnumerable; + + if (fenum != null && senum != null) + { + if (!Equals(fenum, senum)) + { + return false; + } + } + else if (fenum == null ^ senum == null) + { + return false; + } + else if (!Equals(fiter.Current, siter.Current)) + { + return false; + } + + fnext = fiter.MoveNext(); + snext = siter.MoveNext(); + } + + return fnext == snext; + } + + /// + /// This returns a hashcode based on the value of the enumerable. + /// + public static int GetHashCode(IEnumerable enumerable) + { + if (enumerable == null) + { + return 0; + } + + var hashcode = 0; + + foreach (var obj in enumerable) + { + var enum2 = obj as IEnumerable; + var objHash = enum2 == null ? obj.GetHashCode() : GetHashCode(enum2); + + unchecked + { + hashcode = (hashcode*397) ^ (objHash); + } + } + + return hashcode; + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Collections/THashSet.cs b/lib/netcore/Thrift/Collections/THashSet.cs new file mode 100644 index 0000000..011f0a0 --- /dev/null +++ b/lib/netcore/Thrift/Collections/THashSet.cs @@ -0,0 +1,67 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Collections; +using System.Collections.Generic; + +namespace Thrift.Collections +{ + // ReSharper disable once InconsistentNaming + public class THashSet : ICollection + { + private readonly HashSet _set = new HashSet(); + + public int Count => _set.Count; + + public bool IsReadOnly => false; + + public void Add(T item) + { + _set.Add(item); + } + + public void Clear() + { + _set.Clear(); + } + + public bool Contains(T item) + { + return _set.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + _set.CopyTo(array, arrayIndex); + } + + public IEnumerator GetEnumerator() + { + return _set.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable) _set).GetEnumerator(); + } + + public bool Remove(T item) + { + return _set.Remove(item); + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/ITAsyncProcessor.cs b/lib/netcore/Thrift/ITAsyncProcessor.cs new file mode 100644 index 0000000..db8e40a --- /dev/null +++ b/lib/netcore/Thrift/ITAsyncProcessor.cs @@ -0,0 +1,29 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Threading; +using System.Threading.Tasks; +using Thrift.Protocols; + +namespace Thrift +{ + public interface ITAsyncProcessor + { + Task ProcessAsync(TProtocol iprot, TProtocol oprot); + Task ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/ITProcessorFactory.cs b/lib/netcore/Thrift/ITProcessorFactory.cs new file mode 100644 index 0000000..5133e5c --- /dev/null +++ b/lib/netcore/Thrift/ITProcessorFactory.cs @@ -0,0 +1,28 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using Thrift.Server; +using Thrift.Transports; + +namespace Thrift +{ + // ReSharper disable once InconsistentNaming + public interface ITProcessorFactory + { + ITAsyncProcessor GetAsyncProcessor(TClientTransport trans, TBaseServer baseServer = null); + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Properties/AssemblyInfo.cs b/lib/netcore/Thrift/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..61cd3e3 --- /dev/null +++ b/lib/netcore/Thrift/Properties/AssemblyInfo.cs @@ -0,0 +1,56 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +[assembly: AssemblyTitle("Thrift")] +[assembly: AssemblyDescription("C# .NET Core bindings for the Apache Thrift RPC system")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("The Apache Software Foundation")] +[assembly: AssemblyProduct("Thrift")] +[assembly: AssemblyCopyright("The Apache Software Foundation")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +//@TODO where to put License information? + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a exType in this assembly from +// COM, set the ComVisible attribute to true on that exType. + +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM + +[assembly: Guid("df3f8ef0-e0a3-4c86-a65b-8ec84e016b1d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("0.11.0.1")] +[assembly: AssemblyFileVersion("0.11.0.1")] \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/Entities/TField.cs b/lib/netcore/Thrift/Protocols/Entities/TField.cs new file mode 100644 index 0000000..d311535 --- /dev/null +++ b/lib/netcore/Thrift/Protocols/Entities/TField.cs @@ -0,0 +1,37 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +namespace Thrift.Protocols.Entities +{ + // ReSharper disable once InconsistentNaming + public struct TField + { + public TField(string name, TType type, short id) + { + Name = name; + Type = type; + ID = id; + } + + public string Name { get; set; } + + public TType Type { get; set; } + + // ReSharper disable once InconsistentNaming - do not rename - it used for generation + public short ID { get; set; } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/Entities/TList.cs b/lib/netcore/Thrift/Protocols/Entities/TList.cs new file mode 100644 index 0000000..ce23220 --- /dev/null +++ b/lib/netcore/Thrift/Protocols/Entities/TList.cs @@ -0,0 +1,33 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +namespace Thrift.Protocols.Entities +{ + // ReSharper disable once InconsistentNaming + public struct TList + { + public TList(TType elementType, int count) + { + ElementType = elementType; + Count = count; + } + + public TType ElementType { get; set; } + + public int Count { get; set; } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/Entities/TMap.cs b/lib/netcore/Thrift/Protocols/Entities/TMap.cs new file mode 100644 index 0000000..9195593 --- /dev/null +++ b/lib/netcore/Thrift/Protocols/Entities/TMap.cs @@ -0,0 +1,36 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +namespace Thrift.Protocols.Entities +{ + // ReSharper disable once InconsistentNaming + public struct TMap + { + public TMap(TType keyType, TType valueType, int count) + { + KeyType = keyType; + ValueType = valueType; + Count = count; + } + + public TType KeyType { get; set; } + + public TType ValueType { get; set; } + + public int Count { get; set; } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/Entities/TMessage.cs b/lib/netcore/Thrift/Protocols/Entities/TMessage.cs new file mode 100644 index 0000000..17f4929 --- /dev/null +++ b/lib/netcore/Thrift/Protocols/Entities/TMessage.cs @@ -0,0 +1,37 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +namespace Thrift.Protocols.Entities +{ + // ReSharper disable once InconsistentNaming + public struct TMessage + { + public TMessage(string name, TMessageType type, int seqid) + { + Name = name; + Type = type; + SeqID = seqid; + } + + public string Name { get; set; } + + public TMessageType Type { get; set; } + + // ReSharper disable once InconsistentNaming - do not rename - it used for generation + public int SeqID { get; set; } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/Entities/TMessageType.cs b/lib/netcore/Thrift/Protocols/Entities/TMessageType.cs new file mode 100644 index 0000000..d7b9a22 --- /dev/null +++ b/lib/netcore/Thrift/Protocols/Entities/TMessageType.cs @@ -0,0 +1,28 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +namespace Thrift.Protocols.Entities +{ + // ReSharper disable once InconsistentNaming + public enum TMessageType + { + Call = 1, + Reply = 2, + Exception = 3, + Oneway = 4 + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/Entities/TSet.cs b/lib/netcore/Thrift/Protocols/Entities/TSet.cs new file mode 100644 index 0000000..a583b54 --- /dev/null +++ b/lib/netcore/Thrift/Protocols/Entities/TSet.cs @@ -0,0 +1,38 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +namespace Thrift.Protocols.Entities +{ + // ReSharper disable once InconsistentNaming + public struct TSet + { + public TSet(TType elementType, int count) + { + ElementType = elementType; + Count = count; + } + + public TSet(TList list) + : this(list.ElementType, list.Count) + { + } + + public TType ElementType { get; set; } + + public int Count { get; set; } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/Entities/TStruct.cs b/lib/netcore/Thrift/Protocols/Entities/TStruct.cs new file mode 100644 index 0000000..a28dcc3 --- /dev/null +++ b/lib/netcore/Thrift/Protocols/Entities/TStruct.cs @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +namespace Thrift.Protocols.Entities +{ + // ReSharper disable once InconsistentNaming + public struct TStruct + { + public TStruct(string name) + { + Name = name; + } + + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/Entities/TType.cs b/lib/netcore/Thrift/Protocols/Entities/TType.cs new file mode 100644 index 0000000..ebe781c --- /dev/null +++ b/lib/netcore/Thrift/Protocols/Entities/TType.cs @@ -0,0 +1,37 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +namespace Thrift.Protocols.Entities +{ + // ReSharper disable once InconsistentNaming + public enum TType : byte + { + Stop = 0, + Void = 1, + Bool = 2, + Byte = 3, + Double = 4, + I16 = 6, + I32 = 8, + I64 = 10, + String = 11, + Struct = 12, + Map = 13, + Set = 14, + List = 15 + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/ITProtocolFactory.cs b/lib/netcore/Thrift/Protocols/ITProtocolFactory.cs new file mode 100644 index 0000000..ecc5cc4 --- /dev/null +++ b/lib/netcore/Thrift/Protocols/ITProtocolFactory.cs @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using Thrift.Transports; + +namespace Thrift.Protocols +{ + // ReSharper disable once InconsistentNaming + public interface ITProtocolFactory + { + TProtocol GetProtocol(TClientTransport trans); + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/TAbstractBase.cs b/lib/netcore/Thrift/Protocols/TAbstractBase.cs new file mode 100644 index 0000000..eddb85e --- /dev/null +++ b/lib/netcore/Thrift/Protocols/TAbstractBase.cs @@ -0,0 +1,28 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Threading; +using System.Threading.Tasks; + +namespace Thrift.Protocols +{ + // ReSharper disable once InconsistentNaming + public interface TAbstractBase + { + Task WriteAsync(TProtocol tProtocol, CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/TBase.cs b/lib/netcore/Thrift/Protocols/TBase.cs new file mode 100644 index 0000000..cd11099 --- /dev/null +++ b/lib/netcore/Thrift/Protocols/TBase.cs @@ -0,0 +1,28 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Threading; +using System.Threading.Tasks; + +namespace Thrift.Protocols +{ + // ReSharper disable once InconsistentNaming + public interface TBase : TAbstractBase + { + Task ReadAsync(TProtocol tProtocol, CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/TBinaryProtocol.cs b/lib/netcore/Thrift/Protocols/TBinaryProtocol.cs new file mode 100644 index 0000000..fa0c5fc --- /dev/null +++ b/lib/netcore/Thrift/Protocols/TBinaryProtocol.cs @@ -0,0 +1,608 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Thrift.Protocols.Entities; +using Thrift.Transports; + +namespace Thrift.Protocols +{ + // ReSharper disable once InconsistentNaming + public class TBinaryProtocol : TProtocol + { + //TODO: Unit tests + //TODO: Localization + //TODO: pragma + + protected const uint VersionMask = 0xffff0000; + protected const uint Version1 = 0x80010000; + + protected bool StrictRead; + protected bool StrictWrite; + + public TBinaryProtocol(TClientTransport trans) + : this(trans, false, true) + { + } + + public TBinaryProtocol(TClientTransport trans, bool strictRead, bool strictWrite) + : base(trans) + { + StrictRead = strictRead; + StrictWrite = strictWrite; + } + + public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + if (StrictWrite) + { + var version = Version1 | (uint) message.Type; + await WriteI32Async((int) version, cancellationToken); + await WriteStringAsync(message.Name, cancellationToken); + await WriteI32Async(message.SeqID, cancellationToken); + } + else + { + await WriteStringAsync(message.Name, cancellationToken); + await WriteByteAsync((sbyte) message.Type, cancellationToken); + await WriteI32Async(message.SeqID, cancellationToken); + } + } + + public override async Task WriteMessageEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task WriteStructBeginAsync(TStruct struc, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task WriteStructEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await WriteByteAsync((sbyte) field.Type, cancellationToken); + await WriteI16Async(field.ID, cancellationToken); + } + + public override async Task WriteFieldEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task WriteFieldStopAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await WriteByteAsync((sbyte) TType.Stop, cancellationToken); + } + + public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await WriteByteAsync((sbyte) map.KeyType, cancellationToken); + await WriteByteAsync((sbyte) map.ValueType, cancellationToken); + await WriteI32Async(map.Count, cancellationToken); + } + + public override async Task WriteMapEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await WriteByteAsync((sbyte) list.ElementType, cancellationToken); + await WriteI32Async(list.Count, cancellationToken); + } + + public override async Task WriteListEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await WriteByteAsync((sbyte) set.ElementType, cancellationToken); + await WriteI32Async(set.Count, cancellationToken); + } + + public override async Task WriteSetEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await WriteByteAsync(b ? (sbyte) 1 : (sbyte) 0, cancellationToken); + } + + protected internal static byte[] CreateWriteByte(sbyte b) + { + var bout = new byte[1]; + + bout[0] = (byte) b; + + return bout; + } + + public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + var bout = CreateWriteByte(b); + await Trans.WriteAsync(bout, 0, 1, cancellationToken); + } + + protected internal static byte[] CreateWriteI16(short s) + { + var i16Out = new byte[2]; + + i16Out[0] = (byte) (0xff & (s >> 8)); + i16Out[1] = (byte) (0xff & s); + + return i16Out; + } + + public override async Task WriteI16Async(short i16, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + var i16Out = CreateWriteI16(i16); + await Trans.WriteAsync(i16Out, 0, 2, cancellationToken); + } + + protected internal static byte[] CreateWriteI32(int i32) + { + var i32Out = new byte[4]; + + i32Out[0] = (byte) (0xff & (i32 >> 24)); + i32Out[1] = (byte) (0xff & (i32 >> 16)); + i32Out[2] = (byte) (0xff & (i32 >> 8)); + i32Out[3] = (byte) (0xff & i32); + + return i32Out; + } + + public override async Task WriteI32Async(int i32, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + var i32Out = CreateWriteI32(i32); + await Trans.WriteAsync(i32Out, 0, 4, cancellationToken); + } + + protected internal static byte[] CreateWriteI64(long i64) + { + var i64Out = new byte[8]; + + i64Out[0] = (byte) (0xff & (i64 >> 56)); + i64Out[1] = (byte) (0xff & (i64 >> 48)); + i64Out[2] = (byte) (0xff & (i64 >> 40)); + i64Out[3] = (byte) (0xff & (i64 >> 32)); + i64Out[4] = (byte) (0xff & (i64 >> 24)); + i64Out[5] = (byte) (0xff & (i64 >> 16)); + i64Out[6] = (byte) (0xff & (i64 >> 8)); + i64Out[7] = (byte) (0xff & i64); + + return i64Out; + } + + public override async Task WriteI64Async(long i64, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + var i64Out = CreateWriteI64(i64); + await Trans.WriteAsync(i64Out, 0, 8, cancellationToken); + } + + public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await WriteI64Async(BitConverter.DoubleToInt64Bits(d), cancellationToken); + } + + public override async Task WriteBinaryAsync(byte[] b, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await WriteI32Async(b.Length, cancellationToken); + await Trans.WriteAsync(b, 0, b.Length, cancellationToken); + } + + public override async Task ReadMessageBeginAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var message = new TMessage(); + var size = await ReadI32Async(cancellationToken); + if (size < 0) + { + var version = (uint) size & VersionMask; + if (version != Version1) + { + throw new TProtocolException(TProtocolException.BAD_VERSION, + $"Bad version in ReadMessageBegin: {version}"); + } + message.Type = (TMessageType) (size & 0x000000ff); + message.Name = await ReadStringAsync(cancellationToken); + message.SeqID = await ReadI32Async(cancellationToken); + } + else + { + if (StrictRead) + { + throw new TProtocolException(TProtocolException.BAD_VERSION, + "Missing version in ReadMessageBegin, old client?"); + } + message.Name = await ReadStringBodyAsync(size, cancellationToken); + message.Type = (TMessageType) await ReadByteAsync(cancellationToken); + message.SeqID = await ReadI32Async(cancellationToken); + } + return message; + } + + public override async Task ReadMessageEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task ReadStructBeginAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + + //TODO: no read from internal transport? + return new TStruct(); + } + + public override async Task ReadStructEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task ReadFieldBeginAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var field = new TField + { + Type = (TType) await ReadByteAsync(cancellationToken) + }; + + if (field.Type != TType.Stop) + { + field.ID = await ReadI16Async(cancellationToken); + } + + return field; + } + + public override async Task ReadFieldEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task ReadMapBeginAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var map = new TMap + { + KeyType = (TType) await ReadByteAsync(cancellationToken), + ValueType = (TType) await ReadByteAsync(cancellationToken), + Count = await ReadI32Async(cancellationToken) + }; + + return map; + } + + public override async Task ReadMapEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task ReadListBeginAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var list = new TList + { + ElementType = (TType) await ReadByteAsync(cancellationToken), + Count = await ReadI32Async(cancellationToken) + }; + + return list; + } + + public override async Task ReadListEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task ReadSetBeginAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var set = new TSet + { + ElementType = (TType) await ReadByteAsync(cancellationToken), + Count = await ReadI32Async(cancellationToken) + }; + + return set; + } + + public override async Task ReadSetEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task ReadBoolAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + return await ReadByteAsync(cancellationToken) == 1; + } + + public override async Task ReadByteAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var bin = new byte[1]; + await Trans.ReadAllAsync(bin, 0, 1, cancellationToken); //TODO: why readall ? + return (sbyte) bin[0]; + } + + public override async Task ReadI16Async(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var i16In = new byte[2]; + await Trans.ReadAllAsync(i16In, 0, 2, cancellationToken); + var result = (short) (((i16In[0] & 0xff) << 8) | i16In[1] & 0xff); + return result; + } + + public override async Task ReadI32Async(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var i32In = new byte[4]; + await Trans.ReadAllAsync(i32In, 0, 4, cancellationToken); + var result = ((i32In[0] & 0xff) << 24) | ((i32In[1] & 0xff) << 16) | ((i32In[2] & 0xff) << 8) | + i32In[3] & 0xff; + return result; + } + +#pragma warning disable 675 + + protected internal long CreateReadI64(byte[] buf) + { + var result = + ((long) (buf[0] & 0xff) << 56) | + ((long) (buf[1] & 0xff) << 48) | + ((long) (buf[2] & 0xff) << 40) | + ((long) (buf[3] & 0xff) << 32) | + ((long) (buf[4] & 0xff) << 24) | + ((long) (buf[5] & 0xff) << 16) | + ((long) (buf[6] & 0xff) << 8) | + buf[7] & 0xff; + + return result; + } + +#pragma warning restore 675 + + public override async Task ReadI64Async(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var i64In = new byte[8]; + await Trans.ReadAllAsync(i64In, 0, 8, cancellationToken); + return CreateReadI64(i64In); + } + + public override async Task ReadDoubleAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var d = await ReadI64Async(cancellationToken); + return BitConverter.Int64BitsToDouble(d); + } + + public override async Task ReadBinaryAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var size = await ReadI32Async(cancellationToken); + var buf = new byte[size]; + await Trans.ReadAllAsync(buf, 0, size, cancellationToken); + return buf; + } + + private async Task ReadStringBodyAsync(int size, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + + var buf = new byte[size]; + await Trans.ReadAllAsync(buf, 0, size, cancellationToken); + return Encoding.UTF8.GetString(buf, 0, buf.Length); + } + + public class Factory : ITProtocolFactory + { + protected bool StrictRead; + protected bool StrictWrite; + + public Factory() + : this(false, true) + { + } + + public Factory(bool strictRead, bool strictWrite) + { + StrictRead = strictRead; + StrictWrite = strictWrite; + } + + public TProtocol GetProtocol(TClientTransport trans) + { + return new TBinaryProtocol(trans, StrictRead, StrictWrite); + } + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/TCompactProtocol.cs b/lib/netcore/Thrift/Protocols/TCompactProtocol.cs new file mode 100644 index 0000000..6d5e0bf --- /dev/null +++ b/lib/netcore/Thrift/Protocols/TCompactProtocol.cs @@ -0,0 +1,922 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Thrift.Protocols.Entities; +using Thrift.Transports; + +namespace Thrift.Protocols +{ + //TODO: implementation of TProtocol + + // ReSharper disable once InconsistentNaming + public class TCompactProtocol : TProtocol + { + private const byte ProtocolId = 0x82; + private const byte Version = 1; + private const byte VersionMask = 0x1f; // 0001 1111 + private const byte TypeMask = 0xE0; // 1110 0000 + private const byte TypeBits = 0x07; // 0000 0111 + private const int TypeShiftAmount = 5; + private static readonly TStruct AnonymousStruct = new TStruct(string.Empty); + private static readonly TField Tstop = new TField(string.Empty, TType.Stop, 0); + + // ReSharper disable once InconsistentNaming + private static readonly byte[] TTypeToCompactType = new byte[16]; + + /// + /// Used to keep track of the last field for the current and previous structs, so we can do the delta stuff. + /// + private readonly Stack _lastField = new Stack(15); + + /// + /// If we encounter a boolean field begin, save the TField here so it can have the value incorporated. + /// + private TField? _booleanField; + + /// + /// If we Read a field header, and it's a boolean field, save the boolean value here so that ReadBool can use it. + /// + private bool? _boolValue; + + private short _lastFieldId; + + public TCompactProtocol(TClientTransport trans) + : base(trans) + { + TTypeToCompactType[(int) TType.Stop] = Types.Stop; + TTypeToCompactType[(int) TType.Bool] = Types.BooleanTrue; + TTypeToCompactType[(int) TType.Byte] = Types.Byte; + TTypeToCompactType[(int) TType.I16] = Types.I16; + TTypeToCompactType[(int) TType.I32] = Types.I32; + TTypeToCompactType[(int) TType.I64] = Types.I64; + TTypeToCompactType[(int) TType.Double] = Types.Double; + TTypeToCompactType[(int) TType.String] = Types.Binary; + TTypeToCompactType[(int) TType.List] = Types.List; + TTypeToCompactType[(int) TType.Set] = Types.Set; + TTypeToCompactType[(int) TType.Map] = Types.Map; + TTypeToCompactType[(int) TType.Struct] = Types.Struct; + } + + public void Reset() + { + _lastField.Clear(); + _lastFieldId = 0; + } + + public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await Trans.WriteAsync(new[] {ProtocolId}, cancellationToken); + await + Trans.WriteAsync( + new[] {(byte) ((Version & VersionMask) | (((uint) message.Type << TypeShiftAmount) & TypeMask))}, + cancellationToken); + + var bufferTuple = CreateWriteVarInt32((uint) message.SeqID); + await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken); + + await WriteStringAsync(message.Name, cancellationToken); + } + + public override async Task WriteMessageEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + /// + /// Write a struct begin. This doesn't actually put anything on the wire. We + /// use it as an opportunity to put special placeholder markers on the field + /// stack so we can get the field id deltas correct. + /// + public override async Task WriteStructBeginAsync(TStruct struc, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + + _lastField.Push(_lastFieldId); + _lastFieldId = 0; + } + + public override async Task WriteStructEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + + _lastFieldId = _lastField.Pop(); + } + + private async Task WriteFieldBeginInternalAsync(TField field, byte typeOverride, + CancellationToken cancellationToken) + { + // if there's a exType override, use that. + var typeToWrite = typeOverride == 0xFF ? GetCompactType(field.Type) : typeOverride; + + // check if we can use delta encoding for the field id + if ((field.ID > _lastFieldId) && (field.ID - _lastFieldId <= 15)) + { + var b = (byte) (((field.ID - _lastFieldId) << 4) | typeToWrite); + // Write them together + await Trans.WriteAsync(new[] {b}, cancellationToken); + } + else + { + // Write them separate + await Trans.WriteAsync(new[] {typeToWrite}, cancellationToken); + await WriteI16Async(field.ID, cancellationToken); + } + + _lastFieldId = field.ID; + } + + public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken) + { + if (field.Type == TType.Bool) + { + _booleanField = field; + } + else + { + await WriteFieldBeginInternalAsync(field, 0xFF, cancellationToken); + } + } + + public override async Task WriteFieldEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task WriteFieldStopAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await Trans.WriteAsync(new[] {Types.Stop}, cancellationToken); + } + + protected async Task WriteCollectionBeginAsync(TType elemType, int size, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + /* + Abstract method for writing the start of lists and sets. List and sets on + the wire differ only by the exType indicator. + */ + + if (size <= 14) + { + await Trans.WriteAsync(new[] {(byte) ((size << 4) | GetCompactType(elemType))}, cancellationToken); + } + else + { + await Trans.WriteAsync(new[] {(byte) (0xf0 | GetCompactType(elemType))}, cancellationToken); + + var bufferTuple = CreateWriteVarInt32((uint) size); + await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken); + } + } + + public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken) + { + await WriteCollectionBeginAsync(list.ElementType, list.Count, cancellationToken); + } + + public override async Task WriteListEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await WriteCollectionBeginAsync(set.ElementType, set.Count, cancellationToken); + } + + public override async Task WriteSetEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + /* + Write a boolean value. Potentially, this could be a boolean field, in + which case the field header info isn't written yet. If so, decide what the + right exType header is for the value and then Write the field header. + Otherwise, Write a single byte. + */ + + if (_booleanField != null) + { + // we haven't written the field header yet + await + WriteFieldBeginInternalAsync(_booleanField.Value, b ? Types.BooleanTrue : Types.BooleanFalse, + cancellationToken); + _booleanField = null; + } + else + { + // we're not part of a field, so just Write the value. + await Trans.WriteAsync(new[] {b ? Types.BooleanTrue : Types.BooleanFalse}, cancellationToken); + } + } + + public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await Trans.WriteAsync(new[] {(byte) b}, cancellationToken); + } + + public override async Task WriteI16Async(short i16, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + var bufferTuple = CreateWriteVarInt32(IntToZigzag(i16)); + await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken); + } + + protected internal Tuple CreateWriteVarInt32(uint n) + { + // Write an i32 as a varint.Results in 1 - 5 bytes on the wire. + var i32Buf = new byte[5]; + var idx = 0; + + while (true) + { + if ((n & ~0x7F) == 0) + { + i32Buf[idx++] = (byte) n; + break; + } + + i32Buf[idx++] = (byte) ((n & 0x7F) | 0x80); + n >>= 7; + } + + return new Tuple(i32Buf, idx); + } + + public override async Task WriteI32Async(int i32, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + var bufferTuple = CreateWriteVarInt32(IntToZigzag(i32)); + await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken); + } + + protected internal Tuple CreateWriteVarInt64(ulong n) + { + // Write an i64 as a varint. Results in 1-10 bytes on the wire. + var buf = new byte[10]; + var idx = 0; + + while (true) + { + if ((n & ~(ulong) 0x7FL) == 0) + { + buf[idx++] = (byte) n; + break; + } + buf[idx++] = (byte) ((n & 0x7F) | 0x80); + n >>= 7; + } + + return new Tuple(buf, idx); + } + + public override async Task WriteI64Async(long i64, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + var bufferTuple = CreateWriteVarInt64(LongToZigzag(i64)); + await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken); + } + + public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + var data = new byte[8]; + FixedLongToBytes(BitConverter.DoubleToInt64Bits(d), data, 0); + await Trans.WriteAsync(data, cancellationToken); + } + + public override async Task WriteStringAsync(string str, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + var bytes = Encoding.UTF8.GetBytes(str); + + var bufferTuple = CreateWriteVarInt32((uint) bytes.Length); + await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken); + await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken); + } + + public override async Task WriteBinaryAsync(byte[] b, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + var bufferTuple = CreateWriteVarInt32((uint) b.Length); + await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken); + await Trans.WriteAsync(b, 0, b.Length, cancellationToken); + } + + public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + if (map.Count == 0) + { + await Trans.WriteAsync(new[] {(byte) 0}, cancellationToken); + } + else + { + var bufferTuple = CreateWriteVarInt32((uint) map.Count); + await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken); + await + Trans.WriteAsync( + new[] {(byte) ((GetCompactType(map.KeyType) << 4) | GetCompactType(map.ValueType))}, + cancellationToken); + } + } + + public override async Task WriteMapEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task ReadMessageBeginAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var protocolId = (byte) await ReadByteAsync(cancellationToken); + if (protocolId != ProtocolId) + { + throw new TProtocolException($"Expected protocol id {ProtocolId:X} but got {protocolId:X}"); + } + + var versionAndType = (byte) await ReadByteAsync(cancellationToken); + var version = (byte) (versionAndType & VersionMask); + + if (version != Version) + { + throw new TProtocolException($"Expected version {Version} but got {version}"); + } + + var type = (byte) ((versionAndType >> TypeShiftAmount) & TypeBits); + var seqid = (int) await ReadVarInt32Async(cancellationToken); + var messageName = await ReadStringAsync(cancellationToken); + + return new TMessage(messageName, (TMessageType) type, seqid); + } + + public override async Task ReadMessageEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task ReadStructBeginAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + // some magic is here ) + + _lastField.Push(_lastFieldId); + _lastFieldId = 0; + + return AnonymousStruct; + } + + public override async Task ReadStructEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + + /* + Doesn't actually consume any wire data, just removes the last field for + this struct from the field stack. + */ + + // consume the last field we Read off the wire. + _lastFieldId = _lastField.Pop(); + } + + public override async Task ReadFieldBeginAsync(CancellationToken cancellationToken) + { + // Read a field header off the wire. + var type = (byte) await ReadByteAsync(cancellationToken); + // if it's a stop, then we can return immediately, as the struct is over. + if (type == Types.Stop) + { + return Tstop; + } + + short fieldId; + // mask off the 4 MSB of the exType header. it could contain a field id delta. + var modifier = (short) ((type & 0xf0) >> 4); + if (modifier == 0) + { + fieldId = await ReadI16Async(cancellationToken); + } + else + { + fieldId = (short) (_lastFieldId + modifier); + } + + var field = new TField(string.Empty, GetTType((byte) (type & 0x0f)), fieldId); + // if this happens to be a boolean field, the value is encoded in the exType + if (IsBoolType(type)) + { + _boolValue = (byte) (type & 0x0f) == Types.BooleanTrue; + } + + // push the new field onto the field stack so we can keep the deltas going. + _lastFieldId = field.ID; + return field; + } + + public override async Task ReadFieldEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task ReadMapBeginAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + + /* + Read a map header off the wire. If the size is zero, skip Reading the key + and value exType. This means that 0-length maps will yield TMaps without the + "correct" types. + */ + + var size = (int) await ReadVarInt32Async(cancellationToken); + var keyAndValueType = size == 0 ? (byte) 0 : (byte) await ReadByteAsync(cancellationToken); + return new TMap(GetTType((byte) (keyAndValueType >> 4)), GetTType((byte) (keyAndValueType & 0xf)), size); + } + + public override async Task ReadMapEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task ReadSetBeginAsync(CancellationToken cancellationToken) + { + /* + Read a set header off the wire. If the set size is 0-14, the size will + be packed into the element exType header. If it's a longer set, the 4 MSB + of the element exType header will be 0xF, and a varint will follow with the + true size. + */ + + return new TSet(await ReadListBeginAsync(cancellationToken)); + } + + public override async Task ReadBoolAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + /* + Read a boolean off the wire. If this is a boolean field, the value should + already have been Read during ReadFieldBegin, so we'll just consume the + pre-stored value. Otherwise, Read a byte. + */ + + if (_boolValue != null) + { + var result = _boolValue.Value; + _boolValue = null; + return result; + } + + return await ReadByteAsync(cancellationToken) == Types.BooleanTrue; + } + + public override async Task ReadByteAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + // Read a single byte off the wire. Nothing interesting here. + var buf = new byte[1]; + await Trans.ReadAllAsync(buf, 0, 1, cancellationToken); + return (sbyte) buf[0]; + } + + public override async Task ReadI16Async(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + return (short) ZigzagToInt(await ReadVarInt32Async(cancellationToken)); + } + + public override async Task ReadI32Async(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + return ZigzagToInt(await ReadVarInt32Async(cancellationToken)); + } + + public override async Task ReadI64Async(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + return ZigzagToLong(await ReadVarInt64Async(cancellationToken)); + } + + public override async Task ReadDoubleAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var longBits = new byte[8]; + await Trans.ReadAllAsync(longBits, 0, 8, cancellationToken); + + return BitConverter.Int64BitsToDouble(BytesToLong(longBits)); + } + + public override async Task ReadStringAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + + // Reads a byte[] (via ReadBinary), and then UTF-8 decodes it. + var length = (int) await ReadVarInt32Async(cancellationToken); + + if (length == 0) + { + return string.Empty; + } + + var buf = new byte[length]; + await Trans.ReadAllAsync(buf, 0, length, cancellationToken); + + return Encoding.UTF8.GetString(buf); + } + + public override async Task ReadBinaryAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + // Read a byte[] from the wire. + var length = (int) await ReadVarInt32Async(cancellationToken); + if (length == 0) + { + return new byte[0]; + } + + var buf = new byte[length]; + await Trans.ReadAllAsync(buf, 0, length, cancellationToken); + return buf; + } + + public override async Task ReadListBeginAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + + /* + Read a list header off the wire. If the list size is 0-14, the size will + be packed into the element exType header. If it's a longer list, the 4 MSB + of the element exType header will be 0xF, and a varint will follow with the + true size. + */ + + var sizeAndType = (byte) await ReadByteAsync(cancellationToken); + var size = (sizeAndType >> 4) & 0x0f; + if (size == 15) + { + size = (int) await ReadVarInt32Async(cancellationToken); + } + + var type = GetTType(sizeAndType); + return new TList(type, size); + } + + public override async Task ReadListEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task ReadSetEndAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + private static byte GetCompactType(TType ttype) + { + // Given a TType value, find the appropriate TCompactProtocol.Types constant. + return TTypeToCompactType[(int) ttype]; + } + + + private async Task ReadVarInt32Async(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + /* + Read an i32 from the wire as a varint. The MSB of each byte is set + if there is another byte to follow. This can Read up to 5 bytes. + */ + + uint result = 0; + var shift = 0; + + while (true) + { + var b = (byte) await ReadByteAsync(cancellationToken); + result |= (uint) (b & 0x7f) << shift; + if ((b & 0x80) != 0x80) + { + break; + } + shift += 7; + } + + return result; + } + + private async Task ReadVarInt64Async(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + /* + Read an i64 from the wire as a proper varint. The MSB of each byte is set + if there is another byte to follow. This can Read up to 10 bytes. + */ + + var shift = 0; + ulong result = 0; + while (true) + { + var b = (byte) await ReadByteAsync(cancellationToken); + result |= (ulong) (b & 0x7f) << shift; + if ((b & 0x80) != 0x80) + { + break; + } + shift += 7; + } + + return result; + } + + private static int ZigzagToInt(uint n) + { + return (int) (n >> 1) ^ -(int) (n & 1); + } + + private static long ZigzagToLong(ulong n) + { + return (long) (n >> 1) ^ -(long) (n & 1); + } + + private static long BytesToLong(byte[] bytes) + { + /* + Note that it's important that the mask bytes are long literals, + otherwise they'll default to ints, and when you shift an int left 56 bits, + you just get a messed up int. + */ + + return + ((bytes[7] & 0xffL) << 56) | + ((bytes[6] & 0xffL) << 48) | + ((bytes[5] & 0xffL) << 40) | + ((bytes[4] & 0xffL) << 32) | + ((bytes[3] & 0xffL) << 24) | + ((bytes[2] & 0xffL) << 16) | + ((bytes[1] & 0xffL) << 8) | + (bytes[0] & 0xffL); + } + + private static bool IsBoolType(byte b) + { + var lowerNibble = b & 0x0f; + return (lowerNibble == Types.BooleanTrue) || (lowerNibble == Types.BooleanFalse); + } + + private static TType GetTType(byte type) + { + // Given a TCompactProtocol.Types constant, convert it to its corresponding TType value. + switch ((byte) (type & 0x0f)) + { + case Types.Stop: + return TType.Stop; + case Types.BooleanFalse: + case Types.BooleanTrue: + return TType.Bool; + case Types.Byte: + return TType.Byte; + case Types.I16: + return TType.I16; + case Types.I32: + return TType.I32; + case Types.I64: + return TType.I64; + case Types.Double: + return TType.Double; + case Types.Binary: + return TType.String; + case Types.List: + return TType.List; + case Types.Set: + return TType.Set; + case Types.Map: + return TType.Map; + case Types.Struct: + return TType.Struct; + default: + throw new TProtocolException($"Don't know what exType: {(byte) (type & 0x0f)}"); + } + } + + private static ulong LongToZigzag(long n) + { + // Convert l into a zigzag long. This allows negative numbers to be represented compactly as a varint + return (ulong) (n << 1) ^ (ulong) (n >> 63); + } + + private static uint IntToZigzag(int n) + { + // Convert n into a zigzag int. This allows negative numbers to be represented compactly as a varint + return (uint) (n << 1) ^ (uint) (n >> 31); + } + + private static void FixedLongToBytes(long n, byte[] buf, int off) + { + // Convert a long into little-endian bytes in buf starting at off and going until off+7. + buf[off + 0] = (byte) (n & 0xff); + buf[off + 1] = (byte) ((n >> 8) & 0xff); + buf[off + 2] = (byte) ((n >> 16) & 0xff); + buf[off + 3] = (byte) ((n >> 24) & 0xff); + buf[off + 4] = (byte) ((n >> 32) & 0xff); + buf[off + 5] = (byte) ((n >> 40) & 0xff); + buf[off + 6] = (byte) ((n >> 48) & 0xff); + buf[off + 7] = (byte) ((n >> 56) & 0xff); + } + + public class Factory : ITProtocolFactory + { + public TProtocol GetProtocol(TClientTransport trans) + { + return new TCompactProtocol(trans); + } + } + + /// + /// All of the on-wire exType codes. + /// + private static class Types + { + public const byte Stop = 0x00; + public const byte BooleanTrue = 0x01; + public const byte BooleanFalse = 0x02; + public const byte Byte = 0x03; + public const byte I16 = 0x04; + public const byte I32 = 0x05; + public const byte I64 = 0x06; + public const byte Double = 0x07; + public const byte Binary = 0x08; + public const byte List = 0x09; + public const byte Set = 0x0A; + public const byte Map = 0x0B; + public const byte Struct = 0x0C; + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/TJSONProtocol.cs b/lib/netcore/Thrift/Protocols/TJSONProtocol.cs new file mode 100644 index 0000000..a4ddd5b --- /dev/null +++ b/lib/netcore/Thrift/Protocols/TJSONProtocol.cs @@ -0,0 +1,1170 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Thrift.Protocols.Entities; +using Thrift.Protocols.Utilities; +using Thrift.Transports; + +namespace Thrift.Protocols +{ + //TODO: implementation of TProtocol + + /// + /// JSON protocol implementation for thrift. + /// This is a full-featured protocol supporting Write and Read. + /// Please see the C++ class header for a detailed description of the + /// protocol's wire format. + /// Adapted from the Java version. + /// + // ReSharper disable once InconsistentNaming + public class TJsonProtocol : TProtocol + { + private const long Version = 1; + + private const int DefStringSize = 16; + + private static readonly byte[] Comma = {(byte) ','}; + private static readonly byte[] Colon = {(byte) ':'}; + private static readonly byte[] Lbrace = {(byte) '{'}; + private static readonly byte[] Rbrace = {(byte) '}'}; + private static readonly byte[] Lbracket = {(byte) '['}; + private static readonly byte[] Rbracket = {(byte) ']'}; + private static readonly byte[] Quote = {(byte) '"'}; + private static readonly byte[] Backslash = {(byte) '\\'}; + + private static readonly byte[] NameBool = {(byte) 't', (byte) 'f'}; + private static readonly byte[] NameByte = {(byte) 'i', (byte) '8'}; + private static readonly byte[] NameI16 = {(byte) 'i', (byte) '1', (byte) '6'}; + private static readonly byte[] NameI32 = {(byte) 'i', (byte) '3', (byte) '2'}; + private static readonly byte[] NameI64 = {(byte) 'i', (byte) '6', (byte) '4'}; + private static readonly byte[] NameDouble = {(byte) 'd', (byte) 'b', (byte) 'l'}; + private static readonly byte[] NameStruct = {(byte) 'r', (byte) 'e', (byte) 'c'}; + private static readonly byte[] NameString = {(byte) 's', (byte) 't', (byte) 'r'}; + private static readonly byte[] NameMap = {(byte) 'm', (byte) 'a', (byte) 'p'}; + private static readonly byte[] NameList = {(byte) 'l', (byte) 's', (byte) 't'}; + private static readonly byte[] NameSet = {(byte) 's', (byte) 'e', (byte) 't'}; + + private readonly char[] _escapeChars = "\"\\/bfnrt".ToCharArray(); + + private readonly byte[] _escapeCharVals = + { + (byte) '"', (byte) '\\', (byte) '/', (byte) '\b', (byte) '\f', (byte) '\n', (byte) '\r', (byte) '\t' + }; + + private readonly byte[] _escseq = {(byte) '\\', (byte) 'u', (byte) '0', (byte) '0'}; + + private readonly byte[] _jsonCharTable = + { + 0, 0, 0, 0, 0, 0, 0, 0, (byte) 'b', (byte) 't', (byte) 'n', 0, (byte) 'f', (byte) 'r', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, (byte) '"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + + // Temporary buffer used by several methods + private readonly byte[] _tempBuffer = new byte[4]; + + // Current context that we are in + protected JsonBaseContext Context; + + // Stack of nested contexts that we may be in + protected Stack ContextStack = new Stack(); + + // Reader that manages a 1-byte buffer + protected LookaheadReader Reader; + + // Default encoding + protected Encoding Utf8Encoding = Encoding.UTF8; + + /// + /// TJsonProtocol Constructor + /// + public TJsonProtocol(TClientTransport trans) + : base(trans) + { + //throw new NotImplementedException("TJsonProtocol is not fully ready for usage"); + + Context = new JsonBaseContext(this); + Reader = new LookaheadReader(this); + } + + private static byte[] GetTypeNameForTypeId(TType typeId) + { + switch (typeId) + { + case TType.Bool: + return NameBool; + case TType.Byte: + return NameByte; + case TType.I16: + return NameI16; + case TType.I32: + return NameI32; + case TType.I64: + return NameI64; + case TType.Double: + return NameDouble; + case TType.String: + return NameString; + case TType.Struct: + return NameStruct; + case TType.Map: + return NameMap; + case TType.Set: + return NameSet; + case TType.List: + return NameList; + default: + throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized exType"); + } + } + + private static TType GetTypeIdForTypeName(byte[] name) + { + var result = TType.Stop; + if (name.Length > 1) + { + switch (name[0]) + { + case (byte) 'd': + result = TType.Double; + break; + case (byte) 'i': + switch (name[1]) + { + case (byte) '8': + result = TType.Byte; + break; + case (byte) '1': + result = TType.I16; + break; + case (byte) '3': + result = TType.I32; + break; + case (byte) '6': + result = TType.I64; + break; + } + break; + case (byte) 'l': + result = TType.List; + break; + case (byte) 'm': + result = TType.Map; + break; + case (byte) 'r': + result = TType.Struct; + break; + case (byte) 's': + if (name[1] == (byte) 't') + { + result = TType.String; + } + else if (name[1] == (byte) 'e') + { + result = TType.Set; + } + break; + case (byte) 't': + result = TType.Bool; + break; + } + } + if (result == TType.Stop) + { + throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized exType"); + } + return result; + } + + /// + /// Push a new JSON context onto the stack. + /// + protected void PushContext(JsonBaseContext c) + { + ContextStack.Push(Context); + Context = c; + } + + /// + /// Pop the last JSON context off the stack + /// + protected void PopContext() + { + Context = ContextStack.Pop(); + } + + /// + /// Read a byte that must match b[0]; otherwise an exception is thrown. + /// Marked protected to avoid synthetic accessor in JSONListContext.Read + /// and JSONPairContext.Read + /// + protected async Task ReadJsonSyntaxCharAsync(byte[] b, CancellationToken cancellationToken) + { + var ch = await Reader.ReadAsync(cancellationToken); + if (ch != b[0]) + { + throw new TProtocolException(TProtocolException.INVALID_DATA, $"Unexpected character: {(char) ch}"); + } + } + + /// + /// Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its + /// corresponding hex value + /// + private static byte HexVal(byte ch) + { + if ((ch >= '0') && (ch <= '9')) + { + return (byte) ((char) ch - '0'); + } + + if ((ch >= 'a') && (ch <= 'f')) + { + ch += 10; + return (byte) ((char) ch - 'a'); + } + + throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected hex character"); + } + + /// + /// Convert a byte containing a hex value to its corresponding hex character + /// + private static byte HexChar(byte val) + { + val &= 0x0F; + if (val < 10) + { + return (byte) ((char) val + '0'); + } + val -= 10; + return (byte) ((char) val + 'a'); + } + + /// + /// Write the bytes in array buf as a JSON characters, escaping as needed + /// + private async Task WriteJsonStringAsync(byte[] b, CancellationToken cancellationToken) + { + await Context.WriteAsync(cancellationToken); + await Trans.WriteAsync(Quote, cancellationToken); + + var len = b.Length; + for (var i = 0; i < len; i++) + { + if ((b[i] & 0x00FF) >= 0x30) + { + if (b[i] == Backslash[0]) + { + await Trans.WriteAsync(Backslash, cancellationToken); + await Trans.WriteAsync(Backslash, cancellationToken); + } + else + { + await Trans.WriteAsync(b, i, 1, cancellationToken); + } + } + else + { + _tempBuffer[0] = _jsonCharTable[b[i]]; + if (_tempBuffer[0] == 1) + { + await Trans.WriteAsync(b, i, 1, cancellationToken); + } + else if (_tempBuffer[0] > 1) + { + await Trans.WriteAsync(Backslash, cancellationToken); + await Trans.WriteAsync(_tempBuffer, 0, 1, cancellationToken); + } + else + { + await Trans.WriteAsync(_escseq, cancellationToken); + _tempBuffer[0] = HexChar((byte) (b[i] >> 4)); + _tempBuffer[1] = HexChar(b[i]); + await Trans.WriteAsync(_tempBuffer, 0, 2, cancellationToken); + } + } + } + await Trans.WriteAsync(Quote, cancellationToken); + } + + /// + /// Write out number as a JSON value. If the context dictates so, it will be + /// wrapped in quotes to output as a JSON string. + /// + private async Task WriteJsonIntegerAsync(long num, CancellationToken cancellationToken) + { + await Context.WriteAsync(cancellationToken); + var str = num.ToString(); + + var escapeNum = Context.EscapeNumbers(); + if (escapeNum) + { + await Trans.WriteAsync(Quote, cancellationToken); + } + + await Trans.WriteAsync(Utf8Encoding.GetBytes(str), cancellationToken); + + if (escapeNum) + { + await Trans.WriteAsync(Quote, cancellationToken); + } + } + + /// + /// Write out a double as a JSON value. If it is NaN or infinity or if the + /// context dictates escaping, Write out as JSON string. + /// + private async Task WriteJsonDoubleAsync(double num, CancellationToken cancellationToken) + { + await Context.WriteAsync(cancellationToken); + var str = num.ToString("G17", CultureInfo.InvariantCulture); + var special = false; + + switch (str[0]) + { + case 'N': // NaN + case 'I': // Infinity + special = true; + break; + case '-': + if (str[1] == 'I') + { + // -Infinity + special = true; + } + break; + } + + var escapeNum = special || Context.EscapeNumbers(); + + if (escapeNum) + { + await Trans.WriteAsync(Quote, cancellationToken); + } + + await Trans.WriteAsync(Utf8Encoding.GetBytes(str), cancellationToken); + + if (escapeNum) + { + await Trans.WriteAsync(Quote, cancellationToken); + } + } + + /// + /// Write out contents of byte array b as a JSON string with base-64 encoded + /// data + /// + private async Task WriteJsonBase64Async(byte[] b, CancellationToken cancellationToken) + { + await Context.WriteAsync(cancellationToken); + await Trans.WriteAsync(Quote, cancellationToken); + + var len = b.Length; + var off = 0; + + // Ignore padding + var bound = len >= 2 ? len - 2 : 0; + + for (var i = len - 1; i >= bound && b[i] == '='; --i) + { + --len; + } + + while (len >= 3) + { + // Encode 3 bytes at a time + TBase64Utils.Encode(b, off, 3, _tempBuffer, 0); + await Trans.WriteAsync(_tempBuffer, 0, 4, cancellationToken); + off += 3; + len -= 3; + } + + if (len > 0) + { + // Encode remainder + TBase64Utils.Encode(b, off, len, _tempBuffer, 0); + await Trans.WriteAsync(_tempBuffer, 0, len + 1, cancellationToken); + } + + await Trans.WriteAsync(Quote, cancellationToken); + } + + private async Task WriteJsonObjectStartAsync(CancellationToken cancellationToken) + { + await Context.WriteAsync(cancellationToken); + await Trans.WriteAsync(Lbrace, cancellationToken); + PushContext(new JsonPairContext(this)); + } + + private async Task WriteJsonObjectEndAsync(CancellationToken cancellationToken) + { + PopContext(); + await Trans.WriteAsync(Rbrace, cancellationToken); + } + + private async Task WriteJsonArrayStartAsync(CancellationToken cancellationToken) + { + await Context.WriteAsync(cancellationToken); + await Trans.WriteAsync(Lbracket, cancellationToken); + PushContext(new JsonListContext(this)); + } + + private async Task WriteJsonArrayEndAsync(CancellationToken cancellationToken) + { + PopContext(); + await Trans.WriteAsync(Rbracket, cancellationToken); + } + + public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken) + { + await WriteJsonArrayStartAsync(cancellationToken); + await WriteJsonIntegerAsync(Version, cancellationToken); + + var b = Utf8Encoding.GetBytes(message.Name); + await WriteJsonStringAsync(b, cancellationToken); + + await WriteJsonIntegerAsync((long) message.Type, cancellationToken); + await WriteJsonIntegerAsync(message.SeqID, cancellationToken); + } + + public override async Task WriteMessageEndAsync(CancellationToken cancellationToken) + { + await WriteJsonArrayEndAsync(cancellationToken); + } + + public override async Task WriteStructBeginAsync(TStruct struc, CancellationToken cancellationToken) + { + await WriteJsonObjectStartAsync(cancellationToken); + } + + public override async Task WriteStructEndAsync(CancellationToken cancellationToken) + { + await WriteJsonObjectEndAsync(cancellationToken); + } + + public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken) + { + await WriteJsonIntegerAsync(field.ID, cancellationToken); + await WriteJsonObjectStartAsync(cancellationToken); + await WriteJsonStringAsync(GetTypeNameForTypeId(field.Type), cancellationToken); + } + + public override async Task WriteFieldEndAsync(CancellationToken cancellationToken) + { + await WriteJsonObjectEndAsync(cancellationToken); + } + + public override async Task WriteFieldStopAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken) + { + await WriteJsonArrayStartAsync(cancellationToken); + await WriteJsonStringAsync(GetTypeNameForTypeId(map.KeyType), cancellationToken); + await WriteJsonStringAsync(GetTypeNameForTypeId(map.ValueType), cancellationToken); + await WriteJsonIntegerAsync(map.Count, cancellationToken); + await WriteJsonObjectStartAsync(cancellationToken); + } + + public override async Task WriteMapEndAsync(CancellationToken cancellationToken) + { + await WriteJsonObjectEndAsync(cancellationToken); + await WriteJsonArrayEndAsync(cancellationToken); + } + + public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken) + { + await WriteJsonArrayStartAsync(cancellationToken); + await WriteJsonStringAsync(GetTypeNameForTypeId(list.ElementType), cancellationToken); + await WriteJsonIntegerAsync(list.Count, cancellationToken); + } + + public override async Task WriteListEndAsync(CancellationToken cancellationToken) + { + await WriteJsonArrayEndAsync(cancellationToken); + } + + public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken) + { + await WriteJsonArrayStartAsync(cancellationToken); + await WriteJsonStringAsync(GetTypeNameForTypeId(set.ElementType), cancellationToken); + await WriteJsonIntegerAsync(set.Count, cancellationToken); + } + + public override async Task WriteSetEndAsync(CancellationToken cancellationToken) + { + await WriteJsonArrayEndAsync(cancellationToken); + } + + public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken) + { + await WriteJsonIntegerAsync(b ? 1 : 0, cancellationToken); + } + + public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken) + { + await WriteJsonIntegerAsync(b, cancellationToken); + } + + public override async Task WriteI16Async(short i16, CancellationToken cancellationToken) + { + await WriteJsonIntegerAsync(i16, cancellationToken); + } + + public override async Task WriteI32Async(int i32, CancellationToken cancellationToken) + { + await WriteJsonIntegerAsync(i32, cancellationToken); + } + + public override async Task WriteI64Async(long i64, CancellationToken cancellationToken) + { + await WriteJsonIntegerAsync(i64, cancellationToken); + } + + public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken) + { + await WriteJsonDoubleAsync(d, cancellationToken); + } + + public override async Task WriteStringAsync(string s, CancellationToken cancellationToken) + { + var b = Utf8Encoding.GetBytes(s); + await WriteJsonStringAsync(b, cancellationToken); + } + + public override async Task WriteBinaryAsync(byte[] b, CancellationToken cancellationToken) + { + await WriteJsonBase64Async(b, cancellationToken); + } + + /// + /// Read in a JSON string, unescaping as appropriate.. Skip Reading from the + /// context if skipContext is true. + /// + private async Task ReadJsonStringAsync(bool skipContext, CancellationToken cancellationToken) + { + using (var buffer = new MemoryStream()) + { + var codeunits = new List(); + + + if (!skipContext) + { + await Context.ReadAsync(cancellationToken); + } + + await ReadJsonSyntaxCharAsync(Quote, cancellationToken); + + while (true) + { + var ch = await Reader.ReadAsync(cancellationToken); + if (ch == Quote[0]) + { + break; + } + + // escaped? + if (ch != _escseq[0]) + { + await buffer.WriteAsync(new[] {ch}, 0, 1, cancellationToken); + continue; + } + + // distinguish between \uXXXX and \? + ch = await Reader.ReadAsync(cancellationToken); + if (ch != _escseq[1]) // control chars like \n + { + var off = Array.IndexOf(_escapeChars, (char) ch); + if (off == -1) + { + throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected control char"); + } + ch = _escapeCharVals[off]; + await buffer.WriteAsync(new[] {ch}, 0, 1, cancellationToken); + continue; + } + + + // it's \uXXXX + await Trans.ReadAllAsync(_tempBuffer, 0, 4, cancellationToken); + + var wch = (short) ((HexVal(_tempBuffer[0]) << 12) + + (HexVal(_tempBuffer[1]) << 8) + + (HexVal(_tempBuffer[2]) << 4) + + HexVal(_tempBuffer[3])); + + if (char.IsHighSurrogate((char) wch)) + { + if (codeunits.Count > 0) + { + throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected low surrogate char"); + } + codeunits.Add((char) wch); + } + else if (char.IsLowSurrogate((char) wch)) + { + if (codeunits.Count == 0) + { + throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected high surrogate char"); + } + + codeunits.Add((char) wch); + var tmp = Utf8Encoding.GetBytes(codeunits.ToArray()); + await buffer.WriteAsync(tmp, 0, tmp.Length, cancellationToken); + codeunits.Clear(); + } + else + { + var tmp = Utf8Encoding.GetBytes(new[] {(char) wch}); + await buffer.WriteAsync(tmp, 0, tmp.Length, cancellationToken); + } + } + + if (codeunits.Count > 0) + { + throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected low surrogate char"); + } + + return buffer.ToArray(); + } + } + + /// + /// Return true if the given byte could be a valid part of a JSON number. + /// + private static bool IsJsonNumeric(byte b) + { + switch (b) + { + case (byte) '+': + case (byte) '-': + case (byte) '.': + case (byte) '0': + case (byte) '1': + case (byte) '2': + case (byte) '3': + case (byte) '4': + case (byte) '5': + case (byte) '6': + case (byte) '7': + case (byte) '8': + case (byte) '9': + case (byte) 'E': + case (byte) 'e': + return true; + } + + return false; + } + + /// + /// Read in a sequence of characters that are all valid in JSON numbers. Does + /// not do a complete regex check to validate that this is actually a number. + /// + private async Task ReadJsonNumericCharsAsync(CancellationToken cancellationToken) + { + var strbld = new StringBuilder(); + while (true) + { + var ch = await Reader.PeekAsync(cancellationToken); + if (!IsJsonNumeric(ch)) + { + break; + } + strbld.Append((char) await Reader.ReadAsync(cancellationToken)); + } + return strbld.ToString(); + } + + /// + /// Read in a JSON number. If the context dictates, Read in enclosing quotes. + /// + private async Task ReadJsonIntegerAsync(CancellationToken cancellationToken) + { + await Context.ReadAsync(cancellationToken); + if (Context.EscapeNumbers()) + { + await ReadJsonSyntaxCharAsync(Quote, cancellationToken); + } + + var str = await ReadJsonNumericCharsAsync(cancellationToken); + if (Context.EscapeNumbers()) + { + await ReadJsonSyntaxCharAsync(Quote, cancellationToken); + } + + try + { + return long.Parse(str); + } + catch (FormatException) + { + throw new TProtocolException(TProtocolException.INVALID_DATA, "Bad data encounted in numeric data"); + } + } + + /// + /// Read in a JSON double value. Throw if the value is not wrapped in quotes + /// when expected or if wrapped in quotes when not expected. + /// + private async Task ReadJsonDoubleAsync(CancellationToken cancellationToken) + { + await Context.ReadAsync(cancellationToken); + if (await Reader.PeekAsync(cancellationToken) == Quote[0]) + { + var arr = await ReadJsonStringAsync(true, cancellationToken); + var dub = double.Parse(Utf8Encoding.GetString(arr, 0, arr.Length), CultureInfo.InvariantCulture); + + if (!Context.EscapeNumbers() && !double.IsNaN(dub) && !double.IsInfinity(dub)) + { + // Throw exception -- we should not be in a string in this case + throw new TProtocolException(TProtocolException.INVALID_DATA, "Numeric data unexpectedly quoted"); + } + + return dub; + } + + if (Context.EscapeNumbers()) + { + // This will throw - we should have had a quote if escapeNum == true + await ReadJsonSyntaxCharAsync(Quote, cancellationToken); + } + + try + { + return double.Parse(await ReadJsonNumericCharsAsync(cancellationToken), CultureInfo.InvariantCulture); + } + catch (FormatException) + { + throw new TProtocolException(TProtocolException.INVALID_DATA, "Bad data encounted in numeric data"); + } + } + + /// + /// Read in a JSON string containing base-64 encoded data and decode it. + /// + private async Task ReadJsonBase64Async(CancellationToken cancellationToken) + { + var b = await ReadJsonStringAsync(false, cancellationToken); + var len = b.Length; + var off = 0; + var size = 0; + + // reduce len to ignore fill bytes + while ((len > 0) && (b[len - 1] == '=')) + { + --len; + } + + // read & decode full byte triplets = 4 source bytes + while (len > 4) + { + // Decode 4 bytes at a time + TBase64Utils.Decode(b, off, 4, b, size); // NB: decoded in place + off += 4; + len -= 4; + size += 3; + } + + // Don't decode if we hit the end or got a single leftover byte (invalid + // base64 but legal for skip of regular string exType) + if (len > 1) + { + // Decode remainder + TBase64Utils.Decode(b, off, len, b, size); // NB: decoded in place + size += len - 1; + } + + // Sadly we must copy the byte[] (any way around this?) + var result = new byte[size]; + Array.Copy(b, 0, result, 0, size); + return result; + } + + private async Task ReadJsonObjectStartAsync(CancellationToken cancellationToken) + { + await Context.ReadAsync(cancellationToken); + await ReadJsonSyntaxCharAsync(Lbrace, cancellationToken); + PushContext(new JsonPairContext(this)); + } + + private async Task ReadJsonObjectEndAsync(CancellationToken cancellationToken) + { + await ReadJsonSyntaxCharAsync(Rbrace, cancellationToken); + PopContext(); + } + + private async Task ReadJsonArrayStartAsync(CancellationToken cancellationToken) + { + await Context.ReadAsync(cancellationToken); + await ReadJsonSyntaxCharAsync(Lbracket, cancellationToken); + PushContext(new JsonListContext(this)); + } + + private async Task ReadJsonArrayEndAsync(CancellationToken cancellationToken) + { + await ReadJsonSyntaxCharAsync(Rbracket, cancellationToken); + PopContext(); + } + + public override async Task ReadMessageBeginAsync(CancellationToken cancellationToken) + { + var message = new TMessage(); + await ReadJsonArrayStartAsync(cancellationToken); + if (await ReadJsonIntegerAsync(cancellationToken) != Version) + { + throw new TProtocolException(TProtocolException.BAD_VERSION, "Message contained bad version."); + } + + var buf = await ReadJsonStringAsync(false, cancellationToken); + message.Name = Utf8Encoding.GetString(buf, 0, buf.Length); + message.Type = (TMessageType) await ReadJsonIntegerAsync(cancellationToken); + message.SeqID = (int) await ReadJsonIntegerAsync(cancellationToken); + return message; + } + + public override async Task ReadMessageEndAsync(CancellationToken cancellationToken) + { + await ReadJsonArrayEndAsync(cancellationToken); + } + + public override async Task ReadStructBeginAsync(CancellationToken cancellationToken) + { + await ReadJsonObjectStartAsync(cancellationToken); + return new TStruct(); + } + + public override async Task ReadStructEndAsync(CancellationToken cancellationToken) + { + await ReadJsonObjectEndAsync(cancellationToken); + } + + public override async Task ReadFieldBeginAsync(CancellationToken cancellationToken) + { + var field = new TField(); + var ch = await Reader.PeekAsync(cancellationToken); + if (ch == Rbrace[0]) + { + field.Type = TType.Stop; + } + else + { + field.ID = (short) await ReadJsonIntegerAsync(cancellationToken); + await ReadJsonObjectStartAsync(cancellationToken); + field.Type = GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken)); + } + return field; + } + + public override async Task ReadFieldEndAsync(CancellationToken cancellationToken) + { + await ReadJsonObjectEndAsync(cancellationToken); + } + + public override async Task ReadMapBeginAsync(CancellationToken cancellationToken) + { + var map = new TMap(); + await ReadJsonArrayStartAsync(cancellationToken); + map.KeyType = GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken)); + map.ValueType = GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken)); + map.Count = (int) await ReadJsonIntegerAsync(cancellationToken); + await ReadJsonObjectStartAsync(cancellationToken); + return map; + } + + public override async Task ReadMapEndAsync(CancellationToken cancellationToken) + { + await ReadJsonObjectEndAsync(cancellationToken); + await ReadJsonArrayEndAsync(cancellationToken); + } + + public override async Task ReadListBeginAsync(CancellationToken cancellationToken) + { + var list = new TList(); + await ReadJsonArrayStartAsync(cancellationToken); + list.ElementType = GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken)); + list.Count = (int) await ReadJsonIntegerAsync(cancellationToken); + return list; + } + + public override async Task ReadListEndAsync(CancellationToken cancellationToken) + { + await ReadJsonArrayEndAsync(cancellationToken); + } + + public override async Task ReadSetBeginAsync(CancellationToken cancellationToken) + { + var set = new TSet(); + await ReadJsonArrayStartAsync(cancellationToken); + set.ElementType = GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken)); + set.Count = (int) await ReadJsonIntegerAsync(cancellationToken); + return set; + } + + public override async Task ReadSetEndAsync(CancellationToken cancellationToken) + { + await ReadJsonArrayEndAsync(cancellationToken); + } + + public override async Task ReadBoolAsync(CancellationToken cancellationToken) + { + return await ReadJsonIntegerAsync(cancellationToken) != 0; + } + + public override async Task ReadByteAsync(CancellationToken cancellationToken) + { + return (sbyte) await ReadJsonIntegerAsync(cancellationToken); + } + + public override async Task ReadI16Async(CancellationToken cancellationToken) + { + return (short) await ReadJsonIntegerAsync(cancellationToken); + } + + public override async Task ReadI32Async(CancellationToken cancellationToken) + { + return (int) await ReadJsonIntegerAsync(cancellationToken); + } + + public override async Task ReadI64Async(CancellationToken cancellationToken) + { + return await ReadJsonIntegerAsync(cancellationToken); + } + + public override async Task ReadDoubleAsync(CancellationToken cancellationToken) + { + return await ReadJsonDoubleAsync(cancellationToken); + } + + public override async Task ReadStringAsync(CancellationToken cancellationToken) + { + var buf = await ReadJsonStringAsync(false, cancellationToken); + return Utf8Encoding.GetString(buf, 0, buf.Length); + } + + public override async Task ReadBinaryAsync(CancellationToken cancellationToken) + { + return await ReadJsonBase64Async(cancellationToken); + } + + /// + /// Factory for JSON protocol objects + /// + public class Factory : ITProtocolFactory + { + public TProtocol GetProtocol(TClientTransport trans) + { + return new TJsonProtocol(trans); + } + } + + /// + /// Base class for tracking JSON contexts that may require + /// inserting/Reading additional JSON syntax characters + /// This base context does nothing. + /// + protected class JsonBaseContext + { + protected TJsonProtocol Proto; + + public JsonBaseContext(TJsonProtocol proto) + { + Proto = proto; + } + + public virtual async Task WriteAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public virtual async Task ReadAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public virtual bool EscapeNumbers() + { + return false; + } + } + + /// + /// Context for JSON lists. Will insert/Read commas before each item except + /// for the first one + /// + protected class JsonListContext : JsonBaseContext + { + private bool _first = true; + + public JsonListContext(TJsonProtocol protocol) + : base(protocol) + { + } + + public override async Task WriteAsync(CancellationToken cancellationToken) + { + if (_first) + { + _first = false; + } + else + { + await Proto.Trans.WriteAsync(Comma, cancellationToken); + } + } + + public override async Task ReadAsync(CancellationToken cancellationToken) + { + if (_first) + { + _first = false; + } + else + { + await Proto.ReadJsonSyntaxCharAsync(Comma, cancellationToken); + } + } + } + + /// + /// Context for JSON records. Will insert/Read colons before the value portion + /// of each record pair, and commas before each key except the first. In + /// addition, will indicate that numbers in the key position need to be + /// escaped in quotes (since JSON keys must be strings). + /// + protected class JsonPairContext : JsonBaseContext + { + private bool _colon = true; + + private bool _first = true; + + public JsonPairContext(TJsonProtocol proto) + : base(proto) + { + } + + public override async Task WriteAsync(CancellationToken cancellationToken) + { + if (_first) + { + _first = false; + _colon = true; + } + else + { + await Proto.Trans.WriteAsync(_colon ? Colon : Comma, cancellationToken); + _colon = !_colon; + } + } + + public override async Task ReadAsync(CancellationToken cancellationToken) + { + if (_first) + { + _first = false; + _colon = true; + } + else + { + await Proto.ReadJsonSyntaxCharAsync(_colon ? Colon : Comma, cancellationToken); + _colon = !_colon; + } + } + + public override bool EscapeNumbers() + { + return _colon; + } + } + + /// + /// Holds up to one byte from the transport + /// + protected class LookaheadReader + { + private readonly byte[] _data = new byte[1]; + + private bool _hasData; + protected TJsonProtocol Proto; + + public LookaheadReader(TJsonProtocol proto) + { + Proto = proto; + } + + /// + /// Return and consume the next byte to be Read, either taking it from the + /// data buffer if present or getting it from the transport otherwise. + /// + public async Task ReadAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + if (_hasData) + { + _hasData = false; + } + else + { + await Proto.Trans.ReadAllAsync(_data, 0, 1, cancellationToken); + } + return _data[0]; + } + + /// + /// Return the next byte to be Read without consuming, filling the data + /// buffer if it has not been filled alReady. + /// + public async Task PeekAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + if (!_hasData) + { + await Proto.Trans.ReadAllAsync(_data, 0, 1, cancellationToken); + } + _hasData = true; + return _data[0]; + } + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/TMultiplexedProtocol.cs b/lib/netcore/Thrift/Protocols/TMultiplexedProtocol.cs new file mode 100644 index 0000000..5b2202e --- /dev/null +++ b/lib/netcore/Thrift/Protocols/TMultiplexedProtocol.cs @@ -0,0 +1,100 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Threading; +using System.Threading.Tasks; +using Thrift.Protocols.Entities; + +namespace Thrift.Protocols +{ + /** + * TMultiplexedProtocol is a protocol-independent concrete decorator that allows a Thrift + * client to communicate with a multiplexing Thrift server, by prepending the service name + * to the function name during function calls. + * + * NOTE: THIS IS NOT TO BE USED BY SERVERS. + * On the server, use TMultiplexedProcessor to handle requests from a multiplexing client. + * + * This example uses a single socket transport to invoke two services: + * + * TSocketClientTransport transport = new TSocketClientTransport("localhost", 9090); + * transport.open(); + * + * TBinaryProtocol protocol = new TBinaryProtocol(transport); + * + * TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "Calculator"); + * Calculator.Client service = new Calculator.Client(mp); + * + * TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, "WeatherReport"); + * WeatherReport.Client service2 = new WeatherReport.Client(mp2); + * + * System.out.println(service.add(2,2)); + * System.out.println(service2.getTemperature()); + * + */ + + //TODO: implementation of TProtocol + + // ReSharper disable once InconsistentNaming + public class TMultiplexedProtocol : TProtocolDecorator + { + /** Used to delimit the service name from the function name */ + public const string Separator = ":"; + + private readonly string _serviceName; + + /** + * Wrap the specified protocol, allowing it to be used to communicate with a + * multiplexing server. The serviceName is required as it is + * prepended to the message header so that the multiplexing server can broker + * the function call to the proper service. + * + * Args: + * protocol Your communication protocol of choice, e.g. TBinaryProtocol + * serviceName The service name of the service communicating via this protocol. + */ + + public TMultiplexedProtocol(TProtocol protocol, string serviceName) + : base(protocol) + { + _serviceName = serviceName; + } + + /** + * Prepends the service name to the function name, separated by TMultiplexedProtocol.SEPARATOR. + * Args: + * tMessage The original message. + */ + + public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken) + { + switch (message.Type) + { + case TMessageType.Call: + case TMessageType.Oneway: + await + base.WriteMessageBeginAsync( + new TMessage($"{_serviceName}{Separator}{message.Name}", message.Type, message.SeqID), + cancellationToken); + break; + default: + await base.WriteMessageBeginAsync(message, cancellationToken); + break; + } + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/TProtocol.cs b/lib/netcore/Thrift/Protocols/TProtocol.cs new file mode 100644 index 0000000..8fef861 --- /dev/null +++ b/lib/netcore/Thrift/Protocols/TProtocol.cs @@ -0,0 +1,377 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Thrift.Protocols.Entities; +using Thrift.Transports; + +namespace Thrift.Protocols +{ + // ReSharper disable once InconsistentNaming + public abstract class TProtocol : IDisposable + { + private const int DefaultRecursionDepth = 64; + private bool _isDisposed; + protected int RecursionDepth; + + protected TClientTransport Trans; + + protected TProtocol(TClientTransport trans) + { + Trans = trans; + RecursionLimit = DefaultRecursionDepth; + RecursionDepth = 0; + } + + public TClientTransport Transport => Trans; + + //TODO: check for protected + protected int RecursionLimit { get; set; } + + public void Dispose() + { + Dispose(true); + } + + public void IncrementRecursionDepth() + { + if (RecursionDepth < RecursionLimit) + { + ++RecursionDepth; + } + else + { + throw new TProtocolException(TProtocolException.DEPTH_LIMIT, "Depth limit exceeded"); + } + } + + public void DecrementRecursionDepth() + { + --RecursionDepth; + } + + protected virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + (Trans as IDisposable)?.Dispose(); + } + } + _isDisposed = true; + } + + public virtual async Task WriteMessageBeginAsync(TMessage message) + { + await WriteMessageBeginAsync(message, CancellationToken.None); + } + + public abstract Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken); + + public virtual async Task WriteMessageEndAsync() + { + await WriteMessageEndAsync(CancellationToken.None); + } + + public abstract Task WriteMessageEndAsync(CancellationToken cancellationToken); + + public virtual async Task WriteStructBeginAsync(TStruct struc) + { + await WriteStructBeginAsync(struc, CancellationToken.None); + } + + public abstract Task WriteStructBeginAsync(TStruct struc, CancellationToken cancellationToken); + + public virtual async Task WriteStructEndAsync() + { + await WriteStructEndAsync(CancellationToken.None); + } + + public abstract Task WriteStructEndAsync(CancellationToken cancellationToken); + + public virtual async Task WriteFieldBeginAsync(TField field) + { + await WriteFieldBeginAsync(field, CancellationToken.None); + } + + public abstract Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken); + + public virtual async Task WriteFieldEndAsync() + { + await WriteFieldEndAsync(CancellationToken.None); + } + + public abstract Task WriteFieldEndAsync(CancellationToken cancellationToken); + + public virtual async Task WriteFieldStopAsync() + { + await WriteFieldStopAsync(CancellationToken.None); + } + + public abstract Task WriteFieldStopAsync(CancellationToken cancellationToken); + + public virtual async Task WriteMapBeginAsync(TMap map) + { + await WriteMapBeginAsync(map, CancellationToken.None); + } + + public abstract Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken); + + public virtual async Task WriteMapEndAsync() + { + await WriteMapEndAsync(CancellationToken.None); + } + + public abstract Task WriteMapEndAsync(CancellationToken cancellationToken); + + public virtual async Task WriteListBeginAsync(TList list) + { + await WriteListBeginAsync(list, CancellationToken.None); + } + + public abstract Task WriteListBeginAsync(TList list, CancellationToken cancellationToken); + + public virtual async Task WriteListEndAsync() + { + await WriteListEndAsync(CancellationToken.None); + } + + public abstract Task WriteListEndAsync(CancellationToken cancellationToken); + + public virtual async Task WriteSetBeginAsync(TSet set) + { + await WriteSetBeginAsync(set, CancellationToken.None); + } + + public abstract Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken); + + public virtual async Task WriteSetEndAsync() + { + await WriteSetEndAsync(CancellationToken.None); + } + + public abstract Task WriteSetEndAsync(CancellationToken cancellationToken); + + public virtual async Task WriteBoolAsync(bool b) + { + await WriteBoolAsync(b, CancellationToken.None); + } + + public abstract Task WriteBoolAsync(bool b, CancellationToken cancellationToken); + + public virtual async Task WriteByteAsync(sbyte b) + { + await WriteByteAsync(b, CancellationToken.None); + } + + public abstract Task WriteByteAsync(sbyte b, CancellationToken cancellationToken); + + public virtual async Task WriteI16Async(short i16) + { + await WriteI16Async(i16, CancellationToken.None); + } + + public abstract Task WriteI16Async(short i16, CancellationToken cancellationToken); + + public virtual async Task WriteI32Async(int i32) + { + await WriteI32Async(i32, CancellationToken.None); + } + + public abstract Task WriteI32Async(int i32, CancellationToken cancellationToken); + + public virtual async Task WriteI64Async(long i64) + { + await WriteI64Async(i64, CancellationToken.None); + } + + public abstract Task WriteI64Async(long i64, CancellationToken cancellationToken); + + public virtual async Task WriteDoubleAsync(double d) + { + await WriteDoubleAsync(d, CancellationToken.None); + } + + public abstract Task WriteDoubleAsync(double d, CancellationToken cancellationToken); + + public virtual async Task WriteStringAsync(string s) + { + await WriteStringAsync(s, CancellationToken.None); + } + + public virtual async Task WriteStringAsync(string s, CancellationToken cancellationToken) + { + var bytes = Encoding.UTF8.GetBytes(s); + await WriteBinaryAsync(bytes, cancellationToken); + } + + public virtual async Task WriteBinaryAsync(byte[] b) + { + await WriteBinaryAsync(b, CancellationToken.None); + } + + public abstract Task WriteBinaryAsync(byte[] b, CancellationToken cancellationToken); + + public virtual async Task ReadMessageBeginAsync() + { + return await ReadMessageBeginAsync(CancellationToken.None); + } + + public abstract Task ReadMessageBeginAsync(CancellationToken cancellationToken); + + public virtual async Task ReadMessageEndAsync() + { + await ReadMessageEndAsync(CancellationToken.None); + } + + public abstract Task ReadMessageEndAsync(CancellationToken cancellationToken); + + public virtual async Task ReadStructBeginAsync() + { + return await ReadStructBeginAsync(CancellationToken.None); + } + + public abstract Task ReadStructBeginAsync(CancellationToken cancellationToken); + + public virtual async Task ReadStructEndAsync() + { + await ReadStructEndAsync(CancellationToken.None); + } + + public abstract Task ReadStructEndAsync(CancellationToken cancellationToken); + + public virtual async Task ReadFieldBeginAsync() + { + return await ReadFieldBeginAsync(CancellationToken.None); + } + + public abstract Task ReadFieldBeginAsync(CancellationToken cancellationToken); + + public virtual async Task ReadFieldEndAsync() + { + await ReadFieldEndAsync(CancellationToken.None); + } + + public abstract Task ReadFieldEndAsync(CancellationToken cancellationToken); + + public virtual async Task ReadMapBeginAsync() + { + return await ReadMapBeginAsync(CancellationToken.None); + } + + public abstract Task ReadMapBeginAsync(CancellationToken cancellationToken); + + public virtual async Task ReadMapEndAsync() + { + await ReadMapEndAsync(CancellationToken.None); + } + + public abstract Task ReadMapEndAsync(CancellationToken cancellationToken); + + public virtual async Task ReadListBeginAsync() + { + return await ReadListBeginAsync(CancellationToken.None); + } + + public abstract Task ReadListBeginAsync(CancellationToken cancellationToken); + + public virtual async Task ReadListEndAsync() + { + await ReadListEndAsync(CancellationToken.None); + } + + public abstract Task ReadListEndAsync(CancellationToken cancellationToken); + + public virtual async Task ReadSetBeginAsync() + { + return await ReadSetBeginAsync(CancellationToken.None); + } + + public abstract Task ReadSetBeginAsync(CancellationToken cancellationToken); + + public virtual async Task ReadSetEndAsync() + { + await ReadSetEndAsync(CancellationToken.None); + } + + public abstract Task ReadSetEndAsync(CancellationToken cancellationToken); + + public virtual async Task ReadBoolAsync() + { + return await ReadBoolAsync(CancellationToken.None); + } + + public abstract Task ReadBoolAsync(CancellationToken cancellationToken); + + public virtual async Task ReadByteAsync() + { + return await ReadByteAsync(CancellationToken.None); + } + + public abstract Task ReadByteAsync(CancellationToken cancellationToken); + + public virtual async Task ReadI16Async() + { + return await ReadI16Async(CancellationToken.None); + } + + public abstract Task ReadI16Async(CancellationToken cancellationToken); + + public virtual async Task ReadI32Async() + { + return await ReadI32Async(CancellationToken.None); + } + + public abstract Task ReadI32Async(CancellationToken cancellationToken); + + public virtual async Task ReadI64Async() + { + return await ReadI64Async(CancellationToken.None); + } + + public abstract Task ReadI64Async(CancellationToken cancellationToken); + + public virtual async Task ReadDoubleAsync() + { + return await ReadDoubleAsync(CancellationToken.None); + } + + public abstract Task ReadDoubleAsync(CancellationToken cancellationToken); + + public virtual async Task ReadStringAsync() + { + return await ReadStringAsync(CancellationToken.None); + } + + public virtual async Task ReadStringAsync(CancellationToken cancellationToken) + { + var buf = await ReadBinaryAsync(cancellationToken); + return Encoding.UTF8.GetString(buf, 0, buf.Length); + } + + public virtual async Task ReadBinaryAsync() + { + return await ReadBinaryAsync(CancellationToken.None); + } + + public abstract Task ReadBinaryAsync(CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/TProtocolDecorator.cs b/lib/netcore/Thrift/Protocols/TProtocolDecorator.cs new file mode 100644 index 0000000..458b117 --- /dev/null +++ b/lib/netcore/Thrift/Protocols/TProtocolDecorator.cs @@ -0,0 +1,252 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Thrift.Protocols.Entities; + +namespace Thrift.Protocols +{ + // ReSharper disable once InconsistentNaming + /// + /// TProtocolDecorator forwards all requests to an enclosed TProtocol instance, + /// providing a way to author concise concrete decorator subclasses.While it has + /// no abstract methods, it is marked abstract as a reminder that by itself, + /// it does not modify the behaviour of the enclosed TProtocol. + /// + public abstract class TProtocolDecorator : TProtocol + { + private readonly TProtocol _wrappedProtocol; + + protected TProtocolDecorator(TProtocol protocol) + : base(protocol.Transport) + { + if (protocol == null) + { + throw new ArgumentNullException(nameof(protocol)); + } + + _wrappedProtocol = protocol; + } + + public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteMessageBeginAsync(message, cancellationToken); + } + + public override async Task WriteMessageEndAsync(CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteMessageEndAsync(cancellationToken); + } + + public override async Task WriteStructBeginAsync(TStruct struc, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteStructBeginAsync(struc, cancellationToken); + } + + public override async Task WriteStructEndAsync(CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteStructEndAsync(cancellationToken); + } + + public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteFieldBeginAsync(field, cancellationToken); + } + + public override async Task WriteFieldEndAsync(CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteFieldEndAsync(cancellationToken); + } + + public override async Task WriteFieldStopAsync(CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteFieldStopAsync(cancellationToken); + } + + public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteMapBeginAsync(map, cancellationToken); + } + + public override async Task WriteMapEndAsync(CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteMapEndAsync(cancellationToken); + } + + public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteListBeginAsync(list, cancellationToken); + } + + public override async Task WriteListEndAsync(CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteListEndAsync(cancellationToken); + } + + public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteSetBeginAsync(set, cancellationToken); + } + + public override async Task WriteSetEndAsync(CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteSetEndAsync(cancellationToken); + } + + public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteBoolAsync(b, cancellationToken); + } + + public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteByteAsync(b, cancellationToken); + } + + public override async Task WriteI16Async(short i16, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteI16Async(i16, cancellationToken); + } + + public override async Task WriteI32Async(int i32, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteI32Async(i32, cancellationToken); + } + + public override async Task WriteI64Async(long i64, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteI64Async(i64, cancellationToken); + } + + public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteDoubleAsync(d, cancellationToken); + } + + public override async Task WriteStringAsync(string s, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteStringAsync(s, cancellationToken); + } + + public override async Task WriteBinaryAsync(byte[] b, CancellationToken cancellationToken) + { + await _wrappedProtocol.WriteBinaryAsync(b, cancellationToken); + } + + public override async Task ReadMessageBeginAsync(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadMessageBeginAsync(cancellationToken); + } + + public override async Task ReadMessageEndAsync(CancellationToken cancellationToken) + { + await _wrappedProtocol.ReadMessageEndAsync(cancellationToken); + } + + public override async Task ReadStructBeginAsync(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadStructBeginAsync(cancellationToken); + } + + public override async Task ReadStructEndAsync(CancellationToken cancellationToken) + { + await _wrappedProtocol.ReadStructEndAsync(cancellationToken); + } + + public override async Task ReadFieldBeginAsync(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadFieldBeginAsync(cancellationToken); + } + + public override async Task ReadFieldEndAsync(CancellationToken cancellationToken) + { + await _wrappedProtocol.ReadFieldEndAsync(cancellationToken); + } + + public override async Task ReadMapBeginAsync(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadMapBeginAsync(cancellationToken); + } + + public override async Task ReadMapEndAsync(CancellationToken cancellationToken) + { + await _wrappedProtocol.ReadMapEndAsync(cancellationToken); + } + + public override async Task ReadListBeginAsync(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadListBeginAsync(cancellationToken); + } + + public override async Task ReadListEndAsync(CancellationToken cancellationToken) + { + await _wrappedProtocol.ReadListEndAsync(cancellationToken); + } + + public override async Task ReadSetBeginAsync(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadSetBeginAsync(cancellationToken); + } + + public override async Task ReadSetEndAsync(CancellationToken cancellationToken) + { + await _wrappedProtocol.ReadSetEndAsync(cancellationToken); + } + + public override async Task ReadBoolAsync(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadBoolAsync(cancellationToken); + } + + public override async Task ReadByteAsync(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadByteAsync(cancellationToken); + } + + public override async Task ReadI16Async(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadI16Async(cancellationToken); + } + + public override async Task ReadI32Async(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadI32Async(cancellationToken); + } + + public override async Task ReadI64Async(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadI64Async(cancellationToken); + } + + public override async Task ReadDoubleAsync(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadDoubleAsync(cancellationToken); + } + + public override async Task ReadStringAsync(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadStringAsync(cancellationToken); + } + + public override async Task ReadBinaryAsync(CancellationToken cancellationToken) + { + return await _wrappedProtocol.ReadBinaryAsync(cancellationToken); + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/TProtocolException.cs b/lib/netcore/Thrift/Protocols/TProtocolException.cs new file mode 100644 index 0000000..02d0d3f --- /dev/null +++ b/lib/netcore/Thrift/Protocols/TProtocolException.cs @@ -0,0 +1,58 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +namespace Thrift.Protocols +{ + public class TProtocolException : TException + { + // do not rename public contants - they used in generated files + public const int UNKNOWN = 0; + public const int INVALID_DATA = 1; + public const int NEGATIVE_SIZE = 2; + public const int SIZE_LIMIT = 3; + public const int BAD_VERSION = 4; + public const int NOT_IMPLEMENTED = 5; + public const int DEPTH_LIMIT = 6; + + protected int Type = UNKNOWN; + + public TProtocolException() + { + } + + public TProtocolException(int type) + { + Type = type; + } + + public TProtocolException(int type, string message) + : base(message) + { + Type = type; + } + + public TProtocolException(string message) + : base(message) + { + } + + public int GetExceptionType() + { + return Type; + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/Utilities/TBase64Utils.cs b/lib/netcore/Thrift/Protocols/Utilities/TBase64Utils.cs new file mode 100644 index 0000000..15fd45c --- /dev/null +++ b/lib/netcore/Thrift/Protocols/Utilities/TBase64Utils.cs @@ -0,0 +1,101 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; + +namespace Thrift.Protocols.Utilities +{ + // ReSharper disable once InconsistentNaming + internal static class TBase64Utils + { + //TODO: Constants + //TODO: Check for args + //TODO: Unitests + + internal const string EncodeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + private static readonly int[] DecodeTable = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + + internal static void Encode(byte[] src, int srcOff, int len, byte[] dst, int dstOff) + { + if (src == null) + { + throw new ArgumentNullException(nameof(src)); + } + + dst[dstOff] = (byte) EncodeTable[(src[srcOff] >> 2) & 0x3F]; + + if (len == 3) + { + dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)]; + dst[dstOff + 2] = (byte) EncodeTable[((src[srcOff + 1] << 2) & 0x3C) | ((src[srcOff + 2] >> 6) & 0x03)]; + dst[dstOff + 3] = (byte) EncodeTable[src[srcOff + 2] & 0x3F]; + } + else if (len == 2) + { + dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)]; + dst[dstOff + 2] = (byte) EncodeTable[(src[srcOff + 1] << 2) & 0x3C]; + } + else + { + // len == 1 + dst[dstOff + 1] = (byte) EncodeTable[(src[srcOff] << 4) & 0x30]; + } + } + + internal static void Decode(byte[] src, int srcOff, int len, byte[] dst, int dstOff) + { + if (src == null) + { + throw new ArgumentNullException(nameof(src)); + } + + dst[dstOff] = (byte) ((DecodeTable[src[srcOff] & 0x0FF] << 2) | (DecodeTable[src[srcOff + 1] & 0x0FF] >> 4)); + + if (len > 2) + { + dst[dstOff + 1] = + (byte) + (((DecodeTable[src[srcOff + 1] & 0x0FF] << 4) & 0xF0) | (DecodeTable[src[srcOff + 2] & 0x0FF] >> 2)); + if (len > 3) + { + dst[dstOff + 2] = + (byte) + (((DecodeTable[src[srcOff + 2] & 0x0FF] << 6) & 0xC0) | DecodeTable[src[srcOff + 3] & 0x0FF]); + } + } + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Protocols/Utilities/TProtocolUtil.cs b/lib/netcore/Thrift/Protocols/Utilities/TProtocolUtil.cs new file mode 100644 index 0000000..038edb9 --- /dev/null +++ b/lib/netcore/Thrift/Protocols/Utilities/TProtocolUtil.cs @@ -0,0 +1,110 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Threading; +using System.Threading.Tasks; +using Thrift.Protocols.Entities; + +namespace Thrift.Protocols +{ + // ReSharper disable once InconsistentNaming + public static class TProtocolUtil + { + public static async Task SkipAsync(TProtocol prot, TType type, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + + prot.IncrementRecursionDepth(); + try + { + switch (type) + { + case TType.Bool: + await prot.ReadBoolAsync(cancellationToken); + break; + case TType.Byte: + await prot.ReadByteAsync(cancellationToken); + break; + case TType.I16: + await prot.ReadI16Async(cancellationToken); + break; + case TType.I32: + await prot.ReadI32Async(cancellationToken); + break; + case TType.I64: + await prot.ReadI64Async(cancellationToken); + break; + case TType.Double: + await prot.ReadDoubleAsync(cancellationToken); + break; + case TType.String: + // Don't try to decode the string, just skip it. + await prot.ReadBinaryAsync(cancellationToken); + break; + case TType.Struct: + await prot.ReadStructBeginAsync(cancellationToken); + while (true) + { + var field = await prot.ReadFieldBeginAsync(cancellationToken); + if (field.Type == TType.Stop) + { + break; + } + await SkipAsync(prot, field.Type, cancellationToken); + await prot.ReadFieldEndAsync(cancellationToken); + } + await prot.ReadStructEndAsync(cancellationToken); + break; + case TType.Map: + var map = await prot.ReadMapBeginAsync(cancellationToken); + for (var i = 0; i < map.Count; i++) + { + await SkipAsync(prot, map.KeyType, cancellationToken); + await SkipAsync(prot, map.ValueType, cancellationToken); + } + await prot.ReadMapEndAsync(cancellationToken); + break; + case TType.Set: + var set = await prot.ReadSetBeginAsync(cancellationToken); + for (var i = 0; i < set.Count; i++) + { + await SkipAsync(prot, set.ElementType, cancellationToken); + } + await prot.ReadSetEndAsync(cancellationToken); + break; + case TType.List: + var list = await prot.ReadListBeginAsync(cancellationToken); + for (var i = 0; i < list.Count; i++) + { + await SkipAsync(prot, list.ElementType, cancellationToken); + } + await prot.ReadListEndAsync(cancellationToken); + break; + default: + throw new TProtocolException(TProtocolException.INVALID_DATA, "Unknown data type " + type.ToString("d")); + } + } + finally + { + prot.DecrementRecursionDepth(); + } + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Server/AsyncBaseServer.cs b/lib/netcore/Thrift/Server/AsyncBaseServer.cs new file mode 100644 index 0000000..5ff7a32 --- /dev/null +++ b/lib/netcore/Thrift/Server/AsyncBaseServer.cs @@ -0,0 +1,184 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Thrift.Protocols; +using Thrift.Transports; + +namespace Thrift.Server +{ + //TODO: unhandled exceptions, etc. + + // ReSharper disable once InconsistentNaming + public class AsyncBaseServer : TBaseServer + { + private readonly int _clientWaitingDelay; + private volatile Task _serverTask; + + public AsyncBaseServer(ITAsyncProcessor processor, TServerTransport serverTransport, + ITProtocolFactory inputProtocolFactory, ITProtocolFactory outputProtocolFactory, + ILoggerFactory loggerFactory, int clientWaitingDelay = 10) + : this(new SingletonTProcessorFactory(processor), serverTransport, + new TTransportFactory(), new TTransportFactory(), + inputProtocolFactory, outputProtocolFactory, + loggerFactory.CreateLogger(nameof(AsyncBaseServer)), clientWaitingDelay) + { + } + + public AsyncBaseServer(ITProcessorFactory itProcessorFactory, TServerTransport serverTransport, + TTransportFactory inputTransportFactory, TTransportFactory outputTransportFactory, + ITProtocolFactory inputProtocolFactory, ITProtocolFactory outputProtocolFactory, + ILogger logger, int clientWaitingDelay = 10) + : base(itProcessorFactory, serverTransport, inputTransportFactory, outputTransportFactory, + inputProtocolFactory, outputProtocolFactory, logger) + { + _clientWaitingDelay = clientWaitingDelay; + } + + public override async Task ServeAsync(CancellationToken cancellationToken) + { + try + { + // cancelation token + _serverTask = Task.Factory.StartNew(() => StartListening(cancellationToken), + TaskCreationOptions.LongRunning); + await _serverTask; + } + catch (Exception ex) + { + Logger.LogError(ex.ToString()); + } + } + + private async Task StartListening(CancellationToken cancellationToken) + { + ServerTransport.Listen(); + + Logger.LogTrace("Started listening at server"); + + if (ServerEventHandler != null) + { + await ServerEventHandler.PreServeAsync(cancellationToken); + } + + while (!cancellationToken.IsCancellationRequested) + { + if (ServerTransport.IsClientPending()) + { + Logger.LogTrace("Waiting for client connection"); + + try + { + var client = await ServerTransport.AcceptAsync(cancellationToken); + await Task.Factory.StartNew(() => Execute(client, cancellationToken)); + } + catch (TTransportException ttx) + { + Logger.LogTrace($"Transport exception: {ttx}"); + + if (ttx.Type != TTransportException.ExceptionType.Interrupted) + { + Logger.LogError(ttx.ToString()); + } + } + } + else + { + await Task.Delay(TimeSpan.FromMilliseconds(_clientWaitingDelay), cancellationToken); + } + } + + ServerTransport.Close(); + + Logger.LogTrace("Completed listening at server"); + } + + public override void Stop() + { + } + + private async Task Execute(TClientTransport client, CancellationToken cancellationToken) + { + Logger.LogTrace("Started client request processing"); + + var processor = ItProcessorFactory.GetAsyncProcessor(client, this); + + TClientTransport inputTransport = null; + TClientTransport outputTransport = null; + TProtocol inputProtocol = null; + TProtocol outputProtocol = null; + object connectionContext = null; + + try + { + inputTransport = InputTransportFactory.GetTransport(client); + outputTransport = OutputTransportFactory.GetTransport(client); + + inputProtocol = InputProtocolFactory.GetProtocol(inputTransport); + outputProtocol = OutputProtocolFactory.GetProtocol(outputTransport); + + if (ServerEventHandler != null) + { + connectionContext = + await ServerEventHandler.CreateContextAsync(inputProtocol, outputProtocol, cancellationToken); + } + + while (!cancellationToken.IsCancellationRequested) + { + if (!await inputTransport.PeekAsync(cancellationToken)) + { + break; + } + + if (ServerEventHandler != null) + { + await + ServerEventHandler.ProcessContextAsync(connectionContext, inputTransport, cancellationToken); + } + + if (!await processor.ProcessAsync(inputProtocol, outputProtocol, cancellationToken)) + { + break; + } + } + } + catch (TTransportException ttx) + { + Logger.LogTrace($"Transport exception: {ttx}"); + } + catch (Exception x) + { + Logger.LogError($"Error: {x}"); + } + + if (ServerEventHandler != null) + { + await + ServerEventHandler.DeleteContextAsync(connectionContext, inputProtocol, outputProtocol, + cancellationToken); + } + + inputTransport?.Close(); + outputTransport?.Close(); + + Logger.LogTrace("Completed client request processing"); + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Server/TBaseServer.cs b/lib/netcore/Thrift/Server/TBaseServer.cs new file mode 100644 index 0000000..97cc7ff --- /dev/null +++ b/lib/netcore/Thrift/Server/TBaseServer.cs @@ -0,0 +1,86 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Thrift.Protocols; +using Thrift.Transports; + +namespace Thrift.Server +{ + // ReSharper disable once InconsistentNaming + public abstract class TBaseServer + { + protected readonly ILogger Logger; + protected ITProtocolFactory InputProtocolFactory; + protected TTransportFactory InputTransportFactory; + protected ITProcessorFactory ItProcessorFactory; + protected ITProtocolFactory OutputProtocolFactory; + protected TTransportFactory OutputTransportFactory; + + protected TServerEventHandler ServerEventHandler; + protected TServerTransport ServerTransport; + + protected TBaseServer(ITProcessorFactory itProcessorFactory, TServerTransport serverTransport, + TTransportFactory inputTransportFactory, TTransportFactory outputTransportFactory, + ITProtocolFactory inputProtocolFactory, ITProtocolFactory outputProtocolFactory, + ILogger logger) + { + if (itProcessorFactory == null) throw new ArgumentNullException(nameof(itProcessorFactory)); + if (inputTransportFactory == null) throw new ArgumentNullException(nameof(inputTransportFactory)); + if (outputTransportFactory == null) throw new ArgumentNullException(nameof(outputTransportFactory)); + if (inputProtocolFactory == null) throw new ArgumentNullException(nameof(inputProtocolFactory)); + if (outputProtocolFactory == null) throw new ArgumentNullException(nameof(outputProtocolFactory)); + if (logger == null) throw new ArgumentNullException(nameof(logger)); + + ItProcessorFactory = itProcessorFactory; + ServerTransport = serverTransport; + InputTransportFactory = inputTransportFactory; + OutputTransportFactory = outputTransportFactory; + InputProtocolFactory = inputProtocolFactory; + OutputProtocolFactory = outputProtocolFactory; + Logger = logger; + } + + public void SetEventHandler(TServerEventHandler seh) + { + ServerEventHandler = seh; + } + + public TServerEventHandler GetEventHandler() + { + return ServerEventHandler; + } + + public abstract void Stop(); + + public virtual void Start() + { + // do nothing + } + + public virtual async Task ServeAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Server/TServerEventHandler.cs b/lib/netcore/Thrift/Server/TServerEventHandler.cs new file mode 100644 index 0000000..733bb4b --- /dev/null +++ b/lib/netcore/Thrift/Server/TServerEventHandler.cs @@ -0,0 +1,54 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Threading; +using System.Threading.Tasks; +using Thrift.Protocols; +using Thrift.Transports; + +namespace Thrift.Server +{ + //TODO: replacement by event? + + /// + /// Interface implemented by server users to handle events from the server + /// + // ReSharper disable once InconsistentNaming + public interface TServerEventHandler + { + /// + /// Called before the server begins */ + /// + Task PreServeAsync(CancellationToken cancellationToken); + + /// + /// Called when a new client has connected and is about to being processing */ + /// + Task CreateContextAsync(TProtocol input, TProtocol output, CancellationToken cancellationToken); + + /// + /// Called when a client has finished request-handling to delete server context */ + /// + Task DeleteContextAsync(object serverContext, TProtocol input, TProtocol output, + CancellationToken cancellationToken); + + /// + /// Called when a client is about to call the processor */ + /// + Task ProcessContextAsync(object serverContext, TClientTransport transport, CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/SingletonTProcessorFactory.cs b/lib/netcore/Thrift/SingletonTProcessorFactory.cs new file mode 100644 index 0000000..c351233 --- /dev/null +++ b/lib/netcore/Thrift/SingletonTProcessorFactory.cs @@ -0,0 +1,38 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using Thrift.Server; +using Thrift.Transports; + +namespace Thrift +{ + // ReSharper disable once InconsistentNaming + public class SingletonTProcessorFactory : ITProcessorFactory + { + private readonly ITAsyncProcessor _tAsyncProcessor; + + public SingletonTProcessorFactory(ITAsyncProcessor tAsyncProcessor) + { + _tAsyncProcessor = tAsyncProcessor; + } + + public ITAsyncProcessor GetAsyncProcessor(TClientTransport trans, TBaseServer baseServer = null) + { + return _tAsyncProcessor; + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/TApplicationException.cs b/lib/netcore/Thrift/TApplicationException.cs new file mode 100644 index 0000000..f1ea252 --- /dev/null +++ b/lib/netcore/Thrift/TApplicationException.cs @@ -0,0 +1,149 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Threading; +using System.Threading.Tasks; +using Thrift.Protocols; +using Thrift.Protocols.Entities; + +namespace Thrift +{ + // ReSharper disable once InconsistentNaming + public class TApplicationException : TException + { + public enum ExceptionType + { + Unknown, + UnknownMethod, + InvalidMessageType, + WrongMethodName, + BadSequenceId, + MissingResult, + InternalError, + ProtocolError, + InvalidTransform, + InvalidProtocol, + UnsupportedClientType + } + + private const int MessageTypeFieldId = 1; + private const int ExTypeFieldId = 2; + + protected ExceptionType Type; + + public TApplicationException() + { + } + + public TApplicationException(ExceptionType type) + { + Type = type; + } + + public TApplicationException(ExceptionType type, string message) + : base(message) + { + Type = type; + } + + public static async Task ReadAsync(TProtocol iprot, CancellationToken cancellationToken) + { + string message = null; + var type = ExceptionType.Unknown; + + await iprot.ReadStructBeginAsync(cancellationToken); + while (true) + { + var field = await iprot.ReadFieldBeginAsync(cancellationToken); + if (field.Type == TType.Stop) + { + break; + } + + switch (field.ID) + { + case MessageTypeFieldId: + if (field.Type == TType.String) + { + message = await iprot.ReadStringAsync(cancellationToken); + } + else + { + await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken); + } + break; + case ExTypeFieldId: + if (field.Type == TType.I32) + { + type = (ExceptionType) await iprot.ReadI32Async(cancellationToken); + } + else + { + await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken); + } + break; + default: + await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken); + break; + } + + await iprot.ReadFieldEndAsync(cancellationToken); + } + + await iprot.ReadStructEndAsync(cancellationToken); + + return new TApplicationException(type, message); + } + + public async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + + const string messageTypeFieldName = "message"; + const string exTypeFieldName = "exType"; + const string structApplicationExceptionName = "TApplicationException"; + + var struc = new TStruct(structApplicationExceptionName); + var field = new TField(); + + await oprot.WriteStructBeginAsync(struc, cancellationToken); + + if (!string.IsNullOrEmpty(Message)) + { + field.Name = messageTypeFieldName; + field.Type = TType.String; + field.ID = MessageTypeFieldId; + await oprot.WriteFieldBeginAsync(field, cancellationToken); + await oprot.WriteStringAsync(Message, cancellationToken); + await oprot.WriteFieldEndAsync(cancellationToken); + } + + field.Name = exTypeFieldName; + field.Type = TType.I32; + field.ID = ExTypeFieldId; + + await oprot.WriteFieldBeginAsync(field, cancellationToken); + await oprot.WriteI32Async((int) Type, cancellationToken); + await oprot.WriteFieldEndAsync(cancellationToken); + await oprot.WriteFieldStopAsync(cancellationToken); + await oprot.WriteStructEndAsync(cancellationToken); + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/TBaseClient.cs b/lib/netcore/Thrift/TBaseClient.cs new file mode 100644 index 0000000..ca403e5 --- /dev/null +++ b/lib/netcore/Thrift/TBaseClient.cs @@ -0,0 +1,102 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Thrift.Protocols; + +namespace Thrift +{ + /// + /// TBaseClient. + /// Base client for generated clients. + /// Do not change this class without checking generated code (namings, etc.) + /// + public abstract class TBaseClient + { + private readonly TProtocol _inputProtocol; + private readonly TProtocol _outputProtocol; + private bool _isDisposed; + private int _seqId; + public readonly Guid ClientId = Guid.NewGuid(); + + protected TBaseClient(TProtocol inputProtocol, TProtocol outputProtocol) + { + if (inputProtocol == null) + { + throw new ArgumentNullException(nameof(inputProtocol)); + } + + if (outputProtocol == null) + { + throw new ArgumentNullException(nameof(outputProtocol)); + } + + _inputProtocol = inputProtocol; + _outputProtocol = outputProtocol; + } + + public TProtocol InputProtocol => _inputProtocol; + + public TProtocol OutputProtocol => _outputProtocol; + + public int SeqId + { + get { return ++_seqId; } + } + + public virtual async Task OpenTransportAsync() + { + await OpenTransportAsync(CancellationToken.None); + } + + public virtual async Task OpenTransportAsync(CancellationToken cancellationToken) + { + if (!_inputProtocol.Transport.IsOpen) + { + await _inputProtocol.Transport.OpenAsync(cancellationToken); + } + + if (!_inputProtocol.Transport.IsOpen) + { + await _outputProtocol.Transport.OpenAsync(cancellationToken); + } + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + _inputProtocol?.Dispose(); + _outputProtocol?.Dispose(); + } + } + + _isDisposed = true; + } + } +} diff --git a/lib/netcore/Thrift/TException.cs b/lib/netcore/Thrift/TException.cs new file mode 100644 index 0000000..6aa588d --- /dev/null +++ b/lib/netcore/Thrift/TException.cs @@ -0,0 +1,34 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; + +namespace Thrift +{ + // ReSharper disable once InconsistentNaming + public class TException : Exception + { + public TException() + { + } + + public TException(string message) + : base(message) + { + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/TMultiplexedProcessor.cs b/lib/netcore/Thrift/TMultiplexedProcessor.cs new file mode 100644 index 0000000..ad0e749 --- /dev/null +++ b/lib/netcore/Thrift/TMultiplexedProcessor.cs @@ -0,0 +1,143 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Thrift.Protocols; +using Thrift.Protocols.Entities; + +namespace Thrift +{ + // ReSharper disable once InconsistentNaming + public class TMultiplexedProcessor : ITAsyncProcessor + { + //TODO: Localization + + private readonly Dictionary _serviceProcessorMap = + new Dictionary(); + + public async Task ProcessAsync(TProtocol iprot, TProtocol oprot) + { + return await ProcessAsync(iprot, oprot, CancellationToken.None); + } + + public async Task ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + try + { + var message = await iprot.ReadMessageBeginAsync(cancellationToken); + + if ((message.Type != TMessageType.Call) && (message.Type != TMessageType.Oneway)) + { + await FailAsync(oprot, message, TApplicationException.ExceptionType.InvalidMessageType, + "Message exType CALL or ONEWAY expected", cancellationToken); + return false; + } + + // Extract the service name + var index = message.Name.IndexOf(TMultiplexedProtocol.Separator, StringComparison.Ordinal); + if (index < 0) + { + await FailAsync(oprot, message, TApplicationException.ExceptionType.InvalidProtocol, + $"Service name not found in message name: {message.Name}. Did you forget to use a TMultiplexProtocol in your client?", + cancellationToken); + return false; + } + + // Create a new TMessage, something that can be consumed by any TProtocol + var serviceName = message.Name.Substring(0, index); + ITAsyncProcessor actualProcessor; + if (!_serviceProcessorMap.TryGetValue(serviceName, out actualProcessor)) + { + await FailAsync(oprot, message, TApplicationException.ExceptionType.InternalError, + $"Service name not found: {serviceName}. Did you forget to call RegisterProcessor()?", + cancellationToken); + return false; + } + + // Create a new TMessage, removing the service name + var newMessage = new TMessage( + message.Name.Substring(serviceName.Length + TMultiplexedProtocol.Separator.Length), + message.Type, + message.SeqID); + + // Dispatch processing to the stored processor + return + await + actualProcessor.ProcessAsync(new StoredMessageProtocol(iprot, newMessage), oprot, + cancellationToken); + } + catch (IOException) + { + return false; // similar to all other processors + } + } + + public void RegisterProcessor(string serviceName, ITAsyncProcessor processor) + { + if (_serviceProcessorMap.ContainsKey(serviceName)) + { + throw new InvalidOperationException( + $"Processor map already contains processor with name: '{serviceName}'"); + } + + _serviceProcessorMap.Add(serviceName, processor); + } + + private async Task FailAsync(TProtocol oprot, TMessage message, TApplicationException.ExceptionType extype, + string etxt, CancellationToken cancellationToken) + { + var appex = new TApplicationException(extype, etxt); + + var newMessage = new TMessage(message.Name, TMessageType.Exception, message.SeqID); + + await oprot.WriteMessageBeginAsync(newMessage, cancellationToken); + await appex.WriteAsync(oprot, cancellationToken); + await oprot.WriteMessageEndAsync(cancellationToken); + await oprot.Transport.FlushAsync(cancellationToken); + } + + private class StoredMessageProtocol : TProtocolDecorator + { + readonly TMessage _msgBegin; + + public StoredMessageProtocol(TProtocol protocol, TMessage messageBegin) + : base(protocol) + { + _msgBegin = messageBegin; + } + + public override async Task ReadMessageBeginAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + return _msgBegin; + } + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Thrift.csproj b/lib/netcore/Thrift/Thrift.csproj new file mode 100644 index 0000000..e806fed --- /dev/null +++ b/lib/netcore/Thrift/Thrift.csproj @@ -0,0 +1,31 @@ + + + + netstandard2.0 + Thrift + Thrift + true + true + false + false + false + false + false + false + false + false + + + + + + + + + + + + + + + diff --git a/lib/netcore/Thrift/Transports/Client/TBufferedClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TBufferedClientTransport.cs new file mode 100644 index 0000000..86eb735 --- /dev/null +++ b/lib/netcore/Thrift/Transports/Client/TBufferedClientTransport.cs @@ -0,0 +1,210 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Thrift.Transports.Client +{ + // ReSharper disable once InconsistentNaming + public class TBufferedClientTransport : TClientTransport + { + private readonly int _bufSize; + private readonly MemoryStream _inputBuffer = new MemoryStream(0); + private readonly MemoryStream _outputBuffer = new MemoryStream(0); + private readonly TClientTransport _transport; + private bool _isDisposed; + + //TODO: should support only specified input transport? + public TBufferedClientTransport(TClientTransport transport, int bufSize = 1024) + { + if (transport == null) + { + throw new ArgumentNullException(nameof(transport)); + } + + if (bufSize <= 0) + { + throw new ArgumentOutOfRangeException(nameof(bufSize), "Buffer size must be a positive number."); + } + + _transport = transport; + _bufSize = bufSize; + } + + public TClientTransport UnderlyingTransport + { + get + { + CheckNotDisposed(); + + return _transport; + } + } + + public override bool IsOpen => !_isDisposed && _transport.IsOpen; + + public override async Task OpenAsync(CancellationToken cancellationToken) + { + CheckNotDisposed(); + + await _transport.OpenAsync(cancellationToken); + } + + public override void Close() + { + CheckNotDisposed(); + + _transport.Close(); + } + + public override async Task ReadAsync(byte[] buffer, int offset, int length, + CancellationToken cancellationToken) + { + //TODO: investigate how it should work correctly + CheckNotDisposed(); + + ValidateBufferArgs(buffer, offset, length); + + if (!IsOpen) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen); + } + + if (_inputBuffer.Capacity < _bufSize) + { + _inputBuffer.Capacity = _bufSize; + } + + var got = await _inputBuffer.ReadAsync(buffer, offset, length, cancellationToken); + if (got > 0) + { + return got; + } + + _inputBuffer.Seek(0, SeekOrigin.Begin); + _inputBuffer.SetLength(_inputBuffer.Capacity); + + ArraySegment bufSegment; + _inputBuffer.TryGetBuffer(out bufSegment); + + // investigate + var filled = await _transport.ReadAsync(bufSegment.Array, 0, (int) _inputBuffer.Length, cancellationToken); + _inputBuffer.SetLength(filled); + + if (filled == 0) + { + return 0; + } + + return await ReadAsync(buffer, offset, length, cancellationToken); + } + + public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) + { + CheckNotDisposed(); + + ValidateBufferArgs(buffer, offset, length); + + if (!IsOpen) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen); + } + + // Relative offset from "off" argument + var writtenCount = 0; + if (_outputBuffer.Length > 0) + { + var capa = (int) (_outputBuffer.Capacity - _outputBuffer.Length); + var writeSize = capa <= length ? capa : length; + await _outputBuffer.WriteAsync(buffer, offset, writeSize, cancellationToken); + + writtenCount += writeSize; + if (writeSize == capa) + { + //ArraySegment bufSegment; + //_outputBuffer.TryGetBuffer(out bufSegment); + var data = _outputBuffer.ToArray(); + //await _transport.WriteAsync(bufSegment.Array, cancellationToken); + await _transport.WriteAsync(data, cancellationToken); + _outputBuffer.SetLength(0); + } + } + + while (length - writtenCount >= _bufSize) + { + await _transport.WriteAsync(buffer, offset + writtenCount, _bufSize, cancellationToken); + writtenCount += _bufSize; + } + + var remain = length - writtenCount; + if (remain > 0) + { + if (_outputBuffer.Capacity < _bufSize) + { + _outputBuffer.Capacity = _bufSize; + } + await _outputBuffer.WriteAsync(buffer, offset + writtenCount, remain, cancellationToken); + } + } + + public override async Task FlushAsync(CancellationToken cancellationToken) + { + CheckNotDisposed(); + + if (!IsOpen) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen); + } + + if (_outputBuffer.Length > 0) + { + //ArraySegment bufSegment; + var data = _outputBuffer.ToArray(); // TryGetBuffer(out bufSegment); + + await _transport.WriteAsync(data /*bufSegment.Array*/, cancellationToken); + _outputBuffer.SetLength(0); + } + + await _transport.FlushAsync(cancellationToken); + } + + private void CheckNotDisposed() + { + if (_isDisposed) + { + throw new ObjectDisposedException(nameof(_transport)); + } + } + + // IDisposable + protected override void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + _inputBuffer.Dispose(); + _outputBuffer.Dispose(); + } + } + _isDisposed = true; + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/Client/TFramedClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TFramedClientTransport.cs new file mode 100644 index 0000000..f54a42a --- /dev/null +++ b/lib/netcore/Thrift/Transports/Client/TFramedClientTransport.cs @@ -0,0 +1,205 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Thrift.Transports.Client +{ + //TODO: check for correct implementation + + // ReSharper disable once InconsistentNaming + public class TFramedClientTransport : TClientTransport + { + private const int HeaderSize = 4; + private readonly byte[] _headerBuf = new byte[HeaderSize]; + private readonly MemoryStream _readBuffer = new MemoryStream(1024); + private readonly TClientTransport _transport; + private readonly MemoryStream _writeBuffer = new MemoryStream(1024); + + private bool _isDisposed; + + public TFramedClientTransport(TClientTransport transport) + { + if (transport == null) + { + throw new ArgumentNullException(nameof(transport)); + } + + _transport = transport; + + InitWriteBuffer(); + } + + public override bool IsOpen => !_isDisposed && _transport.IsOpen; + + public override async Task OpenAsync(CancellationToken cancellationToken) + { + CheckNotDisposed(); + + await _transport.OpenAsync(cancellationToken); + } + + public override void Close() + { + CheckNotDisposed(); + + _transport.Close(); + } + + public override async Task ReadAsync(byte[] buffer, int offset, int length, + CancellationToken cancellationToken) + { + CheckNotDisposed(); + + ValidateBufferArgs(buffer, offset, length); + + if (!IsOpen) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen); + } + + var got = await _readBuffer.ReadAsync(buffer, offset, length, cancellationToken); + if (got > 0) + { + return got; + } + + // Read another frame of data + await ReadFrameAsync(cancellationToken); + + return await _readBuffer.ReadAsync(buffer, offset, length, cancellationToken); + } + + private async Task ReadFrameAsync(CancellationToken cancellationToken) + { + await _transport.ReadAllAsync(_headerBuf, 0, HeaderSize, cancellationToken); + + var size = DecodeFrameSize(_headerBuf); + + _readBuffer.SetLength(size); + _readBuffer.Seek(0, SeekOrigin.Begin); + + ArraySegment bufSegment; + _readBuffer.TryGetBuffer(out bufSegment); + + var buff = bufSegment.Array; + + await _transport.ReadAllAsync(buff, 0, size, cancellationToken); + } + + public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) + { + CheckNotDisposed(); + + ValidateBufferArgs(buffer, offset, length); + + if (!IsOpen) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen); + } + + if (_writeBuffer.Length + length > int.MaxValue) + { + await FlushAsync(cancellationToken); + } + + await _writeBuffer.WriteAsync(buffer, offset, length, cancellationToken); + } + + public override async Task FlushAsync(CancellationToken cancellationToken) + { + CheckNotDisposed(); + + if (!IsOpen) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen); + } + + //ArraySegment bufSegment; + //_writeBuffer.TryGetBuffer(out bufSegment); + //var buf = bufSegment.Array; + var buf = _writeBuffer.ToArray(); + + //var len = (int)_writeBuffer.Length; + var dataLen = (int) _writeBuffer.Length - HeaderSize; + if (dataLen < 0) + { + throw new InvalidOperationException(); // logic error actually + } + + // Inject message header into the reserved buffer space + EncodeFrameSize(dataLen, buf); + + // Send the entire message at once + await _transport.WriteAsync(buf, cancellationToken); + + InitWriteBuffer(); + + await _transport.FlushAsync(cancellationToken); + } + + private void InitWriteBuffer() + { + // Reserve space for message header to be put right before sending it out + _writeBuffer.SetLength(HeaderSize); + _writeBuffer.Seek(0, SeekOrigin.End); + } + + private static void EncodeFrameSize(int frameSize, byte[] buf) + { + buf[0] = (byte) (0xff & (frameSize >> 24)); + buf[1] = (byte) (0xff & (frameSize >> 16)); + buf[2] = (byte) (0xff & (frameSize >> 8)); + buf[3] = (byte) (0xff & (frameSize)); + } + + private static int DecodeFrameSize(byte[] buf) + { + return + ((buf[0] & 0xff) << 24) | + ((buf[1] & 0xff) << 16) | + ((buf[2] & 0xff) << 8) | + (buf[3] & 0xff); + } + + + private void CheckNotDisposed() + { + if (_isDisposed) + { + throw new ObjectDisposedException("TFramedClientTransport"); + } + } + + // IDisposable + protected override void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + _readBuffer.Dispose(); + _writeBuffer.Dispose(); + } + } + _isDisposed = true; + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/Client/THttpClientTransport.cs b/lib/netcore/Thrift/Transports/Client/THttpClientTransport.cs new file mode 100644 index 0000000..1e83f97 --- /dev/null +++ b/lib/netcore/Thrift/Transports/Client/THttpClientTransport.cs @@ -0,0 +1,228 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; + +namespace Thrift.Transports.Client +{ + // ReSharper disable once InconsistentNaming + public class THttpClientTransport : TClientTransport + { + private readonly X509Certificate[] _certificates; + private readonly Uri _uri; + + // Timeouts in milliseconds + private int _connectTimeout = 30000; + private HttpClient _httpClient; + private Stream _inputStream; + + private bool _isDisposed; + private MemoryStream _outputStream = new MemoryStream(); + + public THttpClientTransport(Uri u, IDictionary customHeaders) + : this(u, Enumerable.Empty(), customHeaders) + { + } + + public THttpClientTransport(Uri u, IEnumerable certificates, + IDictionary customHeaders) + { + _uri = u; + _certificates = (certificates ?? Enumerable.Empty()).ToArray(); + CustomHeaders = customHeaders; + + // due to current bug with performance of Dispose in netcore https://github.com/dotnet/corefx/issues/8809 + // this can be switched to default way (create client->use->dispose per flush) later + _httpClient = CreateClient(); + } + + public IDictionary CustomHeaders { get; } + + public int ConnectTimeout + { + set { _connectTimeout = value; } + } + + public override bool IsOpen => true; + + public override async Task OpenAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override void Close() + { + if (_inputStream != null) + { + _inputStream.Dispose(); + _inputStream = null; + } + + if (_outputStream != null) + { + _outputStream.Dispose(); + _outputStream = null; + } + + if (_httpClient != null) + { + _httpClient.Dispose(); + _httpClient = null; + } + } + + public override async Task ReadAsync(byte[] buffer, int offset, int length, + CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + if (_inputStream == null) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No request has been sent"); + } + + try + { + var ret = await _inputStream.ReadAsync(buffer, offset, length, cancellationToken); + + if (ret == -1) + { + throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "No more data available"); + } + + return ret; + } + catch (IOException iox) + { + throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString()); + } + } + + public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + + await _outputStream.WriteAsync(buffer, offset, length, cancellationToken); + } + + private HttpClient CreateClient() + { + var handler = new HttpClientHandler(); + handler.ClientCertificates.AddRange(_certificates); + + var httpClient = new HttpClient(handler); + + if (_connectTimeout > 0) + { + httpClient.Timeout = TimeSpan.FromSeconds(_connectTimeout); + } + + httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-thrift")); + httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("THttpClientTransport", "0.11.0")); + + if (CustomHeaders != null) + { + foreach (var item in CustomHeaders) + { + httpClient.DefaultRequestHeaders.Add(item.Key, item.Value); + } + } + + return httpClient; + } + + public override async Task FlushAsync(CancellationToken cancellationToken) + { + try + { + try + { + if (_outputStream.CanSeek) + { + _outputStream.Seek(0, SeekOrigin.Begin); + } + + using (var outStream = new StreamContent(_outputStream)) + { + var msg = await _httpClient.PostAsync(_uri, outStream, cancellationToken); + + msg.EnsureSuccessStatusCode(); + + if (_inputStream != null) + { + _inputStream.Dispose(); + _inputStream = null; + } + + _inputStream = await msg.Content.ReadAsStreamAsync(); + if (_inputStream.CanSeek) + { + _inputStream.Seek(0, SeekOrigin.Begin); + } + } + } + catch (IOException iox) + { + throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString()); + } + catch (WebException wx) + { + throw new TTransportException(TTransportException.ExceptionType.Unknown, + "Couldn't connect to server: " + wx); + } + } + finally + { + _outputStream = new MemoryStream(); + } + } + + // IDisposable + protected override void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + _inputStream?.Dispose(); + _outputStream?.Dispose(); + _httpClient?.Dispose(); + } + } + _isDisposed = true; + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/Client/TMemoryBufferClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TMemoryBufferClientTransport.cs new file mode 100644 index 0000000..46a55a6 --- /dev/null +++ b/lib/netcore/Thrift/Transports/Client/TMemoryBufferClientTransport.cs @@ -0,0 +1,97 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Thrift.Transports.Client +{ + // ReSharper disable once InconsistentNaming + public class TMemoryBufferClientTransport : TClientTransport + { + private readonly MemoryStream _byteStream; + private bool _isDisposed; + + public TMemoryBufferClientTransport() + { + _byteStream = new MemoryStream(); + } + + public TMemoryBufferClientTransport(byte[] buf) + { + _byteStream = new MemoryStream(buf); + } + + public override bool IsOpen => true; + + public override async Task OpenAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override void Close() + { + /** do nothing **/ + } + + public override async Task ReadAsync(byte[] buffer, int offset, int length, + CancellationToken cancellationToken) + { + return await _byteStream.ReadAsync(buffer, offset, length, cancellationToken); + } + + public override async Task WriteAsync(byte[] buffer, CancellationToken cancellationToken) + { + await _byteStream.WriteAsync(buffer, 0, buffer.Length, cancellationToken); + } + + public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) + { + await _byteStream.WriteAsync(buffer, offset, length, cancellationToken); + } + + public override async Task FlushAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public byte[] GetBuffer() + { + return _byteStream.ToArray(); + } + + // IDisposable + protected override void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + _byteStream?.Dispose(); + } + } + _isDisposed = true; + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/Client/TNamedPipeClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TNamedPipeClientTransport.cs new file mode 100644 index 0000000..f5e4baf --- /dev/null +++ b/lib/netcore/Thrift/Transports/Client/TNamedPipeClientTransport.cs @@ -0,0 +1,95 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.IO.Pipes; +using System.Threading; +using System.Threading.Tasks; + +namespace Thrift.Transports.Client +{ + // ReSharper disable once InconsistentNaming + public class TNamedPipeClientTransport : TClientTransport + { + private NamedPipeClientStream _client; + + public TNamedPipeClientTransport(string pipe) : this(".", pipe) + { + } + + public TNamedPipeClientTransport(string server, string pipe) + { + var serverName = string.IsNullOrWhiteSpace(server) ? server : "."; + + _client = new NamedPipeClientStream(serverName, pipe, PipeDirection.InOut, PipeOptions.None); + } + + public override bool IsOpen => _client != null && _client.IsConnected; + + public override async Task OpenAsync(CancellationToken cancellationToken) + { + if (IsOpen) + { + throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen); + } + + await _client.ConnectAsync(cancellationToken); + } + + public override void Close() + { + if (_client != null) + { + _client.Dispose(); + _client = null; + } + } + + public override async Task ReadAsync(byte[] buffer, int offset, int length, + CancellationToken cancellationToken) + { + if (_client == null) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen); + } + + return await _client.ReadAsync(buffer, offset, length, cancellationToken); + } + + public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) + { + if (_client == null) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen); + } + + await _client.WriteAsync(buffer, offset, length, cancellationToken); + } + + public override async Task FlushAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + protected override void Dispose(bool disposing) + { + _client.Dispose(); + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/Client/TSocketClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TSocketClientTransport.cs new file mode 100644 index 0000000..a44efe6 --- /dev/null +++ b/lib/netcore/Thrift/Transports/Client/TSocketClientTransport.cs @@ -0,0 +1,144 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +namespace Thrift.Transports.Client +{ + // ReSharper disable once InconsistentNaming + public class TSocketClientTransport : TStreamClientTransport + { + private bool _isDisposed; + + public TSocketClientTransport(TcpClient client) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } + + TcpClient = client; + + if (IsOpen) + { + InputStream = client.GetStream(); + OutputStream = client.GetStream(); + } + } + + public TSocketClientTransport(IPAddress host, int port) + : this(host, port, 0) + { + } + + public TSocketClientTransport(IPAddress host, int port, int timeout) + { + Host = host; + Port = port; + + TcpClient = new TcpClient(); + TcpClient.ReceiveTimeout = TcpClient.SendTimeout = timeout; + TcpClient.Client.NoDelay = true; + } + + public TcpClient TcpClient { get; private set; } + public IPAddress Host { get; } + public int Port { get; } + + public int Timeout + { + set + { + if (TcpClient != null) + { + TcpClient.ReceiveTimeout = TcpClient.SendTimeout = value; + } + } + } + + public override bool IsOpen + { + get + { + if (TcpClient == null) + { + return false; + } + + return TcpClient.Connected; + } + } + + public override async Task OpenAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + + if (IsOpen) + { + throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected"); + } + + if (Port <= 0) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port"); + } + + if (TcpClient == null) + { + throw new InvalidOperationException("Invalid or not initialized tcp client"); + } + + await TcpClient.ConnectAsync(Host, Port); + + InputStream = TcpClient.GetStream(); + OutputStream = TcpClient.GetStream(); + } + + public override void Close() + { + base.Close(); + + if (TcpClient != null) + { + TcpClient.Dispose(); + TcpClient = null; + } + } + + // IDisposable + protected override void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + TcpClient?.Dispose(); + + base.Dispose(disposing); + } + } + _isDisposed = true; + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/Client/TStreamClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TStreamClientTransport.cs new file mode 100644 index 0000000..f7164f0 --- /dev/null +++ b/lib/netcore/Thrift/Transports/Client/TStreamClientTransport.cs @@ -0,0 +1,110 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Thrift.Transports.Client +{ + // ReSharper disable once InconsistentNaming + public class TStreamClientTransport : TClientTransport + { + private bool _isDisposed; + + protected TStreamClientTransport() + { + } + + public TStreamClientTransport(Stream inputStream, Stream outputStream) + { + InputStream = inputStream; + OutputStream = outputStream; + } + + protected Stream OutputStream { get; set; } + + protected Stream InputStream { get; set; } + + public override bool IsOpen => true; + + public override async Task OpenAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override void Close() + { + if (InputStream != null) + { + InputStream.Dispose(); + InputStream = null; + } + + if (OutputStream != null) + { + OutputStream.Dispose(); + OutputStream = null; + } + } + + public override async Task ReadAsync(byte[] buffer, int offset, int length, + CancellationToken cancellationToken) + { + if (InputStream == null) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen, + "Cannot read from null inputstream"); + } + + return await InputStream.ReadAsync(buffer, offset, length, cancellationToken); + } + + public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) + { + if (OutputStream == null) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen, + "Cannot read from null inputstream"); + } + + await OutputStream.WriteAsync(buffer, offset, length, cancellationToken); + } + + public override async Task FlushAsync(CancellationToken cancellationToken) + { + await OutputStream.FlushAsync(cancellationToken); + } + + // IDisposable + protected override void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + InputStream?.Dispose(); + OutputStream?.Dispose(); + } + } + _isDisposed = true; + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/Client/TTlsSocketClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TTlsSocketClientTransport.cs new file mode 100644 index 0000000..a21977b --- /dev/null +++ b/lib/netcore/Thrift/Transports/Client/TTlsSocketClientTransport.cs @@ -0,0 +1,236 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Net; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; + +namespace Thrift.Transports.Client +{ + //TODO: check for correct work + + // ReSharper disable once InconsistentNaming + public class TTlsSocketClientTransport : TStreamClientTransport + { + private readonly X509Certificate2 _certificate; + private readonly RemoteCertificateValidationCallback _certValidator; + private readonly IPAddress _host; + private readonly bool _isServer; + private readonly LocalCertificateSelectionCallback _localCertificateSelectionCallback; + private readonly int _port; + private readonly SslProtocols _sslProtocols; + private TcpClient _client; + private SslStream _secureStream; + private int _timeout; + + public TTlsSocketClientTransport(TcpClient client, X509Certificate2 certificate, bool isServer = false, + RemoteCertificateValidationCallback certValidator = null, + LocalCertificateSelectionCallback localCertificateSelectionCallback = null, + SslProtocols sslProtocols = SslProtocols.Tls12) + { + _client = client; + _certificate = certificate; + _certValidator = certValidator; + _localCertificateSelectionCallback = localCertificateSelectionCallback; + _sslProtocols = sslProtocols; + _isServer = isServer; + + if (isServer && certificate == null) + { + throw new ArgumentException("TTlsSocketClientTransport needs certificate to be used for server", + "certificate"); + } + + if (IsOpen) + { + InputStream = client.GetStream(); + OutputStream = client.GetStream(); + } + } + + public TTlsSocketClientTransport(IPAddress host, int port, string certificatePath, + RemoteCertificateValidationCallback certValidator = null, + LocalCertificateSelectionCallback localCertificateSelectionCallback = null, + SslProtocols sslProtocols = SslProtocols.Tls12) + : this(host, port, 0, + new X509Certificate2(certificatePath), + certValidator, + localCertificateSelectionCallback, + sslProtocols) + { + } + + public TTlsSocketClientTransport(IPAddress host, int port, + X509Certificate2 certificate = null, + RemoteCertificateValidationCallback certValidator = null, + LocalCertificateSelectionCallback localCertificateSelectionCallback = null, + SslProtocols sslProtocols = SslProtocols.Tls12) + : this(host, port, 0, + certificate, + certValidator, + localCertificateSelectionCallback, + sslProtocols) + { + } + + public TTlsSocketClientTransport(IPAddress host, int port, int timeout, + X509Certificate2 certificate, + RemoteCertificateValidationCallback certValidator = null, + LocalCertificateSelectionCallback localCertificateSelectionCallback = null, + SslProtocols sslProtocols = SslProtocols.Tls12) + { + _host = host; + _port = port; + _timeout = timeout; + _certificate = certificate; + _certValidator = certValidator; + _localCertificateSelectionCallback = localCertificateSelectionCallback; + _sslProtocols = sslProtocols; + + InitSocket(); + } + + public int Timeout + { + set { _client.ReceiveTimeout = _client.SendTimeout = _timeout = value; } + } + + public TcpClient TcpClient => _client; + + public IPAddress Host => _host; + + public int Port => _port; + + public override bool IsOpen + { + get + { + if (_client == null) + { + return false; + } + + return _client.Connected; + } + } + + private void InitSocket() + { + _client = new TcpClient(); + _client.ReceiveTimeout = _client.SendTimeout = _timeout; + _client.Client.NoDelay = true; + } + + private bool DefaultCertificateValidator(object sender, X509Certificate certificate, X509Chain chain, + SslPolicyErrors sslValidationErrors) + { + return sslValidationErrors == SslPolicyErrors.None; + } + + public override async Task OpenAsync(CancellationToken cancellationToken) + { + if (IsOpen) + { + throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected"); + } + + if (_host == null) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host"); + } + + if (_port <= 0) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port"); + } + + if (_client == null) + { + InitSocket(); + } + + if (_client != null) + { + await _client.ConnectAsync(_host, _port); + await SetupTlsAsync(); + } + } + + public async Task SetupTlsAsync() + { + var validator = _certValidator ?? DefaultCertificateValidator; + + if (_localCertificateSelectionCallback != null) + { + _secureStream = new SslStream(_client.GetStream(), false, validator, _localCertificateSelectionCallback); + } + else + { + _secureStream = new SslStream(_client.GetStream(), false, validator); + } + + try + { + if (_isServer) + { + // Server authentication + await + _secureStream.AuthenticateAsServerAsync(_certificate, _certValidator != null, _sslProtocols, + true); + } + else + { + // Client authentication + var certs = _certificate != null + ? new X509CertificateCollection {_certificate} + : new X509CertificateCollection(); + + await _secureStream.AuthenticateAsClientAsync(_host.ToString(), certs, _sslProtocols, true); + } + } + catch (Exception) + { + Close(); + throw; + } + + InputStream = _secureStream; + OutputStream = _secureStream; + } + + public override void Close() + { + base.Close(); + if (_client != null) + { + _client.Dispose(); + _client = null; + } + + if (_secureStream != null) + { + _secureStream.Dispose(); + _secureStream = null; + } + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/Server/THttpServerTransport.cs b/lib/netcore/Thrift/Transports/Server/THttpServerTransport.cs new file mode 100644 index 0000000..6073741 --- /dev/null +++ b/lib/netcore/Thrift/Transports/Server/THttpServerTransport.cs @@ -0,0 +1,113 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Thrift.Protocols; +using Thrift.Transports.Client; + +namespace Thrift.Transports.Server +{ + // ReSharper disable once InconsistentNaming + public class THttpServerTransport + { + protected const string ContentType = "application/x-thrift"; + private readonly ILogger _logger; + private readonly RequestDelegate _next; + protected Encoding Encoding = Encoding.UTF8; + + protected ITProtocolFactory InputProtocolFactory; + protected ITProtocolFactory OutputProtocolFactory; + + protected ITAsyncProcessor Processor; + + public THttpServerTransport(ITAsyncProcessor processor, RequestDelegate next, ILoggerFactory loggerFactory) + : this(processor, new TBinaryProtocol.Factory(), next, loggerFactory) + { + } + + public THttpServerTransport(ITAsyncProcessor processor, ITProtocolFactory protocolFactory, RequestDelegate next, + ILoggerFactory loggerFactory) + : this(processor, protocolFactory, protocolFactory, next, loggerFactory) + { + } + + public THttpServerTransport(ITAsyncProcessor processor, ITProtocolFactory inputProtocolFactory, + ITProtocolFactory outputProtocolFactory, RequestDelegate next, ILoggerFactory loggerFactory) + { + if (processor == null) + { + throw new ArgumentNullException(nameof(processor)); + } + + if (inputProtocolFactory == null) + { + throw new ArgumentNullException(nameof(inputProtocolFactory)); + } + + if (outputProtocolFactory == null) + { + throw new ArgumentNullException(nameof(outputProtocolFactory)); + } + + if (loggerFactory == null) + { + throw new ArgumentNullException(nameof(loggerFactory)); + } + + Processor = processor; + InputProtocolFactory = inputProtocolFactory; + OutputProtocolFactory = outputProtocolFactory; + + _next = next; + _logger = loggerFactory.CreateLogger(); + } + + public async Task Invoke(HttpContext context) + { + context.Response.ContentType = ContentType; + await ProcessRequestAsync(context, context.RequestAborted); //TODO: check for correct logic + } + + public async Task ProcessRequestAsync(HttpContext context, CancellationToken cancellationToken) + { + var transport = new TStreamClientTransport(context.Request.Body, context.Response.Body); + + try + { + var input = InputProtocolFactory.GetProtocol(transport); + var output = OutputProtocolFactory.GetProtocol(transport); + + while (await Processor.ProcessAsync(input, output, cancellationToken)) + { + } + } + catch (TTransportException) + { + // Client died, just move on + } + finally + { + transport.Close(); + } + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/Server/TNamedPipeServerTransport.cs b/lib/netcore/Thrift/Transports/Server/TNamedPipeServerTransport.cs new file mode 100644 index 0000000..01195d4 --- /dev/null +++ b/lib/netcore/Thrift/Transports/Server/TNamedPipeServerTransport.cs @@ -0,0 +1,191 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.IO.Pipes; +using System.Threading; +using System.Threading.Tasks; + +namespace Thrift.Transports.Server +{ + // ReSharper disable once InconsistentNaming + public class TNamedPipeServerTransport : TServerTransport + { + /// + /// This is the address of the Pipe on the localhost. + /// + private readonly string _pipeAddress; + + private bool _asyncMode = true; + private volatile bool _isPending = true; + + private NamedPipeServerStream _stream = null; + + public TNamedPipeServerTransport(string pipeAddress) + { + _pipeAddress = pipeAddress; + } + + public override void Listen() + { + // nothing to do here + } + + public override void Close() + { + if (_stream != null) + { + try + { + //TODO: check for disconection + _stream.Disconnect(); + _stream.Dispose(); + } + finally + { + _stream = null; + _isPending = false; + } + } + } + + public override bool IsClientPending() + { + return _isPending; + } + + private void EnsurePipeInstance() + { + if (_stream == null) + { + var direction = PipeDirection.InOut; + var maxconn = 254; + var mode = PipeTransmissionMode.Byte; + var options = _asyncMode ? PipeOptions.Asynchronous : PipeOptions.None; + var inbuf = 4096; + var outbuf = 4096; + // TODO: security + + try + { + _stream = new NamedPipeServerStream(_pipeAddress, direction, maxconn, mode, options, inbuf, outbuf); + } + catch (NotImplementedException) // Mono still does not support async, fallback to sync + { + if (_asyncMode) + { + options &= (~PipeOptions.Asynchronous); + _stream = new NamedPipeServerStream(_pipeAddress, direction, maxconn, mode, options, inbuf, + outbuf); + _asyncMode = false; + } + else + { + throw; + } + } + } + } + + protected override async Task AcceptImplementationAsync(CancellationToken cancellationToken) + { + try + { + EnsurePipeInstance(); + + await _stream.WaitForConnectionAsync(cancellationToken); + + var trans = new ServerTransport(_stream); + _stream = null; // pass ownership to ServerTransport + + //_isPending = false; + + return trans; + } + catch (TTransportException) + { + Close(); + throw; + } + catch (Exception e) + { + Close(); + throw new TTransportException(TTransportException.ExceptionType.NotOpen, e.Message); + } + } + + private class ServerTransport : TClientTransport + { + private readonly NamedPipeServerStream _stream; + + public ServerTransport(NamedPipeServerStream stream) + { + _stream = stream; + } + + public override bool IsOpen => _stream != null && _stream.IsConnected; + + public override async Task OpenAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + public override void Close() + { + _stream?.Dispose(); + } + + public override async Task ReadAsync(byte[] buffer, int offset, int length, + CancellationToken cancellationToken) + { + if (_stream == null) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen); + } + + return await _stream.ReadAsync(buffer, offset, length, cancellationToken); + } + + public override async Task WriteAsync(byte[] buffer, int offset, int length, + CancellationToken cancellationToken) + { + if (_stream == null) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen); + } + + await _stream.WriteAsync(buffer, offset, length, cancellationToken); + } + + public override async Task FlushAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + await Task.FromCanceled(cancellationToken); + } + } + + protected override void Dispose(bool disposing) + { + _stream?.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/Server/TServerFramedTransport.cs b/lib/netcore/Thrift/Transports/Server/TServerFramedTransport.cs new file mode 100644 index 0000000..0b86e9e --- /dev/null +++ b/lib/netcore/Thrift/Transports/Server/TServerFramedTransport.cs @@ -0,0 +1,150 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; +using Thrift.Transports.Client; + +namespace Thrift.Transports.Server +{ + // ReSharper disable once InconsistentNaming + public class TServerFramedTransport : TServerTransport + { + private readonly int _clientTimeout; + private readonly int _port; + private TcpListener _server; + + public TServerFramedTransport(TcpListener listener) + : this(listener, 0) + { + } + + public TServerFramedTransport(TcpListener listener, int clientTimeout) + { + _server = listener; + _clientTimeout = clientTimeout; + } + + public TServerFramedTransport(int port) + : this(port, 0) + { + } + + public TServerFramedTransport(int port, int clientTimeout) + { + _port = port; + _clientTimeout = clientTimeout; + try + { + // Make server socket + _server = new TcpListener(IPAddress.Any, _port); + _server.Server.NoDelay = true; + } + catch (Exception) + { + _server = null; + throw new TTransportException("Could not create ServerSocket on port " + port + "."); + } + } + + public override void Listen() + { + // Make sure not to block on accept + if (_server != null) + { + try + { + _server.Start(); + } + catch (SocketException sx) + { + throw new TTransportException("Could not accept on listening socket: " + sx.Message); + } + } + } + + public override bool IsClientPending() + { + return _server.Pending(); + } + + protected override async Task AcceptImplementationAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + if (_server == null) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket."); + } + + try + { + TFramedClientTransport tSocketTransport = null; + var tcpClient = await _server.AcceptTcpClientAsync(); + + try + { + tSocketTransport = new TFramedClientTransport(new TSocketClientTransport(tcpClient) + { + Timeout = _clientTimeout + }); + + return tSocketTransport; + } + catch (Exception) + { + if (tSocketTransport != null) + { + tSocketTransport.Dispose(); + } + else // Otherwise, clean it up ourselves. + { + ((IDisposable) tcpClient).Dispose(); + } + + throw; + } + } + catch (Exception ex) + { + throw new TTransportException(ex.ToString()); + } + } + + public override void Close() + { + if (_server != null) + { + try + { + _server.Stop(); + } + catch (Exception ex) + { + throw new TTransportException("WARNING: Could not close server socket: " + ex); + } + _server = null; + } + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/Server/TServerSocketTransport.cs b/lib/netcore/Thrift/Transports/Server/TServerSocketTransport.cs new file mode 100644 index 0000000..af154ef --- /dev/null +++ b/lib/netcore/Thrift/Transports/Server/TServerSocketTransport.cs @@ -0,0 +1,162 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; +using Thrift.Transports.Client; + +namespace Thrift.Transports.Server +{ + // ReSharper disable once InconsistentNaming + public class TServerSocketTransport : TServerTransport + { + private readonly int _clientTimeout; + private readonly int _port; + private readonly bool _useBufferedSockets; + private TcpListener _server; + + public TServerSocketTransport(TcpListener listener) + : this(listener, 0) + { + } + + public TServerSocketTransport(TcpListener listener, int clientTimeout) + { + _server = listener; + _clientTimeout = clientTimeout; + } + + public TServerSocketTransport(int port) + : this(port, 0) + { + } + + public TServerSocketTransport(int port, int clientTimeout) + : this(port, clientTimeout, false) + { + } + + public TServerSocketTransport(int port, int clientTimeout, bool useBufferedSockets) + { + _port = port; + _clientTimeout = clientTimeout; + _useBufferedSockets = useBufferedSockets; + try + { + // Make server socket + _server = new TcpListener(IPAddress.Any, _port); + _server.Server.NoDelay = true; + } + catch (Exception) + { + _server = null; + throw new TTransportException("Could not create ServerSocket on port " + port + "."); + } + } + + public override void Listen() + { + // Make sure not to block on accept + if (_server != null) + { + try + { + _server.Start(); + } + catch (SocketException sx) + { + throw new TTransportException("Could not accept on listening socket: " + sx.Message); + } + } + } + + public override bool IsClientPending() + { + return _server.Pending(); + } + + protected override async Task AcceptImplementationAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + if (_server == null) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket."); + } + + try + { + TSocketClientTransport tSocketTransport = null; + var tcpClient = await _server.AcceptTcpClientAsync(); + + try + { + tSocketTransport = new TSocketClientTransport(tcpClient) + { + Timeout = _clientTimeout + }; + + if (_useBufferedSockets) + { + return new TBufferedClientTransport(tSocketTransport); + } + + return tSocketTransport; + } + catch (Exception) + { + if (tSocketTransport != null) + { + tSocketTransport.Dispose(); + } + else // Otherwise, clean it up ourselves. + { + ((IDisposable) tcpClient).Dispose(); + } + + throw; + } + } + catch (Exception ex) + { + throw new TTransportException(ex.ToString()); + } + } + + public override void Close() + { + if (_server != null) + { + try + { + _server.Stop(); + } + catch (Exception ex) + { + throw new TTransportException("WARNING: Could not close server socket: " + ex); + } + _server = null; + } + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/Server/TTlsServerSocketTransport.cs b/lib/netcore/Thrift/Transports/Server/TTlsServerSocketTransport.cs new file mode 100644 index 0000000..49abdac --- /dev/null +++ b/lib/netcore/Thrift/Transports/Server/TTlsServerSocketTransport.cs @@ -0,0 +1,156 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Net; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using Thrift.Transports.Client; + +namespace Thrift.Transports.Server +{ + // ReSharper disable once InconsistentNaming + public class TTlsServerSocketTransport : TServerTransport + { + private readonly RemoteCertificateValidationCallback _clientCertValidator; + private readonly int _clientTimeout = 0; + private readonly LocalCertificateSelectionCallback _localCertificateSelectionCallback; + private readonly int _port; + private readonly X509Certificate2 _serverCertificate; + private readonly SslProtocols _sslProtocols; + private readonly bool _useBufferedSockets; + private TcpListener _server; + + public TTlsServerSocketTransport(int port, X509Certificate2 certificate) + : this(port, false, certificate) + { + } + + public TTlsServerSocketTransport( + int port, + bool useBufferedSockets, + X509Certificate2 certificate, + RemoteCertificateValidationCallback clientCertValidator = null, + LocalCertificateSelectionCallback localCertificateSelectionCallback = null, + SslProtocols sslProtocols = SslProtocols.Tls12) + { + if (!certificate.HasPrivateKey) + { + throw new TTransportException(TTransportException.ExceptionType.Unknown, + "Your server-certificate needs to have a private key"); + } + + _port = port; + _serverCertificate = certificate; + _useBufferedSockets = useBufferedSockets; + _clientCertValidator = clientCertValidator; + _localCertificateSelectionCallback = localCertificateSelectionCallback; + _sslProtocols = sslProtocols; + + try + { + // Create server socket + _server = new TcpListener(IPAddress.Any, _port); + _server.Server.NoDelay = true; + } + catch (Exception) + { + _server = null; + throw new TTransportException($"Could not create ServerSocket on port {port}."); + } + } + + public override void Listen() + { + // Make sure accept is not blocking + if (_server != null) + { + try + { + _server.Start(); + } + catch (SocketException sx) + { + throw new TTransportException($"Could not accept on listening socket: {sx.Message}"); + } + } + } + + public override bool IsClientPending() + { + return _server.Pending(); + } + + protected override async Task AcceptImplementationAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + if (_server == null) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket."); + } + + try + { + var client = await _server.AcceptTcpClientAsync(); + client.SendTimeout = client.ReceiveTimeout = _clientTimeout; + + //wrap the client in an SSL Socket passing in the SSL cert + var tTlsSocket = new TTlsSocketClientTransport(client, _serverCertificate, true, _clientCertValidator, + _localCertificateSelectionCallback, _sslProtocols); + + await tTlsSocket.SetupTlsAsync(); + + if (_useBufferedSockets) + { + var trans = new TBufferedClientTransport(tTlsSocket); + return trans; + } + + return tTlsSocket; + } + catch (Exception ex) + { + throw new TTransportException(ex.ToString()); + } + } + + public override void Close() + { + if (_server != null) + { + try + { + _server.Stop(); + } + catch (Exception ex) + { + throw new TTransportException($"WARNING: Could not close server socket: {ex}"); + } + + _server = null; + } + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/TClientTransport.cs b/lib/netcore/Thrift/Transports/TClientTransport.cs new file mode 100644 index 0000000..cee0a00 --- /dev/null +++ b/lib/netcore/Thrift/Transports/TClientTransport.cs @@ -0,0 +1,178 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Thrift.Transports +{ + //TODO: think about client info + // ReSharper disable once InconsistentNaming + public abstract class TClientTransport : IDisposable + { + private readonly byte[] _peekBuffer = new byte[1]; + private bool _hasPeekByte; + public abstract bool IsOpen { get; } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public async Task PeekAsync(CancellationToken cancellationToken) + { + //If we already have a byte read but not consumed, do nothing. + if (_hasPeekByte) + { + return true; + } + + //If transport closed we can't peek. + if (!IsOpen) + { + return false; + } + + //Try to read one byte. If succeeds we will need to store it for the next read. + try + { + var bytes = await ReadAsync(_peekBuffer, 0, 1, cancellationToken); + if (bytes == 0) + { + return false; + } + } + catch (IOException) + { + return false; + } + + _hasPeekByte = true; + return true; + } + + public virtual async Task OpenAsync() + { + await OpenAsync(CancellationToken.None); + } + + public abstract Task OpenAsync(CancellationToken cancellationToken); + + public abstract void Close(); + + protected static void ValidateBufferArgs(byte[] buffer, int offset, int length) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + if (offset < 0) + { + throw new ArgumentOutOfRangeException(nameof(offset), "Buffer offset is smaller than zero."); + } + + if (length < 0) + { + throw new ArgumentOutOfRangeException(nameof(length), "Buffer length is smaller than zero."); + } + + if (offset + length > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(buffer), "Not enough data."); + } + } + + public virtual async Task ReadAsync(byte[] buffer, int offset, int length) + { + return await ReadAsync(buffer, offset, length, CancellationToken.None); + } + + public abstract Task ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken); + + public virtual async Task ReadAllAsync(byte[] buffer, int offset, int length) + { + return await ReadAllAsync(buffer, offset, length, CancellationToken.None); + } + + public virtual async Task ReadAllAsync(byte[] buffer, int offset, int length, + CancellationToken cancellationToken) + { + ValidateBufferArgs(buffer, offset, length); + + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var retrieved = 0; + + //If we previously peeked a byte, we need to use that first. + if (_hasPeekByte) + { + buffer[offset + retrieved++] = _peekBuffer[0]; + _hasPeekByte = false; + } + + while (retrieved < length) + { + if (cancellationToken.IsCancellationRequested) + { + return await Task.FromCanceled(cancellationToken); + } + + var returnedCount = await ReadAsync(buffer, offset + retrieved, length - retrieved, cancellationToken); + if (returnedCount <= 0) + { + throw new TTransportException(TTransportException.ExceptionType.EndOfFile, + "Cannot read, Remote side has closed"); + } + retrieved += returnedCount; + } + return retrieved; + } + + public virtual async Task WriteAsync(byte[] buffer) + { + await WriteAsync(buffer, CancellationToken.None); + } + + public virtual async Task WriteAsync(byte[] buffer, CancellationToken cancellationToken) + { + await WriteAsync(buffer, 0, buffer.Length, CancellationToken.None); + } + + public virtual async Task WriteAsync(byte[] buffer, int offset, int length) + { + await WriteAsync(buffer, offset, length, CancellationToken.None); + } + + public abstract Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken); + + public virtual async Task FlushAsync() + { + await FlushAsync(CancellationToken.None); + } + + public abstract Task FlushAsync(CancellationToken cancellationToken); + + protected abstract void Dispose(bool disposing); + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/TServerTransport.cs b/lib/netcore/Thrift/Transports/TServerTransport.cs new file mode 100644 index 0000000..d49feb6 --- /dev/null +++ b/lib/netcore/Thrift/Transports/TServerTransport.cs @@ -0,0 +1,54 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Threading; +using System.Threading.Tasks; + +namespace Thrift.Transports +{ + // ReSharper disable once InconsistentNaming + public abstract class TServerTransport + { + public abstract void Listen(); + public abstract void Close(); + public abstract bool IsClientPending(); + + protected virtual async Task AcceptImplementationAsync() + { + return await AcceptImplementationAsync(CancellationToken.None); + } + + protected abstract Task AcceptImplementationAsync(CancellationToken cancellationToken); + + public async Task AcceptAsync() + { + return await AcceptAsync(CancellationToken.None); + } + + public async Task AcceptAsync(CancellationToken cancellationToken) + { + var transport = await AcceptImplementationAsync(cancellationToken); + + if (transport == null) + { + throw new TTransportException("AcceptAsync() should not return null"); + } + + return transport; + } + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/TTransportException.cs b/lib/netcore/Thrift/Transports/TTransportException.cs new file mode 100644 index 0000000..b7c42e3 --- /dev/null +++ b/lib/netcore/Thrift/Transports/TTransportException.cs @@ -0,0 +1,58 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +namespace Thrift.Transports +{ + // ReSharper disable once InconsistentNaming + public class TTransportException : TException + { + public enum ExceptionType + { + Unknown, + NotOpen, + AlreadyOpen, + TimedOut, + EndOfFile, + Interrupted + } + + protected ExceptionType ExType; + + public TTransportException() + { + } + + public TTransportException(ExceptionType exType) + : this() + { + ExType = exType; + } + + public TTransportException(ExceptionType exType, string message) + : base(message) + { + ExType = exType; + } + + public TTransportException(string message) + : base(message) + { + } + + public ExceptionType Type => ExType; + } +} \ No newline at end of file diff --git a/lib/netcore/Thrift/Transports/TTransportFactory.cs b/lib/netcore/Thrift/Transports/TTransportFactory.cs new file mode 100644 index 0000000..26c3cc4 --- /dev/null +++ b/lib/netcore/Thrift/Transports/TTransportFactory.cs @@ -0,0 +1,35 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +namespace Thrift.Transports +{ + /// + /// From Mark Slee & Aditya Agarwal of Facebook: + /// Factory class used to create wrapped instance of Transports. + /// This is used primarily in servers, which get Transports from + /// a ServerTransport and then may want to mutate them (i.e. create + /// a BufferedTransport from the underlying base transport) + /// + // ReSharper disable once InconsistentNaming + public class TTransportFactory + { + public virtual TClientTransport GetTransport(TClientTransport trans) + { + return trans; + } + } +} \ No newline at end of file diff --git a/lib/nodejs/Makefile.am b/lib/nodejs/Makefile.am new file mode 100755 index 0000000..9a7b4eb --- /dev/null +++ b/lib/nodejs/Makefile.am @@ -0,0 +1,42 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# We call npm twice to work around npm issues + +stubs: $(top_srcdir)/test/ThriftTest.thrift + $(THRIFT) --gen js:node -o test/ $(top_srcdir)/test/ThriftTest.thrift + +deps: $(top_srcdir)/package.json + $(NPM) install $(top_srcdir)/ || $(NPM) install $(top_srcdir)/ + +all-local: deps + +precross: deps stubs + +check: deps + cd $(top_srcdir) && $(NPM) test && cd lib/nodejs + +clean-local: + $(RM) -r test/gen-nodejs + $(RM) -r $(top_srcdir)/node_modules + +EXTRA_DIST = \ + examples \ + lib \ + test \ + coding_standards.md \ + README.md diff --git a/lib/nodejs/Makefile.in b/lib/nodejs/Makefile.in new file mode 100644 index 0000000..736e129 --- /dev/null +++ b/lib/nodejs/Makefile.in @@ -0,0 +1,647 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# We call npm twice to work around npm issues +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/nodejs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + examples \ + lib \ + test \ + coding_standards.md \ + README.md + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/nodejs/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/nodejs/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am all-local check check-am clean clean-generic \ + clean-libtool clean-local cscopelist-am ctags-am distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +stubs: $(top_srcdir)/test/ThriftTest.thrift + $(THRIFT) --gen js:node -o test/ $(top_srcdir)/test/ThriftTest.thrift + +deps: $(top_srcdir)/package.json + $(NPM) install $(top_srcdir)/ || $(NPM) install $(top_srcdir)/ + +all-local: deps + +precross: deps stubs + +check: deps + cd $(top_srcdir) && $(NPM) test && cd lib/nodejs + +clean-local: + $(RM) -r test/gen-nodejs + $(RM) -r $(top_srcdir)/node_modules + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/nodejs/README.md b/lib/nodejs/README.md new file mode 100644 index 0000000..8c25380 --- /dev/null +++ b/lib/nodejs/README.md @@ -0,0 +1,68 @@ +Thrift Node.js Library +========================= + +License +------- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + +## Compatibility + +node version 4 or later is required + +## Install + + npm install thrift + +## Thrift Compiler + +You can compile IDL sources for Node.js with the following command: + + thrift --gen js:node thrift_file + +## Cassandra Client Example: + +Here is a Cassandra example: + + var thrift = require('thrift'), + Cassandra = require('./gen-nodejs/Cassandra') + ttypes = require('./gen-nodejs/cassandra_types'); + + var connection = thrift.createConnection("localhost", 9160), + client = thrift.createClient(Cassandra, connection); + + connection.on('error', function(err) { + console.error(err); + }); + + client.get_slice("Keyspace", "key", new ttypes.ColumnParent({column_family: "ExampleCF"}), new ttypes.SlicePredicate({slice_range: new ttypes.SliceRange({start: '', finish: ''})}), ttypes.ConsistencyLevel.ONE, function(err, data) { + if (err) { + // handle err + } else { + // data == [ttypes.ColumnOrSuperColumn, ...] + } + connection.end(); + }); + + +## Int64 + +Since JavaScript represents all numbers as doubles, int64 values cannot be accurately represented naturally. To solve this, int64 values in responses will be wrapped with Thrift.Int64 objects. The Int64 implementation used is [broofa/node-int64](https://github.com/broofa/node-int64). + +## Client and server examples + +Several example clients and servers are included in the thrift/lib/nodejs/examples folder and the cross language tutorial thrift/tutorial/nodejs folder. diff --git a/lib/nodejs/coding_standards.md b/lib/nodejs/coding_standards.md new file mode 100644 index 0000000..fa0390b --- /dev/null +++ b/lib/nodejs/coding_standards.md @@ -0,0 +1 @@ +Please follow [General Coding Standards](/doc/coding_standards.md) diff --git a/lib/nodejs/examples/Makefile b/lib/nodejs/examples/Makefile new file mode 100644 index 0000000..87157db --- /dev/null +++ b/lib/nodejs/examples/Makefile @@ -0,0 +1,24 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +all: + ../../../compiler/cpp/thrift --gen js:node user.thrift + +server: all + NODE_PATH=../lib:../lib/thrift:$(NODE_PATH) node server.js + +client: all + NODE_PATH=../lib:../lib/thrift:$(NODE_PATH) node client.js diff --git a/lib/nodejs/examples/README.md b/lib/nodejs/examples/README.md new file mode 100644 index 0000000..7350c10 --- /dev/null +++ b/lib/nodejs/examples/README.md @@ -0,0 +1,40 @@ +# Thrift Node.js Examples + +## License +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + +## Running the user example + +Generate the bindings: + + ../../../compiler/cpp/thrift --gen js:node user.thrift + ../../../compiler/cpp/thrift --gen js:node --gen py hello.thrift + +To run the user example, first start up the server in one terminal: + + NODE_PATH=../lib:../lib/thrift node server.js + +Now run the client: + + NODE_PATH=../lib:../lib/thrift node client.js + +For an example using JavaScript in the browser to connect to +a node.js server look at hello.html, hello.js and hello.thrift + +HTTP examples are provided also: httpClient.js and httpServer.js +You can test HTTP cross platform with the httpServer.py Python server diff --git a/lib/nodejs/examples/client.js b/lib/nodejs/examples/client.js new file mode 100644 index 0000000..c83b342 --- /dev/null +++ b/lib/nodejs/examples/client.js @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var thrift = require('thrift'); + +var UserStorage = require('./gen-nodejs/UserStorage.js'), + ttypes = require('./gen-nodejs/user_types'); + +var connection = thrift.createConnection('localhost', 9090), + client = thrift.createClient(UserStorage, connection); + +var user = new ttypes.UserProfile({uid: 1, + name: "Mark Slee", + blurb: "I'll find something to put here."}); + +connection.on('error', function(err) { + console.error(err); +}); + +client.store(user, function(err, response) { + if (err) { + console.error(err); + } else { + console.log("client stored:", user.uid); + client.retrieve(user.uid, function(err, responseUser) { + if (err) { + console.error(err); + } else { + console.log("client retrieved:", responseUser.uid); + connection.end(); + } + }); + } +}); diff --git a/lib/nodejs/examples/client_multitransport.js b/lib/nodejs/examples/client_multitransport.js new file mode 100644 index 0000000..1e37de3 --- /dev/null +++ b/lib/nodejs/examples/client_multitransport.js @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var thrift = require('thrift'), + ttransport = require('thrift/transport'); + +var UserStorage = require('./gen-nodejs/UserStorage'), + ttypes = require('./gen-nodejs/user_types'); + +var f_conn = thrift.createConnection('localhost', 9090), // default: framed + f_client = thrift.createClient(UserStorage, f_conn); +var b_conn = thrift.createConnection('localhost', 9091, {transport: ttransport.TBufferedTransport}), + b_client = thrift.createClient(UserStorage, b_conn); +var user1 = new ttypes.UserProfile({uid: 1, + name: "Mark Slee", + blurb: "I'll find something to put here."}); +var user2 = new ttypes.UserProfile({uid: 2, + name: "Satoshi Tagomori", + blurb: "ok, let's test with buffered transport."}); + +f_conn.on('error', function(err) { + console.error("framed:", err); +}); + +f_client.store(user1, function(err, response) { + if (err) { console.error(err); return; } + + console.log("stored:", user1.uid, " as ", user1.name); + b_client.retrieve(user1.uid, function(err, responseUser) { + if (err) { console.error(err); return; } + console.log("retrieved:", responseUser.uid, " as ", responseUser.name); + }); +}); + +b_client.store(user2, function(err, response) { + if (err) { console.error(err); return; } + + console.log("stored:", user2.uid, " as ", user2.name); + f_client.retrieve(user2.uid, function(err, responseUser) { + if (err) { console.error(err); return; } + console.log("retrieved:", responseUser.uid, " as ", responseUser.name); + }); +}); diff --git a/lib/nodejs/examples/hello.html b/lib/nodejs/examples/hello.html new file mode 100644 index 0000000..fe85a7e --- /dev/null +++ b/lib/nodejs/examples/hello.html @@ -0,0 +1,65 @@ + + + + + Apache Thrift JavaScript Browser Client Demo + + + + + +

Apache Thrift JavaScript Browser Client Demo

+

This html file demonstrates Apache Thrift JavaScrpt RPC between a browser client to a node.js server. Clicking the buttons below will call the RPC functions hosted by the Apache Thrift server at localhost:8585. The file hello.js contains the JavaScript node.js server required. Here are the steps to get the example running:

+
    +
  1. Install Node.js
    nodejs.org
  2. +
  3. Install Apache Thrift for node (note that the node package manager will create the node_modules folder in the current directory so make sure to run npm from the same directory as hello.js so that the server can find the Thrift libraries. This example requires Apache Thrift 0.9.2+)
    $ npm install thrift
  4. +
  5. Compile the hello.idl for JavaScript and Node.js (you'll need to have the Apache Thrift compiler installed for this step. This also needs to be executed in the same directory as hello.js because hello.js and hello.html look for the gen-nodejs and gen-js directories here.)
    $ thrift -gen js -gen js:node hello.thrift
  6. +
  7. Run the node server in the directory with the hello.html file
    $ node hello.js
  8. +
  9. Copy the Apache Thrift JavaScript library, thrift.js, into the directory with this html file.
    $ cp ...../thrift.js . (you should be able to use Bower to install the browser based Apache Thrift library in the near future.)
    +
  10. Reload this page in a browser through the node server using using the URL:
    http://localhost:8585/hello.html
    then click a button below to make an RPC call
  11. +
+ + + +

Server Response:

+

Server Dbl:

+ + + diff --git a/lib/nodejs/examples/hello.js b/lib/nodejs/examples/hello.js new file mode 100644 index 0000000..8b7c4e4 --- /dev/null +++ b/lib/nodejs/examples/hello.js @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var thrift = require('thrift'); +var HelloSvc = require('./gen-nodejs/HelloSvc.js'); +var TimesTwoSvc = require('./gen-nodejs/TimesTwo.js'); + +var helloHandler = { + hello_func: function(result) { + this.call_counter = this.call_counter || 0; + console.log("Client call: " + (++this.call_counter)); + result(null, "Hello Apache Thrift for JavaScript " + this.call_counter); + } +} + +var timesTwoHandler = { + dbl: function(val, result) { + console.log("Client call: " + val); + result(null, val * 2); + } +} + +var helloService = { + transport: thrift.TBufferedTransport, + protocol: thrift.TJSONProtocol, + processor: HelloSvc, + handler: helloHandler +}; + +var dblService = { + transport: thrift.TBufferedTransport, + protocol: thrift.TJSONProtocol, + processor: TimesTwoSvc, + handler: timesTwoHandler +}; + +var ServerOptions = { + files: ".", + services: { + "/hello": helloService, + "/dbl": dblService, + } +} + +var server = thrift.createWebServer(ServerOptions); +var port = 8585; +server.listen(port); +console.log("Http/Thrift Server running on port: " + port); diff --git a/lib/nodejs/examples/hello.thrift b/lib/nodejs/examples/hello.thrift new file mode 100644 index 0000000..deaf5a5 --- /dev/null +++ b/lib/nodejs/examples/hello.thrift @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +service HelloSvc { + string hello_func(), +} + +service TimesTwo { + i64 dbl(1: i64 val), +} + + diff --git a/lib/nodejs/examples/httpClient.js b/lib/nodejs/examples/httpClient.js new file mode 100644 index 0000000..19cc0c3 --- /dev/null +++ b/lib/nodejs/examples/httpClient.js @@ -0,0 +1,23 @@ +var thrift = require('thrift'); +var helloSvc = require('./gen-nodejs/HelloSvc.js'); + +var options = { + transport: thrift.TBufferedTransport, + protocol: thrift.TJSONProtocol, + path: "/hello", + headers: {"Connection": "close"}, + https: false +}; + +var connection = thrift.createHttpConnection("localhost", 9090, options); +var client = thrift.createHttpClient(helloSvc, connection); + +connection.on("error", function(err) { + console.log("Error: " + err); +}); + +client.hello_func(function(error, result) { + console.log("Msg from server: " + result); +}); + + diff --git a/lib/nodejs/examples/httpServer.js b/lib/nodejs/examples/httpServer.js new file mode 100644 index 0000000..acae136 --- /dev/null +++ b/lib/nodejs/examples/httpServer.js @@ -0,0 +1,31 @@ +var thrift = require('thrift'); +var helloSvc = require('./gen-nodejs/HelloSvc'); + +//ServiceHandler: Implement the hello service +var helloHandler = { + hello_func: function (result) { + console.log("Received Hello call"); + result(null, "Hello from Node.js"); + } +}; + +//ServiceOptions: The I/O stack for the service +var helloSvcOpt = { + handler: helloHandler, + processor: helloSvc, + protocol: thrift.TJSONProtocol, + transport: thrift.TBufferedTransport +}; + +//ServerOptions: Define server features +var serverOpt = { + services: { + "/hello": helloSvcOpt + } +} + +//Create and start the web server +var port = 9090; +thrift.createWebServer(serverOpt).listen(port); +console.log("Http/Thrift Server running on port: " + port); + diff --git a/lib/nodejs/examples/httpServer.py b/lib/nodejs/examples/httpServer.py new file mode 100644 index 0000000..b712fcd --- /dev/null +++ b/lib/nodejs/examples/httpServer.py @@ -0,0 +1,18 @@ +import sys +sys.path.append('gen-py') + +from hello import HelloSvc +from thrift.protocol import TJSONProtocol +from thrift.server import THttpServer + +class HelloSvcHandler: + def hello_func(self): + print("Hello Called") + return "hello from Python" + +processor = HelloSvc.Processor(HelloSvcHandler()) +protoFactory = TJSONProtocol.TJSONProtocolFactory() +port = 9090 +server = THttpServer.THttpServer(processor, ("localhost", port), protoFactory) +print "Python server running on port " + str(port) +server.serve() diff --git a/lib/nodejs/examples/parse.js b/lib/nodejs/examples/parse.js new file mode 100644 index 0000000..168a1ae --- /dev/null +++ b/lib/nodejs/examples/parse.js @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +/** + + This is a standalone deserialize/parse example if you just want to deserialize + thrift decoupled from cassandra server + + 1. acquire thrift template specification files from who ever built it (eg: EXAMPLE.thrift) + + 2. Install thrift on local machine + + 3. generate thrift clients for nodejs using template specification files (#1) + thrift --gen js:node schema/EXAMPLE.thrift + + This creates creates gen-node.js directory containing a new file, GENERATED.js + + 4. Inside GENERATED.js is a class you will want to instanciate. Find this class name and plug + it into the example code below (ie, "YOUR_CLASS_NAME") + */ + +function parseThrift(thriftEncodedData, callback) { + var thrift = require('thrift'); + var transport = new thrift.TFramedTransport(thriftEncodedData); + var protocol = new thrift.TBinaryProtocol(transport); + + var clientClass = require('../gen-nodejs/GENERATED').YOUR_CLASS_NAME; + var client = new clientClass(); + client.read(protocol); + callback(null, client); +} diff --git a/lib/nodejs/examples/server.js b/lib/nodejs/examples/server.js new file mode 100644 index 0000000..1c482fe --- /dev/null +++ b/lib/nodejs/examples/server.js @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var thrift = require('thrift'); + +var UserStorage = require('./gen-nodejs/UserStorage.js'), + ttypes = require('./gen-nodejs/user_types'); + +var users = {}; + +var server = thrift.createServer(UserStorage, { + store: function(user, result) { + console.log("server stored:", user.uid); + users[user.uid] = user; + result(null); + }, + + retrieve: function(uid, result) { + console.log("server retrieved:", uid); + result(null, users[uid]); + }, +}); + +server.listen(9090); diff --git a/lib/nodejs/examples/server_http.js b/lib/nodejs/examples/server_http.js new file mode 100644 index 0000000..ef2dc83 --- /dev/null +++ b/lib/nodejs/examples/server_http.js @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var connect = require('connect'); +var thrift = require('thrift'); + +var UserStorage = require('./gen-nodejs/UserStorage'), + ttypes = require('./gen-nodejs/user_types'); + +var users = {}; + +var store = function(user, result) { + console.log("stored:", user.uid); + users[user.uid] = user; + result(null); +}; +var retrieve = function(uid, result) { + console.log("retrieved:", uid); + result(null, users[uid]); +}; + +var server_http = thrift.createHttpServer(UserStorage, { + store: store, + retrieve: retrieve +}); +server_http.listen(9090); + +var server_connect = connect(thrift.httpMiddleware(UserStorage, { + store: store, + retrieve: retrieve +})); +server_http.listen(9091); + +var server_connect_json = connect(thrift.httpMiddleware(UserStorage, { + store: store, + retrieve: retrieve +}, {protocol: thrift.TJSONProtocol})); +server_connect_json.listen(9092); diff --git a/lib/nodejs/examples/server_multitransport.js b/lib/nodejs/examples/server_multitransport.js new file mode 100644 index 0000000..a348e68 --- /dev/null +++ b/lib/nodejs/examples/server_multitransport.js @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var thrift = require('thrift'), + ttransport = require('thrift/transport'); + +var UserStorage = require('./gen-nodejs/UserStorage'), + ttypes = require('./gen-nodejs/user_types'); + +var users = {}; + +var store = function(user, result) { + console.log("stored:", user.uid); + users[user.uid] = user; + result(null); +}; +var retrieve = function(uid, result) { + console.log("retrieved:", uid); + result(null, users[uid]); +}; + +var server_framed = thrift.createServer(UserStorage, { + store: store, + retrieve: retrieve +}); +server_framed.listen(9090); +var server_buffered = thrift.createServer(UserStorage, { + store: store, + retrieve: retrieve +}, {transport: ttransport.TBufferedTransport}); +server_buffered.listen(9091); diff --git a/lib/nodejs/examples/user.thrift b/lib/nodejs/examples/user.thrift new file mode 100644 index 0000000..d087fd4 --- /dev/null +++ b/lib/nodejs/examples/user.thrift @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +struct UserProfile { + 1: i32 uid, + 2: string name, + 3: string blurb +} + +service UserStorage { + void store(1: UserProfile user), + UserProfile retrieve(1: i32 uid) +} diff --git a/lib/nodejs/lib/thrift/binary.js b/lib/nodejs/lib/thrift/binary.js new file mode 100644 index 0000000..9813ffd --- /dev/null +++ b/lib/nodejs/lib/thrift/binary.js @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var POW_8 = Math.pow(2, 8); +var POW_16 = Math.pow(2, 16); +var POW_24 = Math.pow(2, 24); +var POW_32 = Math.pow(2, 32); +var POW_40 = Math.pow(2, 40); +var POW_48 = Math.pow(2, 48); +var POW_52 = Math.pow(2, 52); +var POW_1022 = Math.pow(2, 1022); + +exports.readByte = function(b){ + return b > 127 ? b-256 : b; +}; + +exports.readI16 = function(buff, off) { + off = off || 0; + var v = buff[off + 1]; + v += buff[off] << 8; + if (buff[off] & 128) { + v -= POW_16; + } + return v; +}; + +exports.readI32 = function(buff, off) { + off = off || 0; + var v = buff[off + 3]; + v += buff[off + 2] << 8; + v += buff[off + 1] << 16; + v += buff[off] * POW_24; + if (buff[off] & 0x80) { + v -= POW_32; + } + return v; +}; + +exports.writeI16 = function(buff, v) { + buff[1] = v & 0xff; + v >>= 8; + buff[0] = v & 0xff; + return buff; +}; + +exports.writeI32 = function(buff, v) { + buff[3] = v & 0xff; + v >>= 8; + buff[2] = v & 0xff; + v >>= 8; + buff[1] = v & 0xff; + v >>= 8; + buff[0] = v & 0xff; + return buff; +}; + +exports.readDouble = function(buff, off) { + off = off || 0; + var signed = buff[off] & 0x80; + var e = (buff[off+1] & 0xF0) >> 4; + e += (buff[off] & 0x7F) << 4; + + var m = buff[off+7]; + m += buff[off+6] << 8; + m += buff[off+5] << 16; + m += buff[off+4] * POW_24; + m += buff[off+3] * POW_32; + m += buff[off+2] * POW_40; + m += (buff[off+1] & 0x0F) * POW_48; + + switch (e) { + case 0: + e = -1022; + break; + case 2047: + return m ? NaN : (signed ? -Infinity : Infinity); + default: + m += POW_52; + e -= 1023; + } + + if (signed) { + m *= -1; + } + + return m * Math.pow(2, e - 52); +}; + +/* + * Based on code from the jspack module: + * http://code.google.com/p/jspack/ + */ +exports.writeDouble = function(buff, v) { + var m, e, c; + + buff[0] = (v < 0 ? 0x80 : 0x00); + + v = Math.abs(v); + if (v !== v) { + // NaN, use QNaN IEEE format + m = 2251799813685248; + e = 2047; + } else if (v === Infinity) { + m = 0; + e = 2047; + } else { + e = Math.floor(Math.log(v) / Math.LN2); + c = Math.pow(2, -e); + if (v * c < 1) { + e--; + c *= 2; + } + + if (e + 1023 >= 2047) + { + // Overflow + m = 0; + e = 2047; + } + else if (e + 1023 >= 1) + { + // Normalized - term order matters, as Math.pow(2, 52-e) and v*Math.pow(2, 52) can overflow + m = (v*c-1) * POW_52; + e += 1023; + } + else + { + // Denormalized - also catches the '0' case, somewhat by chance + m = (v * POW_1022) * POW_52; + e = 0; + } + } + + buff[1] = (e << 4) & 0xf0; + buff[0] |= (e >> 4) & 0x7f; + + buff[7] = m & 0xff; + m = Math.floor(m / POW_8); + buff[6] = m & 0xff; + m = Math.floor(m / POW_8); + buff[5] = m & 0xff; + m = Math.floor(m / POW_8); + buff[4] = m & 0xff; + m >>= 8; + buff[3] = m & 0xff; + m >>= 8; + buff[2] = m & 0xff; + m >>= 8; + buff[1] |= m & 0x0f; + + return buff; +}; diff --git a/lib/nodejs/lib/thrift/binary_protocol.js b/lib/nodejs/lib/thrift/binary_protocol.js new file mode 100644 index 0000000..0c0ee50 --- /dev/null +++ b/lib/nodejs/lib/thrift/binary_protocol.js @@ -0,0 +1,364 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var log = require('./log'); +var binary = require('./binary'); +var Int64 = require('node-int64'); +var Thrift = require('./thrift'); +var Type = Thrift.Type; + +module.exports = TBinaryProtocol; + +// JavaScript supports only numeric doubles, therefore even hex values are always signed. +// The largest integer value which can be represented in JavaScript is +/-2^53. +// Bitwise operations convert numbers to 32 bit integers but perform sign extension +// upon assigning values back to variables. +var VERSION_MASK = -65536, // 0xffff0000 + VERSION_1 = -2147418112, // 0x80010000 + TYPE_MASK = 0x000000ff; + +function TBinaryProtocol(trans, strictRead, strictWrite) { + this.trans = trans; + this.strictRead = (strictRead !== undefined ? strictRead : false); + this.strictWrite = (strictWrite !== undefined ? strictWrite : true); +}; + +TBinaryProtocol.prototype.flush = function() { + return this.trans.flush(); +}; + +TBinaryProtocol.prototype.writeMessageBegin = function(name, type, seqid) { + if (this.strictWrite) { + this.writeI32(VERSION_1 | type); + this.writeString(name); + this.writeI32(seqid); + } else { + this.writeString(name); + this.writeByte(type); + this.writeI32(seqid); + } + // Record client seqid to find callback again + if (this._seqid) { + log.warning('SeqId already set', { 'name': name }); + } else { + this._seqid = seqid; + this.trans.setCurrSeqId(seqid); + } +}; + +TBinaryProtocol.prototype.writeMessageEnd = function() { + if (this._seqid) { + this._seqid = null; + } else { + log.warning('No seqid to unset'); + } +}; + +TBinaryProtocol.prototype.writeStructBegin = function(name) { +}; + +TBinaryProtocol.prototype.writeStructEnd = function() { +}; + +TBinaryProtocol.prototype.writeFieldBegin = function(name, type, id) { + this.writeByte(type); + this.writeI16(id); +}; + +TBinaryProtocol.prototype.writeFieldEnd = function() { +}; + +TBinaryProtocol.prototype.writeFieldStop = function() { + this.writeByte(Type.STOP); +}; + +TBinaryProtocol.prototype.writeMapBegin = function(ktype, vtype, size) { + this.writeByte(ktype); + this.writeByte(vtype); + this.writeI32(size); +}; + +TBinaryProtocol.prototype.writeMapEnd = function() { +}; + +TBinaryProtocol.prototype.writeListBegin = function(etype, size) { + this.writeByte(etype); + this.writeI32(size); +}; + +TBinaryProtocol.prototype.writeListEnd = function() { +}; + +TBinaryProtocol.prototype.writeSetBegin = function(etype, size) { + this.writeByte(etype); + this.writeI32(size); +}; + +TBinaryProtocol.prototype.writeSetEnd = function() { +}; + +TBinaryProtocol.prototype.writeBool = function(bool) { + if (bool) { + this.writeByte(1); + } else { + this.writeByte(0); + } +}; + +TBinaryProtocol.prototype.writeByte = function(b) { + this.trans.write(new Buffer([b])); +}; + +TBinaryProtocol.prototype.writeI16 = function(i16) { + this.trans.write(binary.writeI16(new Buffer(2), i16)); +}; + +TBinaryProtocol.prototype.writeI32 = function(i32) { + this.trans.write(binary.writeI32(new Buffer(4), i32)); +}; + +TBinaryProtocol.prototype.writeI64 = function(i64) { + if (i64.buffer) { + this.trans.write(i64.buffer); + } else { + this.trans.write(new Int64(i64).buffer); + } +}; + +TBinaryProtocol.prototype.writeDouble = function(dub) { + this.trans.write(binary.writeDouble(new Buffer(8), dub)); +}; + +TBinaryProtocol.prototype.writeStringOrBinary = function(name, encoding, arg) { + if (typeof(arg) === 'string') { + this.writeI32(Buffer.byteLength(arg, encoding)); + this.trans.write(new Buffer(arg, encoding)); + } else if ((arg instanceof Buffer) || + (Object.prototype.toString.call(arg) == '[object Uint8Array]')) { + // Buffers in Node.js under Browserify may extend UInt8Array instead of + // defining a new object. We detect them here so we can write them + // correctly + this.writeI32(arg.length); + this.trans.write(arg); + } else { + throw new Error(name + ' called without a string/Buffer argument: ' + arg); + } +}; + +TBinaryProtocol.prototype.writeString = function(arg) { + this.writeStringOrBinary('writeString', 'utf8', arg); +}; + +TBinaryProtocol.prototype.writeBinary = function(arg) { + this.writeStringOrBinary('writeBinary', 'binary', arg); +}; + +TBinaryProtocol.prototype.readMessageBegin = function() { + var sz = this.readI32(); + var type, name, seqid; + + if (sz < 0) { + var version = sz & VERSION_MASK; + if (version != VERSION_1) { + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "Bad version in readMessageBegin: " + sz); + } + type = sz & TYPE_MASK; + name = this.readString(); + seqid = this.readI32(); + } else { + if (this.strictRead) { + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "No protocol version header"); + } + name = this.trans.read(sz); + type = this.readByte(); + seqid = this.readI32(); + } + return {fname: name, mtype: type, rseqid: seqid}; +}; + +TBinaryProtocol.prototype.readMessageEnd = function() { +}; + +TBinaryProtocol.prototype.readStructBegin = function() { + return {fname: ''}; +}; + +TBinaryProtocol.prototype.readStructEnd = function() { +}; + +TBinaryProtocol.prototype.readFieldBegin = function() { + var type = this.readByte(); + if (type == Type.STOP) { + return {fname: null, ftype: type, fid: 0}; + } + var id = this.readI16(); + return {fname: null, ftype: type, fid: id}; +}; + +TBinaryProtocol.prototype.readFieldEnd = function() { +}; + +TBinaryProtocol.prototype.readMapBegin = function() { + var ktype = this.readByte(); + var vtype = this.readByte(); + var size = this.readI32(); + return {ktype: ktype, vtype: vtype, size: size}; +}; + +TBinaryProtocol.prototype.readMapEnd = function() { +}; + +TBinaryProtocol.prototype.readListBegin = function() { + var etype = this.readByte(); + var size = this.readI32(); + return {etype: etype, size: size}; +}; + +TBinaryProtocol.prototype.readListEnd = function() { +}; + +TBinaryProtocol.prototype.readSetBegin = function() { + var etype = this.readByte(); + var size = this.readI32(); + return {etype: etype, size: size}; +}; + +TBinaryProtocol.prototype.readSetEnd = function() { +}; + +TBinaryProtocol.prototype.readBool = function() { + var b = this.readByte(); + if (b === 0) { + return false; + } + return true; +}; + +TBinaryProtocol.prototype.readByte = function() { + return this.trans.readByte(); +}; + +TBinaryProtocol.prototype.readI16 = function() { + return this.trans.readI16(); +}; + +TBinaryProtocol.prototype.readI32 = function() { + return this.trans.readI32(); +}; + +TBinaryProtocol.prototype.readI64 = function() { + var buff = this.trans.read(8); + return new Int64(buff); +}; + +TBinaryProtocol.prototype.readDouble = function() { + return this.trans.readDouble(); +}; + +TBinaryProtocol.prototype.readBinary = function() { + var len = this.readI32(); + if (len === 0) { + return new Buffer(0); + } + + if (len < 0) { + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative binary size"); + } + return this.trans.read(len); +}; + +TBinaryProtocol.prototype.readString = function() { + var len = this.readI32(); + if (len === 0) { + return ""; + } + + if (len < 0) { + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative string size"); + } + return this.trans.readString(len); +}; + +TBinaryProtocol.prototype.getTransport = function() { + return this.trans; +}; + +TBinaryProtocol.prototype.skip = function(type) { + switch (type) { + case Type.STOP: + return; + case Type.BOOL: + this.readBool(); + break; + case Type.BYTE: + this.readByte(); + break; + case Type.I16: + this.readI16(); + break; + case Type.I32: + this.readI32(); + break; + case Type.I64: + this.readI64(); + break; + case Type.DOUBLE: + this.readDouble(); + break; + case Type.STRING: + this.readString(); + break; + case Type.STRUCT: + this.readStructBegin(); + while (true) { + var r = this.readFieldBegin(); + if (r.ftype === Type.STOP) { + break; + } + this.skip(r.ftype); + this.readFieldEnd(); + } + this.readStructEnd(); + break; + case Type.MAP: + var mapBegin = this.readMapBegin(); + for (var i = 0; i < mapBegin.size; ++i) { + this.skip(mapBegin.ktype); + this.skip(mapBegin.vtype); + } + this.readMapEnd(); + break; + case Type.SET: + var setBegin = this.readSetBegin(); + for (var i2 = 0; i2 < setBegin.size; ++i2) { + this.skip(setBegin.etype); + } + this.readSetEnd(); + break; + case Type.LIST: + var listBegin = this.readListBegin(); + for (var i3 = 0; i3 < listBegin.size; ++i3) { + this.skip(listBegin.etype); + } + this.readListEnd(); + break; + default: + throw new Error("Invalid type: " + type); + } +}; diff --git a/lib/nodejs/lib/thrift/browser.js b/lib/nodejs/lib/thrift/browser.js new file mode 100644 index 0000000..4593a8f --- /dev/null +++ b/lib/nodejs/lib/thrift/browser.js @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +exports.Thrift = require('./thrift'); + +var xhrConnection = require('./xhr_connection'); +exports.XHRConnection = xhrConnection.XHRConnection; +exports.createXHRConnection = xhrConnection.createXHRConnection; +exports.createXHRClient = xhrConnection.createXHRClient; + +exports.Multiplexer = require('./multiplexed_protocol').Multiplexer; + +exports.TWebSocketTransport = require('./ws_transport'); +exports.TBufferedTransport = require('./buffered_transport'); +exports.TFramedTransport = require('./framed_transport'); + +exports.Protocol = exports.TJSONProtocol = require('./json_protocol'); +exports.TBinaryProtocol = require('./binary_protocol'); +exports.TCompactProtocol = require('./compact_protocol'); diff --git a/lib/nodejs/lib/thrift/buffered_transport.js b/lib/nodejs/lib/thrift/buffered_transport.js new file mode 100644 index 0000000..13636b5 --- /dev/null +++ b/lib/nodejs/lib/thrift/buffered_transport.js @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var binary = require('./binary'); +var InputBufferUnderrunError = require('./input_buffer_underrun_error'); + +module.exports = TBufferedTransport; + +function TBufferedTransport(buffer, callback) { + this.defaultReadBufferSize = 1024; + this.writeBufferSize = 512; // Soft Limit + this.inBuf = new Buffer(this.defaultReadBufferSize); + this.readCursor = 0; + this.writeCursor = 0; // for input buffer + this.outBuffers = []; + this.outCount = 0; + this.onFlush = callback; +}; + +TBufferedTransport.receiver = function(callback, seqid) { + var reader = new TBufferedTransport(); + + return function(data) { + if (reader.writeCursor + data.length > reader.inBuf.length) { + var buf = new Buffer(reader.writeCursor + data.length); + reader.inBuf.copy(buf, 0, 0, reader.writeCursor); + reader.inBuf = buf; + } + data.copy(reader.inBuf, reader.writeCursor, 0); + reader.writeCursor += data.length; + + callback(reader, seqid); + }; +}; + + +TBufferedTransport.prototype.commitPosition = function(){ + var unreadSize = this.writeCursor - this.readCursor; + var bufSize = (unreadSize * 2 > this.defaultReadBufferSize) ? + unreadSize * 2 : this.defaultReadBufferSize; + var buf = new Buffer(bufSize); + if (unreadSize > 0) { + this.inBuf.copy(buf, 0, this.readCursor, this.writeCursor); + } + this.readCursor = 0; + this.writeCursor = unreadSize; + this.inBuf = buf; +}; + +TBufferedTransport.prototype.rollbackPosition = function(){ + this.readCursor = 0; +} + + // TODO: Implement open/close support +TBufferedTransport.prototype.isOpen = function() { + return true; +}; + +TBufferedTransport.prototype.open = function() { +}; + +TBufferedTransport.prototype.close = function() { +}; + + // Set the seqid of the message in the client + // So that callbacks can be found +TBufferedTransport.prototype.setCurrSeqId = function(seqid) { + this._seqid = seqid; +}; + +TBufferedTransport.prototype.ensureAvailable = function(len) { + if (this.readCursor + len > this.writeCursor) { + throw new InputBufferUnderrunError(); + } +}; + +TBufferedTransport.prototype.read = function(len) { + this.ensureAvailable(len); + var buf = new Buffer(len); + this.inBuf.copy(buf, 0, this.readCursor, this.readCursor + len); + this.readCursor += len; + return buf; +}; + +TBufferedTransport.prototype.readByte = function() { + this.ensureAvailable(1); + return binary.readByte(this.inBuf[this.readCursor++]); +}; + +TBufferedTransport.prototype.readI16 = function() { + this.ensureAvailable(2); + var i16 = binary.readI16(this.inBuf, this.readCursor); + this.readCursor += 2; + return i16; +}; + +TBufferedTransport.prototype.readI32 = function() { + this.ensureAvailable(4); + var i32 = binary.readI32(this.inBuf, this.readCursor); + this.readCursor += 4; + return i32; +}; + +TBufferedTransport.prototype.readDouble = function() { + this.ensureAvailable(8); + var d = binary.readDouble(this.inBuf, this.readCursor); + this.readCursor += 8; + return d; +}; + +TBufferedTransport.prototype.readString = function(len) { + this.ensureAvailable(len); + var str = this.inBuf.toString('utf8', this.readCursor, this.readCursor + len); + this.readCursor += len; + return str; +}; + +TBufferedTransport.prototype.borrow = function() { + var obj = {buf: this.inBuf, readIndex: this.readCursor, writeIndex: this.writeCursor}; + return obj; +}; + +TBufferedTransport.prototype.consume = function(bytesConsumed) { + this.readCursor += bytesConsumed; +}; + +TBufferedTransport.prototype.write = function(buf) { + if (typeof(buf) === "string") { + buf = new Buffer(buf, 'utf8'); + } + this.outBuffers.push(buf); + this.outCount += buf.length; +}; + +TBufferedTransport.prototype.flush = function() { + // If the seqid of the callback is available pass it to the onFlush + // Then remove the current seqid + var seqid = this._seqid; + this._seqid = null; + + if (this.outCount < 1) { + return; + } + + var msg = new Buffer(this.outCount), + pos = 0; + this.outBuffers.forEach(function(buf) { + buf.copy(msg, pos, 0); + pos += buf.length; + }); + + if (this.onFlush) { + // Passing seqid through this call to get it to the connection + this.onFlush(msg, seqid); + } + + this.outBuffers = []; + this.outCount = 0; +} diff --git a/lib/nodejs/lib/thrift/compact_protocol.js b/lib/nodejs/lib/thrift/compact_protocol.js new file mode 100644 index 0000000..5c531e5 --- /dev/null +++ b/lib/nodejs/lib/thrift/compact_protocol.js @@ -0,0 +1,917 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var log = require('./log'); +var Int64 = require('node-int64'); +var Thrift = require('./thrift'); +var Type = Thrift.Type; + +module.exports = TCompactProtocol; + +var POW_8 = Math.pow(2, 8); +var POW_24 = Math.pow(2, 24); +var POW_32 = Math.pow(2, 32); +var POW_40 = Math.pow(2, 40); +var POW_48 = Math.pow(2, 48); +var POW_52 = Math.pow(2, 52); +var POW_1022 = Math.pow(2, 1022); + +/** + * Constructor Function for the Compact Protocol. + * @constructor + * @param {object} [trans] - The underlying transport to read/write. + * @classdesc The Apache Thrift Protocol layer performs serialization + * of base types, the compact protocol serializes data in binary + * form with minimal space used for scalar values. + */ +function TCompactProtocol(trans) { + this.trans = trans; + this.lastField_ = []; + this.lastFieldId_ = 0; + this.string_limit_ = 0; + this.string_buf_ = null; + this.string_buf_size_ = 0; + this.container_limit_ = 0; + this.booleanField_ = { + name: null, + hasBoolValue: false + }; + this.boolValue_ = { + hasBoolValue: false, + boolValue: false + }; +}; + + +// +// Compact Protocol Constants +// + +/** + * Compact Protocol ID number. + * @readonly + * @const {number} PROTOCOL_ID + */ +TCompactProtocol.PROTOCOL_ID = -126; //1000 0010 + +/** + * Compact Protocol version number. + * @readonly + * @const {number} VERSION_N + */ +TCompactProtocol.VERSION_N = 1; + +/** + * Compact Protocol version mask for combining protocol version and message type in one byte. + * @readonly + * @const {number} VERSION_MASK + */ +TCompactProtocol.VERSION_MASK = 0x1f; //0001 1111 + +/** + * Compact Protocol message type mask for combining protocol version and message type in one byte. + * @readonly + * @const {number} TYPE_MASK + */ +TCompactProtocol.TYPE_MASK = -32; //1110 0000 + +/** + * Compact Protocol message type bits for ensuring message type bit size. + * @readonly + * @const {number} TYPE_BITS + */ +TCompactProtocol.TYPE_BITS = 7; //0000 0111 + +/** + * Compact Protocol message type shift amount for combining protocol version and message type in one byte. + * @readonly + * @const {number} TYPE_SHIFT_AMOUNT + */ +TCompactProtocol.TYPE_SHIFT_AMOUNT = 5; + +/** + * Compact Protocol type IDs used to keep type data within one nibble. + * @readonly + * @property {number} CT_STOP - End of a set of fields. + * @property {number} CT_BOOLEAN_TRUE - Flag for Boolean field with true value (packed field and value). + * @property {number} CT_BOOLEAN_FALSE - Flag for Boolean field with false value (packed field and value). + * @property {number} CT_BYTE - Signed 8 bit integer. + * @property {number} CT_I16 - Signed 16 bit integer. + * @property {number} CT_I32 - Signed 32 bit integer. + * @property {number} CT_I64 - Signed 64 bit integer (2^53 max in JavaScript). + * @property {number} CT_DOUBLE - 64 bit IEEE 854 floating point. + * @property {number} CT_BINARY - Array of bytes (used for strings also). + * @property {number} CT_LIST - A collection type (unordered). + * @property {number} CT_SET - A collection type (unordered and without repeated values). + * @property {number} CT_MAP - A collection type (map/associative-array/dictionary). + * @property {number} CT_STRUCT - A multifield type. + */ +TCompactProtocol.Types = { + CT_STOP: 0x00, + CT_BOOLEAN_TRUE: 0x01, + CT_BOOLEAN_FALSE: 0x02, + CT_BYTE: 0x03, + CT_I16: 0x04, + CT_I32: 0x05, + CT_I64: 0x06, + CT_DOUBLE: 0x07, + CT_BINARY: 0x08, + CT_LIST: 0x09, + CT_SET: 0x0A, + CT_MAP: 0x0B, + CT_STRUCT: 0x0C +}; + +/** + * Array mapping Compact type IDs to standard Thrift type IDs. + * @readonly + */ +TCompactProtocol.TTypeToCType = [ + TCompactProtocol.Types.CT_STOP, // T_STOP + 0, // unused + TCompactProtocol.Types.CT_BOOLEAN_TRUE, // T_BOOL + TCompactProtocol.Types.CT_BYTE, // T_BYTE + TCompactProtocol.Types.CT_DOUBLE, // T_DOUBLE + 0, // unused + TCompactProtocol.Types.CT_I16, // T_I16 + 0, // unused + TCompactProtocol.Types.CT_I32, // T_I32 + 0, // unused + TCompactProtocol.Types.CT_I64, // T_I64 + TCompactProtocol.Types.CT_BINARY, // T_STRING + TCompactProtocol.Types.CT_STRUCT, // T_STRUCT + TCompactProtocol.Types.CT_MAP, // T_MAP + TCompactProtocol.Types.CT_SET, // T_SET + TCompactProtocol.Types.CT_LIST, // T_LIST +]; + + +// +// Compact Protocol Utilities +// + +/** + * Returns the underlying transport layer. + * @return {object} The underlying transport layer. + */TCompactProtocol.prototype.getTransport = function() { + return this.trans; +}; + +/** + * Lookup a Compact Protocol Type value for a given Thrift Type value. + * N.B. Used only internally. + * @param {number} ttype - Thrift type value + * @returns {number} Compact protocol type value + */ +TCompactProtocol.prototype.getCompactType = function(ttype) { + return TCompactProtocol.TTypeToCType[ttype]; +}; + +/** + * Lookup a Thrift Type value for a given Compact Protocol Type value. + * N.B. Used only internally. + * @param {number} type - Compact Protocol type value + * @returns {number} Thrift Type value + */ +TCompactProtocol.prototype.getTType = function(type) { + switch (type) { + case Type.STOP: + return Type.STOP; + case TCompactProtocol.Types.CT_BOOLEAN_FALSE: + case TCompactProtocol.Types.CT_BOOLEAN_TRUE: + return Type.BOOL; + case TCompactProtocol.Types.CT_BYTE: + return Type.BYTE; + case TCompactProtocol.Types.CT_I16: + return Type.I16; + case TCompactProtocol.Types.CT_I32: + return Type.I32; + case TCompactProtocol.Types.CT_I64: + return Type.I64; + case TCompactProtocol.Types.CT_DOUBLE: + return Type.DOUBLE; + case TCompactProtocol.Types.CT_BINARY: + return Type.STRING; + case TCompactProtocol.Types.CT_LIST: + return Type.LIST; + case TCompactProtocol.Types.CT_SET: + return Type.SET; + case TCompactProtocol.Types.CT_MAP: + return Type.MAP; + case TCompactProtocol.Types.CT_STRUCT: + return Type.STRUCT; + default: + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Unknown type: " + type); + } + return Type.STOP; +}; + + +// +// Compact Protocol write operations +// + +/** + * Send any buffered bytes to the end point. + */ +TCompactProtocol.prototype.flush = function() { + return this.trans.flush(); +}; + +/** + * Writes an RPC message header + * @param {string} name - The method name for the message. + * @param {number} type - The type of message (CALL, REPLY, EXCEPTION, ONEWAY). + * @param {number} seqid - The call sequence number (if any). + */ +TCompactProtocol.prototype.writeMessageBegin = function(name, type, seqid) { + this.writeByte(TCompactProtocol.PROTOCOL_ID); + this.writeByte((TCompactProtocol.VERSION_N & TCompactProtocol.VERSION_MASK) | + ((type << TCompactProtocol.TYPE_SHIFT_AMOUNT) & TCompactProtocol.TYPE_MASK)); + this.writeVarint32(seqid); + this.writeString(name); + + // Record client seqid to find callback again + if (this._seqid) { + log.warning('SeqId already set', { 'name': name }); + } else { + this._seqid = seqid; + this.trans.setCurrSeqId(seqid); + } +}; + +TCompactProtocol.prototype.writeMessageEnd = function() { +}; + +TCompactProtocol.prototype.writeStructBegin = function(name) { + this.lastField_.push(this.lastFieldId_); + this.lastFieldId_ = 0; +}; + +TCompactProtocol.prototype.writeStructEnd = function() { + this.lastFieldId_ = this.lastField_.pop(); +}; + +/** + * Writes a struct field header + * @param {string} name - The field name (not written with the compact protocol). + * @param {number} type - The field data type (a normal Thrift field Type). + * @param {number} id - The IDL field Id. + */ +TCompactProtocol.prototype.writeFieldBegin = function(name, type, id) { + if (type != Type.BOOL) { + return this.writeFieldBeginInternal(name, type, id, -1); + } + + this.booleanField_.name = name; + this.booleanField_.fieldType = type; + this.booleanField_.fieldId = id; +}; + +TCompactProtocol.prototype.writeFieldEnd = function() { +}; + +TCompactProtocol.prototype.writeFieldStop = function() { + this.writeByte(TCompactProtocol.Types.CT_STOP); +}; + +/** + * Writes a map collection header + * @param {number} keyType - The Thrift type of the map keys. + * @param {number} valType - The Thrift type of the map values. + * @param {number} size - The number of k/v pairs in the map. + */ +TCompactProtocol.prototype.writeMapBegin = function(keyType, valType, size) { + if (size === 0) { + this.writeByte(0); + } else { + this.writeVarint32(size); + this.writeByte(this.getCompactType(keyType) << 4 | this.getCompactType(valType)); + } +}; + +TCompactProtocol.prototype.writeMapEnd = function() { +}; + +/** + * Writes a list collection header + * @param {number} elemType - The Thrift type of the list elements. + * @param {number} size - The number of elements in the list. + */ +TCompactProtocol.prototype.writeListBegin = function(elemType, size) { + this.writeCollectionBegin(elemType, size); +}; + +TCompactProtocol.prototype.writeListEnd = function() { +}; + +/** + * Writes a set collection header + * @param {number} elemType - The Thrift type of the set elements. + * @param {number} size - The number of elements in the set. + */ +TCompactProtocol.prototype.writeSetBegin = function(elemType, size) { + this.writeCollectionBegin(elemType, size); +}; + +TCompactProtocol.prototype.writeSetEnd = function() { +}; + +TCompactProtocol.prototype.writeBool = function(value) { + if (this.booleanField_.name !== null) { + // we haven't written the field header yet + this.writeFieldBeginInternal(this.booleanField_.name, + this.booleanField_.fieldType, + this.booleanField_.fieldId, + (value ? TCompactProtocol.Types.CT_BOOLEAN_TRUE + : TCompactProtocol.Types.CT_BOOLEAN_FALSE)); + this.booleanField_.name = null; + } else { + // we're not part of a field, so just write the value + this.writeByte((value ? TCompactProtocol.Types.CT_BOOLEAN_TRUE + : TCompactProtocol.Types.CT_BOOLEAN_FALSE)); + } +}; + +TCompactProtocol.prototype.writeByte = function(b) { + this.trans.write(new Buffer([b])); +}; + +TCompactProtocol.prototype.writeI16 = function(i16) { + this.writeVarint32(this.i32ToZigzag(i16)); +}; + +TCompactProtocol.prototype.writeI32 = function(i32) { + this.writeVarint32(this.i32ToZigzag(i32)); +}; + +TCompactProtocol.prototype.writeI64 = function(i64) { + this.writeVarint64(this.i64ToZigzag(i64)); +}; + +// Little-endian, unlike TBinaryProtocol +TCompactProtocol.prototype.writeDouble = function(v) { + var buff = new Buffer(8); + var m, e, c; + + buff[7] = (v < 0 ? 0x80 : 0x00); + + v = Math.abs(v); + if (v !== v) { + // NaN, use QNaN IEEE format + m = 2251799813685248; + e = 2047; + } else if (v === Infinity) { + m = 0; + e = 2047; + } else { + e = Math.floor(Math.log(v) / Math.LN2); + c = Math.pow(2, -e); + if (v * c < 1) { + e--; + c *= 2; + } + + if (e + 1023 >= 2047) + { + // Overflow + m = 0; + e = 2047; + } + else if (e + 1023 >= 1) + { + // Normalized - term order matters, as Math.pow(2, 52-e) and v*Math.pow(2, 52) can overflow + m = (v*c-1) * POW_52; + e += 1023; + } + else + { + // Denormalized - also catches the '0' case, somewhat by chance + m = (v * POW_1022) * POW_52; + e = 0; + } + } + + buff[6] = (e << 4) & 0xf0; + buff[7] |= (e >> 4) & 0x7f; + + buff[0] = m & 0xff; + m = Math.floor(m / POW_8); + buff[1] = m & 0xff; + m = Math.floor(m / POW_8); + buff[2] = m & 0xff; + m = Math.floor(m / POW_8); + buff[3] = m & 0xff; + m >>= 8; + buff[4] = m & 0xff; + m >>= 8; + buff[5] = m & 0xff; + m >>= 8; + buff[6] |= m & 0x0f; + + this.trans.write(buff); +}; + +TCompactProtocol.prototype.writeStringOrBinary = function(name, encoding, arg) { + if (typeof arg === 'string') { + this.writeVarint32(Buffer.byteLength(arg, encoding)) ; + this.trans.write(new Buffer(arg, encoding)); + } else if (arg instanceof Buffer || + Object.prototype.toString.call(arg) == '[object Uint8Array]') { + // Buffers in Node.js under Browserify may extend UInt8Array instead of + // defining a new object. We detect them here so we can write them + // correctly + this.writeVarint32(arg.length); + this.trans.write(arg); + } else { + throw new Error(name + ' called without a string/Buffer argument: ' + arg); + } +}; + +TCompactProtocol.prototype.writeString = function(arg) { + this.writeStringOrBinary('writeString', 'utf8', arg); +}; + +TCompactProtocol.prototype.writeBinary = function(arg) { + this.writeStringOrBinary('writeBinary', 'binary', arg); +}; + + +// +// Compact Protocol internal write methods +// + +TCompactProtocol.prototype.writeFieldBeginInternal = function(name, + fieldType, + fieldId, + typeOverride) { + //If there's a type override, use that. + var typeToWrite = (typeOverride == -1 ? this.getCompactType(fieldType) : typeOverride); + //Check if we can delta encode the field id + if (fieldId > this.lastFieldId_ && fieldId - this.lastFieldId_ <= 15) { + //Include the type delta with the field ID + this.writeByte((fieldId - this.lastFieldId_) << 4 | typeToWrite); + } else { + //Write separate type and ID values + this.writeByte(typeToWrite); + this.writeI16(fieldId); + } + this.lastFieldId_ = fieldId; +}; + +TCompactProtocol.prototype.writeCollectionBegin = function(elemType, size) { + if (size <= 14) { + //Combine size and type in one byte if possible + this.writeByte(size << 4 | this.getCompactType(elemType)); + } else { + this.writeByte(0xf0 | this.getCompactType(elemType)); + this.writeVarint32(size); + } +}; + +/** + * Write an i32 as a varint. Results in 1-5 bytes on the wire. + */ +TCompactProtocol.prototype.writeVarint32 = function(n) { + var buf = new Buffer(5); + var wsize = 0; + while (true) { + if ((n & ~0x7F) === 0) { + buf[wsize++] = n; + break; + } else { + buf[wsize++] = ((n & 0x7F) | 0x80); + n = n >>> 7; + } + } + var wbuf = new Buffer(wsize); + buf.copy(wbuf,0,0,wsize); + this.trans.write(wbuf); +}; + +/** + * Write an i64 as a varint. Results in 1-10 bytes on the wire. + * N.B. node-int64 is always big endian + */ +TCompactProtocol.prototype.writeVarint64 = function(n) { + if (typeof n === "number"){ + n = new Int64(n); + } + if (! (n instanceof Int64)) { + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Expected Int64 or Number, found: " + n); + } + + var buf = new Buffer(10); + var wsize = 0; + var hi = n.buffer.readUInt32BE(0, true); + var lo = n.buffer.readUInt32BE(4, true); + var mask = 0; + while (true) { + if (((lo & ~0x7F) === 0) && (hi === 0)) { + buf[wsize++] = lo; + break; + } else { + buf[wsize++] = ((lo & 0x7F) | 0x80); + mask = hi << 25; + lo = lo >>> 7; + hi = hi >>> 7; + lo = lo | mask; + } + } + var wbuf = new Buffer(wsize); + buf.copy(wbuf,0,0,wsize); + this.trans.write(wbuf); +}; + +/** + * Convert l into a zigzag long. This allows negative numbers to be + * represented compactly as a varint. + */ +TCompactProtocol.prototype.i64ToZigzag = function(l) { + if (typeof l === 'string') { + l = new Int64(parseInt(l, 10)); + } else if (typeof l === 'number') { + l = new Int64(l); + } + if (! (l instanceof Int64)) { + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Expected Int64 or Number, found: " + l); + } + var hi = l.buffer.readUInt32BE(0, true); + var lo = l.buffer.readUInt32BE(4, true); + var sign = hi >>> 31; + hi = ((hi << 1) | (lo >>> 31)) ^ ((!!sign) ? 0xFFFFFFFF : 0); + lo = (lo << 1) ^ ((!!sign) ? 0xFFFFFFFF : 0); + return new Int64(hi, lo); +}; + +/** + * Convert n into a zigzag int. This allows negative numbers to be + * represented compactly as a varint. + */ +TCompactProtocol.prototype.i32ToZigzag = function(n) { + return (n << 1) ^ ((n & 0x80000000) ? 0xFFFFFFFF : 0); +}; + + +// +// Compact Protocol read operations +// + +TCompactProtocol.prototype.readMessageBegin = function() { + //Read protocol ID + var protocolId = this.trans.readByte(); + if (protocolId != TCompactProtocol.PROTOCOL_ID) { + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "Bad protocol identifier " + protocolId); + } + + //Read Version and Type + var versionAndType = this.trans.readByte(); + var version = (versionAndType & TCompactProtocol.VERSION_MASK); + if (version != TCompactProtocol.VERSION_N) { + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "Bad protocol version " + version); + } + var type = ((versionAndType >> TCompactProtocol.TYPE_SHIFT_AMOUNT) & TCompactProtocol.TYPE_BITS); + + //Read SeqId + var seqid = this.readVarint32(); + + //Read name + var name = this.readString(); + + return {fname: name, mtype: type, rseqid: seqid}; +}; + +TCompactProtocol.prototype.readMessageEnd = function() { +}; + +TCompactProtocol.prototype.readStructBegin = function() { + this.lastField_.push(this.lastFieldId_); + this.lastFieldId_ = 0; + return {fname: ''}; +}; + +TCompactProtocol.prototype.readStructEnd = function() { + this.lastFieldId_ = this.lastField_.pop(); +}; + +TCompactProtocol.prototype.readFieldBegin = function() { + var fieldId = 0; + var b = this.trans.readByte(b); + var type = (b & 0x0f); + + if (type == TCompactProtocol.Types.CT_STOP) { + return {fname: null, ftype: Thrift.Type.STOP, fid: 0}; + } + + //Mask off the 4 MSB of the type header to check for field id delta. + var modifier = ((b & 0x000000f0) >>> 4); + if (modifier === 0) { + //If not a delta read the field id. + fieldId = this.readI16(); + } else { + //Recover the field id from the delta + fieldId = (this.lastFieldId_ + modifier); + } + var fieldType = this.getTType(type); + + //Boolean are encoded with the type + if (type == TCompactProtocol.Types.CT_BOOLEAN_TRUE || + type == TCompactProtocol.Types.CT_BOOLEAN_FALSE) { + this.boolValue_.hasBoolValue = true; + this.boolValue_.boolValue = + (type == TCompactProtocol.Types.CT_BOOLEAN_TRUE ? true : false); + } + + //Save the new field for the next delta computation. + this.lastFieldId_ = fieldId; + return {fname: null, ftype: fieldType, fid: fieldId}; +}; + +TCompactProtocol.prototype.readFieldEnd = function() { +}; + +TCompactProtocol.prototype.readMapBegin = function() { + var msize = this.readVarint32(); + if (msize < 0) { + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative map size"); + } + + var kvType = 0; + if (msize !== 0) { + kvType = this.trans.readByte(); + } + + var keyType = this.getTType((kvType & 0xf0) >>> 4); + var valType = this.getTType(kvType & 0xf); + return {ktype: keyType, vtype: valType, size: msize}; +}; + +TCompactProtocol.prototype.readMapEnd = function() { +}; + +TCompactProtocol.prototype.readListBegin = function() { + var size_and_type = this.trans.readByte(); + + var lsize = (size_and_type >>> 4) & 0x0000000f; + if (lsize == 15) { + lsize = this.readVarint32(); + } + + if (lsize < 0) { + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative list size"); + } + + var elemType = this.getTType(size_and_type & 0x0000000f); + + return {etype: elemType, size: lsize}; +}; + +TCompactProtocol.prototype.readListEnd = function() { +}; + +TCompactProtocol.prototype.readSetBegin = function() { + return this.readListBegin(); +}; + +TCompactProtocol.prototype.readSetEnd = function() { +}; + +TCompactProtocol.prototype.readBool = function() { + var value = false; + var rsize = 0; + if (this.boolValue_.hasBoolValue === true) { + value = this.boolValue_.boolValue; + this.boolValue_.hasBoolValue = false; + } else { + var res = this.trans.readByte(); + rsize = res.rsize; + value = (res.value == TCompactProtocol.Types.CT_BOOLEAN_TRUE); + } + return value; +}; + +TCompactProtocol.prototype.readByte = function() { + return this.trans.readByte(); +}; + +TCompactProtocol.prototype.readI16 = function() { + return this.readI32(); +}; + +TCompactProtocol.prototype.readI32 = function() { + return this.zigzagToI32(this.readVarint32()); +}; + +TCompactProtocol.prototype.readI64 = function() { + return this.zigzagToI64(this.readVarint64()); +}; + +// Little-endian, unlike TBinaryProtocol +TCompactProtocol.prototype.readDouble = function() { + var buff = this.trans.read(8); + var off = 0; + + var signed = buff[off + 7] & 0x80; + var e = (buff[off+6] & 0xF0) >> 4; + e += (buff[off+7] & 0x7F) << 4; + + var m = buff[off]; + m += buff[off+1] << 8; + m += buff[off+2] << 16; + m += buff[off+3] * POW_24; + m += buff[off+4] * POW_32; + m += buff[off+5] * POW_40; + m += (buff[off+6] & 0x0F) * POW_48; + + switch (e) { + case 0: + e = -1022; + break; + case 2047: + return m ? NaN : (signed ? -Infinity : Infinity); + default: + m += POW_52; + e -= 1023; + } + + if (signed) { + m *= -1; + } + + return m * Math.pow(2, e - 52); +}; + +TCompactProtocol.prototype.readBinary = function() { + var size = this.readVarint32(); + if (size === 0) { + return new Buffer(0); + } + + if (size < 0) { + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative binary size"); + } + return this.trans.read(size); +}; + +TCompactProtocol.prototype.readString = function() { + var size = this.readVarint32(); + // Catch empty string case + if (size === 0) { + return ""; + } + + // Catch error cases + if (size < 0) { + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative string size"); + } + return this.trans.readString(size); +}; + + +// +// Compact Protocol internal read operations +// + +/** + * Read an i32 from the wire as a varint. The MSB of each byte is set + * if there is another byte to follow. This can read up to 5 bytes. + */ +TCompactProtocol.prototype.readVarint32 = function() { + return this.readVarint64().toNumber(); +}; + +/** + * Read an i64 from the wire as a proper varint. The MSB of each byte is set + * if there is another byte to follow. This can read up to 10 bytes. + */ +TCompactProtocol.prototype.readVarint64 = function() { + var rsize = 0; + var lo = 0; + var hi = 0; + var shift = 0; + while (true) { + var b = this.trans.readByte(); + rsize ++; + if (shift <= 25) { + lo = lo | ((b & 0x7f) << shift); + } else if (25 < shift && shift < 32) { + lo = lo | ((b & 0x7f) << shift); + hi = hi | ((b & 0x7f) >>> (32-shift)); + } else { + hi = hi | ((b & 0x7f) << (shift-32)); + } + shift += 7; + if (!(b & 0x80)) { + break; + } + if (rsize >= 10) { + throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Variable-length int over 10 bytes."); + } + } + return new Int64(hi, lo); +}; + +/** + * Convert from zigzag int to int. + */ +TCompactProtocol.prototype.zigzagToI32 = function(n) { + return (n >>> 1) ^ (-1 * (n & 1)); +}; + +/** + * Convert from zigzag long to long. + */ +TCompactProtocol.prototype.zigzagToI64 = function(n) { + var hi = n.buffer.readUInt32BE(0, true); + var lo = n.buffer.readUInt32BE(4, true); + + var neg = new Int64(hi & 0, lo & 1); + neg._2scomp(); + var hi_neg = neg.buffer.readUInt32BE(0, true); + var lo_neg = neg.buffer.readUInt32BE(4, true); + + var hi_lo = (hi << 31); + hi = (hi >>> 1) ^ (hi_neg); + lo = ((lo >>> 1) | hi_lo) ^ (lo_neg); + return new Int64(hi, lo); +}; + +TCompactProtocol.prototype.skip = function(type) { + switch (type) { + case Type.STOP: + return; + case Type.BOOL: + this.readBool(); + break; + case Type.BYTE: + this.readByte(); + break; + case Type.I16: + this.readI16(); + break; + case Type.I32: + this.readI32(); + break; + case Type.I64: + this.readI64(); + break; + case Type.DOUBLE: + this.readDouble(); + break; + case Type.STRING: + this.readString(); + break; + case Type.STRUCT: + this.readStructBegin(); + while (true) { + var r = this.readFieldBegin(); + if (r.ftype === Type.STOP) { + break; + } + this.skip(r.ftype); + this.readFieldEnd(); + } + this.readStructEnd(); + break; + case Type.MAP: + var mapBegin = this.readMapBegin(); + for (var i = 0; i < mapBegin.size; ++i) { + this.skip(mapBegin.ktype); + this.skip(mapBegin.vtype); + } + this.readMapEnd(); + break; + case Type.SET: + var setBegin = this.readSetBegin(); + for (var i2 = 0; i2 < setBegin.size; ++i2) { + this.skip(setBegin.etype); + } + this.readSetEnd(); + break; + case Type.LIST: + var listBegin = this.readListBegin(); + for (var i3 = 0; i3 < listBegin.size; ++i3) { + this.skip(listBegin.etype); + } + this.readListEnd(); + break; + default: + throw new Error("Invalid type: " + type); + } +}; diff --git a/lib/nodejs/lib/thrift/connection.js b/lib/nodejs/lib/thrift/connection.js new file mode 100644 index 0000000..273339b --- /dev/null +++ b/lib/nodejs/lib/thrift/connection.js @@ -0,0 +1,357 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var util = require('util'); +var EventEmitter = require('events').EventEmitter; +var constants = require('constants'); +var net = require('net'); +var tls = require('tls'); +var thrift = require('./thrift'); +var log = require('./log'); + +var TBufferedTransport = require('./buffered_transport'); +var TBinaryProtocol = require('./binary_protocol'); +var InputBufferUnderrunError = require('./input_buffer_underrun_error'); + +var createClient = require('./create_client'); + +var binary = require('./binary'); + +var Connection = exports.Connection = function(stream, options) { + var self = this; + EventEmitter.call(this); + + this.seqId2Service = {}; + this.connection = stream; + this.ssl = (stream.encrypted); + this.options = options || {}; + this.transport = this.options.transport || TBufferedTransport; + this.protocol = this.options.protocol || TBinaryProtocol; + this.offline_queue = []; + this.connected = false; + this.initialize_retry_vars(); + + this._debug = this.options.debug || false; + if (this.options.max_attempts && + !isNaN(this.options.max_attempts) && + this.options.max_attempts > 0) { + this.max_attempts = +this.options.max_attempts; + } + this.retry_max_delay = null; + if (this.options.retry_max_delay !== undefined && + !isNaN(this.options.retry_max_delay) && + this.options.retry_max_delay > 0) { + this.retry_max_delay = this.options.retry_max_delay; + } + this.connect_timeout = false; + if (this.options.connect_timeout && + !isNaN(this.options.connect_timeout) && + this.options.connect_timeout > 0) { + this.connect_timeout = +this.options.connect_timeout; + } + + this.connection.addListener(this.ssl ? "secureConnect" : "connect", function() { + self.connected = true; + + this.setTimeout(self.options.timeout || 0); + this.setNoDelay(); + this.frameLeft = 0; + this.framePos = 0; + this.frame = null; + self.initialize_retry_vars(); + + self.offline_queue.forEach(function(data) { + self.connection.write(data); + }); + + self.emit("connect"); + }); + + this.connection.addListener("error", function(err) { + // Only emit the error if no-one else is listening on the connection + // or if someone is listening on us, because Node turns unhandled + // 'error' events into exceptions. + if (self.connection.listeners('error').length === 1 || + self.listeners('error').length > 0) { + self.emit("error", err); + } + }); + + // Add a close listener + this.connection.addListener("close", function() { + self.connection_gone(); // handle close event. try to reconnect + }); + + this.connection.addListener("timeout", function() { + self.emit("timeout"); + }); + + this.connection.addListener("data", self.transport.receiver(function(transport_with_data) { + var message = new self.protocol(transport_with_data); + try { + while (true) { + var header = message.readMessageBegin(); + var dummy_seqid = header.rseqid * -1; + var client = self.client; + //The Multiplexed Protocol stores a hash of seqid to service names + // in seqId2Service. If the SeqId is found in the hash we need to + // lookup the appropriate client for this call. + // The connection.client object is a single client object when not + // multiplexing, when using multiplexing it is a service name keyed + // hash of client objects. + //NOTE: The 2 way interdependencies between protocols, transports, + // connections and clients in the Node.js implementation are irregular + // and make the implementation difficult to extend and maintain. We + // should bring this stuff inline with typical thrift I/O stack + // operation soon. + // --ra + var service_name = self.seqId2Service[header.rseqid]; + if (service_name) { + client = self.client[service_name]; + } + /*jshint -W083 */ + client._reqs[dummy_seqid] = function(err, success){ + transport_with_data.commitPosition(); + + var callback = client._reqs[header.rseqid]; + delete client._reqs[header.rseqid]; + if (service_name) { + delete self.seqId2Service[header.rseqid]; + } + if (callback) { + callback(err, success); + } + }; + /*jshint +W083 */ + + if(client['recv_' + header.fname]) { + client['recv_' + header.fname](message, header.mtype, dummy_seqid); + } else { + delete client._reqs[dummy_seqid]; + self.emit("error", + new thrift.TApplicationException(thrift.TApplicationExceptionType.WRONG_METHOD_NAME, + "Received a response to an unknown RPC function")); + } + } + } + catch (e) { + if (e instanceof InputBufferUnderrunError) { + transport_with_data.rollbackPosition(); + } + else { + self.emit('error', e); + } + } + })); +}; +util.inherits(Connection, EventEmitter); + +Connection.prototype.end = function() { + this.connection.end(); +}; + +Connection.prototype.destroy = function() { + this.connection.destroy(); +}; + +Connection.prototype.initialize_retry_vars = function () { + this.retry_timer = null; + this.retry_totaltime = 0; + this.retry_delay = 150; + this.retry_backoff = 1.7; + this.attempts = 0; +}; + +Connection.prototype.write = function(data) { + if (!this.connected) { + this.offline_queue.push(data); + return; + } + this.connection.write(data); +}; + +Connection.prototype.connection_gone = function () { + var self = this; + this.connected = false; + + // If a retry is already in progress, just let that happen + if (this.retry_timer) { + return; + } + // We cannot reconnect a secure socket. + if (!this.max_attempts || this.ssl) { + self.emit("close"); + return; + } + + if (this.retry_max_delay !== null && this.retry_delay >= this.retry_max_delay) { + this.retry_delay = this.retry_max_delay; + } else { + this.retry_delay = Math.floor(this.retry_delay * this.retry_backoff); + } + + log.debug("Retry connection in " + this.retry_delay + " ms"); + + if (this.max_attempts && this.attempts >= this.max_attempts) { + this.retry_timer = null; + console.error("thrift: Couldn't get thrift connection after " + this.max_attempts + " attempts."); + self.emit("close"); + return; + } + + this.attempts += 1; + this.emit("reconnecting", { + delay: self.retry_delay, + attempt: self.attempts + }); + + this.retry_timer = setTimeout(function () { + log.debug("Retrying connection..."); + + self.retry_totaltime += self.retry_delay; + + if (self.connect_timeout && self.retry_totaltime >= self.connect_timeout) { + self.retry_timer = null; + console.error("thrift: Couldn't get thrift connection after " + self.retry_totaltime + "ms."); + self.emit("close"); + return; + } + + self.connection.connect(self.port, self.host); + self.retry_timer = null; + }, this.retry_delay); +}; + +exports.createConnection = function(host, port, options) { + var stream = net.createConnection(port, host); + var connection = new Connection(stream, options); + connection.host = host; + connection.port = port; + + return connection; +}; + +exports.createSSLConnection = function(host, port, options) { + if (!('secureProtocol' in options) && !('secureOptions' in options)) { + options.secureProtocol = "SSLv23_method"; + options.secureOptions = constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3; + } + + var stream = tls.connect(port, host, options); + var connection = new Connection(stream, options); + connection.host = host; + connection.port = port; + + return connection; +}; + + +exports.createClient = createClient; + +var child_process = require('child_process'); +var StdIOConnection = exports.StdIOConnection = function(command, options) { + var command_parts = command.split(' '); + command = command_parts[0]; + var args = command_parts.splice(1,command_parts.length -1); + var child = this.child = child_process.spawn(command,args); + + var self = this; + EventEmitter.call(this); + + this.connection = child.stdin; + this.options = options || {}; + this.transport = this.options.transport || TBufferedTransport; + this.protocol = this.options.protocol || TBinaryProtocol; + this.offline_queue = []; + + if (log.getLogLevel() === 'debug') { + this.child.stderr.on('data', function (err) { + log.debug(err.toString(), 'CHILD ERROR'); + }); + + this.child.on('exit', function (code,signal) { + log.debug(code + ':' + signal, 'CHILD EXITED'); + }); + } + + this.frameLeft = 0; + this.framePos = 0; + this.frame = null; + this.connected = true; + + self.offline_queue.forEach(function(data) { + self.connection.write(data); + }); + + + this.connection.addListener("error", function(err) { + self.emit("error", err); + }); + + // Add a close listener + this.connection.addListener("close", function() { + self.emit("close"); + }); + + child.stdout.addListener("data", self.transport.receiver(function(transport_with_data) { + var message = new self.protocol(transport_with_data); + try { + var header = message.readMessageBegin(); + var dummy_seqid = header.rseqid * -1; + var client = self.client; + client._reqs[dummy_seqid] = function(err, success){ + transport_with_data.commitPosition(); + + var callback = client._reqs[header.rseqid]; + delete client._reqs[header.rseqid]; + if (callback) { + callback(err, success); + } + }; + client['recv_' + header.fname](message, header.mtype, dummy_seqid); + } + catch (e) { + if (e instanceof InputBufferUnderrunError) { + transport_with_data.rollbackPosition(); + } + else { + throw e; + } + } + })); +}; + +util.inherits(StdIOConnection, EventEmitter); + +StdIOConnection.prototype.end = function() { + this.connection.end(); +}; + +StdIOConnection.prototype.write = function(data) { + if (!this.connected) { + this.offline_queue.push(data); + return; + } + this.connection.write(data); +}; + +exports.createStdIOConnection = function(command,options){ + return new StdIOConnection(command,options); +}; + +exports.createStdIOClient = createClient; diff --git a/lib/nodejs/lib/thrift/create_client.js b/lib/nodejs/lib/thrift/create_client.js new file mode 100644 index 0000000..d6b77a8 --- /dev/null +++ b/lib/nodejs/lib/thrift/create_client.js @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +module.exports = createClient; + +/** + * Creates a new client object for the specified Thrift service. + * @param {object} ServiceClient - The module containing the generated service client + * @param {Connection} Connection - The connection to use. + * @returns {object} The client object. + */ +function createClient(ServiceClient, connection) { + // TODO validate required options and throw otherwise + if (ServiceClient.Client) { + ServiceClient = ServiceClient.Client; + } + // TODO detangle these initialization calls + // creating "client" requires + // - new service client instance + // + // New service client instance requires + // - new transport instance + // - protocol class reference + // + // New transport instance requires + // - Buffer to use (or none) + // - Callback to call on flush + + // Wrap the write method + var writeCb = function(buf, seqid) { + connection.write(buf, seqid); + }; + var transport = new connection.transport(undefined, writeCb); + var client = new ServiceClient(transport, connection.protocol); + transport.client = client; + connection.client = client; + return client; +}; diff --git a/lib/nodejs/lib/thrift/framed_transport.js b/lib/nodejs/lib/thrift/framed_transport.js new file mode 100644 index 0000000..6947925 --- /dev/null +++ b/lib/nodejs/lib/thrift/framed_transport.js @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var binary = require('./binary'); +var InputBufferUnderrunError = require('./input_buffer_underrun_error'); + +module.exports = TFramedTransport; + +function TFramedTransport(buffer, callback) { + this.inBuf = buffer || new Buffer(0); + this.outBuffers = []; + this.outCount = 0; + this.readPos = 0; + this.onFlush = callback; +}; + +TFramedTransport.receiver = function(callback, seqid) { + var residual = null; + + return function(data) { + // Prepend any residual data from our previous read + if (residual) { + data = Buffer.concat([residual, data]); + residual = null; + } + + // framed transport + while (data.length) { + if (data.length < 4) { + // Not enough bytes to continue, save and resume on next packet + residual = data; + return; + } + var frameSize = binary.readI32(data, 0); + if (data.length < 4 + frameSize) { + // Not enough bytes to continue, save and resume on next packet + residual = data; + return; + } + + var frame = data.slice(4, 4 + frameSize); + residual = data.slice(4 + frameSize); + + callback(new TFramedTransport(frame), seqid); + + data = residual; + residual = null; + } + }; +}; + +TFramedTransport.prototype.commitPosition = function(){}, +TFramedTransport.prototype.rollbackPosition = function(){}, + + // TODO: Implement open/close support +TFramedTransport.prototype.isOpen = function() { + return true; +}; +TFramedTransport.prototype.open = function() {}; +TFramedTransport.prototype.close = function() {}; + + // Set the seqid of the message in the client + // So that callbacks can be found +TFramedTransport.prototype.setCurrSeqId = function(seqid) { + this._seqid = seqid; +}; + +TFramedTransport.prototype.ensureAvailable = function(len) { + if (this.readPos + len > this.inBuf.length) { + throw new InputBufferUnderrunError(); + } +}; + +TFramedTransport.prototype.read = function(len) { // this function will be used for each frames. + this.ensureAvailable(len); + var end = this.readPos + len; + + if (this.inBuf.length < end) { + throw new Error('read(' + len + ') failed - not enough data'); + } + + var buf = this.inBuf.slice(this.readPos, end); + this.readPos = end; + return buf; +}; + +TFramedTransport.prototype.readByte = function() { + this.ensureAvailable(1); + return binary.readByte(this.inBuf[this.readPos++]); +}; + +TFramedTransport.prototype.readI16 = function() { + this.ensureAvailable(2); + var i16 = binary.readI16(this.inBuf, this.readPos); + this.readPos += 2; + return i16; +}; + +TFramedTransport.prototype.readI32 = function() { + this.ensureAvailable(4); + var i32 = binary.readI32(this.inBuf, this.readPos); + this.readPos += 4; + return i32; +}; + +TFramedTransport.prototype.readDouble = function() { + this.ensureAvailable(8); + var d = binary.readDouble(this.inBuf, this.readPos); + this.readPos += 8; + return d; +}; + +TFramedTransport.prototype.readString = function(len) { + this.ensureAvailable(len); + var str = this.inBuf.toString('utf8', this.readPos, this.readPos + len); + this.readPos += len; + return str; +}; + +TFramedTransport.prototype.borrow = function() { + return { + buf: this.inBuf, + readIndex: this.readPos, + writeIndex: this.inBuf.length + }; +}; + +TFramedTransport.prototype.consume = function(bytesConsumed) { + this.readPos += bytesConsumed; +}; + +TFramedTransport.prototype.write = function(buf, encoding) { + if (typeof(buf) === "string") { + buf = new Buffer(buf, encoding || 'utf8'); + } + this.outBuffers.push(buf); + this.outCount += buf.length; +}; + +TFramedTransport.prototype.flush = function() { + // If the seqid of the callback is available pass it to the onFlush + // Then remove the current seqid + var seqid = this._seqid; + this._seqid = null; + + var out = new Buffer(this.outCount), + pos = 0; + this.outBuffers.forEach(function(buf) { + buf.copy(out, pos, 0); + pos += buf.length; + }); + + if (this.onFlush) { + // TODO: optimize this better, allocate one buffer instead of both: + var msg = new Buffer(out.length + 4); + binary.writeI32(msg, out.length); + out.copy(msg, 4, 0, out.length); + if (this.onFlush) { + // Passing seqid through this call to get it to the connection + this.onFlush(msg, seqid); + } + } + + this.outBuffers = []; + this.outCount = 0; +}; diff --git a/lib/nodejs/lib/thrift/http_connection.js b/lib/nodejs/lib/thrift/http_connection.js new file mode 100644 index 0000000..5085538 --- /dev/null +++ b/lib/nodejs/lib/thrift/http_connection.js @@ -0,0 +1,256 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var util = require('util'); +var http = require('http'); +var https = require('https'); +var EventEmitter = require('events').EventEmitter; +var thrift = require('./thrift'); + +var TBufferedTransport = require('./buffered_transport'); +var TBinaryProtocol = require('./binary_protocol'); +var InputBufferUnderrunError = require('./input_buffer_underrun_error'); + +var createClient = require('./create_client'); + +/** + * @class + * @name ConnectOptions + * @property {string} transport - The Thrift layered transport to use (TBufferedTransport, etc). + * @property {string} protocol - The Thrift serialization protocol to use (TBinaryProtocol, etc.). + * @property {string} path - The URL path to POST to (e.g. "/", "/mySvc", "/thrift/quoteSvc", etc.). + * @property {object} headers - A standard Node.js header hash, an object hash containing key/value + * pairs where the key is the header name string and the value is the header value string. + * @property {boolean} https - True causes the connection to use https, otherwise http is used. + * @property {object} nodeOptions - Options passed on to node. + * @example + * //Use a connection that requires ssl/tls, closes the connection after each request, + * // uses the buffered transport layer, uses the JSON protocol and directs RPC traffic + * // to https://thrift.example.com:9090/hello + * var thrift = require('thrift'); + * var options = { + * transport: thrift.TBufferedTransport, + * protocol: thrift.TJSONProtocol, + * path: "/hello", + * headers: {"Connection": "close"}, + * https: true + * }; + * var con = thrift.createHttpConnection("thrift.example.com", 9090, options); + * var client = thrift.createHttpClient(myService, connection); + * client.myServiceFunction(); + */ + +/** + * Initializes a Thrift HttpConnection instance (use createHttpConnection() rather than + * instantiating directly). + * @constructor + * @param {string} host - The host name or IP to connect to. + * @param {number} port - The TCP port to connect to. + * @param {ConnectOptions} options - The configuration options to use. + * @throws {error} Exceptions other than InputBufferUnderrunError are rethrown + * @event {error} The "error" event is fired when a Node.js error event occurs during + * request or response processing, in which case the node error is passed on. An "error" + * event may also be fired when the connection can not map a response back to the + * appropriate client (an internal error), generating a TApplicationException. + * @classdesc HttpConnection objects provide Thrift end point transport + * semantics implemented over the Node.js http.request() method. + * @see {@link createHttpConnection} + */ +var HttpConnection = exports.HttpConnection = function(host, port, options) { + //Initialize the emitter base object + EventEmitter.call(this); + + //Set configuration + var self = this; + this.options = options || {}; + this.host = host; + this.port = port; + this.https = this.options.https || false; + this.transport = this.options.transport || TBufferedTransport; + this.protocol = this.options.protocol || TBinaryProtocol; + + //Prepare Node.js options + this.nodeOptions = { + host: this.host, + port: this.port || 80, + path: this.options.path || '/', + method: 'POST', + headers: this.options.headers || {}, + responseType: this.options.responseType || null + }; + for (var attrname in this.options.nodeOptions) { + this.nodeOptions[attrname] = this.options.nodeOptions[attrname]; + } + /*jshint -W069 */ + if (! this.nodeOptions.headers['Connection']) { + this.nodeOptions.headers['Connection'] = 'keep-alive'; + } + /*jshint +W069 */ + + //The sequence map is used to map seqIDs back to the + // calling client in multiplexed scenarios + this.seqId2Service = {}; + + function decodeCallback(transport_with_data) { + var proto = new self.protocol(transport_with_data); + try { + while (true) { + var header = proto.readMessageBegin(); + var dummy_seqid = header.rseqid * -1; + var client = self.client; + //The Multiplexed Protocol stores a hash of seqid to service names + // in seqId2Service. If the SeqId is found in the hash we need to + // lookup the appropriate client for this call. + // The client var is a single client object when not multiplexing, + // when using multiplexing it is a service name keyed hash of client + // objects. + //NOTE: The 2 way interdependencies between protocols, transports, + // connections and clients in the Node.js implementation are irregular + // and make the implementation difficult to extend and maintain. We + // should bring this stuff inline with typical thrift I/O stack + // operation soon. + // --ra + var service_name = self.seqId2Service[header.rseqid]; + if (service_name) { + client = self.client[service_name]; + delete self.seqId2Service[header.rseqid]; + } + /*jshint -W083 */ + client._reqs[dummy_seqid] = function(err, success){ + transport_with_data.commitPosition(); + var clientCallback = client._reqs[header.rseqid]; + delete client._reqs[header.rseqid]; + if (clientCallback) { + process.nextTick(function() { + clientCallback(err, success); + }); + } + }; + /*jshint +W083 */ + if(client['recv_' + header.fname]) { + client['recv_' + header.fname](proto, header.mtype, dummy_seqid); + } else { + delete client._reqs[dummy_seqid]; + self.emit("error", + new thrift.TApplicationException( + thrift.TApplicationExceptionType.WRONG_METHOD_NAME, + "Received a response to an unknown RPC function")); + } + } + } + catch (e) { + if (e instanceof InputBufferUnderrunError) { + transport_with_data.rollbackPosition(); + } else { + self.emit('error', e); + } + } + } + + + //Response handler + ////////////////////////////////////////////////// + this.responseCallback = function(response) { + var data = []; + var dataLen = 0; + + if (response.statusCode !== 200) { + this.emit("error", new THTTPException(statusCode, response)); + } + + response.on('error', function (e) { + self.emit("error", e); + }); + + // When running directly under node, chunk will be a buffer, + // however, when running in a Browser (e.g. Browserify), chunk + // will be a string or an ArrayBuffer. + response.on('data', function (chunk) { + if ((typeof chunk == 'string') || + (Object.prototype.toString.call(chunk) == '[object Uint8Array]')) { + // Wrap ArrayBuffer/string in a Buffer so data[i].copy will work + data.push(new Buffer(chunk)); + } else { + data.push(chunk); + } + dataLen += chunk.length; + }); + + response.on('end', function(){ + var buf = new Buffer(dataLen); + for (var i=0, len=data.length, pos=0; i= 0; --i) { + buffer[i] = (~b[o + i] + (incremented ? 0 : 1)) & 0xff; + incremented |= b[o + i]; + } + b = buffer; + } + var high2 = b[o + 1] + (b[o] << 8); + // Lesser 11 digits with exceeding values but is under 53 bits capacity. + var low = b[o + 7] + (b[o + 6] << 8) + (b[o + 5] << 16) + + b[o + 4] * POW2_24 // Bit shift renders 32th bit as sign, so use multiplication + + (b[o + 3] + (b[o + 2] << 8)) * POW2_32 + high2 * 74976710656; // The literal is 2^48 % 10^11 + // 12th digit and greater. + var high = Math.floor(low / POW10_11) + high2 * 2814; // The literal is 2^48 / 10^11 + // Make it exactly 11 with leading zeros. + low = ('00000000000' + String(low % POW10_11)).slice(-11); + return (negative ? '-' : '') + String(high) + low; + } +}; + +Int64Util.fromDecimalString = function(text) { + var negative = text.charAt(0) === '-'; + if (text.length < (negative ? 17 : 16)) { + // The magnitude is smaller than 2^53. + return new Int64(+text); + } else if (text.length > (negative ? 20 : 19)) { + throw new RangeError('Too many digits for Int64: ' + text); + } else { + // Most significant (up to 5) digits + var high5 = +text.slice(negative ? 1 : 0, -15); + var low = +text.slice(-15) + high5 * 2764472320; // The literal is 10^15 % 2^32 + var high = Math.floor(low / POW2_32) + high5 * 232830; // The literal is 10^15 / 2^&32 + low = low % POW2_32; + if (high >= POW2_31 && + !(negative && high == POW2_31 && low == 0) // Allow minimum Int64 + ) { + throw new RangeError('The magnitude is too large for Int64.'); + } + if (negative) { + // 2's complement + high = ~high; + if (low === 0) { + high = (high + 1) & 0xffffffff; + } else { + low = ~low + 1; + } + high = 0x80000000 | high; + } + return new Int64(high, low); + } +}; diff --git a/lib/nodejs/lib/thrift/json_parse.js b/lib/nodejs/lib/thrift/json_parse.js new file mode 100644 index 0000000..93b0bf2 --- /dev/null +++ b/lib/nodejs/lib/thrift/json_parse.js @@ -0,0 +1,299 @@ +/* + * Imported from Douglas Crockford's reference implementation with minimum modification + * to handle Int64. + * + * https://github.com/douglascrockford/JSON-js/blob/c98948ae1944a28e2e8ebc3717894e580aeaaa05/json_parse.js + * + * Original license header: + * + * json_parse.js + * 2015-05-02 + * Public Domain. + * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + */ + + +/*jslint for */ + +/*property + at, b, call, charAt, f, fromCharCode, hasOwnProperty, message, n, name, + prototype, push, r, t, text +*/ + +var Int64 = require('node-int64'); +var Int64Util = require('./int64_util'); + +var json_parse = module.exports = (function () { + "use strict"; + +// This is a function that can parse a JSON text, producing a JavaScript +// data structure. It is a simple, recursive descent parser. It does not use +// eval or regular expressions, so it can be used as a model for implementing +// a JSON parser in other languages. + +// We are defining the function inside of another function to avoid creating +// global variables. + + var at, // The index of the current character + ch, // The current character + escapee = { + '"': '"', + '\\': '\\', + '/': '/', + b: '\b', + f: '\f', + n: '\n', + r: '\r', + t: '\t' + }, + text, + + error = function (m) { + +// Call error when something is wrong. + + throw new SyntaxError(m); + }, + + next = function (c) { + +// If a c parameter is provided, verify that it matches the current character. + + if (c && c !== ch) { + error("Expected '" + c + "' instead of '" + ch + "'"); + } + +// Get the next character. When there are no more characters, +// return the empty string. + + ch = text.charAt(at); + at += 1; + return ch; + }, + + number = function () { + +// Parse a number value. + + var number, + string = ''; + + if (ch === '-') { + string = '-'; + next('-'); + } + while (ch >= '0' && ch <= '9') { + string += ch; + next(); + } + if (ch === '.') { + string += '.'; + while (next() && ch >= '0' && ch <= '9') { + string += ch; + } + } + if (ch === 'e' || ch === 'E') { + string += ch; + next(); + if (ch === '-' || ch === '+') { + string += ch; + next(); + } + while (ch >= '0' && ch <= '9') { + string += ch; + next(); + } + } + number = +string; + if (!isFinite(number)) { + error("Bad number"); + } else if (number >= Int64.MAX_INT || number <= Int64.MIN_INT) { + // Return raw string for further process in TJSONProtocol + return string; + } else { + return number; + } + }, + + string = function () { + +// Parse a string value. + + var hex, + i, + string = '', + uffff; + +// When parsing for string values, we must look for " and \ characters. + + if (ch === '"') { + while (next()) { + if (ch === '"') { + next(); + return string; + } + if (ch === '\\') { + next(); + if (ch === 'u') { + uffff = 0; + for (i = 0; i < 4; i += 1) { + hex = parseInt(next(), 16); + if (!isFinite(hex)) { + break; + } + uffff = uffff * 16 + hex; + } + string += String.fromCharCode(uffff); + } else if (typeof escapee[ch] === 'string') { + string += escapee[ch]; + } else { + break; + } + } else { + string += ch; + } + } + } + error("Bad string"); + }, + + white = function () { + +// Skip whitespace. + + while (ch && ch <= ' ') { + next(); + } + }, + + word = function () { + +// true, false, or null. + + switch (ch) { + case 't': + next('t'); + next('r'); + next('u'); + next('e'); + return true; + case 'f': + next('f'); + next('a'); + next('l'); + next('s'); + next('e'); + return false; + case 'n': + next('n'); + next('u'); + next('l'); + next('l'); + return null; + } + error("Unexpected '" + ch + "'"); + }, + + value, // Place holder for the value function. + + array = function () { + +// Parse an array value. + + var array = []; + + if (ch === '[') { + next('['); + white(); + if (ch === ']') { + next(']'); + return array; // empty array + } + while (ch) { + array.push(value()); + white(); + if (ch === ']') { + next(']'); + return array; + } + next(','); + white(); + } + } + error("Bad array"); + }, + + object = function () { + +// Parse an object value. + + var key, + object = {}; + + if (ch === '{') { + next('{'); + white(); + if (ch === '}') { + next('}'); + return object; // empty object + } + while (ch) { + key = string(); + white(); + next(':'); + if (Object.hasOwnProperty.call(object, key)) { + error('Duplicate key "' + key + '"'); + } + object[key] = value(); + white(); + if (ch === '}') { + next('}'); + return object; + } + next(','); + white(); + } + } + error("Bad object"); + }; + + value = function () { + +// Parse a JSON value. It could be an object, an array, a string, a number, +// or a word. + + white(); + switch (ch) { + case '{': + return object(); + case '[': + return array(); + case '"': + return string(); + case '-': + return number(); + default: + return ch >= '0' && ch <= '9' + ? number() + : word(); + } + }; + +// Return the json_parse function. It will have access to all of the above +// functions and variables. + + return function (source) { + var result; + + text = source; + at = 0; + ch = ' '; + result = value(); + white(); + if (ch) { + error("Syntax error"); + } + + return result; + }; +}()); diff --git a/lib/nodejs/lib/thrift/json_protocol.js b/lib/nodejs/lib/thrift/json_protocol.js new file mode 100644 index 0000000..84c62f2 --- /dev/null +++ b/lib/nodejs/lib/thrift/json_protocol.js @@ -0,0 +1,742 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var Int64 = require('node-int64'); +var InputBufferUnderrunError = require('./transport').InputBufferUnderrunError; +var Thrift = require('./thrift'); +var Type = Thrift.Type; +var util = require("util"); + +var Int64Util = require('./int64_util'); +var json_parse = require('./json_parse'); + +var InputBufferUnderrunError = require('./input_buffer_underrun_error'); + +module.exports = TJSONProtocol; + +/** + * Initializes a Thrift JSON protocol instance. + * @constructor + * @param {Thrift.Transport} trans - The transport to serialize to/from. + * @classdesc Apache Thrift Protocols perform serialization which enables cross + * language RPC. The Protocol type is the JavaScript browser implementation + * of the Apache Thrift TJSONProtocol. + * @example + * var protocol = new Thrift.Protocol(transport); + */ +function TJSONProtocol(trans) { + this.tstack = []; + this.tpos = []; + this.trans = trans; +}; + +/** + * Thrift IDL type Id to string mapping. + * @readonly + * @see {@link Thrift.Type} + */ +TJSONProtocol.Type = {}; +TJSONProtocol.Type[Type.BOOL] = '"tf"'; +TJSONProtocol.Type[Type.BYTE] = '"i8"'; +TJSONProtocol.Type[Type.I16] = '"i16"'; +TJSONProtocol.Type[Type.I32] = '"i32"'; +TJSONProtocol.Type[Type.I64] = '"i64"'; +TJSONProtocol.Type[Type.DOUBLE] = '"dbl"'; +TJSONProtocol.Type[Type.STRUCT] = '"rec"'; +TJSONProtocol.Type[Type.STRING] = '"str"'; +TJSONProtocol.Type[Type.MAP] = '"map"'; +TJSONProtocol.Type[Type.LIST] = '"lst"'; +TJSONProtocol.Type[Type.SET] = '"set"'; + +/** + * Thrift IDL type string to Id mapping. + * @readonly + * @see {@link Thrift.Type} + */ +TJSONProtocol.RType = {}; +TJSONProtocol.RType.tf = Type.BOOL; +TJSONProtocol.RType.i8 = Type.BYTE; +TJSONProtocol.RType.i16 = Type.I16; +TJSONProtocol.RType.i32 = Type.I32; +TJSONProtocol.RType.i64 = Type.I64; +TJSONProtocol.RType.dbl = Type.DOUBLE; +TJSONProtocol.RType.rec = Type.STRUCT; +TJSONProtocol.RType.str = Type.STRING; +TJSONProtocol.RType.map = Type.MAP; +TJSONProtocol.RType.lst = Type.LIST; +TJSONProtocol.RType.set = Type.SET; + +/** + * The TJSONProtocol version number. + * @readonly + * @const {number} Version + * @memberof Thrift.Protocol + */ +TJSONProtocol.Version = 1; + +TJSONProtocol.prototype.flush = function() { + this.writeToTransportIfStackIsFlushable(); + return this.trans.flush(); +}; + +TJSONProtocol.prototype.writeToTransportIfStackIsFlushable = function() { + if (this.tstack.length === 1) { + this.trans.write(this.tstack.pop()); + } +}; + +/** + * Serializes the beginning of a Thrift RPC message. + * @param {string} name - The service method to call. + * @param {Thrift.MessageType} messageType - The type of method call. + * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift). + */ +TJSONProtocol.prototype.writeMessageBegin = function(name, messageType, seqid) { + this.tstack.push([TJSONProtocol.Version, '"' + name + '"', messageType, seqid]); +}; + +/** + * Serializes the end of a Thrift RPC message. + */ +TJSONProtocol.prototype.writeMessageEnd = function() { + var obj = this.tstack.pop(); + + this.wobj = this.tstack.pop(); + this.wobj.push(obj); + + this.wbuf = '[' + this.wobj.join(',') + ']'; + + // we assume there is nothing more to come so we write + this.trans.write(this.wbuf); +}; + +/** + * Serializes the beginning of a struct. + * @param {string} name - The name of the struct. + */ +TJSONProtocol.prototype.writeStructBegin = function(name) { + this.tpos.push(this.tstack.length); + this.tstack.push({}); +}; + +/** + * Serializes the end of a struct. + */ +TJSONProtocol.prototype.writeStructEnd = function() { + var p = this.tpos.pop(); + var struct = this.tstack[p]; + var str = '{'; + var first = true; + for (var key in struct) { + if (first) { + first = false; + } else { + str += ','; + } + + str += key + ':' + struct[key]; + } + + str += '}'; + this.tstack[p] = str; + + this.writeToTransportIfStackIsFlushable(); +}; + +/** + * Serializes the beginning of a struct field. + * @param {string} name - The name of the field. + * @param {Thrift.Protocol.Type} fieldType - The data type of the field. + * @param {number} fieldId - The field's unique identifier. + */ +TJSONProtocol.prototype.writeFieldBegin = function(name, fieldType, fieldId) { + this.tpos.push(this.tstack.length); + this.tstack.push({ 'fieldId': '"' + + fieldId + '"', 'fieldType': TJSONProtocol.Type[fieldType] + }); +}; + +/** + * Serializes the end of a field. + */ +TJSONProtocol.prototype.writeFieldEnd = function() { + var value = this.tstack.pop(); + var fieldInfo = this.tstack.pop(); + + if (':' + value === ":[object Object]") { + this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' + + fieldInfo.fieldType + ':' + JSON.stringify(value) + '}'; + } else { + this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' + + fieldInfo.fieldType + ':' + value + '}'; + } + this.tpos.pop(); + + this.writeToTransportIfStackIsFlushable(); +}; + +/** + * Serializes the end of the set of fields for a struct. + */ +TJSONProtocol.prototype.writeFieldStop = function() { +}; + +/** + * Serializes the beginning of a map collection. + * @param {Thrift.Type} keyType - The data type of the key. + * @param {Thrift.Type} valType - The data type of the value. + * @param {number} [size] - The number of elements in the map (ignored). + */ +TJSONProtocol.prototype.writeMapBegin = function(keyType, valType, size) { + //size is invalid, we'll set it on end. + this.tpos.push(this.tstack.length); + this.tstack.push([TJSONProtocol.Type[keyType], TJSONProtocol.Type[valType], 0]); +}; + +/** + * Serializes the end of a map. + */ +TJSONProtocol.prototype.writeMapEnd = function() { + var p = this.tpos.pop(); + + if (p == this.tstack.length) { + return; + } + + if ((this.tstack.length - p - 1) % 2 !== 0) { + this.tstack.push(''); + } + + var size = (this.tstack.length - p - 1) / 2; + + this.tstack[p][this.tstack[p].length - 1] = size; + + var map = '}'; + var first = true; + while (this.tstack.length > p + 1) { + var v = this.tstack.pop(); + var k = this.tstack.pop(); + if (first) { + first = false; + } else { + map = ',' + map; + } + + if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings + map = k + ':' + v + map; + } + map = '{' + map; + + this.tstack[p].push(map); + this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; + + this.writeToTransportIfStackIsFlushable(); +}; + +/** + * Serializes the beginning of a list collection. + * @param {Thrift.Type} elemType - The data type of the elements. + * @param {number} size - The number of elements in the list. + */ +TJSONProtocol.prototype.writeListBegin = function(elemType, size) { + this.tpos.push(this.tstack.length); + this.tstack.push([TJSONProtocol.Type[elemType], size]); +}; + +/** + * Serializes the end of a list. + */ +TJSONProtocol.prototype.writeListEnd = function() { + var p = this.tpos.pop(); + + while (this.tstack.length > p + 1) { + var tmpVal = this.tstack[p + 1]; + this.tstack.splice(p + 1, 1); + this.tstack[p].push(tmpVal); + } + + this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; + + this.writeToTransportIfStackIsFlushable(); +}; + +/** + * Serializes the beginning of a set collection. + * @param {Thrift.Type} elemType - The data type of the elements. + * @param {number} size - The number of elements in the list. + */ +TJSONProtocol.prototype.writeSetBegin = function(elemType, size) { + this.tpos.push(this.tstack.length); + this.tstack.push([TJSONProtocol.Type[elemType], size]); +}; + +/** + * Serializes the end of a set. + */ +TJSONProtocol.prototype.writeSetEnd = function() { + var p = this.tpos.pop(); + + while (this.tstack.length > p + 1) { + var tmpVal = this.tstack[p + 1]; + this.tstack.splice(p + 1, 1); + this.tstack[p].push(tmpVal); + } + + this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; + + this.writeToTransportIfStackIsFlushable(); +}; + +/** Serializes a boolean */ +TJSONProtocol.prototype.writeBool = function(bool) { + this.tstack.push(bool ? 1 : 0); +}; + +/** Serializes a number */ +TJSONProtocol.prototype.writeByte = function(byte) { + this.tstack.push(byte); +}; + +/** Serializes a number */ +TJSONProtocol.prototype.writeI16 = function(i16) { + this.tstack.push(i16); +}; + +/** Serializes a number */ +TJSONProtocol.prototype.writeI32 = function(i32) { + this.tstack.push(i32); +}; + +/** Serializes a number */ +TJSONProtocol.prototype.writeI64 = function(i64) { + if (i64 instanceof Int64) { + this.tstack.push(Int64Util.toDecimalString(i64)); + } else { + this.tstack.push(i64); + } +}; + +/** Serializes a number */ +TJSONProtocol.prototype.writeDouble = function(dub) { + this.tstack.push(dub); +}; + +/** Serializes a string */ +TJSONProtocol.prototype.writeString = function(arg) { + // We do not encode uri components for wire transfer: + if (arg === null) { + this.tstack.push(null); + } else { + if (typeof arg === 'string') { + var str = arg; + } else if (arg instanceof Buffer) { + var str = arg.toString('utf8'); + } else { + throw new Error('writeString called without a string/Buffer argument: ' + arg); + } + + // concat may be slower than building a byte buffer + var escapedString = ''; + for (var i = 0; i < str.length; i++) { + var ch = str.charAt(i); // a single double quote: " + if (ch === '\"') { + escapedString += '\\\"'; // write out as: \" + } else if (ch === '\\') { // a single backslash: \ + escapedString += '\\\\'; // write out as: \\ + /* Currently escaped forward slashes break TJSONProtocol. + * As it stands, we can simply pass forward slashes into + * our strings across the wire without being escaped. + * I think this is the protocol's bug, not thrift.js + * } else if(ch === '/') { // a single forward slash: / + * escapedString += '\\/'; // write out as \/ + * } + */ + } else if (ch === '\b') { // a single backspace: invisible + escapedString += '\\b'; // write out as: \b" + } else if (ch === '\f') { // a single formfeed: invisible + escapedString += '\\f'; // write out as: \f" + } else if (ch === '\n') { // a single newline: invisible + escapedString += '\\n'; // write out as: \n" + } else if (ch === '\r') { // a single return: invisible + escapedString += '\\r'; // write out as: \r" + } else if (ch === '\t') { // a single tab: invisible + escapedString += '\\t'; // write out as: \t" + } else { + escapedString += ch; // Else it need not be escaped + } + } + this.tstack.push('"' + escapedString + '"'); + } +}; + +/** Serializes a string */ +TJSONProtocol.prototype.writeBinary = function(arg) { + if (typeof arg === 'string') { + var buf = new Buffer(arg, 'binary'); + } else if (arg instanceof Buffer || + Object.prototype.toString.call(arg) == '[object Uint8Array]') { + var buf = arg; + } else { + throw new Error('writeBinary called without a string/Buffer argument: ' + arg); + } + this.tstack.push('"' + buf.toString('base64') + '"'); +}; + +/** + * @class + * @name AnonReadMessageBeginReturn + * @property {string} fname - The name of the service method. + * @property {Thrift.MessageType} mtype - The type of message call. + * @property {number} rseqid - The sequence number of the message (0 in Thrift RPC). + */ +/** + * Deserializes the beginning of a message. + * @returns {AnonReadMessageBeginReturn} + */ +TJSONProtocol.prototype.readMessageBegin = function() { + this.rstack = []; + this.rpos = []; + + //Borrow the inbound transport buffer and ensure data is present/consistent + var transBuf = this.trans.borrow(); + if (transBuf.readIndex >= transBuf.writeIndex) { + throw new InputBufferUnderrunError(); + } + var cursor = transBuf.readIndex; + + if (transBuf.buf[cursor] !== 0x5B) { //[ + throw new Error("Malformed JSON input, no opening bracket"); + } + + //Parse a single message (there may be several in the buffer) + // TODO: Handle characters using multiple code units + cursor++; + var openBracketCount = 1; + var inString = false; + for (; cursor < transBuf.writeIndex; cursor++) { + var chr = transBuf.buf[cursor]; + //we use hexa charcode here because data[i] returns an int and not a char + if (inString) { + if (chr === 0x22) { //" + inString = false; + } else if (chr === 0x5C) { //\ + //escaped character, skip + cursor += 1; + } + } else { + if (chr === 0x5B) { //[ + openBracketCount += 1; + } else if (chr === 0x5D) { //] + openBracketCount -= 1; + if (openBracketCount === 0) { + //end of json message detected + break; + } + } else if (chr === 0x22) { //" + inString = true; + } + } + } + + if (openBracketCount !== 0) { + // Missing closing bracket. Can be buffer underrun. + throw new InputBufferUnderrunError(); + } + + //Reconstitute the JSON object and conume the necessary bytes + this.robj = json_parse(transBuf.buf.slice(transBuf.readIndex, cursor+1).toString()); + this.trans.consume(cursor + 1 - transBuf.readIndex); + + //Verify the protocol version + var version = this.robj.shift(); + if (version != TJSONProtocol.Version) { + throw new Error('Wrong thrift protocol version: ' + version); + } + + //Objectify the thrift message {name/type/sequence-number} for return + // and then save the JSON object in rstack + var r = {}; + r.fname = this.robj.shift(); + r.mtype = this.robj.shift(); + r.rseqid = this.robj.shift(); + this.rstack.push(this.robj.shift()); + return r; +}; + +/** Deserializes the end of a message. */ +TJSONProtocol.prototype.readMessageEnd = function() { +}; + +/** + * Deserializes the beginning of a struct. + * @param {string} [name] - The name of the struct (ignored) + * @returns {object} - An object with an empty string fname property + */ +TJSONProtocol.prototype.readStructBegin = function() { + var r = {}; + r.fname = ''; + + //incase this is an array of structs + if (this.rstack[this.rstack.length - 1] instanceof Array) { + this.rstack.push(this.rstack[this.rstack.length - 1].shift()); + } + + return r; +}; + +/** Deserializes the end of a struct. */ +TJSONProtocol.prototype.readStructEnd = function() { + this.rstack.pop(); +}; + +/** + * @class + * @name AnonReadFieldBeginReturn + * @property {string} fname - The name of the field (always ''). + * @property {Thrift.Type} ftype - The data type of the field. + * @property {number} fid - The unique identifier of the field. + */ +/** + * Deserializes the beginning of a field. + * @returns {AnonReadFieldBeginReturn} + */ +TJSONProtocol.prototype.readFieldBegin = function() { + var r = {}; + + var fid = -1; + var ftype = Type.STOP; + + //get a fieldId + for (var f in (this.rstack[this.rstack.length - 1])) { + if (f === null) { + continue; + } + + fid = parseInt(f, 10); + this.rpos.push(this.rstack.length); + + var field = this.rstack[this.rstack.length - 1][fid]; + + //remove so we don't see it again + delete this.rstack[this.rstack.length - 1][fid]; + + this.rstack.push(field); + + break; + } + + if (fid != -1) { + //should only be 1 of these but this is the only + //way to match a key + for (var i in (this.rstack[this.rstack.length - 1])) { + if (TJSONProtocol.RType[i] === null) { + continue; + } + + ftype = TJSONProtocol.RType[i]; + this.rstack[this.rstack.length - 1] = this.rstack[this.rstack.length - 1][i]; + } + } + + r.fname = ''; + r.ftype = ftype; + r.fid = fid; + + return r; +}; + +/** Deserializes the end of a field. */ +TJSONProtocol.prototype.readFieldEnd = function() { + var pos = this.rpos.pop(); + + //get back to the right place in the stack + while (this.rstack.length > pos) { + this.rstack.pop(); + } +}; + +/** + * @class + * @name AnonReadMapBeginReturn + * @property {Thrift.Type} ktype - The data type of the key. + * @property {Thrift.Type} vtype - The data type of the value. + * @property {number} size - The number of elements in the map. + */ +/** + * Deserializes the beginning of a map. + * @returns {AnonReadMapBeginReturn} + */ +TJSONProtocol.prototype.readMapBegin = function() { + var map = this.rstack.pop(); + var first = map.shift(); + if (first instanceof Array) { + this.rstack.push(map); + map = first; + first = map.shift(); + } + + var r = {}; + r.ktype = TJSONProtocol.RType[first]; + r.vtype = TJSONProtocol.RType[map.shift()]; + r.size = map.shift(); + + + this.rpos.push(this.rstack.length); + this.rstack.push(map.shift()); + + return r; +}; + +/** Deserializes the end of a map. */ +TJSONProtocol.prototype.readMapEnd = function() { + this.readFieldEnd(); +}; + +/** + * @class + * @name AnonReadColBeginReturn + * @property {Thrift.Type} etype - The data type of the element. + * @property {number} size - The number of elements in the collection. + */ +/** + * Deserializes the beginning of a list. + * @returns {AnonReadColBeginReturn} + */ +TJSONProtocol.prototype.readListBegin = function() { + var list = this.rstack[this.rstack.length - 1]; + + var r = {}; + r.etype = TJSONProtocol.RType[list.shift()]; + r.size = list.shift(); + + this.rpos.push(this.rstack.length); + this.rstack.push(list.shift()); + + return r; +}; + +/** Deserializes the end of a list. */ +TJSONProtocol.prototype.readListEnd = function() { + var pos = this.rpos.pop() - 2; + var st = this.rstack; + st.pop(); + if (st instanceof Array && st.length > pos && st[pos].length > 0) { + st.push(st[pos].shift()); + } +}; + +/** + * Deserializes the beginning of a set. + * @returns {AnonReadColBeginReturn} + */ +TJSONProtocol.prototype.readSetBegin = function() { + return this.readListBegin(); +}; + +/** Deserializes the end of a set. */ +TJSONProtocol.prototype.readSetEnd = function() { + return this.readListEnd(); +}; + +TJSONProtocol.prototype.readBool = function() { + return this.readValue() == '1'; +}; + +TJSONProtocol.prototype.readByte = function() { + return this.readI32(); +}; + +TJSONProtocol.prototype.readI16 = function() { + return this.readI32(); +}; + +TJSONProtocol.prototype.readI32 = function(f) { + return +this.readValue(); +} + +/** Returns the next value found in the protocol buffer */ +TJSONProtocol.prototype.readValue = function(f) { + if (f === undefined) { + f = this.rstack[this.rstack.length - 1]; + } + + var r = {}; + + if (f instanceof Array) { + if (f.length === 0) { + r.value = undefined; + } else { + r.value = f.shift(); + } + } else if (!(f instanceof Int64) && f instanceof Object) { + for (var i in f) { + if (i === null) { + continue; + } + this.rstack.push(f[i]); + delete f[i]; + + r.value = i; + break; + } + } else { + r.value = f; + this.rstack.pop(); + } + + return r.value; +}; + +TJSONProtocol.prototype.readI64 = function() { + var n = this.readValue() + if (typeof n === 'string') { + // Assuming no one is sending in 1.11111e+33 format + return Int64Util.fromDecimalString(n); + } else { + return new Int64(n); + } +}; + +TJSONProtocol.prototype.readDouble = function() { + return this.readI32(); +}; + +TJSONProtocol.prototype.readBinary = function() { + return new Buffer(this.readValue(), 'base64'); +}; + +TJSONProtocol.prototype.readString = function() { + return this.readValue(); +}; + +/** + * Returns the underlying transport. + * @readonly + * @returns {Thrift.Transport} The underlying transport. + */ +TJSONProtocol.prototype.getTransport = function() { + return this.trans; +}; + +/** + * Method to arbitrarily skip over data + */ +TJSONProtocol.prototype.skip = function(type) { + throw new Error('skip not supported yet'); +}; diff --git a/lib/nodejs/lib/thrift/log.js b/lib/nodejs/lib/thrift/log.js new file mode 100644 index 0000000..053e813 --- /dev/null +++ b/lib/nodejs/lib/thrift/log.js @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var util = require('util'); + +var disabled = function () {}; +var logFunc = console.log; +var logLevel = 'error'; // default level + +function factory(level) { + return function () { + // better use spread syntax, but due to compatibility, + // use legacy method here. + var args = ['thrift: [' + level + '] '].concat(Array.from(arguments)); + return logFunc(util.format.apply(null, args)); + }; +} + +var trace = disabled; +var debug = disabled; +var error = disabled; +var warning = disabled; +var info = disabled; + +exports.setLogFunc = function (func) { + logFunc = func; +}; + +var setLogLevel = exports.setLogLevel = function (level) { + trace = debug = error = warning = info = disabled; + logLevel = level; + switch (logLevel) { + case 'trace': + trace = factory('TRACE'); + case 'debug': + debug = factory('DEBUG'); + case 'error': + error = factory('ERROR'); + case 'warning': + warning = factory('WARN'); + case 'info': + info = factory('INFO'); + } +}; + +// set default +setLogLevel(logLevel); + +exports.getLogLevel = function () { + return logLevel; +}; + +exports.trace = function () { + return trace.apply(null, arguments); +}; + +exports.debug = function () { + return debug.apply(null, arguments); +}; + +exports.error = function () { + return error.apply(null, arguments); +}; + +exports.warning = function () { + return warning.apply(null, arguments); +}; + +exports.info = function () { + return info.apply(null, arguments); +}; diff --git a/lib/nodejs/lib/thrift/multiplexed_processor.js b/lib/nodejs/lib/thrift/multiplexed_processor.js new file mode 100644 index 0000000..67b62f7 --- /dev/null +++ b/lib/nodejs/lib/thrift/multiplexed_processor.js @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var Thrift = require('./thrift'); + +exports.MultiplexedProcessor = MultiplexedProcessor; + +function MultiplexedProcessor(stream, options) { + this.services = {}; +}; + +MultiplexedProcessor.prototype.registerProcessor = function(name, handler) { + this.services[name] = handler; +}; + +MultiplexedProcessor.prototype.process = function(inp, out) { + var begin = inp.readMessageBegin(); + + if (begin.mtype != Thrift.MessageType.CALL && begin.mtype != Thrift.MessageType.ONEWAY) { + throw new Thrift.TException('TMultiplexedProcessor: Unexpected message type'); + } + + var p = begin.fname.split(':'); + var sname = p[0]; + var fname = p[1]; + + if (! (sname in this.services)) { + throw new Thrift.TException('TMultiplexedProcessor: Unknown service: ' + sname); + } + + //construct a proxy object which stubs the readMessageBegin + //for the service + var inpProxy = {}; + + for (var attr in inp) { + inpProxy[attr] = inp[attr]; + } + + inpProxy.readMessageBegin = function() { + return { + fname: fname, + mtype: begin.mtype, + rseqid: begin.rseqid + }; + }; + + this.services[sname].process(inpProxy, out); +}; diff --git a/lib/nodejs/lib/thrift/multiplexed_protocol.js b/lib/nodejs/lib/thrift/multiplexed_protocol.js new file mode 100644 index 0000000..d078aa2 --- /dev/null +++ b/lib/nodejs/lib/thrift/multiplexed_protocol.js @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var util = require('util'); +var Thrift = require('./thrift'); + +exports.Multiplexer = Multiplexer; + +function Wrapper(serviceName, protocol, connection) { + + function MultiplexProtocol(trans, strictRead, strictWrite) { + protocol.call(this, trans, strictRead, strictWrite); + }; + + util.inherits(MultiplexProtocol, protocol); + + MultiplexProtocol.prototype.writeMessageBegin = function(name, type, seqid) { + if (type == Thrift.MessageType.CALL || type == Thrift.MessageType.ONEWAY) { + connection.seqId2Service[seqid] = serviceName; + MultiplexProtocol.super_.prototype.writeMessageBegin.call(this, + serviceName + ":" + name, + type, + seqid); + } else { + MultiplexProtocol.super_.prototype.writeMessageBegin.call(this, name, type, seqid); + } + }; + + return MultiplexProtocol; +}; + +function Multiplexer() { + this.seqid = 0; +}; + +Multiplexer.prototype.createClient = function(serviceName, ServiceClient, connection) { + if (ServiceClient.Client) { + ServiceClient = ServiceClient.Client; + } + var writeCb = function(buf, seqid) { + connection.write(buf,seqid); + }; + var transport = new connection.transport(undefined, writeCb); + var protocolWrapper = new Wrapper(serviceName, connection.protocol, connection); + var client = new ServiceClient(transport, protocolWrapper); + var self = this; + client.new_seqid = function() { + self.seqid += 1; + return self.seqid; + }; + + if (typeof connection.client !== 'object') { + connection.client = {}; + } + connection.client[serviceName] = client; + + return client; +}; diff --git a/lib/nodejs/lib/thrift/protocol.js b/lib/nodejs/lib/thrift/protocol.js new file mode 100644 index 0000000..a70ebe2 --- /dev/null +++ b/lib/nodejs/lib/thrift/protocol.js @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +module.exports.TBinaryProtocol = require('./binary_protocol'); +module.exports.TCompactProtocol = require('./compact_protocol'); +module.exports.TJSONProtocol = require('./json_protocol'); diff --git a/lib/nodejs/lib/thrift/server.js b/lib/nodejs/lib/thrift/server.js new file mode 100644 index 0000000..e124acc --- /dev/null +++ b/lib/nodejs/lib/thrift/server.js @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var constants = require('constants'); +var net = require('net'); +var tls = require('tls'); + +var TBufferedTransport = require('./buffered_transport'); +var TBinaryProtocol = require('./binary_protocol'); +var InputBufferUnderrunError = require('./input_buffer_underrun_error'); + +/** + * Create a Thrift server which can serve one or multiple services. + * @param {object} processor - A normal or multiplexedProcessor (must + * be preconstructed with the desired handler). + * @param {ServerOptions} options - Optional additional server configuration. + * @returns {object} - The Apache Thrift Multiplex Server. + */ +exports.createMultiplexServer = function(processor, options) { + var transport = (options && options.transport) ? options.transport : TBufferedTransport; + var protocol = (options && options.protocol) ? options.protocol : TBinaryProtocol; + + function serverImpl(stream) { + var self = this; + stream.on('error', function(err) { + self.emit('error', err); + }); + stream.on('data', transport.receiver(function(transportWithData) { + var input = new protocol(transportWithData); + var output = new protocol(new transport(undefined, function(buf) { + try { + stream.write(buf); + } catch (err) { + self.emit('error', err); + stream.end(); + } + })); + + try { + do { + processor.process(input, output); + transportWithData.commitPosition(); + } while (true); + } catch (err) { + if (err instanceof InputBufferUnderrunError) { + //The last data in the buffer was not a complete message, wait for the rest + transportWithData.rollbackPosition(); + } + else if (err.message === "Invalid type: undefined") { + //No more data in the buffer + //This trap is a bit hackish + //The next step to improve the node behavior here is to have + // the compiler generated process method throw a more explicit + // error when the network buffer is empty (regardles of the + // protocol/transport stack in use) and replace this heuristic. + // Also transports should probably not force upper layers to + // manage their buffer positions (i.e. rollbackPosition() and + // commitPosition() should be eliminated in lieu of a transport + // encapsulated buffer management strategy.) + transportWithData.rollbackPosition(); + } + else { + //Unexpected error + self.emit('error', err); + stream.end(); + } + } + })); + + stream.on('end', function() { + stream.end(); + }); + } + + if (options && options.tls) { + if (!('secureProtocol' in options.tls) && !('secureOptions' in options.tls)) { + options.tls.secureProtocol = "SSLv23_method"; + options.tls.secureOptions = constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3; + } + return tls.createServer(options.tls, serverImpl); + } else { + return net.createServer(serverImpl); + } +}; + +/** + * Create a single service Apache Thrift server. + * @param {object} processor - A service class or processor function. + * @param {ServerOptions} options - Optional additional server configuration. + * @returns {object} - The Apache Thrift Multiplex Server. + */ +exports.createServer = function(processor, handler, options) { + if (processor.Processor) { + processor = processor.Processor; + } + return exports.createMultiplexServer(new processor(handler), options); +}; diff --git a/lib/nodejs/lib/thrift/thrift.js b/lib/nodejs/lib/thrift/thrift.js new file mode 100644 index 0000000..f2b2896 --- /dev/null +++ b/lib/nodejs/lib/thrift/thrift.js @@ -0,0 +1,232 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var util = require('util'); + +var Type = exports.Type = { + STOP: 0, + VOID: 1, + BOOL: 2, + BYTE: 3, + I08: 3, + DOUBLE: 4, + I16: 6, + I32: 8, + I64: 10, + STRING: 11, + UTF7: 11, + STRUCT: 12, + MAP: 13, + SET: 14, + LIST: 15, + UTF8: 16, + UTF16: 17 +}; + +exports.MessageType = { + CALL: 1, + REPLY: 2, + EXCEPTION: 3, + ONEWAY: 4 +}; + +exports.TException = TException; + +function TException(message) { + Error.call(this); + Error.captureStackTrace(this, this.constructor); + this.name = this.constructor.name; + this.message = message; +}; +util.inherits(TException, Error); + +var TApplicationExceptionType = exports.TApplicationExceptionType = { + UNKNOWN: 0, + UNKNOWN_METHOD: 1, + INVALID_MESSAGE_TYPE: 2, + WRONG_METHOD_NAME: 3, + BAD_SEQUENCE_ID: 4, + MISSING_RESULT: 5, + INTERNAL_ERROR: 6, + PROTOCOL_ERROR: 7, + INVALID_TRANSFORM: 8, + INVALID_PROTOCOL: 9, + UNSUPPORTED_CLIENT_TYPE: 10 +}; + +exports.TApplicationException = TApplicationException; + +function TApplicationException(type, message) { + TException.call(this); + Error.captureStackTrace(this, this.constructor); + this.type = type || TApplicationExceptionType.UNKNOWN; + this.name = this.constructor.name; + this.message = message; +}; +util.inherits(TApplicationException, TException); + +TApplicationException.prototype.read = function(input) { + var ftype; + var ret = input.readStructBegin('TApplicationException'); + + while(1){ + ret = input.readFieldBegin(); + if(ret.ftype == Type.STOP) + break; + + switch(ret.fid){ + case 1: + if( ret.ftype == Type.STRING ){ + ret = input.readString(); + this.message = ret; + } else { + ret = input.skip(ret.ftype); + } + break; + case 2: + if( ret.ftype == Type.I32 ){ + ret = input.readI32(); + this.type = ret; + } else { + ret = input.skip(ret.ftype); + } + break; + default: + ret = input.skip(ret.ftype); + break; + } + input.readFieldEnd(); + } + input.readStructEnd(); +}; + +TApplicationException.prototype.write = function(output){ + output.writeStructBegin('TApplicationException'); + + if (this.message) { + output.writeFieldBegin('message', Type.STRING, 1); + output.writeString(this.message); + output.writeFieldEnd(); + } + + if (this.code) { + output.writeFieldBegin('type', Type.I32, 2); + output.writeI32(this.code); + output.writeFieldEnd(); + } + + output.writeFieldStop(); + output.writeStructEnd(); +}; + +var TProtocolExceptionType = exports.TProtocolExceptionType = { + UNKNOWN: 0, + INVALID_DATA: 1, + NEGATIVE_SIZE: 2, + SIZE_LIMIT: 3, + BAD_VERSION: 4, + NOT_IMPLEMENTED: 5, + DEPTH_LIMIT: 6 +}; + + +exports.TProtocolException = TProtocolException; + +function TProtocolException(type, message) { + Error.call(this); + Error.captureStackTrace(this, this.constructor); + this.name = this.constructor.name; + this.type = type; + this.message = message; +}; +util.inherits(TProtocolException, Error); + +exports.objectLength = function(obj) { + return Object.keys(obj).length; +}; + +exports.inherits = function(constructor, superConstructor) { + util.inherits(constructor, superConstructor); +}; + +var copyList, copyMap; + +copyList = function(lst, types) { + + if (!lst) {return lst; } + + var type; + + if (types.shift === undefined) { + type = types; + } + else { + type = types[0]; + } + var Type = type; + + var len = lst.length, result = [], i, val; + for (i = 0; i < len; i++) { + val = lst[i]; + if (type === null) { + result.push(val); + } + else if (type === copyMap || type === copyList) { + result.push(type(val, types.slice(1))); + } + else { + result.push(new Type(val)); + } + } + return result; +}; + +copyMap = function(obj, types){ + + if (!obj) {return obj; } + + var type; + + if (types.shift === undefined) { + type = types; + } + else { + type = types[0]; + } + var Type = type; + + var result = {}, val; + for(var prop in obj) { + if(obj.hasOwnProperty(prop)) { + val = obj[prop]; + if (type === null) { + result[prop] = val; + } + else if (type === copyMap || type === copyList) { + result[prop] = type(val, types.slice(1)); + } + else { + result[prop] = new Type(val); + } + } + } + return result; +}; + +module.exports.copyMap = copyMap; +module.exports.copyList = copyList; diff --git a/lib/nodejs/lib/thrift/transport.js b/lib/nodejs/lib/thrift/transport.js new file mode 100644 index 0000000..59daa98 --- /dev/null +++ b/lib/nodejs/lib/thrift/transport.js @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +module.exports.TBufferedTransport = require('./buffered_transport'); +module.exports.TFramedTransport = require('./framed_transport'); +module.exports.InputBufferUnderrunError = require('./input_buffer_underrun_error'); diff --git a/lib/nodejs/lib/thrift/web_server.js b/lib/nodejs/lib/thrift/web_server.js new file mode 100644 index 0000000..0093c8a --- /dev/null +++ b/lib/nodejs/lib/thrift/web_server.js @@ -0,0 +1,559 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var http = require('http'); +var https = require('https'); +var url = require("url"); +var path = require("path"); +var fs = require("fs"); +var crypto = require("crypto"); +var log = require('./log'); + +var MultiplexedProcessor = require('./multiplexed_processor').MultiplexedProcessor; + +var TBufferedTransport = require('./buffered_transport'); +var TBinaryProtocol = require('./binary_protocol'); +var InputBufferUnderrunError = require('./input_buffer_underrun_error'); + +// WSFrame constructor and prototype +///////////////////////////////////////////////////////////////////// + +/** Apache Thrift RPC Web Socket Transport + * Frame layout conforming to RFC 6455 circa 12/2011 + * + * Theoretical frame size limit is 4GB*4GB, however the Node Buffer + * limit is 1GB as of v0.10. The frame length encoding is also + * configured for a max of 4GB presently and needs to be adjusted + * if Node/Browsers become capabile of > 4GB frames. + * + * - FIN is 1 if the message is complete + * - RSV1/2/3 are always 0 + * - Opcode is 1(TEXT) for TJSONProtocol and 2(BIN) for TBinaryProtocol + * - Mask Present bit is 1 sending to-server and 0 sending to-client + * - Payload Len: + * + If < 126: then represented directly + * + If >=126: but within range of an unsigned 16 bit integer + * then Payload Len is 126 and the two following bytes store + * the length + * + Else: Payload Len is 127 and the following 8 bytes store the + * length as an unsigned 64 bit integer + * - Masking key is a 32 bit key only present when sending to the server + * - Payload follows the masking key or length + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-------+-+-------------+-------------------------------+ + * |F|R|R|R| opcode|M| Payload len | Extended payload length | + * |I|S|S|S| (4) |A| (7) | (16/64) | + * |N|V|V|V| |S| | (if payload len==126/127) | + * | |1|2|3| |K| | | + * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + * | Extended payload length continued, if payload len == 127 | + * + - - - - - - - - - - - - - - - +-------------------------------+ + * | |Masking-key, if MASK set to 1 | + * +-------------------------------+-------------------------------+ + * | Masking-key (continued) | Payload Data | + * +-------------------------------- - - - - - - - - - - - - - - - + + * : Payload Data continued ... : + * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + * | Payload Data continued ... | + * +---------------------------------------------------------------+ + */ +var wsFrame = { + /** Encodes a WebSocket frame + * + * @param {Buffer} data - The raw data to encode + * @param {Buffer} mask - The mask to apply when sending to server, null for no mask + * @param {Boolean} binEncoding - True for binary encoding, false for text encoding + * @returns {Buffer} - The WebSocket frame, ready to send + */ + encode: function(data, mask, binEncoding) { + var frame = new Buffer(wsFrame.frameSizeFromData(data, mask)); + //Byte 0 - FIN & OPCODE + frame[0] = wsFrame.fin.FIN + + (binEncoding ? wsFrame.frameOpCodes.BIN : wsFrame.frameOpCodes.TEXT); + //Byte 1 or 1-3 or 1-9 - MASK FLAG & SIZE + var payloadOffset = 2; + if (data.length < 0x7E) { + frame[1] = data.length + (mask ? wsFrame.mask.TO_SERVER : wsFrame.mask.TO_CLIENT); + } else if (data.length < 0xFFFF) { + frame[1] = 0x7E + (mask ? wsFrame.mask.TO_SERVER : wsFrame.mask.TO_CLIENT); + frame.writeUInt16BE(data.length, 2, true); + payloadOffset = 4; + } else { + frame[1] = 0x7F + (mask ? wsFrame.mask.TO_SERVER : wsFrame.mask.TO_CLIENT); + frame.writeUInt32BE(0, 2, true); + frame.writeUInt32BE(data.length, 6, true); + payloadOffset = 10; + } + //MASK + if (mask) { + mask.copy(frame, payloadOffset, 0, 4); + payloadOffset += 4; + } + //Payload + data.copy(frame, payloadOffset); + if (mask) { + wsFrame.applyMask(frame.slice(payloadOffset), frame.slice(payloadOffset-4,payloadOffset)); + } + return frame; + }, + + /** + * @class + * @name WSDecodeResult + * @property {Buffer} data - The decoded data for the first ATRPC message + * @property {Buffer} mask - The frame mask + * @property {Boolean} binEncoding - True if binary (TBinaryProtocol), + * False if text (TJSONProtocol) + * @property {Buffer} nextFrame - Multiple ATRPC messages may be sent in a + * single WebSocket frame, this Buffer contains + * any bytes remaining to be decoded + * @property {Boolean} FIN - True is the message is complete + */ + + /** Decodes a WebSocket frame + * + * @param {Buffer} frame - The raw inbound frame, if this is a continuation + * frame it must have a mask property with the mask. + * @returns {WSDecodeResult} - The decoded payload + * + * @see {@link WSDecodeResult} + */ + decode: function(frame) { + var result = { + data: null, + mask: null, + binEncoding: false, + nextFrame: null, + FIN: true + }; + + //Byte 0 - FIN & OPCODE + if (wsFrame.fin.FIN != (frame[0] & wsFrame.fin.FIN)) { + result.FIN = false; + } + result.binEncoding = (wsFrame.frameOpCodes.BIN == (frame[0] & wsFrame.frameOpCodes.BIN)); + //Byte 1 or 1-3 or 1-9 - SIZE + var lenByte = (frame[1] & 0x0000007F); + var len = lenByte; + var dataOffset = 2; + if (lenByte == 0x7E) { + len = frame.readUInt16BE(2); + dataOffset = 4; + } else if (lenByte == 0x7F) { + len = frame.readUInt32BE(6); + dataOffset = 10; + } + //MASK + if (wsFrame.mask.TO_SERVER == (frame[1] & wsFrame.mask.TO_SERVER)) { + result.mask = new Buffer(4); + frame.copy(result.mask, 0, dataOffset, dataOffset + 4); + dataOffset += 4; + } + //Payload + result.data = new Buffer(len); + frame.copy(result.data, 0, dataOffset, dataOffset+len); + if (result.mask) { + wsFrame.applyMask(result.data, result.mask); + } + //Next Frame + if (frame.length > dataOffset+len) { + result.nextFrame = new Buffer(frame.length - (dataOffset+len)); + frame.copy(result.nextFrame, 0, dataOffset+len, frame.length); + } + //Don't forward control frames + if (frame[0] & wsFrame.frameOpCodes.FINCTRL) { + result.data = null; + } + + return result; + }, + + /** Masks/Unmasks data + * + * @param {Buffer} data - data to mask/unmask in place + * @param {Buffer} mask - the mask + */ + applyMask: function(data, mask){ + //TODO: look into xoring words at a time + var dataLen = data.length; + var maskLen = mask.length; + for (var i = 0; i < dataLen; i++) { + data[i] = data[i] ^ mask[i%maskLen]; + } + }, + + /** Computes frame size on the wire from data to be sent + * + * @param {Buffer} data - data.length is the assumed payload size + * @param {Boolean} mask - true if a mask will be sent (TO_SERVER) + */ + frameSizeFromData: function(data, mask) { + var headerSize = 10; + if (data.length < 0x7E) { + headerSize = 2; + } else if (data.length < 0xFFFF) { + headerSize = 4; + } + return headerSize + data.length + (mask ? 4 : 0); + }, + + frameOpCodes: { + CONT: 0x00, + TEXT: 0x01, + BIN: 0x02, + CTRL: 0x80 + }, + + mask: { + TO_SERVER: 0x80, + TO_CLIENT: 0x00 + }, + + fin: { + CONT: 0x00, + FIN: 0x80 + } +}; + + +// createWebServer constructor and options +///////////////////////////////////////////////////////////////////// + +/** + * @class + * @name ServerOptions + * @property {array} cors - Array of CORS origin strings to permit requests from. + * @property {string} files - Path to serve static files from, if absent or "" + * static file service is disabled. + * @property {object} headers - An object hash mapping header strings to header value + * strings, these headers are transmitted in response to + * static file GET operations. + * @property {object} services - An object hash mapping service URI strings + * to ServiceOptions objects + * @property {object} tls - Node.js TLS options (see: nodejs.org/api/tls.html), + * if not present or null regular http is used, + * at least a key and a cert must be defined to use SSL/TLS + * @see {@link ServiceOptions} + */ + +/** + * @class + * @name ServiceOptions + * @property {object} transport - The layered transport to use (defaults + * to TBufferedTransport). + * @property {object} protocol - The serialization Protocol to use (defaults to + * TBinaryProtocol). + * @property {object} processor - The Thrift Service class/processor generated + * by the IDL Compiler for the service (the "cls" + * key can also be used for this attribute). + * @property {object} handler - The handler methods for the Thrift Service. + */ + +/** + * Create a Thrift server which can serve static files and/or one or + * more Thrift Services. + * @param {ServerOptions} options - The server configuration. + * @returns {object} - The Apache Thrift Web Server. + */ +exports.createWebServer = function(options) { + var baseDir = options.files; + var contentTypesByExtension = { + '.txt': 'text/plain', + '.html': 'text/html', + '.css': 'text/css', + '.xml': 'application/xml', + '.json': 'application/json', + '.js': 'application/javascript', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.gif': 'image/gif', + '.png': 'image/png', + '.svg': 'image/svg+xml' + }; + + //Setup all of the services + var services = options.services; + for (var uri in services) { + var svcObj = services[uri]; + + //Setup the processor + if (svcObj.processor instanceof MultiplexedProcessor) { + //Multiplex processors have pre embedded processor/handler pairs, save as is + svcObj.processor = svcObj.processor; + } else { + //For historical reasons Node.js supports processors passed in directly or via the + // IDL Compiler generated class housing the processor. Also, the options property + // for a Processor has been called both cls and processor at different times. We + // support any of the four possibilities here. + var processor = (svcObj.processor) ? (svcObj.processor.Processor || svcObj.processor) : + (svcObj.cls.Processor || svcObj.cls); + //Processors can be supplied as constructed objects with handlers already embedded, + // if a handler is provided we construct a new processor, if not we use the processor + // object directly + if (svcObj.handler) { + svcObj.processor = new processor(svcObj.handler); + } else { + svcObj.processor = processor; + } + } + svcObj.transport = svcObj.transport ? svcObj.transport : TBufferedTransport; + svcObj.protocol = svcObj.protocol ? svcObj.protocol : TBinaryProtocol; + } + + //Verify CORS requirements + function VerifyCORSAndSetHeaders(request, response) { + if (request.headers.origin && options.cors) { + if (options.cors["*"] || options.cors[request.headers.origin]) { + //Allow, origin allowed + response.setHeader("access-control-allow-origin", request.headers.origin); + response.setHeader("access-control-allow-methods", "GET, POST, OPTIONS"); + response.setHeader("access-control-allow-headers", "content-type, accept"); + response.setHeader("access-control-max-age", "60"); + return true; + } else { + //Disallow, origin denied + return false; + } + } + //Allow, CORS is not in use + return true; + } + + + //Handle OPTIONS method (CORS) + /////////////////////////////////////////////////// + function processOptions(request, response) { + if (VerifyCORSAndSetHeaders(request, response)) { + response.writeHead("204", "No Content", {"content-length": 0}); + } else { + response.writeHead("403", "Origin " + request.headers.origin + " not allowed", {}); + } + response.end(); + } + + + //Handle POST methods (TXHRTransport) + /////////////////////////////////////////////////// + function processPost(request, response) { + //Lookup service + var uri = url.parse(request.url).pathname; + var svc = services[uri]; + if (!svc) { + response.writeHead("403", "No Apache Thrift Service at " + uri, {}); + response.end(); + return; + } + + //Verify CORS requirements + if (!VerifyCORSAndSetHeaders(request, response)) { + response.writeHead("403", "Origin " + request.headers.origin + " not allowed", {}); + response.end(); + return; + } + + //Process XHR payload + request.on('data', svc.transport.receiver(function(transportWithData) { + var input = new svc.protocol(transportWithData); + var output = new svc.protocol(new svc.transport(undefined, function(buf) { + try { + response.writeHead(200); + response.end(buf); + } catch (err) { + response.writeHead(500); + response.end(); + } + })); + + try { + svc.processor.process(input, output); + transportWithData.commitPosition(); + } catch (err) { + if (err instanceof InputBufferUnderrunError) { + transportWithData.rollbackPosition(); + } else { + response.writeHead(500); + response.end(); + } + } + })); + } + + + //Handle GET methods (Static Page Server) + /////////////////////////////////////////////////// + function processGet(request, response) { + //Undefined or empty base directory means do not serve static files + if (!baseDir || "" === baseDir) { + response.writeHead(404); + response.end(); + return; + } + + //Verify CORS requirements + if (!VerifyCORSAndSetHeaders(request, response)) { + response.writeHead("403", "Origin " + request.headers.origin + " not allowed", {}); + response.end(); + return; + } + + //Locate the file requested and send it + var uri = url.parse(request.url).pathname; + var filename = path.join(baseDir, uri); + fs.exists(filename, function(exists) { + if(!exists) { + response.writeHead(404); + response.end(); + return; + } + + if (fs.statSync(filename).isDirectory()) { + filename += '/index.html'; + } + + fs.readFile(filename, "binary", function(err, file) { + if (err) { + response.writeHead(500); + response.end(err + "\n"); + return; + } + var headers = {}; + var contentType = contentTypesByExtension[path.extname(filename)]; + if (contentType) { + headers["Content-Type"] = contentType; + } + for (var k in options.headers) { + headers[k] = options.headers[k]; + } + response.writeHead(200, headers); + response.write(file, "binary"); + response.end(); + }); + }); + } + + + //Handle WebSocket calls (TWebSocketTransport) + /////////////////////////////////////////////////// + function processWS(data, socket, svc, binEncoding) { + svc.transport.receiver(function(transportWithData) { + var input = new svc.protocol(transportWithData); + var output = new svc.protocol(new svc.transport(undefined, function(buf) { + try { + var frame = wsFrame.encode(buf, null, binEncoding); + socket.write(frame); + } catch (err) { + //TODO: Add better error processing + } + })); + + try { + svc.processor.process(input, output); + transportWithData.commitPosition(); + } + catch (err) { + if (err instanceof InputBufferUnderrunError) { + transportWithData.rollbackPosition(); + } + else { + //TODO: Add better error processing + } + } + })(data); + } + + //Create the server (HTTP or HTTPS) + var server = null; + if (options.tls) { + server = https.createServer(options.tls); + } else { + server = http.createServer(); + } + + //Wire up listeners for upgrade(to WebSocket) & request methods for: + // - GET static files, + // - POST XHR Thrift services + // - OPTIONS CORS requests + server.on('request', function(request, response) { + if (request.method === 'POST') { + processPost(request, response); + } else if (request.method === 'GET') { + processGet(request, response); + } else if (request.method === 'OPTIONS') { + processOptions(request, response); + } else { + response.writeHead(500); + response.end(); + } + }).on('upgrade', function(request, socket, head) { + //Lookup service + var svc; + try { + svc = services[Object.keys(services)[0]]; + } catch(e) { + socket.write("HTTP/1.1 403 No Apache Thrift Service available\r\n\r\n"); + return; + } + //Perform upgrade + var hash = crypto.createHash("sha1"); + hash.update(request.headers['sec-websocket-key'] + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + socket.write("HTTP/1.1 101 Switching Protocols\r\n" + + "Upgrade: websocket\r\n" + + "Connection: Upgrade\r\n" + + "Sec-WebSocket-Accept: " + hash.digest("base64") + "\r\n" + + "Sec-WebSocket-Origin: " + request.headers.origin + "\r\n" + + "Sec-WebSocket-Location: ws://" + request.headers.host + request.url + "\r\n" + + "\r\n"); + //Handle WebSocket traffic + var data = null; + socket.on('data', function(frame) { + try { + while (frame) { + var result = wsFrame.decode(frame); + //Prepend any existing decoded data + if (data) { + if (result.data) { + var newData = new Buffer(data.length + result.data.length); + data.copy(newData); + result.data.copy(newData, data.length); + result.data = newData; + } else { + result.data = data; + } + data = null; + } + //If this completes a message process it + if (result.FIN) { + processWS(result.data, socket, svc, result.binEncoding); + } else { + data = result.data; + } + //Prepare next frame for decoding (if any) + frame = result.nextFrame; + } + } catch(e) { + log.error('TWebSocketTransport Exception: ' + e); + socket.destroy(); + } + }); + }); + + //Return the server + return server; +}; diff --git a/lib/nodejs/lib/thrift/ws_connection.js b/lib/nodejs/lib/thrift/ws_connection.js new file mode 100644 index 0000000..052cbd4 --- /dev/null +++ b/lib/nodejs/lib/thrift/ws_connection.js @@ -0,0 +1,286 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var util = require('util'); +var WebSocket = require('ws'); +var EventEmitter = require("events").EventEmitter; +var thrift = require('./thrift'); +var ttransport = require('./transport'); +var tprotocol = require('./protocol'); + +var TBufferedTransport = require('./buffered_transport'); +var TJSONProtocol = require('./json_protocol'); +var InputBufferUnderrunError = require('./input_buffer_underrun_error'); + +var createClient = require('./create_client'); + +exports.WSConnection = WSConnection; + +/** + * @class + * @name WSConnectOptions + * @property {string} transport - The Thrift layered transport to use (TBufferedTransport, etc). + * @property {string} protocol - The Thrift serialization protocol to use (TJSONProtocol, etc.). + * @property {string} path - The URL path to connect to (e.g. "/", "/mySvc", "/thrift/quoteSvc", etc.). + * @property {object} headers - A standard Node.js header hash, an object hash containing key/value + * pairs where the key is the header name string and the value is the header value string. + * @property {boolean} secure - True causes the connection to use wss, otherwise ws is used. + * @property {object} wsOptions - Options passed on to WebSocket. + * @example + * //Use a secured websocket connection + * // uses the buffered transport layer, uses the JSON protocol and directs RPC traffic + * // to wss://thrift.example.com:9090/hello + * var thrift = require('thrift'); + * var options = { + * transport: thrift.TBufferedTransport, + * protocol: thrift.TJSONProtocol, + * path: "/hello", + * secure: true + * }; + * var con = thrift.createWSConnection("thrift.example.com", 9090, options); + * con.open() + * var client = thrift.createWSClient(myService, connection); + * client.myServiceFunction(); + * con.close() + */ + +/** + * Initializes a Thrift WSConnection instance (use createWSConnection() rather than + * instantiating directly). + * @constructor + * @param {string} host - The host name or IP to connect to. + * @param {number} port - The TCP port to connect to. + * @param {WSConnectOptions} options - The configuration options to use. + * @throws {error} Exceptions other than ttransport.InputBufferUnderrunError are rethrown + * @event {error} The "error" event is fired when a Node.js error event occurs during + * request or response processing, in which case the node error is passed on. An "error" + * event may also be fired when the connectison can not map a response back to the + * appropriate client (an internal error), generating a TApplicationException. + * @classdesc WSConnection objects provide Thrift end point transport + * semantics implemented using Websockets. + * @see {@link createWSConnection} + */ +function WSConnection(host, port, options) { + //Initialize the emitter base object + EventEmitter.call(this); + + //Set configuration + var self = this; + this.options = options || {}; + this.host = host; + this.port = port; + this.secure = this.options.secure || false; + this.transport = this.options.transport || TBufferedTransport; + this.protocol = this.options.protocol || TJSONProtocol; + this.path = this.options.path; + this.send_pending = []; + + //The sequence map is used to map seqIDs back to the + // calling client in multiplexed scenarios + this.seqId2Service = {}; + + //Prepare WebSocket options + this.wsOptions = { + host: this.host, + port: this.port || 80, + path: this.options.path || '/', + headers: this.options.headers || {} + }; + for (var attrname in this.options.wsOptions) { + this.wsOptions[attrname] = this.options.wsOptions[attrname]; + } +}; +util.inherits(WSConnection, EventEmitter); + +WSConnection.prototype.__reset = function() { + this.socket = null; //The web socket + this.send_pending = []; //Buffers/Callback pairs waiting to be sent +}; + +WSConnection.prototype.__onOpen = function() { + var self = this; + this.emit("open"); + if (this.send_pending.length > 0) { + //If the user made calls before the connection was fully + //open, send them now + this.send_pending.forEach(function(data) { + self.socket.send(data); + }); + this.send_pending = []; + } +}; + +WSConnection.prototype.__onClose = function(evt) { + this.emit("close"); + this.__reset(); +}; + +WSConnection.prototype.__decodeCallback = function(transport_with_data) { + var proto = new this.protocol(transport_with_data); + try { + while (true) { + var header = proto.readMessageBegin(); + var dummy_seqid = header.rseqid * -1; + var client = this.client; + //The Multiplexed Protocol stores a hash of seqid to service names + // in seqId2Service. If the SeqId is found in the hash we need to + // lookup the appropriate client for this call. + // The client var is a single client object when not multiplexing, + // when using multiplexing it is a service name keyed hash of client + // objects. + //NOTE: The 2 way interdependencies between protocols, transports, + // connections and clients in the Node.js implementation are irregular + // and make the implementation difficult to extend and maintain. We + // should bring this stuff inline with typical thrift I/O stack + // operation soon. + // --ra + var service_name = this.seqId2Service[header.rseqid]; + if (service_name) { + client = this.client[service_name]; + delete this.seqId2Service[header.rseqid]; + } + /*jshint -W083 */ + client._reqs[dummy_seqid] = function(err, success) { + transport_with_data.commitPosition(); + var clientCallback = client._reqs[header.rseqid]; + delete client._reqs[header.rseqid]; + if (clientCallback) { + clientCallback(err, success); + } + }; + /*jshint +W083 */ + if (client['recv_' + header.fname]) { + client['recv_' + header.fname](proto, header.mtype, dummy_seqid); + } else { + delete client._reqs[dummy_seqid]; + this.emit("error", + new thrift.TApplicationException( + thrift.TApplicationExceptionType.WRONG_METHOD_NAME, + "Received a response to an unknown RPC function")); + } + } + } catch (e) { + if (e instanceof InputBufferUnderrunError) { + transport_with_data.rollbackPosition(); + } else { + throw e; + } + } +}; + +WSConnection.prototype.__onData = function(data) { + if (Object.prototype.toString.call(data) == "[object ArrayBuffer]") { + data = new Uint8Array(data); + } + var buf = new Buffer(data); + this.transport.receiver(this.__decodeCallback.bind(this))(buf); + +}; + +WSConnection.prototype.__onMessage = function(evt) { + this.__onData(evt.data); +}; + +WSConnection.prototype.__onError = function(evt) { + this.emit("error", evt); + this.socket.close(); +}; + +/** + * Returns true if the transport is open + * @readonly + * @returns {boolean} + */ +WSConnection.prototype.isOpen = function() { + return this.socket && this.socket.readyState == this.socket.OPEN; +}; + +/** + * Opens the transport connection + */ +WSConnection.prototype.open = function() { + //If OPEN/CONNECTING/CLOSING ignore additional opens + if (this.socket && this.socket.readyState != this.socket.CLOSED) { + return; + } + //If there is no socket or the socket is closed: + this.socket = new WebSocket(this.uri(), "", this.wsOptions); + this.socket.binaryType = 'arraybuffer'; + this.socket.onopen = this.__onOpen.bind(this); + this.socket.onmessage = this.__onMessage.bind(this); + this.socket.onerror = this.__onError.bind(this); + this.socket.onclose = this.__onClose.bind(this); +}; + +/** + * Closes the transport connection + */ +WSConnection.prototype.close = function() { + this.socket.close(); +}; + +/** + * Return URI for the connection + * @returns {string} URI + */ +WSConnection.prototype.uri = function() { + var schema = this.secure ? 'wss' : 'ws'; + var port = ''; + var path = this.path || '/'; + var host = this.host; + + // avoid port if default for schema + if (this.port && (('wss' == schema && this.port != 443) || + ('ws' == schema && this.port != 80))) { + port = ':' + this.port; + } + + return schema + '://' + host + port + path; +}; + +/** + * Writes Thrift message data to the connection + * @param {Buffer} data - A Node.js Buffer containing the data to write + * @returns {void} No return value. + * @event {error} the "error" event is raised upon request failure passing the + * Node.js error object to the listener. + */ +WSConnection.prototype.write = function(data) { + if (this.isOpen()) { + //Send data and register a callback to invoke the client callback + this.socket.send(data); + } else { + //Queue the send to go out __onOpen + this.send_pending.push(data); + } +}; + +/** + * Creates a new WSConnection object, used by Thrift clients to connect + * to Thrift HTTP based servers. + * @param {string} host - The host name or IP to connect to. + * @param {number} port - The TCP port to connect to. + * @param {WSConnectOptions} options - The configuration options to use. + * @returns {WSConnection} The connection object. + * @see {@link WSConnectOptions} + */ +exports.createWSConnection = function(host, port, options) { + return new WSConnection(host, port, options); +}; + +exports.createWSClient = createClient; diff --git a/lib/nodejs/lib/thrift/ws_transport.js b/lib/nodejs/lib/thrift/ws_transport.js new file mode 100644 index 0000000..3513b84 --- /dev/null +++ b/lib/nodejs/lib/thrift/ws_transport.js @@ -0,0 +1,206 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var log = require('./log'); + +module.exports = TWebSocketTransport; + +/** + * Constructor Function for the WebSocket transport. + * @constructor + * @param {string} [url] - The URL to connect to. + * @classdesc The Apache Thrift Transport layer performs byte level I/O + * between RPC clients and servers. The JavaScript TWebSocketTransport object + * uses the WebSocket protocol. Target servers must implement WebSocket. + * (see: node.js example server_http.js). + * @example + * var transport = new Thrift.TWebSocketTransport("http://localhost:8585"); + */ +function TWebSocketTransport(url) { + this.__reset(url); +}; + + +TWebSocketTransport.prototype.__reset = function(url) { + this.url = url; //Where to connect + this.socket = null; //The web socket + this.callbacks = []; //Pending callbacks + this.send_pending = []; //Buffers/Callback pairs waiting to be sent + this.send_buf = ''; //Outbound data, immutable until sent + this.recv_buf = ''; //Inbound data + this.rb_wpos = 0; //Network write position in receive buffer + this.rb_rpos = 0; //Client read position in receive buffer +}; + +/** + * Sends the current WS request and registers callback. The async + * parameter is ignored (WS flush is always async) and the callback + * function parameter is required. + * @param {object} async - Ignored. + * @param {object} callback - The client completion callback. + * @returns {undefined|string} Nothing (undefined) + */ +TWebSocketTransport.prototype.flush = function(async, callback) { + var self = this; + if (this.isOpen()) { + //Send data and register a callback to invoke the client callback + this.socket.send(this.send_buf); + this.callbacks.push((function() { + var clientCallback = callback; + return function(msg) { + self.setRecvBuffer(msg); + clientCallback(); + }; + }())); + } else { + //Queue the send to go out __onOpen + this.send_pending.push({ + buf: this.send_buf, + cb: callback + }); + } +}; + +TWebSocketTransport.prototype.__onOpen = function() { + var self = this; + if (this.send_pending.length > 0) { + //If the user made calls before the connection was fully + //open, send them now + this.send_pending.forEach(function(elem) { + this.socket.send(elem.buf); + this.callbacks.push((function() { + var clientCallback = elem.cb; + return function(msg) { + self.setRecvBuffer(msg); + clientCallback(); + }; + }())); + }); + this.send_pending = []; + } +}; + +TWebSocketTransport.prototype.__onClose = function(evt) { + this.__reset(this.url); +}; + +TWebSocketTransport.prototype.__onMessage = function(evt) { + if (this.callbacks.length) { + this.callbacks.shift()(evt.data); + } +}; + +TWebSocketTransport.prototype.__onError = function(evt) { + log.error('websocket: ' + evt.toString()); + this.socket.close(); +}; + +/** + * Sets the buffer to use when receiving server responses. + * @param {string} buf - The buffer to receive server responses. + */ +TWebSocketTransport.prototype.setRecvBuffer = function(buf) { + this.recv_buf = buf; + this.recv_buf_sz = this.recv_buf.length; + this.wpos = this.recv_buf.length; + this.rpos = 0; +}; + +/** + * Returns true if the transport is open + * @readonly + * @returns {boolean} + */ +TWebSocketTransport.prototype.isOpen = function() { + return this.socket && this.socket.readyState == this.socket.OPEN; +}; + +/** + * Opens the transport connection + */ +TWebSocketTransport.prototype.open = function() { + //If OPEN/CONNECTING/CLOSING ignore additional opens + if (this.socket && this.socket.readyState != this.socket.CLOSED) { + return; + } + //If there is no socket or the socket is closed: + this.socket = new WebSocket(this.url); + this.socket.onopen = this.__onOpen.bind(this); + this.socket.onmessage = this.__onMessage.bind(this); + this.socket.onerror = this.__onError.bind(this); + this.socket.onclose = this.__onClose.bind(this); +}; + +/** + * Closes the transport connection + */ +TWebSocketTransport.prototype.close = function() { + this.socket.close(); +}; + +/** + * Returns the specified number of characters from the response + * buffer. + * @param {number} len - The number of characters to return. + * @returns {string} Characters sent by the server. + */ +TWebSocketTransport.prototype.read = function(len) { + var avail = this.wpos - this.rpos; + + if (avail === 0) { + return ''; + } + + var give = len; + + if (avail < len) { + give = avail; + } + + var ret = this.read_buf.substr(this.rpos, give); + this.rpos += give; + + //clear buf when complete? + return ret; +}; + +/** + * Returns the entire response buffer. + * @returns {string} Characters sent by the server. + */ +TWebSocketTransport.prototype.readAll = function() { + return this.recv_buf; +}; + +/** + * Sets the send buffer to buf. + * @param {string} buf - The buffer to send. + */ +TWebSocketTransport.prototype.write = function(buf) { + this.send_buf = buf; +}; + +/** + * Returns the send buffer. + * @readonly + * @returns {string} The send buffer. + */ +TWebSocketTransport.prototype.getSendBuffer = function() { + return this.send_buf; +}; diff --git a/lib/nodejs/lib/thrift/xhr_connection.js b/lib/nodejs/lib/thrift/xhr_connection.js new file mode 100644 index 0000000..6459c90 --- /dev/null +++ b/lib/nodejs/lib/thrift/xhr_connection.js @@ -0,0 +1,280 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var util = require('util'); +var EventEmitter = require("events").EventEmitter; +var thrift = require('./thrift'); + +var TBufferedTransport = require('./buffered_transport'); +var TJSONProtocol = require('./json_protocol'); +var InputBufferUnderrunError = require('./input_buffer_underrun_error'); + +var createClient = require('./create_client'); + +exports.XHRConnection = XHRConnection; + +/** + * Constructor Function for the XHR Connection. + * If you do not specify a host and port then XHRConnection will default to the + * host and port of the page from which this javascript is served. + * @constructor + * @param {string} [url] - The URL to connect to. + * @classdesc TXHRConnection objects provide Thrift end point transport + * semantics implemented using XHR. + * @example + * var transport = new Thrift.TXHRConnection('localhost', 9099, {}); + */ +function XHRConnection(host, port, options) { + this.options = options || {}; + this.wpos = 0; + this.rpos = 0; + this.useCORS = (options && options.useCORS); + this.send_buf = ''; + this.recv_buf = ''; + this.transport = options.transport || TBufferedTransport; + this.protocol = options.protocol || TJSONProtocol; + this.headers = options.headers || {}; + + host = host || window.location.host; + port = port || window.location.port; + var prefix = options.https ? 'https://' : 'http://'; + var path = options.path || '/'; + + if (port === '') { + port = undefined; + } + + if (!port || port === 80 || port === '80') { + this.url = prefix + host + path; + } else { + this.url = prefix + host + ':' + port + path; + } + + //The sequence map is used to map seqIDs back to the + // calling client in multiplexed scenarios + this.seqId2Service = {}; +}; + +util.inherits(XHRConnection, EventEmitter); + +/** +* Gets the browser specific XmlHttpRequest Object. +* @returns {object} the browser XHR interface object +*/ +XHRConnection.prototype.getXmlHttpRequestObject = function() { + try { return new XMLHttpRequest(); } catch (e1) { } + try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { } + try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { } + + throw "Your browser doesn't support XHR."; +}; + +/** + * Sends the current XRH request if the transport was created with a URL + * and the async parameter is false. If the transport was not created with + * a URL, or the async parameter is True and no callback is provided, or + * the URL is an empty string, the current send buffer is returned. + * @param {object} async - If true the current send buffer is returned. + * @param {object} callback - Optional async completion callback + * @returns {undefined|string} Nothing or the current send buffer. + * @throws {string} If XHR fails. + */ +XHRConnection.prototype.flush = function() { + var self = this; + if (this.url === undefined || this.url === '') { + return this.send_buf; + } + + var xreq = this.getXmlHttpRequestObject(); + + if (xreq.overrideMimeType) { + xreq.overrideMimeType('application/json'); + } + + xreq.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + self.setRecvBuffer(this.responseText); + } + }; + + xreq.open('POST', this.url, true); + + Object.keys(this.headers).forEach(function(headerKey) { + xreq.setRequestHeader(headerKey, self.headers[headerKey]); + }); + + xreq.send(this.send_buf); +}; + +/** + * Sets the buffer to provide the protocol when deserializing. + * @param {string} buf - The buffer to supply the protocol. + */ +XHRConnection.prototype.setRecvBuffer = function(buf) { + this.recv_buf = buf; + this.recv_buf_sz = this.recv_buf.length; + this.wpos = this.recv_buf.length; + this.rpos = 0; + + if (Object.prototype.toString.call(buf) == "[object ArrayBuffer]") { + var data = new Uint8Array(buf); + } + var thing = new Buffer(data || buf); + + this.transport.receiver(this.__decodeCallback.bind(this))(thing); + +}; + +XHRConnection.prototype.__decodeCallback = function(transport_with_data) { + var proto = new this.protocol(transport_with_data); + try { + while (true) { + var header = proto.readMessageBegin(); + var dummy_seqid = header.rseqid * -1; + var client = this.client; + //The Multiplexed Protocol stores a hash of seqid to service names + // in seqId2Service. If the SeqId is found in the hash we need to + // lookup the appropriate client for this call. + // The client var is a single client object when not multiplexing, + // when using multiplexing it is a service name keyed hash of client + // objects. + //NOTE: The 2 way interdependencies between protocols, transports, + // connections and clients in the Node.js implementation are irregular + // and make the implementation difficult to extend and maintain. We + // should bring this stuff inline with typical thrift I/O stack + // operation soon. + // --ra + var service_name = this.seqId2Service[header.rseqid]; + if (service_name) { + client = this.client[service_name]; + delete this.seqId2Service[header.rseqid]; + } + /*jshint -W083 */ + client._reqs[dummy_seqid] = function(err, success) { + transport_with_data.commitPosition(); + var clientCallback = client._reqs[header.rseqid]; + delete client._reqs[header.rseqid]; + if (clientCallback) { + clientCallback(err, success); + } + }; + /*jshint +W083 */ + if (client['recv_' + header.fname]) { + client['recv_' + header.fname](proto, header.mtype, dummy_seqid); + } else { + delete client._reqs[dummy_seqid]; + this.emit("error", + new thrift.TApplicationException( + thrift.TApplicationExceptionType.WRONG_METHOD_NAME, + "Received a response to an unknown RPC function")); + } + } + } catch (e) { + if (e instanceof InputBufferUnderrunError) { + transport_with_data.rollbackPosition(); + } else { + throw e; + } + } +}; + +/** + * Returns true if the transport is open, XHR always returns true. + * @readonly + * @returns {boolean} Always True. + */ +XHRConnection.prototype.isOpen = function() { + return true; +}; + +/** + * Opens the transport connection, with XHR this is a nop. + */ +XHRConnection.prototype.open = function() {}; + +/** + * Closes the transport connection, with XHR this is a nop. + */ +XHRConnection.prototype.close = function() {}; + +/** + * Returns the specified number of characters from the response + * buffer. + * @param {number} len - The number of characters to return. + * @returns {string} Characters sent by the server. + */ +XHRConnection.prototype.read = function(len) { + var avail = this.wpos - this.rpos; + + if (avail === 0) { + return ''; + } + + var give = len; + + if (avail < len) { + give = avail; + } + + var ret = this.read_buf.substr(this.rpos, give); + this.rpos += give; + + //clear buf when complete? + return ret; +}; + +/** + * Returns the entire response buffer. + * @returns {string} Characters sent by the server. + */ +XHRConnection.prototype.readAll = function() { + return this.recv_buf; +}; + +/** + * Sets the send buffer to buf. + * @param {string} buf - The buffer to send. + */ +XHRConnection.prototype.write = function(buf) { + this.send_buf = buf; + this.flush(); +}; + +/** + * Returns the send buffer. + * @readonly + * @returns {string} The send buffer. + */ +XHRConnection.prototype.getSendBuffer = function() { + return this.send_buf; +}; + +/** + * Creates a new TXHRTransport object, used by Thrift clients to connect + * to Thrift HTTP based servers. + * @param {string} host - The host name or IP to connect to. + * @param {number} port - The TCP port to connect to. + * @param {XHRConnectOptions} options - The configuration options to use. + * @returns {XHRConnection} The connection object. + * @see {@link XHRConnectOptions} + */ +exports.createXHRConnection = function(host, port, options) { + return new XHRConnection(host, port, options); +}; + +exports.createXHRClient = createClient; diff --git a/lib/nodejs/test/binary.test.js b/lib/nodejs/test/binary.test.js new file mode 100644 index 0000000..38ba634 --- /dev/null +++ b/lib/nodejs/test/binary.test.js @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var test = require('tape'); +var binary = require('thrift/binary'); + +var cases = { + "Should read signed byte": function(assert){ + assert.equal(1, binary.readByte(0x01)); + assert.equal(-1, binary.readByte(0xFF)); + + assert.equal(127, binary.readByte(0x7F)); + assert.equal(-128, binary.readByte(0x80)); + assert.end(); + }, + "Should write byte": function(assert){ + //Protocol simply writes to the buffer. Nothing to test.. yet. + assert.ok(true); + assert.end(); + }, + "Should read I16": function(assert) { + assert.equal(0, binary.readI16([0x00, 0x00])); + assert.equal(1, binary.readI16([0x00, 0x01])); + assert.equal(-1, binary.readI16([0xff, 0xff])); + + // Min I16 + assert.equal(-32768, binary.readI16([0x80, 0x00])); + // Max I16 + assert.equal(32767, binary.readI16([0x7f, 0xff])); + assert.end(); + }, + + "Should write I16": function(assert) { + assert.deepEqual([0x00, 0x00], binary.writeI16([], 0)); + assert.deepEqual([0x00, 0x01], binary.writeI16([], 1)); + assert.deepEqual([0xff, 0xff], binary.writeI16([], -1)); + + // Min I16 + assert.deepEqual([0x80, 0x00], binary.writeI16([], -32768)); + // Max I16 + assert.deepEqual([0x7f, 0xff], binary.writeI16([], 32767)); + assert.end(); + }, + + "Should read I32": function(assert) { + assert.equal(0, binary.readI32([0x00, 0x00, 0x00, 0x00])); + assert.equal(1, binary.readI32([0x00, 0x00, 0x00, 0x01])); + assert.equal(-1, binary.readI32([0xff, 0xff, 0xff, 0xff])); + + // Min I32 + assert.equal(-2147483648, binary.readI32([0x80, 0x00, 0x00, 0x00])); + // Max I32 + assert.equal(2147483647, binary.readI32([0x7f, 0xff, 0xff, 0xff])); + assert.end(); + }, + + "Should write I32": function(assert) { + assert.deepEqual([0x00, 0x00, 0x00, 0x00], binary.writeI32([], 0)); + assert.deepEqual([0x00, 0x00, 0x00, 0x01], binary.writeI32([], 1)); + assert.deepEqual([0xff, 0xff, 0xff, 0xff], binary.writeI32([], -1)); + + // Min I32 + assert.deepEqual([0x80, 0x00, 0x00, 0x00], binary.writeI32([], -2147483648)); + // Max I32 + assert.deepEqual([0x7f, 0xff, 0xff, 0xff], binary.writeI32([], 2147483647)); + assert.end(); + }, + + "Should read doubles": function(assert) { + assert.equal(0, binary.readDouble([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + assert.equal(0, binary.readDouble([0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + assert.equal(1, binary.readDouble([0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + assert.equal(2, binary.readDouble([0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + assert.equal(-2, binary.readDouble([0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + + assert.equal(Math.PI, binary.readDouble([0x40, 0x9, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18])) + + assert.equal(Infinity, binary.readDouble([0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + assert.equal(-Infinity, binary.readDouble([0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + + assert.ok(isNaN(binary.readDouble([0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))) + + assert.equal(1/3, binary.readDouble([0x3f, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55])) + + // Min subnormal positive double + assert.equal(4.9406564584124654e-324, binary.readDouble([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01])) + // Min normal positive double + assert.equal(2.2250738585072014e-308, binary.readDouble([0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + // Max positive double + assert.equal(1.7976931348623157e308, binary.readDouble([0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])) + assert.end(); + }, + + "Should write doubles": function(assert) { + assert.deepEqual([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], 0)); + assert.deepEqual([0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], 1)); + assert.deepEqual([0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], 2)); + assert.deepEqual([0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], -2)); + + assert.deepEqual([0x40, 0x9, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18], binary.writeDouble([], Math.PI)); + + assert.deepEqual([0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], Infinity)); + assert.deepEqual([0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], -Infinity)); + + assert.deepEqual([0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], NaN)); + + assert.deepEqual([0x3f, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55], binary.writeDouble([], 1/3)); + + // Min subnormal positive double + assert.deepEqual([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01], binary.writeDouble([], 4.9406564584124654e-324)); + // Min normal positive double + assert.deepEqual([0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], 2.2250738585072014e-308)); + // Max positive double + assert.deepEqual([0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], binary.writeDouble([], 1.7976931348623157e308)); + assert.end(); + } +}; + +Object.keys(cases).forEach(function(caseName) { + test(caseName, cases[caseName]); +}); diff --git a/lib/nodejs/test/browser_client.js b/lib/nodejs/test/browser_client.js new file mode 100644 index 0000000..72fd837 --- /dev/null +++ b/lib/nodejs/test/browser_client.js @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var assert = require('assert'); +var thrift = require('thrift'); +var helpers = require('./helpers'); +var ThriftTest = require('./gen-nodejs/ThriftTest'); +var ThriftTestDriver = require('./test_driver').ThriftTestDriver; + +// createXHRConnection createWSConnection +var connection = thrift.createXHRConnection("localhost", 9090, { + transport: helpers.transports['buffered'], + protocol: helpers.protocols['json'], + path: '/test' +}); + +connection.on('error', function(err) { + assert(false, err); +}); + +// Uncomment the following line to start a websockets connection +// connection.open(); + +// createWSClient createXHRClient +var client = thrift.createXHRClient(ThriftTest, connection); + +ThriftTestDriver(client, function (status) { + console.log('Browser:', status); +}); diff --git a/lib/nodejs/test/certificates.README b/lib/nodejs/test/certificates.README new file mode 100644 index 0000000..06c507e --- /dev/null +++ b/lib/nodejs/test/certificates.README @@ -0,0 +1,7 @@ +server.crt AND server.key ARE PROVIDED FOR TEST PURPOSE AND SHOULD *NEVER* BE USED IN PRODUCTION + + +Origin of the test key and cert is the folder test/keys of Apache Thrift source code distribution + +We need copies for npm deployment + diff --git a/lib/nodejs/test/client.js b/lib/nodejs/test/client.js new file mode 100644 index 0000000..006fad2 --- /dev/null +++ b/lib/nodejs/test/client.js @@ -0,0 +1,136 @@ +#!/usr/bin/env node + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var fs = require('fs'); +var assert = require('assert'); +var thrift = require('thrift'); +var helpers = require('./helpers'); +var ThriftTest = require('./gen-nodejs/ThriftTest'); +var ThriftTestDriver = require('./test_driver').ThriftTestDriver; +var ThriftTestDriverPromise = require('./test_driver').ThriftTestDriverPromise; +var SecondService = require('./gen-nodejs/SecondService'); +var ttypes = require('./gen-nodejs/ThriftTest_types'); + +var program = require('commander'); + +program + .option('-p, --protocol ', 'Set thrift protocol (binary|compact|json) [protocol]') + .option('-t, --transport ', 'Set thrift transport (buffered|framed|http) [transport]') + .option('--port ', 'Set thrift server port number to connect', 9090) + .option('--host ', 'Set thrift server host to connect', 'localhost') + .option('--ssl', 'use SSL transport') + .option('--promise', 'test with promise style functions') + .option('-t, --type ', 'Select server type (http|multiplex|tcp|websocket)', 'tcp') + .parse(process.argv); + +var host = program.host; +var port = program.port; +var type = program.type; +var ssl = program.ssl; +var promise = program.promise; + +/* for compatibility with cross test invocation for http transport testing */ +if (program.transport === 'http') { + program.transport = 'buffered'; + type = 'http'; +} + +var options = { + transport: helpers.transports[program.transport], + protocol: helpers.protocols[program.protocol] +}; + +if (type === 'http' || type === 'websocket') { + options.path = '/test'; +} + +if (type === 'http') { + options.headers = {"Connection": "close"}; +} + +if (ssl) { + if (type === 'tcp' || type === 'multiplex') { + options.rejectUnauthorized = false; + } else if (type === 'http') { + options.nodeOptions = { rejectUnauthorized: false }; + options.https = true; + } else if (type === 'websocket') { + options.wsOptions = { rejectUnauthorized: false }; + options.secure = true; + } +} + +var connection; +var client; +var testDriver = promise ? ThriftTestDriverPromise : ThriftTestDriver; + +if (type === 'tcp' || type === 'multiplex') { + connection = ssl ? + thrift.createSSLConnection(host, port, options) : + thrift.createConnection(host, port, options); +} else if (type === 'http') { + connection = thrift.createHttpConnection(host, port, options); +} else if (type === 'websocket') { + connection = thrift.createWSConnection(host, port, options); + connection.open(); +} + +connection.on('error', function(err) { + assert(false, err); +}); + +if (type === 'tcp') { + client = thrift.createClient(ThriftTest, connection); + runTests(); +} else if (type === 'multiplex') { + var mp = new thrift.Multiplexer(); + client = mp.createClient("ThriftTest", ThriftTest, connection); + secondclient = mp.createClient("SecondService", SecondService, connection); + + connection.on('connect', function() { + secondclient.secondtestString("Test", function(err, response) { + assert(!err); + assert.equal("testString(\"Test\")", response); + }); + + runTests(); + }); +} else if (type === 'http') { + client = thrift.createHttpClient(ThriftTest, connection); + runTests(); +} else if (type === 'websocket') { + client = thrift.createWSClient(ThriftTest, connection); + runTests(); +} + +function runTests() { + testDriver(client, function (status) { + console.log(status); + if (type !== 'http' && type !== 'websocket') { + connection.end(); + } + if (type !== 'multiplex') { + process.exit(0); + } + }); +} + +exports.expressoTest = function() {}; diff --git a/lib/nodejs/test/deep-constructor.test.js b/lib/nodejs/test/deep-constructor.test.js new file mode 100644 index 0000000..145b668 --- /dev/null +++ b/lib/nodejs/test/deep-constructor.test.js @@ -0,0 +1,333 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var ttypes = require('./gen-nodejs/JsDeepConstructorTest_types'); +var thrift = require('thrift'); +var test = require('tape'); +var bufferEquals = require('buffer-equals'); + +function serializeBinary(data) { + var buff; + var transport = new thrift.TBufferedTransport(null, function(msg){ + buff = msg; + }); + var prot = new thrift.TBinaryProtocol(transport); + data.write(prot); + prot.flush(); + return buff; + +} + + +function deserializeBinary(serialized, type) { + var t = new thrift.TFramedTransport(serialized); + var p = new thrift.TBinaryProtocol(t); + var data = new type(); + data.read(p); + return data; +} + + +function serializeJSON(data) { + var buff; + var transport = new thrift.TBufferedTransport(null, function(msg){ + buff = msg; + }); + var protocol = new thrift.TJSONProtocol(transport); + protocol.writeMessageBegin("", 0, 0); + data.write(protocol); + protocol.writeMessageEnd(); + protocol.flush(); + return buff; +} + + +function deserializeJSON(serialized, type) { + var transport = new thrift.TFramedTransport(serialized); + var protocol = new thrift.TJSONProtocol(transport); + protocol.readMessageBegin(); + var data = new type(); + data.read(protocol); + protocol.readMessageEnd(); + return data; +} + + +function createThriftObj() { + + return new ttypes.Complex({ + + struct_field: new ttypes.Simple({value: 'a'}), + + struct_list_field: [ + new ttypes.Simple({value: 'b'}), + new ttypes.Simple({value: 'c'}), + ], + + struct_set_field: [ + new ttypes.Simple({value: 'd'}), + new ttypes.Simple({value: 'e'}), + ], + + struct_map_field: { + A: new ttypes.Simple({value: 'f'}), + B: new ttypes.Simple({value: 'g'}) + }, + + struct_nested_containers_field: [ + [ + { + C: [ + new ttypes.Simple({value: 'h'}), + new ttypes.Simple({value: 'i'}) + ] + } + ] + ], + + struct_nested_containers_field2: { + D: [ + { + DA: new ttypes.Simple({value: 'j'}) + }, + { + DB: new ttypes.Simple({value: 'k'}) + } + ] + }, + + list_of_list_field: [ + ['l00', 'l01', 'l02'], + ['l10', 'l11', 'l12'], + ['l20', 'l21', 'l22'], + ], + + list_of_list_of_list_field: [ + [['m000', 'm001', 'm002'], ['m010', 'm011', 'm012'], ['m020', 'm021', 'm022']], + [['m100', 'm101', 'm102'], ['m110', 'm111', 'm112'], ['m120', 'm121', 'm122']], + [['m200', 'm201', 'm202'], ['m210', 'm211', 'm212'], ['m220', 'm221', 'm222']], + ], + + + }); +} + + +function createJsObj() { + + return { + + struct_field: {value: 'a'}, + + struct_list_field: [ + {value: 'b'}, + {value: 'c'}, + ], + + struct_set_field: [ + {value: 'd'}, + {value: 'e'}, + ], + + struct_map_field: { + A: {value: 'f'}, + B: {value: 'g'} + }, + + struct_nested_containers_field: [ + [ + { + C: [ + {value: 'h'}, + {value: 'i'} + ] + } + ] + ], + + struct_nested_containers_field2: { + D: [ + { + DA: {value: 'j'} + }, + { + DB: {value: 'k'} + } + ] + }, + + list_of_list_field: [ + ['l00', 'l01', 'l02'], + ['l10', 'l11', 'l12'], + ['l20', 'l21', 'l22'], + ], + + list_of_list_of_list_field: [ + [['m000', 'm001', 'm002'], ['m010', 'm011', 'm012'], ['m020', 'm021', 'm022']], + [['m100', 'm101', 'm102'], ['m110', 'm111', 'm112'], ['m120', 'm121', 'm122']], + [['m200', 'm201', 'm202'], ['m210', 'm211', 'm212'], ['m220', 'm221', 'm222']], + ], + + }; +} + + +function assertValues(obj, assert) { + assert.equals(obj.struct_field.value, 'a'); + assert.equals(obj.struct_list_field[0].value, 'b'); + assert.equals(obj.struct_list_field[1].value, 'c'); + assert.equals(obj.struct_set_field[0].value, 'd'); + assert.equals(obj.struct_set_field[1].value, 'e'); + assert.equals(obj.struct_map_field.A.value, 'f'); + assert.equals(obj.struct_map_field.B.value, 'g'); + assert.equals(obj.struct_nested_containers_field[0][0].C[0].value, 'h'); + assert.equals(obj.struct_nested_containers_field[0][0].C[1].value, 'i'); + assert.equals(obj.struct_nested_containers_field2.D[0].DA.value, 'j'); + assert.equals(obj.struct_nested_containers_field2.D[1].DB.value, 'k'); + assert.equals(obj.list_of_list_field[0][0], 'l00'); + assert.equals(obj.list_of_list_field[0][1], 'l01'); + assert.equals(obj.list_of_list_field[0][2], 'l02'); + assert.equals(obj.list_of_list_field[1][0], 'l10'); + assert.equals(obj.list_of_list_field[1][1], 'l11'); + assert.equals(obj.list_of_list_field[1][2], 'l12'); + assert.equals(obj.list_of_list_field[2][0], 'l20'); + assert.equals(obj.list_of_list_field[2][1], 'l21'); + assert.equals(obj.list_of_list_field[2][2], 'l22'); + + assert.equals(obj.list_of_list_of_list_field[0][0][0], 'm000'); + assert.equals(obj.list_of_list_of_list_field[0][0][1], 'm001'); + assert.equals(obj.list_of_list_of_list_field[0][0][2], 'm002'); + assert.equals(obj.list_of_list_of_list_field[0][1][0], 'm010'); + assert.equals(obj.list_of_list_of_list_field[0][1][1], 'm011'); + assert.equals(obj.list_of_list_of_list_field[0][1][2], 'm012'); + assert.equals(obj.list_of_list_of_list_field[0][2][0], 'm020'); + assert.equals(obj.list_of_list_of_list_field[0][2][1], 'm021'); + assert.equals(obj.list_of_list_of_list_field[0][2][2], 'm022'); + + assert.equals(obj.list_of_list_of_list_field[1][0][0], 'm100'); + assert.equals(obj.list_of_list_of_list_field[1][0][1], 'm101'); + assert.equals(obj.list_of_list_of_list_field[1][0][2], 'm102'); + assert.equals(obj.list_of_list_of_list_field[1][1][0], 'm110'); + assert.equals(obj.list_of_list_of_list_field[1][1][1], 'm111'); + assert.equals(obj.list_of_list_of_list_field[1][1][2], 'm112'); + assert.equals(obj.list_of_list_of_list_field[1][2][0], 'm120'); + assert.equals(obj.list_of_list_of_list_field[1][2][1], 'm121'); + assert.equals(obj.list_of_list_of_list_field[1][2][2], 'm122'); + + assert.equals(obj.list_of_list_of_list_field[2][0][0], 'm200'); + assert.equals(obj.list_of_list_of_list_field[2][0][1], 'm201'); + assert.equals(obj.list_of_list_of_list_field[2][0][2], 'm202'); + assert.equals(obj.list_of_list_of_list_field[2][1][0], 'm210'); + assert.equals(obj.list_of_list_of_list_field[2][1][1], 'm211'); + assert.equals(obj.list_of_list_of_list_field[2][1][2], 'm212'); + assert.equals(obj.list_of_list_of_list_field[2][2][0], 'm220'); + assert.equals(obj.list_of_list_of_list_field[2][2][1], 'm221'); + assert.equals(obj.list_of_list_of_list_field[2][2][2], 'm222'); +} + +function createTestCases(serialize, deserialize) { + + var cases = { + + "Serialize/deserialize should return equal object": function(assert){ + var tObj = createThriftObj(); + var received = deserialize(serialize(tObj), ttypes.Complex); + assert.ok(tObj !== received, 'not the same object'); + assert.deepEqual(tObj, received); + assert.end(); + }, + + "Nested structs and containers initialized from plain js objects should serialize same as if initialized from thrift objects": function(assert) { + var tObj1 = createThriftObj(); + var tObj2 = new ttypes.Complex(createJsObj()); + assertValues(tObj2, assert); + var s1 = serialize(tObj1); + var s2 = serialize(tObj2); + assert.ok(bufferEquals(s1, s2)); + assert.end(); + }, + + "Modifications to args object should not affect constructed Thrift object": function (assert) { + + var args = createJsObj(); + assertValues(args, assert); + + var tObj = new ttypes.Complex(args); + assertValues(tObj, assert); + + args.struct_field.value = 'ZZZ'; + args.struct_list_field[0].value = 'ZZZ'; + args.struct_list_field[1].value = 'ZZZ'; + args.struct_set_field[0].value = 'ZZZ'; + args.struct_set_field[1].value = 'ZZZ'; + args.struct_map_field.A.value = 'ZZZ'; + args.struct_map_field.B.value = 'ZZZ'; + args.struct_nested_containers_field[0][0].C[0] = 'ZZZ'; + args.struct_nested_containers_field[0][0].C[1] = 'ZZZ'; + args.struct_nested_containers_field2.D[0].DA = 'ZZZ'; + args.struct_nested_containers_field2.D[0].DB = 'ZZZ'; + + assertValues(tObj, assert); + assert.end(); + }, + + "nulls are ok": function(assert) { + var tObj = new ttypes.Complex({ + struct_field: null, + struct_list_field: null, + struct_set_field: null, + struct_map_field: null, + struct_nested_containers_field: null, + struct_nested_containers_field2: null + }); + var received = deserialize(serialize(tObj), ttypes.Complex); + assert.strictEqual(tObj.struct_field, null); + assert.ok(tObj !== received); + assert.deepEqual(tObj, received); + assert.end(); + }, + + "Can make list with objects": function(assert) { + var tObj = new ttypes.ComplexList({ + "struct_list_field": [new ttypes.Complex({})] + }); + var innerObj = tObj.struct_list_field[0]; + assert.ok(innerObj instanceof ttypes.Complex) + assert.strictEqual(innerObj.struct_field, null); + assert.strictEqual(innerObj.struct_list_field, null); + assert.strictEqual(innerObj.struct_set_field, null); + assert.strictEqual(innerObj.struct_map_field, null); + assert.strictEqual(innerObj.struct_nested_containers_field, null); + assert.strictEqual(innerObj.struct_nested_containers_field2, null); + assert.end(); + } + + }; + return cases; +} + + +function run(name, cases){ + Object.keys(cases).forEach(function(caseName) { + test(name + ': ' + caseName, cases[caseName]); + }); +} + +run('binary', createTestCases(serializeBinary, deserializeBinary)); +run('json', createTestCases(serializeJSON, deserializeJSON)); diff --git a/lib/nodejs/test/exceptions.js b/lib/nodejs/test/exceptions.js new file mode 100644 index 0000000..0a75770 --- /dev/null +++ b/lib/nodejs/test/exceptions.js @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +'use strict'; +var test = require('tape'); +var thrift = require('../lib/thrift/thrift.js'); +var InputBufferUnderrunError = require('../lib/thrift/input_buffer_underrun_error'); + +test('TApplicationException', function t(assert) { + var e = new thrift.TApplicationException(1, 'foo'); + assert.ok(e instanceof thrift.TApplicationException, 'is instanceof TApplicationException'); + assert.ok(e instanceof thrift.TException, 'is instanceof TException'); + assert.ok(e instanceof Error, 'is instanceof Error'); + assert.equal(typeof e.stack, 'string', 'has stack trace'); + assert.ok(/^TApplicationException: foo/.test(e.stack), 'Stack trace has correct error name and message'); + assert.ok(e.stack.indexOf('test/exceptions.js:7:11') !== -1, 'stack trace starts on correct line and column'); + assert.equal(e.name, 'TApplicationException', 'has function name TApplicationException'); + assert.equal(e.message, 'foo', 'has error message "foo"'); + assert.equal(e.type, 1, 'has type 1'); + assert.end(); +}); + +test('TException', function t(assert) { + var e = new thrift.TException('foo'); + assert.ok(e instanceof thrift.TException, 'is instanceof TException'); + assert.ok(e instanceof Error, 'is instanceof Error'); + assert.equal(typeof e.stack, 'string', 'has stack trace'); + assert.ok(/^TException: foo/.test(e.stack), 'Stack trace has correct error name and message'); + assert.ok(e.stack.indexOf('test/exceptions.js:21:11') !== -1, 'stack trace starts on correct line and column'); + assert.equal(e.name, 'TException', 'has function name TException'); + assert.equal(e.message, 'foo', 'has error message "foo"'); + assert.end(); +}); + +test('TProtocolException', function t(assert) { + var e = new thrift.TProtocolException(1, 'foo'); + assert.ok(e instanceof thrift.TProtocolException, 'is instanceof TProtocolException'); + assert.ok(e instanceof Error, 'is instanceof Error'); + assert.equal(typeof e.stack, 'string', 'has stack trace'); + assert.ok(/^TProtocolException: foo/.test(e.stack), 'Stack trace has correct error name and message'); + assert.ok(e.stack.indexOf('test/exceptions.js:33:11') !== -1, 'stack trace starts on correct line and column'); + assert.equal(e.name, 'TProtocolException', 'has function name TProtocolException'); + assert.equal(e.message, 'foo', 'has error message "foo"'); + assert.equal(e.type, 1, 'has type 1'); + assert.end(); +}); + +test('InputBufferUnderrunError', function t(assert) { + var e = new InputBufferUnderrunError('foo'); + assert.ok(e instanceof InputBufferUnderrunError, 'is instanceof InputBufferUnderrunError'); + assert.ok(e instanceof Error, 'is instanceof Error'); + assert.equal(typeof e.stack, 'string', 'has stack trace'); + assert.ok(/^InputBufferUnderrunError: foo/.test(e.stack), 'Stack trace has correct error name and message'); + assert.ok(e.stack.indexOf('test/exceptions.js:46:11') !== -1, 'stack trace starts on correct line and column'); + assert.equal(e.name, 'InputBufferUnderrunError', 'has function name InputBufferUnderrunError'); + assert.equal(e.message, 'foo', 'has error message "foo"'); + assert.end(); +}); diff --git a/lib/nodejs/test/helpers.js b/lib/nodejs/test/helpers.js new file mode 100644 index 0000000..5f828b3 --- /dev/null +++ b/lib/nodejs/test/helpers.js @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +'use strict'; +var thrift = require('../lib/thrift'); + +module.exports.transports = { + 'buffered': thrift.TBufferedTransport, + 'framed': thrift.TFramedTransport +}; + +module.exports.protocols = { + 'json': thrift.TJSONProtocol, + 'binary': thrift.TBinaryProtocol, + 'compact': thrift.TCompactProtocol +}; diff --git a/lib/nodejs/test/server.crt b/lib/nodejs/test/server.crt new file mode 100644 index 0000000..8a5ef3c --- /dev/null +++ b/lib/nodejs/test/server.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD +VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs +MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV +BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3 +DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy +MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU +MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh +cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ +bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ +GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6 +L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg +2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw +AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX +wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n +AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME +GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 +DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5 +U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm +T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD +1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I +p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO +r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0 +-----END CERTIFICATE----- diff --git a/lib/nodejs/test/server.js b/lib/nodejs/test/server.js new file mode 100644 index 0000000..8f2e06b --- /dev/null +++ b/lib/nodejs/test/server.js @@ -0,0 +1,106 @@ +#!/usr/bin/env node + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * 'License'); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var fs = require('fs'); +var path = require('path'); +var thrift = require('../lib/thrift'); +var program = require('commander'); +var helpers = require('./helpers'); + +var ThriftTest = require('./gen-nodejs/ThriftTest'); +var SecondService = require('./gen-nodejs/SecondService'); +var ThriftTestHandler = require('./test_handler').AsyncThriftTestHandler; +var ThriftTestHandlerPromise = require('./test_handler').SyncThriftTestHandler; +var ttypes = require('./gen-nodejs/ThriftTest_types'); + +program + .option('-p, --protocol ', 'Set thrift protocol (binary|compact|json)', 'binary') + .option('-t, --transport ', 'Set thrift transport (buffered|framed|http)', 'buffered') + .option('--ssl', 'use ssl transport') + .option('--port ', 'Set thrift server port', 9090) + .option('--promise', 'test with promise style functions') + .option('-t, --type ', 'Select server type (http|multiplex|tcp|websocket)', 'tcp') + .parse(process.argv); + +var port = program.port; +var type = program.type; +var ssl = program.ssl; +var promise = program.promise; + +var handler = program.promise ? ThriftTestHandler : ThriftTestHandlerPromise; + +if (program.transport === 'http') { + program.transport = 'buffered'; + type = 'http'; +} + +var options = { + transport: helpers.transports[program.transport], + protocol: helpers.protocols[program.protocol] +}; + +if (type === 'http' || type ==='websocket') { + options.handler = handler; + options.processor = ThriftTest; + + options = { + services: { "/test": options }, + cors: { + '*': true + } + } +} + +if (type === 'multiplex') { + var SecondServiceHandler = { + secondtestString: function(thing, result) { + console.log('testString("' + thing + '")'); + result(null, 'testString("' + thing + '")'); + } + }; + + var processor = new thrift.MultiplexedProcessor(); + + processor.registerProcessor("ThriftTest", + new ThriftTest.Processor(ThriftTestHandler)); + + processor.registerProcessor("SecondService", + new SecondService.Processor(SecondServiceHandler)); + +} + +if (ssl) { + options.tls = { + key: fs.readFileSync(path.resolve(__dirname, 'server.key')), + cert: fs.readFileSync(path.resolve(__dirname, 'server.crt')) + }; +} + +var server; +if (type === 'tcp') { + server = thrift.createServer(ThriftTest, handler, options); +} else if (type === 'multiplex') { + server = thrift.createMultiplexServer(processor, options); +} else if (type === 'http' || type === 'websocket') { + server = thrift.createWebServer(options); +} + +server.listen(port); diff --git a/lib/nodejs/test/server.key b/lib/nodejs/test/server.key new file mode 100644 index 0000000..263cfce --- /dev/null +++ b/lib/nodejs/test/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR +tLQVDSGQGV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCy +SN8I2Xw6L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/H +jKNg6ZKg2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQB +GmZmMIUwAinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xk +u62LipkXwCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDm +trhVQF4nAgMBAAECggEAW/y52YYW6ypROGbZ94DQpFV0kLO7qT8q0Ksxw5sPNaIt +fEPRIymDa8ikyHWJS5Oxmw84wo5jnJV26jaLmwe2Lupq7Xf1lqej8f5LJtuv7cQR +xfzp1vM65KJFFJHp6WqjGqJ6HSSZOpVDsnQYcXQjQCdpyAmaSWd3p+FqYSZ1mQmD +bFNI7jqpczWSZhTdotQ7p7Hn9TVCehflP3yGIB3bQ+wCcCB85dOBz201L+YgaIck +Sz43A4NvWaQIRLRDw7s9GW4jY5T0Jv282WIeAlVpVxLIwu48r4R4yGTIx9Ydowvq +57+Y5iPPjAXxu0V9t00oS3bYxDaKh2DUfc/5zowq8QKBgQDYNVPXmaG0aIH4vjQ9 +7fRdw/UDkYcQbn6CnglQOu77/S8ogQzpKCVJgJgkZNqOVtQMEPzekGEcLTbje1gU +8Bky2k+PL9UwbFy0emnOVh4rqrNXHsRvJcehNT/PRb5hjF3MUMFV/0iD4b+naFaE +jrSWiZ2ZXj2qfwAK52GFbtOuBQKBgQDJYQuGiY0r22E4waJmCSKczoBT3cwlVzWj +V2ljgA9RHLNTVkvNNYQLGu2qngFrtwpeaSnsMDerVG4wKAQWyCnYzxVrlnC4uDrJ +HXuFEltBWi9Ffbgfsnd3749AT0oBP1NT2tMleguyf5DFgjCR3VRJLdrVaaZ8row/ +LqKcFMqnOwKBgB+OIO99l7E584Y3VG6ZdSneOLtNmRXX2pT7tcZE465ZdHGH7Dd3 +SYHhx9K/+Xn+yDH+pLli/xlarAEldmSP6k2WuTfftlC78AfTOfAId5zN7CDR9791 +Fx67I9X/itq33tS8EIuZl57P6uXm/4GXRloWOa8xpvRkVsBApuYPl8t1AoGATQDS +y2sllDObBXzlgGbV2WgNIgSZ311toTv3jJiXQsjauW8yJRHln+l4H9mzaWDgkiFc +ang1kUoDqF5k0eFQPxtQcYdhKwEnWWfwp33RbzfxA32DPnubuzzbZhfrkHaKgnIW +cyor9uFYlm2l7ODZLfJez2RKyTplXnOSsmQw6akCgYAz3dj9Hskyj+HVJ+ht1OcE +c7ai/ESkSA7Vajp0tjJp0EKjW/zq8DvUSXOtcdnJgkKycFluLwbmnaN4txBds1C1 +Qr8Rt2sUCCBNZe1L6DHe3XBdbkJe9sgZVNTjtUSQrzy8UhvsCqG4YWeCu07Szcbc +rdPUV9/uQkdx8VrShxlD8A== +-----END PRIVATE KEY----- diff --git a/lib/nodejs/test/test-cases.js b/lib/nodejs/test/test-cases.js new file mode 100644 index 0000000..bd66dc4 --- /dev/null +++ b/lib/nodejs/test/test-cases.js @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +'use strict'; + +var ttypes = require('./gen-nodejs/ThriftTest_types'); +var Int64 = require('node-int64'); + +//all Languages in UTF-8 +/*jshint -W100 */ +var stringTest = module.exports.stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " + + "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " + + "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, " + + "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, " + + "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, " + + "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, " + + "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, " + + "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, " + + "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, " + + "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, " + + "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, " + + "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, " + + "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, " + + "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa " + + "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa " + + "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪" + + "Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, " + + "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, " + + "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, " + + "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple " + + "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, " + + "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, " + + "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, " + + "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, " + + "Bân-lâm-gú, 粵語"; +/*jshint +W100 */ + +var specialCharacters = module.exports.specialCharacters = 'quote: \" backslash:' + + ' forwardslash-escaped: \/ ' + + ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + + ' now-all-of-them-together: "\\\/\b\n\r\t' + + ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><' + + ' char-to-test-json-parsing: ]] \"]] \\" }}}{ [[[ '; + +var mapTestInput = module.exports.mapTestInput = { + "a":"123", "a b":"with spaces ", "same":"same", "0":"numeric key", + "longValue":stringTest, stringTest:"long key" +}; + +var simple = [ + ['testVoid', undefined], + ['testString', 'Test'], + ['testString', ''], + ['testString', stringTest], + ['testString', specialCharacters], + ['testBool', true], + ['testBool', false], + ['testByte', 1], + ['testByte', 0], + ['testByte', -1], + ['testByte', -127], + ['testI32', -1], + ['testDouble', -5.2098523], + ['testDouble', 7.012052175215044], + ['testEnum', ttypes.Numberz.ONE], + ['testI64', 5], + ['testI64', -5], + ['testI64', 734359738368], + ['testI64', -734359738368], + ['testI64', new Int64(new Buffer([0, 0x20, 0, 0, 0, 0, 0, 1]))], // 2^53+1 + ['testI64', new Int64( + new Buffer([0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]))], // -2^53-1 + ['testTypedef', 69] +] + +var mapout = {}; +for (var i = 0; i < 5; ++i) { + mapout[i] = i-10; +} + +var deep = [ + ['testList', [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]], +]; + +var deepUnordered = [ + ['testMap', mapout], + ['testSet', [1,2,3]], + ['testStringMap', mapTestInput] +]; + +var out = new ttypes.Xtruct({ + string_thing: 'Zero', + byte_thing: 1, + i32_thing: -3, + i64_thing: 1000000 +}); + +var out2 = new ttypes.Xtruct2(); +out2.byte_thing = 1; +out2.struct_thing = out; +out2.i32_thing = 5; + +var crazy = new ttypes.Insanity({ + "userMap":{ "5":5, "8":8 }, + "xtructs":[new ttypes.Xtruct({ + "string_thing":"Goodbye4", + "byte_thing":4, + "i32_thing":4, + "i64_thing":4 + }), new ttypes.Xtruct({ + "string_thing":"Hello2", + "byte_thing":2, + "i32_thing":2, + "i64_thing":2 + })] +}); + +var crazy2 = new ttypes.Insanity({ + "userMap":{ "5":5, "8":8 }, + "xtructs":[{ + "string_thing":"Goodbye4", + "byte_thing":4, + "i32_thing":4, + "i64_thing":4 + }, { + "string_thing":"Hello2", + "byte_thing":2, + "i32_thing":2, + "i64_thing":2 + }] +}); + + +var insanity = { + "1":{ "2": crazy, "3": crazy }, + "2":{ "6":{ "userMap":{}, "xtructs":[] } } +}; + +module.exports.simple = simple; +module.exports.deep = deep; +module.exports.deepUnordered = deepUnordered; + +module.exports.out = out; +module.exports.out2 = out2; +module.exports.crazy = crazy; +module.exports.crazy2 = crazy2; +module.exports.insanity = insanity; diff --git a/lib/nodejs/test/testAll.sh b/lib/nodejs/test/testAll.sh new file mode 100755 index 0000000..aae451a --- /dev/null +++ b/lib/nodejs/test/testAll.sh @@ -0,0 +1,108 @@ +#! /bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +if [ -n "${1}" ]; then + COVER=${1}; +fi + +DIR="$( cd "$( dirname "$0" )" && pwd )" + +ISTANBUL="$DIR/../../../node_modules/istanbul/lib/cli.js" +RUNBROWSER="$DIR/../../../node_modules/run-browser/bin/cli.js" + +REPORT_PREFIX="${DIR}/../coverage/report" + +COUNT=0 + +export NODE_PATH="${DIR}:${DIR}/../lib:${NODE_PATH}" + +testServer() +{ + echo " Testing $1 Client/Server with protocol $2 and transport $3 $4"; + RET=0 + if [ -n "${COVER}" ]; then + ${ISTANBUL} cover ${DIR}/server.js --dir ${REPORT_PREFIX}${COUNT} --handle-sigint -- --type $1 -p $2 -t $3 $4 & + COUNT=$((COUNT+1)) + else + node ${DIR}/server.js --type $1 -p $2 -t $3 $4 & + fi + SERVERPID=$! + sleep 0.1 + if [ -n "${COVER}" ]; then + ${ISTANBUL} cover ${DIR}/client.js --dir ${REPORT_PREFIX}${COUNT} -- --type $1 -p $2 -t $3 $4 || RET=1 + COUNT=$((COUNT+1)) + else + node ${DIR}/client.js --type $1 -p $2 -t $3 $4 || RET=1 + fi + kill -2 $SERVERPID || RET=1 + wait $SERVERPID + return $RET +} + +testBrowser() +{ + echo " Testing browser client with http server with json protocol and buffered transport"; + RET=0 + node ${DIR}/server.js --type http -p json -t buffered & + SERVERPID=$! + sleep 1 + ${RUNBROWSER} ${DIR}/browser_client.js --phantom || RET=1 + kill -2 $SERVERPID || RET=1 + return $RET +} + +TESTOK=0 + +#generating thrift code + +${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node ${DIR}/../../../test/ThriftTest.thrift +${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node ${DIR}/../../../test/JsDeepConstructorTest.thrift + +#unit tests + +node ${DIR}/binary.test.js || TESTOK=1 +node ${DIR}/deep-constructor.test.js || TESTOK=1 + +#integration tests + +for type in tcp multiplex websocket http +do + + for protocol in compact binary json + do + + for transport in buffered framed + do + testServer $type $protocol $transport || TESTOK=1 + testServer $type $protocol $transport --ssl || TESTOK=1 + testServer $type $protocol $transport --promise || TESTOK=1 + done + done +done + +# XHR only until phantomjs 2 is released. +# testBrowser + +if [ -n "${COVER}" ]; then + ${ISTANBUL} report --dir "${DIR}/../coverage" --include "${DIR}/../coverage/report*/coverage.json" lcov cobertura html + rm -r ${DIR}/../coverage/report*/* + rmdir ${DIR}/../coverage/report* +fi + +exit $TESTOK diff --git a/lib/nodejs/test/test_driver.js b/lib/nodejs/test/test_driver.js new file mode 100644 index 0000000..03ec513 --- /dev/null +++ b/lib/nodejs/test/test_driver.js @@ -0,0 +1,327 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * 'License'); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + // This is the Node.js test driver for the standard Apache Thrift + // test service. The driver invokes every function defined in the + // Thrift Test service with a representative range of parameters. + // + // The ThriftTestDriver function requires a client object + // connected to a server hosting the Thrift Test service and + // supports an optional callback function which is called with + // a status message when the test is complete. + +var test = require('tape'); +//var assert = require('assert'); +var ttypes = require('./gen-nodejs/ThriftTest_types'); +var TException = require('thrift').Thrift.TException; +var Int64 = require('node-int64'); +var testCases = require('./test-cases'); + +exports.ThriftTestDriver = function(client, callback) { + + test('NodeJS Style Callback Client Tests', function(assert) { + + var checkRecursively = makeRecursiveCheck(assert); + + function makeAsserter(assertionFn) { + return function(c) { + var fnName = c[0]; + var expected = c[1]; + client[fnName](expected, function(err, actual) { + assert.error(err, fnName + ': no callback error'); + assertionFn(actual, expected, fnName); + }) + }; + } + + testCases.simple.forEach(makeAsserter(function(a, e, m){ + if (a instanceof Int64) { + var e64 = e instanceof Int64 ? e : new Int64(e); + assert.deepEqual(a.buffer, e64.buffer, m); + } else { + assert.equal(a, e, m); + } + })); + testCases.deep.forEach(makeAsserter(assert.deepEqual)); + testCases.deepUnordered.forEach(makeAsserter(makeUnorderedDeepEqual(assert))); + + var arr = []; + for (var i = 0; i < 256; ++i) { + arr[i] = 255 - i; + } + var buf = new Buffer(arr); + client.testBinary(buf, function(err, response) { + assert.error(err, 'testBinary: no callback error'); + assert.equal(response.length, 256, 'testBinary'); + assert.deepEqual(response, buf, 'testBinary(Buffer)'); + }); + var buf = new Buffer(arr); + client.testBinary(buf.toString('binary'), function(err, response) { + assert.error(err, 'testBinary: no callback error'); + assert.equal(response.length, 256, 'testBinary'); + assert.deepEqual(response, buf, 'testBinary(string)'); + }); + + client.testMapMap(42, function(err, response) { + var expected = { + "4": {"1":1, "2":2, "3":3, "4":4}, + "-4": {"-4":-4, "-3":-3, "-2":-2, "-1":-1} + }; + assert.error(err, 'testMapMap: no callback error'); + assert.deepEqual(expected, response, 'testMapMap'); + }); + + client.testStruct(testCases.out, function(err, response) { + assert.error(err, 'testStruct: no callback error'); + checkRecursively(testCases.out, response, 'testStruct'); + }); + + client.testNest(testCases.out2, function(err, response) { + assert.error(err, 'testNest: no callback error'); + checkRecursively(testCases.out2, response, 'testNest'); + }); + + client.testInsanity(testCases.crazy, function(err, response) { + assert.error(err, 'testInsanity: no callback error'); + checkRecursively(testCases.insanity, response, 'testInsanity'); + }); + + client.testInsanity(testCases.crazy2, function(err, response) { + assert.error(err, 'testInsanity2: no callback error'); + checkRecursively(testCases.insanity, response, 'testInsanity2'); + }); + + client.testException('TException', function(err, response) { + assert.ok(err instanceof TException, 'testException: correct error type'); + assert.ok(!response, 'testException: no response'); + }); + + client.testException('Xception', function(err, response) { + assert.ok(err instanceof ttypes.Xception, 'testException: correct error type'); + assert.ok(!response, 'testException: no response'); + assert.equal(err.errorCode, 1001, 'testException: correct error code'); + assert.equal('Xception', err.message, 'testException: correct error message'); + }); + + client.testException('no Exception', function(err, response) { + assert.error(err, 'testException: no callback error'); + assert.ok(!response, 'testException: no response'); + }); + + client.testOneway(0, function(err, response) { + assert.fail('testOneway should not answer'); + }); + + checkOffByOne(function(done) { + client.testI32(-1, function(err, response) { + assert.error(err, 'checkOffByOne: no callback error'); + assert.equal(-1, response); + assert.end(); + done(); + }); + }, callback); + + }); +}; + +exports.ThriftTestDriverPromise = function(client, callback) { + + test('Q Promise Client Tests', function(assert) { + + var checkRecursively = makeRecursiveCheck(assert); + + function fail(msg) { + return function() { + assert.fail(msg); + } + } + + function makeAsserter(assertionFn) { + return function(c) { + var fnName = c[0]; + var expected = c[1]; + client[fnName](expected) + .then(function(actual) { + assertionFn(actual, expected, fnName); + }) + .fail(fail('fnName')); + }; + } + + testCases.simple.forEach(makeAsserter(function(a, e, m){ + if (a instanceof Int64) { + var e64 = e instanceof Int64 ? e : new Int64(e); + assert.deepEqual(a.buffer, e64.buffer, m); + } else { + assert.equal(a, e, m); + } + })); + testCases.deep.forEach(makeAsserter(assert.deepEqual)); + testCases.deepUnordered.forEach(makeAsserter(makeUnorderedDeepEqual(assert))); + + client.testStruct(testCases.out) + .then(function(response) { + checkRecursively(testCases.out, response, 'testStruct'); + }) + .fail(fail('testStruct')); + + client.testNest(testCases.out2) + .then(function(response) { + checkRecursively(testCases.out2, response, 'testNest'); + }) + .fail(fail('testNest')); + + client.testInsanity(testCases.crazy) + .then(function(response) { + checkRecursively(testCases.insanity, response, 'testInsanity'); + }) + .fail(fail('testInsanity')); + + client.testInsanity(testCases.crazy2) + .then(function(response) { + checkRecursively(testCases.insanity, response, 'testInsanity2'); + }) + .fail(fail('testInsanity2')); + + client.testException('TException') + .then(function(response) { + fail('testException: TException'); + }) + .fail(function(err) { + assert.ok(err instanceof TException); + }); + + client.testException('Xception') + .then(function(response) { + fail('testException: Xception'); + }) + .fail(function(err) { + assert.ok(err instanceof ttypes.Xception); + assert.equal(err.errorCode, 1001); + assert.equal('Xception', err.message); + }); + + client.testException('no Exception') + .then(function(response) { + assert.equal(undefined, response); //void + }) + .fail(fail('testException')); + + client.testOneway(0, fail('testOneway: should not answer')); + + checkOffByOne(function(done) { + client.testI32(-1) + .then(function(response) { + assert.equal(-1, response); + assert.end(); + done(); + }) + .fail(fail('checkOffByOne')); + }, callback); + }); +}; + + +// Helper Functions +// ========================================================= + +function makeRecursiveCheck(assert) { + + return function (map1, map2, msg) { + var equal = true; + + var equal = checkRecursively(map1, map2); + + assert.ok(equal, msg); + + // deepEqual doesn't work with fields using node-int64 + function checkRecursively(map1, map2) { + if (typeof map1 !== 'function' && typeof map2 !== 'function') { + if (!map1 || typeof map1 !== 'object') { + //Handle int64 types (which use node-int64 in Node.js JavaScript) + if ((typeof map1 === "number") && (typeof map2 === "object") && + (map2.buffer) && (map2.buffer instanceof Buffer) && (map2.buffer.length === 8)) { + var n = new Int64(map2.buffer); + return map1 === n.toNumber(); + } else { + return map1 == map2; + } + } else { + return Object.keys(map1).every(function(key) { + return checkRecursively(map1[key], map2[key]); + }); + } + } + } + } +} + +function checkOffByOne(done, callback) { + + var retry_limit = 30; + var retry_interval = 100; + var test_complete = false; + var retrys = 0; + + /** + * redo a simple test after the oneway to make sure we aren't "off by one" -- + * if the server treated oneway void like normal void, this next test will + * fail since it will get the void confirmation rather than the correct + * result. In this circumstance, the client will throw the exception: + * + * Because this is the last test against the server, when it completes + * the entire suite is complete by definition (the tests run serially). + */ + done(function() { + test_complete = true; + }); + + //We wait up to retry_limit * retry_interval for the test suite to complete + function TestForCompletion() { + if(test_complete && callback) { + callback("Server successfully tested!"); + } else { + if (++retrys < retry_limit) { + setTimeout(TestForCompletion, retry_interval); + } else if (callback) { + callback("Server test failed to complete after " + + (retry_limit * retry_interval / 1000) + " seconds"); + } + } + } + + setTimeout(TestForCompletion, retry_interval); +} + +function makeUnorderedDeepEqual(assert) { + return function(actual, expected, name) { + assert.equal(actual.length, expected.length, name); + for (var k in actual) { + var found = false; + for (var k2 in expected) { + if (actual[k] === expected[k2]) { + found = true; + } + } + if (!found) { + assert.fail('Unexpected value ' + actual[k] + ' with key ' + k); + } + } + }; +} diff --git a/lib/nodejs/test/test_handler.js b/lib/nodejs/test/test_handler.js new file mode 100644 index 0000000..5c89f7a --- /dev/null +++ b/lib/nodejs/test/test_handler.js @@ -0,0 +1,227 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * 'License'); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//This is the server side Node test handler for the standard +// Apache Thrift test service. + +var ttypes = require('./gen-nodejs/ThriftTest_types'); +var TException = require('thrift').Thrift.TException; + +function makeSyncHandler(label) { + return function(thing) { + //console.log(label + '(\'' + thing + '\')'); + return thing; + } +} + +var syncHandlers = { + testVoid: testVoid, + testMapMap: testMapMap, + testInsanity: testInsanity, + testMulti: testMulti, + testException: testException, + testMultiException: testMultiException, + testOneway: testOneway +}; + +function makeAsyncHandler(label) { + return function(thing, result) { + thing = syncHandlers[label](thing); + result(null, thing); + } +} + +var asyncHandlers = { + testVoid: testVoidAsync, + testMulti: testMultiAsync, + testException: testExceptionAsync, + testMultiException: testMultiExceptionAsync, + testOneway: testOnewayAsync +}; + +var identityHandlers = [ + 'testString', + 'testBool', + 'testByte', + 'testI32', + 'testI64', + 'testDouble', + 'testBinary', + 'testStruct', + 'testNest', + 'testMap', + 'testStringMap', + 'testSet', + 'testList', + 'testEnum', + 'testTypedef' +]; + +function testVoid() { + //console.log('testVoid()'); +} + +function testVoidAsync(result) { + result(testVoid()); +} + +function testMapMap(hello) { + //console.log('testMapMap(' + hello + ')'); + + var mapmap = []; + var pos = []; + var neg = []; + for (var i = 1; i < 5; i++) { + pos[i] = i; + neg[-i] = -i; + } + mapmap[4] = pos; + mapmap[-4] = neg; + + return mapmap; +} + +function testInsanity(argument) { + //console.log('testInsanity('); + //console.log(argument); + //console.log(')'); + + var first_map = []; + var second_map = []; + + first_map[ttypes.Numberz.TWO] = argument; + first_map[ttypes.Numberz.THREE] = argument; + + var looney = new ttypes.Insanity(); + second_map[ttypes.Numberz.SIX] = looney; + + var insane = []; + insane[1] = first_map; + insane[2] = second_map; + + //console.log('insane result:'); + //console.log(insane); + return insane; +} + +function testMulti(arg0, arg1, arg2, arg3, arg4, arg5) { + //console.log('testMulti()'); + + var hello = new ttypes.Xtruct(); + hello.string_thing = 'Hello2'; + hello.byte_thing = arg0; + hello.i32_thing = arg1; + hello.i64_thing = arg2; + return hello; +} + +function testMultiAsync(arg0, arg1, arg2, arg3, arg4, arg5, result) { + var hello = testMulti(arg0, arg1, arg2, arg3, arg4, arg5); + result(null, hello); +} + +function testException(arg) { + //console.log('testException('+arg+')'); + if (arg === 'Xception') { + var x = new ttypes.Xception(); + x.errorCode = 1001; + x.message = arg; + throw x; + } else if (arg === 'TException') { + throw new TException(arg); + } else { + return; + } +} + +function testExceptionAsync(arg, result) { + //console.log('testException('+arg+')'); + if (arg === 'Xception') { + var x = new ttypes.Xception(); + x.errorCode = 1001; + x.message = arg; + result(x); + } else if (arg === 'TException') { + result(new TException(arg)); + } else { + result(null); + } +} + +function testMultiException(arg0, arg1) { + //console.log('testMultiException(' + arg0 + ', ' + arg1 + ')'); + if (arg0 === ('Xception')) { + var x = new ttypes.Xception(); + x.errorCode = 1001; + x.message = 'This is an Xception'; + throw x; + } else if (arg0 === ('Xception2')) { + var x2 = new ttypes.Xception2(); + x2.errorCode = 2002; + x2.struct_thing = new ttypes.Xtruct(); + x2.struct_thing.string_thing = 'This is an Xception2'; + throw x2; + } + + var res = new ttypes.Xtruct(); + res.string_thing = arg1; + return res; +} + +function testMultiExceptionAsync(arg0, arg1, result) { + //console.log('testMultiException(' + arg0 + ', ' + arg1 + ')'); + if (arg0 === ('Xception')) { + var x = new ttypes.Xception(); + x.errorCode = 1001; + x.message = 'This is an Xception'; + result(x); + } else if (arg0 === ('Xception2')) { + var x2 = new ttypes.Xception2(); + x2.errorCode = 2002; + x2.struct_thing = new ttypes.Xtruct(); + x2.struct_thing.string_thing = 'This is an Xception2'; + result(x2); + } else { + var res = new ttypes.Xtruct(); + res.string_thing = arg1; + result(null, res); + } +} + +function testOneway(sleepFor) { + //console.log('testOneway(' + sleepFor + ') => JavaScript (like Rust) never sleeps!'); +} + +function testOnewayAsync(sleepFor, result) { + testOneway(sleepFor); +} + +identityHandlers.forEach(function(label) { + syncHandlers[label] = makeSyncHandler(label); + asyncHandlers[label] = makeAsyncHandler(label); +}); + +['testMapMap', 'testInsanity'].forEach(function(label) { + asyncHandlers[label] = makeAsyncHandler(label); +}); + +exports.ThriftTestHandler = asyncHandlers; + +exports.AsyncThriftTestHandler = asyncHandlers; +exports.SyncThriftTestHandler = asyncHandlers; diff --git a/lib/ocaml/DEVELOPMENT b/lib/ocaml/DEVELOPMENT new file mode 100644 index 0000000..3d5a03c --- /dev/null +++ b/lib/ocaml/DEVELOPMENT @@ -0,0 +1,76 @@ +Thrift OCaml Development +======================== + +Prerequisites +------------- + +In order to build this library, you must have the following installed: + + * The OCaml compiler, preferably >4.00 + * The Oasis build tool + +In addition you may want to install OPAM, which will allow you to setup an +OCaml development environment that's isolated from your system installation, +much like virutalenv for Python or the myriad systems available for Ruby. If +you have OPAM installed, then installing Oasis is as simple as running: + + $ opam install oasis + +Building +-------- + +Once all the prerequisites have been installed, run the following commands: + + $ oasis setup + $ ./configure + $ make + +The `oasis setup` command will generate the configure script and Makefile, +along with other files that opam will use to create an installable library. +The cofigure script will ensure that all build dependencies are installed, and +make will actually build the library. + +To remove files that the compiler geneates, run: + + $ make clean + +To remove those files _as well as_ files that the setup and configure process +generates, run: + + $ rm `cat .gitignore` + +Installing +---------- + +If you're using opam, simply run the following command: + + $ make install + +While development, you may want to install your latest build on the system to +test against other libraries or programs. To do this, use: + + $ make reinstall + +Distribution +------------ + +The de facto preferred method for distributing OCaml libraries is through the +OPAM package repository. To publish the latest package, issue a pull request +against the following github repository: + + https://github.com/ocaml/opam-repository + +The pull requestion should add the following directory structure and files: + + package + |__thrift + |__thrift. + |__ descr + |__ opam + |__ url + +Templates for the following files can be found in the opam/ subdirectory of +this library's root, with XXX(...) indicating fields that need to be filled +out. You can find further documentation here: + + http://opam.ocaml.org/doc/Packaging.html diff --git a/lib/ocaml/README.md b/lib/ocaml/README.md new file mode 100644 index 0000000..5a47a42 --- /dev/null +++ b/lib/ocaml/README.md @@ -0,0 +1,119 @@ +Thrift OCaml Software Library + +License +======= + +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + + +Library +======= + +The library abstract classes, exceptions, and general use functions +are mostly jammed in Thrift.ml (an exception being +TServer). + +Generally, classes are used, however they are often put in their own +module along with other relevant types and functions. The classes +often called t, exceptions are called E. + +Implementations live in their own files. There is TBinaryProtocol, +TSocket, TThreadedServer, TSimpleServer, and TServerSocket. + +A note on making the library: Running make should create native, debug +code libraries, and a toplevel. + + +Struct format +------------- +Structs are turned into classes. The fields are all option types and +are initially None. Write is a method, but reading is done by a +separate function (since there is no such thing as a static +class). The class type is t and is in a module with the name of the +struct. + + +enum format +----------- +Enums are put in their own module along with +functions to_i and of_i which convert the ocaml types into ints. For +example: + +enum Numberz +{ + ONE = 1, + TWO, + THREE, + FIVE = 5, + SIX, + EIGHT = 8 +} + +==> + +module Numberz = +struct +type t = +| ONE +| TWO +| THREE +| FIVE +| SIX +| EIGHT + +let of_i = ... +let to_i = ... +end + +typedef format +-------------- +Typedef turns into the type declaration: +typedef i64 UserId + +==> + +type userid Int64.t + +exception format +---------------- +The same as structs except that the module also has an exception type +E of t that is raised/caught. + +For example, with an exception Xception, +raise (Xception.E (new Xception.t)) +and +try + ... +with Xception.E e -> ... + +list format +----------- +Lists are turned into OCaml native lists. + +Map/Set formats +--------------- +These are both turned into Hashtbl.t's. Set values are bool. + +Services +-------- +The client is a class "client" parametrized on input and output +protocols. The processor is a class parametrized on a handler. A +handler is a class inheriting the iface abstract class. Unlike other +implementations, client does not implement iface since iface functions +must take option arguments so as to deal with the case where a client +does not send all the arguments. diff --git a/lib/ocaml/TODO b/lib/ocaml/TODO new file mode 100644 index 0000000..4d1dc77 --- /dev/null +++ b/lib/ocaml/TODO @@ -0,0 +1,5 @@ +Write interfaces +Clean up the code generator +Avoid capture properly instead of relying on the user not to use _ + + diff --git a/lib/ocaml/_oasis b/lib/ocaml/_oasis new file mode 100644 index 0000000..19033e6 --- /dev/null +++ b/lib/ocaml/_oasis @@ -0,0 +1,19 @@ +Name: libthrift-ocaml +Version: 0.11.0 +OASISFormat: 0.3 +Synopsis: OCaml bindings for the Apache Thrift RPC system +Authors: Apache Thrift Developers +License: Apache-2.0 +Homepage: http://thrift.apache.org +BuildTools: ocamlbuild +Plugins: META (0.3), + DevFiles (0.3) + +Library "libthrift-ocaml" + Path: src + FindlibName: thrift + buildTools: ocamlbuild + BuildDepends: threads + Modules: Thrift,TBinaryProtocol,TSocket,TFramedTransport,TChannelTransport,TServer,TSimpleServer,TServerSocket,TThreadedServer + XMETARequires: threads + diff --git a/lib/ocaml/coding_standards.md b/lib/ocaml/coding_standards.md new file mode 100644 index 0000000..fa0390b --- /dev/null +++ b/lib/ocaml/coding_standards.md @@ -0,0 +1 @@ +Please follow [General Coding Standards](/doc/coding_standards.md) diff --git a/lib/ocaml/descr b/lib/ocaml/descr new file mode 100644 index 0000000..a41749d --- /dev/null +++ b/lib/ocaml/descr @@ -0,0 +1 @@ +OCaml bindings for the Apache Thrift RPC system diff --git a/lib/ocaml/opam b/lib/ocaml/opam new file mode 100644 index 0000000..9dbc3d9 --- /dev/null +++ b/lib/ocaml/opam @@ -0,0 +1,8 @@ +opam-version: "1" +maintainer: "XXX(FILL ME IN WITH EMAIL)" +build: [ + [make] + [make "install"] +] +remove: [["ocamlfind" "remove" "thrift"]] +depends: ["ocamlfind"] diff --git a/lib/ocaml/src/Makefile b/lib/ocaml/src/Makefile new file mode 100644 index 0000000..a97ade5 --- /dev/null +++ b/lib/ocaml/src/Makefile @@ -0,0 +1,26 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +SOURCES = Thrift.ml TBinaryProtocol.ml TSocket.ml TFramedTransport.ml TChannelTransport.ml TServer.ml TSimpleServer.ml TServerSocket.ml TThreadedServer.ml +RESULT = thrift +LIBS = unix threads +THREADS = yes +all: native-code-library debug-code-library top +OCAMLMAKEFILE = ../OCamlMakefile +include $(OCAMLMAKEFILE) diff --git a/lib/ocaml/src/TBinaryProtocol.ml b/lib/ocaml/src/TBinaryProtocol.ml new file mode 100644 index 0000000..6d7500e --- /dev/null +++ b/lib/ocaml/src/TBinaryProtocol.ml @@ -0,0 +1,171 @@ +(* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*) + +open Thrift + +module P = Protocol + +let get_byte i b = 255 land (i lsr (8*b)) +let get_byte32 i b = 255 land (Int32.to_int (Int32.shift_right i (8*b))) +let get_byte64 i b = 255 land (Int64.to_int (Int64.shift_right i (8*b))) + + +let tv = P.t_type_to_i +let vt = P.t_type_of_i + + +let comp_int b n = + let s = ref 0l in + let sb = 32 - 8*n in + for i=0 to (n-1) do + s:= Int32.logor !s (Int32.shift_left (Int32.of_int (int_of_char b.[i])) (8*(n-1-i))) + done; + Int32.shift_right (Int32.shift_left !s sb) sb + +let comp_int64 b n = + let s = ref 0L in + for i=0 to (n-1) do + s:=Int64.logor !s (Int64.shift_left (Int64.of_int (int_of_char b.[i])) (8*(n-1-i))) + done; + !s + +let version_mask = 0xffff0000l +let version_1 = 0x80010000l + +class t trans = +object (self) + inherit P.t trans + val ibyte = String.create 8 + method writeBool b = + ibyte.[0] <- char_of_int (if b then 1 else 0); + trans#write ibyte 0 1 + method writeByte i = + ibyte.[0] <- char_of_int (get_byte i 0); + trans#write ibyte 0 1 + method writeI16 i = + let gb = get_byte i in + ibyte.[1] <- char_of_int (gb 0); + ibyte.[0] <- char_of_int (gb 1); + trans#write ibyte 0 2 + method writeI32 i = + let gb = get_byte32 i in + for i=0 to 3 do + ibyte.[3-i] <- char_of_int (gb i) + done; + trans#write ibyte 0 4 + method writeI64 i= + let gb = get_byte64 i in + for i=0 to 7 do + ibyte.[7-i] <- char_of_int (gb i) + done; + trans#write ibyte 0 8 + method writeDouble d = + self#writeI64 (Int64.bits_of_float d) + method writeString s= + let n = String.length s in + self#writeI32 (Int32.of_int n); + trans#write s 0 n + method writeBinary a = self#writeString a + method writeMessageBegin (n,t,s) = + self#writeI32 (Int32.logor version_1 (Int32.of_int (P.message_type_to_i t))); + self#writeString n; + self#writeI32 (Int32.of_int s) + method writeMessageEnd = () + method writeStructBegin s = () + method writeStructEnd = () + method writeFieldBegin (n,t,i) = + self#writeByte (tv t); + self#writeI16 i + method writeFieldEnd = () + method writeFieldStop = + self#writeByte (tv (P.T_STOP)) + method writeMapBegin (k,v,s) = + self#writeByte (tv k); + self#writeByte (tv v); + self#writeI32 (Int32.of_int s) + method writeMapEnd = () + method writeListBegin (t,s) = + self#writeByte (tv t); + self#writeI32 (Int32.of_int s) + method writeListEnd = () + method writeSetBegin (t,s) = + self#writeByte (tv t); + self#writeI32 (Int32.of_int s) + method writeSetEnd = () + method readByte = + ignore (trans#readAll ibyte 0 1); + Int32.to_int (comp_int ibyte 1) + method readI16 = + ignore (trans#readAll ibyte 0 2); + Int32.to_int (comp_int ibyte 2) + method readI32 = + ignore (trans#readAll ibyte 0 4); + comp_int ibyte 4 + method readI64 = + ignore (trans#readAll ibyte 0 8); + comp_int64 ibyte 8 + method readDouble = + Int64.float_of_bits (self#readI64) + method readBool = + self#readByte = 1 + method readString = + let sz = Int32.to_int (self#readI32) in + let buf = String.create sz in + ignore (trans#readAll buf 0 sz); + buf + method readBinary = self#readString + method readMessageBegin = + let ver = self#readI32 in + if Int32.compare (Int32.logand ver version_mask) version_1 != 0 then + raise (P.E (P.BAD_VERSION, "Missing version identifier")) + else + let s = self#readString in + let mt = P.message_type_of_i (Int32.to_int (Int32.logand ver 0xFFl)) in + (s,mt, Int32.to_int self#readI32) + method readMessageEnd = () + method readStructBegin = + "" + method readStructEnd = () + method readFieldBegin = + let t = (vt (self#readByte)) + in + if t != P.T_STOP then + ("",t,self#readI16) + else ("",t,0); + method readFieldEnd = () + method readMapBegin = + let kt = vt (self#readByte) in + let vt = vt (self#readByte) in + (kt,vt, Int32.to_int self#readI32) + method readMapEnd = () + method readListBegin = + let t = vt (self#readByte) in + (t, Int32.to_int self#readI32) + method readListEnd = () + method readSetBegin = + let t = vt (self#readByte) in + (t, Int32.to_int self#readI32); + method readSetEnd = () +end + +class factory = +object + inherit P.factory + method getProtocol tr = new t tr +end diff --git a/lib/ocaml/src/TChannelTransport.ml b/lib/ocaml/src/TChannelTransport.ml new file mode 100644 index 0000000..0f7d616 --- /dev/null +++ b/lib/ocaml/src/TChannelTransport.ml @@ -0,0 +1,39 @@ +(* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*) + +open Thrift +module T = Transport + +class t (i,o) = +object (self) + val mutable opened = true + inherit Transport.t + method isOpen = opened + method opn = () + method close = close_in i; opened <- false + method read buf off len = + if opened then + try + really_input i buf off len; len + with _ -> raise (T.E (T.UNKNOWN, ("TChannelTransport: Could not read "^(string_of_int len)))) + else + raise (T.E (T.NOT_OPEN, "TChannelTransport: Channel was closed")) + method write buf off len = output o buf off len + method flush = flush o +end diff --git a/lib/ocaml/src/TFramedTransport.ml b/lib/ocaml/src/TFramedTransport.ml new file mode 100644 index 0000000..1be51e7 --- /dev/null +++ b/lib/ocaml/src/TFramedTransport.ml @@ -0,0 +1,93 @@ +open Thrift + +module T = Transport + +let c_0xff_32 = Int32.of_string "0xff" + +(* Copied from OCamlnet rtypes.ml *) +let encode_frame_size x = + let s = String.create 4 in + let n3 = Int32.to_int (Int32.shift_right_logical x 24) land 0xff in + let n2 = Int32.to_int (Int32.shift_right_logical x 16) land 0xff in + let n1 = Int32.to_int (Int32.shift_right_logical x 8) land 0xff in + let n0 = Int32.to_int (Int32.logand x c_0xff_32) in + String.unsafe_set s 0 (Char.unsafe_chr n3); + String.unsafe_set s 1 (Char.unsafe_chr n2); + String.unsafe_set s 2 (Char.unsafe_chr n1); + String.unsafe_set s 3 (Char.unsafe_chr n0); + s + +let decode_frame_size s = + let n3 = Int32.of_int (Char.code s.[0]) in + let n2 = Int32.of_int (Char.code s.[1]) in + let n1 = Int32.of_int (Char.code s.[2]) in + let n0 = Int32.of_int (Char.code s.[3]) in + Int32.logor + (Int32.shift_left n3 24) + (Int32.logor + (Int32.shift_left n2 16) + (Int32.logor + (Int32.shift_left n1 8) + n0)) + +class t ?(max_length=Sys.max_string_length) (transport: T.t) = +object (self) + inherit T.t + + method isOpen = transport#isOpen + method opn = transport#opn + method close = transport#close + + val mutable read_buf = None + val mutable read_buf_offset = 0 + val mutable write_buf = "" + + method private read_frame = + let len_buf = String.create 4 in + assert (transport#readAll len_buf 0 4 = 4); + + let size = Int32.to_int (decode_frame_size len_buf) in + + (if size < 0 + then failwith (Printf.sprintf "Read a negative frame size (%i)!" size)); + + (if size > max_length + then failwith (Printf.sprintf "Frame size (%i) larger than max length (%i)!" size max_length)); + + let buf = String.create size in + assert (transport#readAll buf 0 size = size); + read_buf <- Some buf; + read_buf_offset <- 0 + + method private read_from_frame frame buf off len = + let to_copy = min len ((String.length frame) - read_buf_offset) in + String.blit frame read_buf_offset buf off to_copy; + read_buf_offset <- read_buf_offset + to_copy; + to_copy + + method read buf off len = + match read_buf with + | Some frame -> + let i = self#read_from_frame frame buf off len in + if i > 0 + then i + else begin + self#read_frame; + self#read_from_frame frame buf off len + end + | None -> + self#read_frame; + self#read buf off len + + method write buf off len = + write_buf <- write_buf ^ (String.sub buf off len) + + method flush = + let encoded_size = encode_frame_size (Int32.of_int (String.length write_buf)) in + transport#write encoded_size 0 (String.length encoded_size); + transport#write write_buf 0 (String.length write_buf); + transport#flush; + write_buf <- "" +end + + diff --git a/lib/ocaml/src/TServer.ml b/lib/ocaml/src/TServer.ml new file mode 100644 index 0000000..fc51efa --- /dev/null +++ b/lib/ocaml/src/TServer.ml @@ -0,0 +1,42 @@ +(* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*) + +open Thrift + +class virtual t + (pf : Processor.t) + (st : Transport.server_t) + (tf : Transport.factory) + (ipf : Protocol.factory) + (opf : Protocol.factory)= +object + method virtual serve : unit +end;; + + + +let run_basic_server proc port = + Unix.establish_server (fun inp -> fun out -> + let trans = new TChannelTransport.t (inp,out) in + let proto = new TBinaryProtocol.t (trans :> Transport.t) in + try + while proc#process proto proto do () done; () + with e -> ()) (Unix.ADDR_INET (Unix.inet_addr_of_string "127.0.0.1",port)) + + diff --git a/lib/ocaml/src/TServerSocket.ml b/lib/ocaml/src/TServerSocket.ml new file mode 100644 index 0000000..405ef82 --- /dev/null +++ b/lib/ocaml/src/TServerSocket.ml @@ -0,0 +1,41 @@ +(* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*) + +open Thrift + +class t port = +object + inherit Transport.server_t + val mutable sock = None + method listen = + let s = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in + sock <- Some s; + Unix.bind s (Unix.ADDR_INET (Unix.inet_addr_any, port)); + Unix.listen s 256 + method close = + match sock with + Some s -> Unix.shutdown s Unix.SHUTDOWN_ALL; Unix.close s; + sock <- None + | _ -> () + method acceptImpl = + match sock with + Some s -> let (fd,_) = Unix.accept s in + new TChannelTransport.t (Unix.in_channel_of_descr fd,Unix.out_channel_of_descr fd) + | _ -> raise (Transport.E (Transport.NOT_OPEN,"TServerSocket: Not listening but tried to accept")) +end diff --git a/lib/ocaml/src/TSimpleServer.ml b/lib/ocaml/src/TSimpleServer.ml new file mode 100644 index 0000000..2927c08 --- /dev/null +++ b/lib/ocaml/src/TSimpleServer.ml @@ -0,0 +1,40 @@ +(* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*) + +open Thrift +module S = TServer + +class t pf st tf ipf opf = +object + inherit S.t pf st tf ipf opf + method serve = + try + st#listen; + while true do + let c = st#accept in + let trans = tf#getTransport c in + let inp = ipf#getProtocol trans in + let op = opf#getProtocol trans in + try + while (pf#process inp op) do () done; + trans#close + with e -> trans#close; raise e + done + with _ -> () +end diff --git a/lib/ocaml/src/TSocket.ml b/lib/ocaml/src/TSocket.ml new file mode 100644 index 0000000..109e11c --- /dev/null +++ b/lib/ocaml/src/TSocket.ml @@ -0,0 +1,59 @@ +(* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*) + +open Thrift + +module T = Transport + +class t host port= +object (self) + inherit T.t + val mutable chans = None + method isOpen = chans != None + method opn = + try + let addr = (let {Unix.h_addr_list=x} = Unix.gethostbyname host in x.(0)) in + chans <- Some(Unix.open_connection (Unix.ADDR_INET (addr,port))) + with + Unix.Unix_error (e,fn,_) -> raise (T.E (T.NOT_OPEN, ("TSocket: Could not connect to "^host^":"^(string_of_int port)^" because: "^fn^":"^(Unix.error_message e)))) + | _ -> raise (T.E (T.NOT_OPEN, ("TSocket: Could not connect to "^host^":"^(string_of_int port)))) + + method close = + match chans with + None -> () + | Some(inc,out) -> (Unix.shutdown_connection inc; + close_in inc; + chans <- None) + method read buf off len = match chans with + None -> raise (T.E (T.NOT_OPEN, "TSocket: Socket not open")) + | Some(i,o) -> + try + really_input i buf off len; len + with + Unix.Unix_error (e,fn,_) -> raise (T.E (T.UNKNOWN, ("TSocket: Could not read "^(string_of_int len)^" from "^host^":"^(string_of_int port)^" because: "^fn^":"^(Unix.error_message e)))) + | _ -> raise (T.E (T.UNKNOWN, ("TSocket: Could not read "^(string_of_int len)^" from "^host^":"^(string_of_int port)))) + method write buf off len = match chans with + None -> raise (T.E (T.NOT_OPEN, "TSocket: Socket not open")) + | Some(i,o) -> output o buf off len + method flush = match chans with + None -> raise (T.E (T.NOT_OPEN, "TSocket: Socket not open")) + | Some(i,o) -> flush o +end + + diff --git a/lib/ocaml/src/TThreadedServer.ml b/lib/ocaml/src/TThreadedServer.ml new file mode 100644 index 0000000..4462dbd --- /dev/null +++ b/lib/ocaml/src/TThreadedServer.ml @@ -0,0 +1,45 @@ +(* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*) + +open Thrift + +class t + (pf : Processor.t) + (st : Transport.server_t) + (tf : Transport.factory) + (ipf : Protocol.factory) + (opf : Protocol.factory)= +object + inherit TServer.t pf st tf ipf opf + method serve = + st#listen; + while true do + let tr = tf#getTransport (st#accept) in + ignore (Thread.create + (fun _ -> + let ip = ipf#getProtocol tr in + let op = opf#getProtocol tr in + try + while pf#process ip op do + () + done + with _ -> ()) ()) + done +end + diff --git a/lib/ocaml/src/Thrift.ml b/lib/ocaml/src/Thrift.ml new file mode 100644 index 0000000..f0d7a42 --- /dev/null +++ b/lib/ocaml/src/Thrift.ml @@ -0,0 +1,383 @@ +(* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*) + +exception Break;; +exception Thrift_error;; +exception Field_empty of string;; + +class t_exn = +object + val mutable message = "" + method get_message = message + method set_message s = message <- s +end;; + +module Transport = +struct + type exn_type = + | UNKNOWN + | NOT_OPEN + | ALREADY_OPEN + | TIMED_OUT + | END_OF_FILE;; + + exception E of exn_type * string + + class virtual t = + object (self) + method virtual isOpen : bool + method virtual opn : unit + method virtual close : unit + method virtual read : string -> int -> int -> int + method readAll buf off len = + let got = ref 0 in + let ret = ref 0 in + while !got < len do + ret := self#read buf (off+(!got)) (len - (!got)); + if !ret <= 0 then + raise (E (UNKNOWN, "Cannot read. Remote side has closed.")); + got := !got + !ret + done; + !got + method virtual write : string -> int -> int -> unit + method virtual flush : unit + end + + class factory = + object + method getTransport (t : t) = t + end + + class virtual server_t = + object (self) + method virtual listen : unit + method accept = self#acceptImpl + method virtual close : unit + method virtual acceptImpl : t + end + +end;; + + + +module Protocol = +struct + type t_type = + | T_STOP + | T_VOID + | T_BOOL + | T_BYTE + | T_I08 + | T_I16 + | T_I32 + | T_U64 + | T_I64 + | T_DOUBLE + | T_STRING + | T_UTF7 + | T_STRUCT + | T_MAP + | T_SET + | T_LIST + | T_UTF8 + | T_UTF16 + + let t_type_to_i = function + T_STOP -> 0 + | T_VOID -> 1 + | T_BOOL -> 2 + | T_BYTE -> 3 + | T_I08 -> 3 + | T_I16 -> 6 + | T_I32 -> 8 + | T_U64 -> 9 + | T_I64 -> 10 + | T_DOUBLE -> 4 + | T_STRING -> 11 + | T_UTF7 -> 11 + | T_STRUCT -> 12 + | T_MAP -> 13 + | T_SET -> 14 + | T_LIST -> 15 + | T_UTF8 -> 16 + | T_UTF16 -> 17 + + let t_type_of_i = function + 0 -> T_STOP + | 1 -> T_VOID + | 2 -> T_BOOL + | 3 -> T_BYTE + | 6-> T_I16 + | 8 -> T_I32 + | 9 -> T_U64 + | 10 -> T_I64 + | 4 -> T_DOUBLE + | 11 -> T_STRING + | 12 -> T_STRUCT + | 13 -> T_MAP + | 14 -> T_SET + | 15 -> T_LIST + | 16 -> T_UTF8 + | 17 -> T_UTF16 + | _ -> raise Thrift_error + + type message_type = + | CALL + | REPLY + | EXCEPTION + | ONEWAY + + let message_type_to_i = function + | CALL -> 1 + | REPLY -> 2 + | EXCEPTION -> 3 + | ONEWAY -> 4 + + let message_type_of_i = function + | 1 -> CALL + | 2 -> REPLY + | 3 -> EXCEPTION + | 4 -> ONEWAY + | _ -> raise Thrift_error + + class virtual t (trans: Transport.t) = + object (self) + val mutable trans_ = trans + method getTransport = trans_ + (* writing methods *) + method virtual writeMessageBegin : string * message_type * int -> unit + method virtual writeMessageEnd : unit + method virtual writeStructBegin : string -> unit + method virtual writeStructEnd : unit + method virtual writeFieldBegin : string * t_type * int -> unit + method virtual writeFieldEnd : unit + method virtual writeFieldStop : unit + method virtual writeMapBegin : t_type * t_type * int -> unit + method virtual writeMapEnd : unit + method virtual writeListBegin : t_type * int -> unit + method virtual writeListEnd : unit + method virtual writeSetBegin : t_type * int -> unit + method virtual writeSetEnd : unit + method virtual writeBool : bool -> unit + method virtual writeByte : int -> unit + method virtual writeI16 : int -> unit + method virtual writeI32 : Int32.t -> unit + method virtual writeI64 : Int64.t -> unit + method virtual writeDouble : float -> unit + method virtual writeString : string -> unit + method virtual writeBinary : string -> unit + (* reading methods *) + method virtual readMessageBegin : string * message_type * int + method virtual readMessageEnd : unit + method virtual readStructBegin : string + method virtual readStructEnd : unit + method virtual readFieldBegin : string * t_type * int + method virtual readFieldEnd : unit + method virtual readMapBegin : t_type * t_type * int + method virtual readMapEnd : unit + method virtual readListBegin : t_type * int + method virtual readListEnd : unit + method virtual readSetBegin : t_type * int + method virtual readSetEnd : unit + method virtual readBool : bool + method virtual readByte : int + method virtual readI16 : int + method virtual readI32: Int32.t + method virtual readI64 : Int64.t + method virtual readDouble : float + method virtual readString : string + method virtual readBinary : string + (* skippage *) + method skip typ = + match typ with + | T_STOP -> () + | T_VOID -> () + | T_BOOL -> ignore self#readBool + | T_BYTE + | T_I08 -> ignore self#readByte + | T_I16 -> ignore self#readI16 + | T_I32 -> ignore self#readI32 + | T_U64 + | T_I64 -> ignore self#readI64 + | T_DOUBLE -> ignore self#readDouble + | T_STRING -> ignore self#readString + | T_UTF7 -> () + | T_STRUCT -> ignore ((ignore self#readStructBegin); + (try + while true do + let (_,t,_) = self#readFieldBegin in + if t = T_STOP then + raise Break + else + (self#skip t; + self#readFieldEnd) + done + with Break -> ()); + self#readStructEnd) + | T_MAP -> ignore (let (k,v,s) = self#readMapBegin in + for i=0 to s do + self#skip k; + self#skip v; + done; + self#readMapEnd) + | T_SET -> ignore (let (t,s) = self#readSetBegin in + for i=0 to s do + self#skip t + done; + self#readSetEnd) + | T_LIST -> ignore (let (t,s) = self#readListBegin in + for i=0 to s do + self#skip t + done; + self#readListEnd) + | T_UTF8 -> () + | T_UTF16 -> () + end + + class virtual factory = + object + method virtual getProtocol : Transport.t -> t + end + + type exn_type = + | UNKNOWN + | INVALID_DATA + | NEGATIVE_SIZE + | SIZE_LIMIT + | BAD_VERSION + | NOT_IMPLEMENTED + | DEPTH_LIMIT + + exception E of exn_type * string;; + +end;; + + +module Processor = +struct + class virtual t = + object + method virtual process : Protocol.t -> Protocol.t -> bool + end;; + + class factory (processor : t) = + object + val processor_ = processor + method getProcessor (trans : Transport.t) = processor_ + end;; +end + + +(* Ugly *) +module Application_Exn = +struct + type typ= + | UNKNOWN + | UNKNOWN_METHOD + | INVALID_MESSAGE_TYPE + | WRONG_METHOD_NAME + | BAD_SEQUENCE_ID + | MISSING_RESULT + | INTERNAL_ERROR + | PROTOCOL_ERROR + | INVALID_TRANSFORM + | INVALID_PROTOCOL + | UNSUPPORTED_CLIENT_TYPE + + let typ_of_i = function + 0l -> UNKNOWN + | 1l -> UNKNOWN_METHOD + | 2l -> INVALID_MESSAGE_TYPE + | 3l -> WRONG_METHOD_NAME + | 4l -> BAD_SEQUENCE_ID + | 5l -> MISSING_RESULT + | 6l -> INTERNAL_ERROR + | 7l -> PROTOCOL_ERROR + | 8l -> INVALID_TRANSFORM + | 9l -> INVALID_PROTOCOL + | 10l -> UNSUPPORTED_CLIENT_TYPE + | _ -> raise Thrift_error;; + let typ_to_i = function + | UNKNOWN -> 0l + | UNKNOWN_METHOD -> 1l + | INVALID_MESSAGE_TYPE -> 2l + | WRONG_METHOD_NAME -> 3l + | BAD_SEQUENCE_ID -> 4l + | MISSING_RESULT -> 5l + | INTERNAL_ERROR -> 6l + | PROTOCOL_ERROR -> 7l + | INVALID_TRANSFORM -> 8l + | INVALID_PROTOCOL -> 9l + | UNSUPPORTED_CLIENT_TYPE -> 10l + + class t = + object (self) + inherit t_exn + val mutable typ = UNKNOWN + method get_type = typ + method set_type t = typ <- t + method write (oprot : Protocol.t) = + oprot#writeStructBegin "TApplicationExeception"; + if self#get_message != "" then + (oprot#writeFieldBegin ("message",Protocol.T_STRING, 1); + oprot#writeString self#get_message; + oprot#writeFieldEnd) + else (); + oprot#writeFieldBegin ("type",Protocol.T_I32,2); + oprot#writeI32 (typ_to_i typ); + oprot#writeFieldEnd; + oprot#writeFieldStop; + oprot#writeStructEnd + end;; + + let create typ msg = + let e = new t in + e#set_type typ; + e#set_message msg; + e + + let read (iprot : Protocol.t) = + let msg = ref "" in + let typ = ref 0l in + ignore iprot#readStructBegin; + (try + while true do + let (name,ft,id) =iprot#readFieldBegin in + if ft = Protocol.T_STOP + then raise Break + else (); + (match id with + | 1 -> (if ft = Protocol.T_STRING + then msg := (iprot#readString) + else iprot#skip ft) + | 2 -> (if ft = Protocol.T_I32 + then typ := iprot#readI32 + else iprot#skip ft) + | _ -> iprot#skip ft); + iprot#readFieldEnd + done + with Break -> ()); + iprot#readStructEnd; + let e = new t in + e#set_type (typ_of_i !typ); + e#set_message !msg; + e;; + + exception E of t +end;; diff --git a/lib/ocaml/url b/lib/ocaml/url new file mode 100644 index 0000000..fe4d604 --- /dev/null +++ b/lib/ocaml/url @@ -0,0 +1,2 @@ +archive: "XXX(FILL ME IN WITH URL)" +checksum: "XXX(FILL ME IN WITH MD5)" diff --git a/lib/perl/Makefile.PL b/lib/perl/Makefile.PL new file mode 100644 index 0000000..ee7a436 --- /dev/null +++ b/lib/perl/Makefile.PL @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use ExtUtils::MakeMaker; +WriteMakefile( ABSTRACT => 'Apache Thrift is a software framework for scalable cross-language services development.', + AUTHOR => 'Apache Thrift ', + LICENSE => 'apache_2_0', + MIN_PERL_VERSION => '5.010000', + NAME => 'Thrift', + NEEDS_LINKING => 0, + PREREQ_PM => { + 'Bit::Vector' => 0, + 'Class::Accessor' => 0 + }, + VERSION_FROM => 'lib/Thrift.pm' ); diff --git a/lib/perl/Makefile.am b/lib/perl/Makefile.am new file mode 100644 index 0000000..fa0f16b --- /dev/null +++ b/lib/perl/Makefile.am @@ -0,0 +1,108 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +SUBDIRS = test + +Makefile-perl.mk : Makefile.PL + $(PERL) Makefile.PL MAKEFILE=Makefile-perl.mk INSTALLDIRS=$(INSTALLDIRS) INSTALL_BASE=$(PERL_PREFIX) + +all-local: Makefile-perl.mk + $(MAKE) -f $< + find blib -name 'Makefile*' -exec rm -f {} \; + +install-exec-local: Makefile-perl.mk + $(MAKE) -f $< install DESTDIR=$(DESTDIR)/ + +clean-local: + if test -f Makefile-perl.mk ; then \ + $(MAKE) -f Makefile-perl.mk clean ; \ + fi + $(RM) Makefile-perl.mk.old + $(RM) -r gen-perl gen-perl2 + +EXTRA_DIST = \ + coding_standards.md \ + build-cpan-dist.sh \ + Makefile.PL \ + test.pl \ + lib/Thrift.pm \ + lib/Thrift.pm \ + lib/Thrift/BinaryProtocol.pm \ + lib/Thrift/BufferedTransport.pm \ + lib/Thrift/Exception.pm \ + lib/Thrift/FramedTransport.pm \ + lib/Thrift/HttpClient.pm \ + lib/Thrift/MemoryBuffer.pm \ + lib/Thrift/MessageType.pm \ + lib/Thrift/MultiplexedProcessor.pm \ + lib/Thrift/MultiplexedProtocol.pm \ + lib/Thrift/Protocol.pm \ + lib/Thrift/ProtocolDecorator.pm \ + lib/Thrift/Server.pm \ + lib/Thrift/ServerSocket.pm \ + lib/Thrift/Socket.pm \ + lib/Thrift/SSLSocket.pm \ + lib/Thrift/SSLServerSocket.pm \ + lib/Thrift/UnixServerSocket.pm \ + lib/Thrift/UnixSocket.pm \ + lib/Thrift/Type.pm \ + lib/Thrift/Transport.pm \ + README.md + +THRIFT = @top_builddir@/compiler/cpp/thrift +THRIFT_IF = @top_srcdir@/test/ThriftTest.thrift +NAME_BENCHMARKSERVICE = @top_srcdir@/lib/rb/benchmark/Benchmark.thrift +NAME_AGGR = @top_srcdir@/contrib/async-test/aggr.thrift + +THRIFTTEST_GEN = \ + gen-perl/ThriftTest/Constants.pm \ + gen-perl/ThriftTest/SecondService.pm \ + gen-perl/ThriftTest/ThriftTest.pm \ + gen-perl/ThriftTest/Types.pm + +BENCHMARK_GEN = \ + gen-perl/BenchmarkService.pm \ + gen-perl/Constants.pm \ + gen-perl/Types.pm + +AGGR_GEN = \ + gen-perl2/Aggr.pm \ + gen-perl2/Constants.pm \ + gen-perl2/Types.pm + +PERL_GEN = \ + $(THRIFTTEST_GEN) \ + $(BENCHMARK_GEN) \ + $(AGGR_GEN) + +BUILT_SOURCES = $(PERL_GEN) + +check-local: $(PERL_GEN) + $(PERL) -Iblib/lib -I@abs_srcdir@ -I@builddir@/gen-perl2 -I@builddir@/gen-perl \ + @abs_srcdir@/test.pl @abs_srcdir@/test/*.t + +$(THRIFTTEST_GEN): $(THRIFT_IF) $(THRIFT) + $(THRIFT) --gen perl $< + +$(BENCHMARK_GEN): $(NAME_BENCHMARKSERVICE) $(THRIFT) + $(THRIFT) --gen perl $< + +$(AGGR_GEN): $(NAME_AGGR) $(THRIFT) + $(MKDIR_P) gen-perl2 + $(THRIFT) -out gen-perl2 --gen perl $< diff --git a/lib/perl/Makefile.in b/lib/perl/Makefile.in new file mode 100644 index 0000000..717f5ca --- /dev/null +++ b/lib/perl/Makefile.in @@ -0,0 +1,896 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/perl +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @top_builddir@/compiler/cpp/thrift +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = test +EXTRA_DIST = \ + coding_standards.md \ + build-cpan-dist.sh \ + Makefile.PL \ + test.pl \ + lib/Thrift.pm \ + lib/Thrift.pm \ + lib/Thrift/BinaryProtocol.pm \ + lib/Thrift/BufferedTransport.pm \ + lib/Thrift/Exception.pm \ + lib/Thrift/FramedTransport.pm \ + lib/Thrift/HttpClient.pm \ + lib/Thrift/MemoryBuffer.pm \ + lib/Thrift/MessageType.pm \ + lib/Thrift/MultiplexedProcessor.pm \ + lib/Thrift/MultiplexedProtocol.pm \ + lib/Thrift/Protocol.pm \ + lib/Thrift/ProtocolDecorator.pm \ + lib/Thrift/Server.pm \ + lib/Thrift/ServerSocket.pm \ + lib/Thrift/Socket.pm \ + lib/Thrift/SSLSocket.pm \ + lib/Thrift/SSLServerSocket.pm \ + lib/Thrift/UnixServerSocket.pm \ + lib/Thrift/UnixSocket.pm \ + lib/Thrift/Type.pm \ + lib/Thrift/Transport.pm \ + README.md + +THRIFT_IF = @top_srcdir@/test/ThriftTest.thrift +NAME_BENCHMARKSERVICE = @top_srcdir@/lib/rb/benchmark/Benchmark.thrift +NAME_AGGR = @top_srcdir@/contrib/async-test/aggr.thrift +THRIFTTEST_GEN = \ + gen-perl/ThriftTest/Constants.pm \ + gen-perl/ThriftTest/SecondService.pm \ + gen-perl/ThriftTest/ThriftTest.pm \ + gen-perl/ThriftTest/Types.pm + +BENCHMARK_GEN = \ + gen-perl/BenchmarkService.pm \ + gen-perl/Constants.pm \ + gen-perl/Types.pm + +AGGR_GEN = \ + gen-perl2/Aggr.pm \ + gen-perl2/Constants.pm \ + gen-perl2/Types.pm + +PERL_GEN = \ + $(THRIFTTEST_GEN) \ + $(BENCHMARK_GEN) \ + $(AGGR_GEN) + +BUILT_SOURCES = $(PERL_GEN) +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/perl/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/perl/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-recursive +all-am: Makefile all-local +installdirs: installdirs-recursive +installdirs-am: +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-exec-local + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +style: style-recursive + +style-am: style-local + +uninstall-am: + +.MAKE: $(am__recursive_targets) all check check-am install install-am \ + install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \ + check check-am check-local clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags ctags-am distclean \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-exec-local install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am style-am style-local tags tags-am uninstall \ + uninstall-am + +.PRECIOUS: Makefile + + +Makefile-perl.mk : Makefile.PL + $(PERL) Makefile.PL MAKEFILE=Makefile-perl.mk INSTALLDIRS=$(INSTALLDIRS) INSTALL_BASE=$(PERL_PREFIX) + +all-local: Makefile-perl.mk + $(MAKE) -f $< + find blib -name 'Makefile*' -exec rm -f {} \; + +install-exec-local: Makefile-perl.mk + $(MAKE) -f $< install DESTDIR=$(DESTDIR)/ + +clean-local: + if test -f Makefile-perl.mk ; then \ + $(MAKE) -f Makefile-perl.mk clean ; \ + fi + $(RM) Makefile-perl.mk.old + $(RM) -r gen-perl gen-perl2 + +check-local: $(PERL_GEN) + $(PERL) -Iblib/lib -I@abs_srcdir@ -I@builddir@/gen-perl2 -I@builddir@/gen-perl \ + @abs_srcdir@/test.pl @abs_srcdir@/test/*.t + +$(THRIFTTEST_GEN): $(THRIFT_IF) $(THRIFT) + $(THRIFT) --gen perl $< + +$(BENCHMARK_GEN): $(NAME_BENCHMARKSERVICE) $(THRIFT) + $(THRIFT) --gen perl $< + +$(AGGR_GEN): $(NAME_AGGR) $(THRIFT) + $(MKDIR_P) gen-perl2 + $(THRIFT) -out gen-perl2 --gen perl $< + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/perl/README.md b/lib/perl/README.md new file mode 100644 index 0000000..bd1e5b2 --- /dev/null +++ b/lib/perl/README.md @@ -0,0 +1,124 @@ +Thrift Perl Software Library + +# Summary + +Apache Thrift is a software framework for scalable cross-language services development. +It combines a software stack with a code generation engine to build services that work +efficiently and seamlessly between many programming languages. A language-neutral IDL +is used to generate functioning client libraries and server-side handling frameworks. + +# License + +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + +# For More Information + +See the [Apache Thrift Web Site](http://thrift.apache.org/) for more information. + +# Using Thrift with Perl + +Thrift requires Perl >= 5.10.0 + +Unexpected exceptions in a service handler are converted to +TApplicationException with type INTERNAL ERROR and the string +of the exception is delivered as the message. + +On the client side, exceptions are thrown with die, so be sure +to wrap eval{} statments around any code that contains exceptions. + +Please see tutoral and test dirs for examples. + +The Perl ForkingServer ignores SIGCHLD allowing the forks to be +reaped by the operating system naturally when they exit. This means +one cannot use a custom SIGCHLD handler in the consuming perl +implementation that calls serve(). It is acceptable to use +a custom SIGCHLD handler within a thrift handler implementation +as the ForkingServer resets the forked child process to use +default signal handling. + +# Dependencies + +The following modules are not provided by Perl 5.10.0 but are required +to use Thrift. + +## Runtime + + * Bit::Vector + * Class::Accessor + +### HttpClient Transport + +These are only required if using Thrift::HttpClient: + + * HTTP::Request + * IO::String + * LWP::UserAgent + +### SSL/TLS + +These are only required if using Thrift::SSLSocket or Thrift::SSLServerSocket: + + * IO::Socket::SSL + +# Breaking Changes + +## 0.10.0 + +The socket classes were refactored in 0.10.0 so that there is one package per +file. This means `use Socket;` no longer defines SSLSocket. You can use this +technique to make your application run against 0.10.0 as well as earlier versions: + +`eval { require Thrift::SSLSocket; } or do { require Thrift::Socket; }` + +## 0.11.0 + + * Namespaces of packages that were not scoped within Thrift have been fixed. + ** TApplicationException is now Thrift::TApplicationException + ** TException is now Thrift::TException + ** TMessageType is now Thrift::TMessageType + ** TProtocolException is now Thrift::TProtocolException + ** TProtocolFactory is now Thrift::TProtocolFactory + ** TTransportException is now Thrift::TTransportException + ** TType is now Thrift::TType + +If you need a single version of your code to work with both older and newer thrift +namespace changes, you can make the new, correct namespaces behave like the old ones +in your files with this technique to create an alias, which will allow you code to +run against either version of the perl runtime for thrift: + +`BEGIN {*TType:: = *Thrift::TType::}` + + * Packages found in Thrift.pm were moved into the Thrift/ directory in separate files: + ** Thrift::TApplicationException is now in Thrift/Exception.pm + ** Thrift::TException is now in Thrift/Exception.pm + ** Thrift::TMessageType is now in Thrift/MessageType.pm + ** Thrift::TType is now in Thrift/Type.pm + +If you need to modify your code to work against both older or newer thrift versions, +you can deal with these changes in a backwards compatible way in your projects using eval: + +`eval { require Thrift::Exception; require Thrift::MessageType; require Thrift::Type; } + or do { require Thrift; }` + +# Deprecations + +## 0.11.0 + +Thrift::HttpClient setRecvTimeout() and setSendTimeout() are deprecated. +Use setTimeout instead. + diff --git a/lib/perl/build-cpan-dist.sh b/lib/perl/build-cpan-dist.sh new file mode 100755 index 0000000..1765e6d --- /dev/null +++ b/lib/perl/build-cpan-dist.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# +# This script is intended to be used after tagging the repository and updating +# the version files for a release. It will create a CPAN archive. + +perl Makefile.PL +make +make manifest +make dist diff --git a/lib/perl/coding_standards.md b/lib/perl/coding_standards.md new file mode 100644 index 0000000..e4e8255 --- /dev/null +++ b/lib/perl/coding_standards.md @@ -0,0 +1,2 @@ +Please follow [General Coding Standards](/doc/coding_standards.md). +Additional perl coding standards can be found in [perlstyle](http://perldoc.perl.org/perlstyle.html). diff --git a/lib/perl/lib/Thrift.pm b/lib/perl/lib/Thrift.pm new file mode 100644 index 0000000..cb62353 --- /dev/null +++ b/lib/perl/lib/Thrift.pm @@ -0,0 +1,36 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +# +# Versioning +# +# Every perl module for Thrift will have the same version +# declaration. For a production build, change it below to +# something like "v0.11.0" and all of the packages in all +# of the files will pick it up from here. +# + +package Thrift; +use version 0.77; our $VERSION = version->declare("v0.11.0"); + +1; diff --git a/lib/perl/lib/Thrift/BinaryProtocol.pm b/lib/perl/lib/Thrift/BinaryProtocol.pm new file mode 100644 index 0000000..61937e4 --- /dev/null +++ b/lib/perl/lib/Thrift/BinaryProtocol.pm @@ -0,0 +1,514 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Bit::Vector; +use Encode; +use Thrift; +use Thrift::Exception; +use Thrift::MessageType; +use Thrift::Protocol; +use Thrift::Type; +use utf8; + +# +# Binary implementation of the Thrift protocol. +# +package Thrift::BinaryProtocol; +use base('Thrift::Protocol'); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +use constant VERSION_MASK => 0xffff0000; +use constant VERSION_1 => 0x80010000; +use constant IS_BIG_ENDIAN => unpack("h*", pack("s", 1)) =~ /01/; + +sub new +{ + my $classname = shift; + my $trans = shift; + my $self = $classname->SUPER::new($trans); + + return bless($self,$classname); +} + +sub writeMessageBegin +{ + my $self = shift; + my ($name, $type, $seqid) = @_; + + return + $self->writeI32(VERSION_1 | $type) + + $self->writeString($name) + + $self->writeI32($seqid); +} + +sub writeMessageEnd +{ + my $self = shift; + return 0; +} + +sub writeStructBegin{ + my $self = shift; + my $name = shift; + return 0; +} + +sub writeStructEnd +{ + my $self = shift; + return 0; +} + +sub writeFieldBegin +{ + my $self = shift; + my ($fieldName, $fieldType, $fieldId) = @_; + + return + $self->writeByte($fieldType) + + $self->writeI16($fieldId); +} + +sub writeFieldEnd +{ + my $self = shift; + return 0; +} + +sub writeFieldStop +{ + my $self = shift; + return $self->writeByte(Thrift::TType::STOP); +} + +sub writeMapBegin +{ + my $self = shift; + my ($keyType, $valType, $size) = @_; + + return + $self->writeByte($keyType) + + $self->writeByte($valType) + + $self->writeI32($size); +} + +sub writeMapEnd +{ + my $self = shift; + return 0; +} + +sub writeListBegin +{ + my $self = shift; + my ($elemType, $size) = @_; + + return + $self->writeByte($elemType) + + $self->writeI32($size); +} + +sub writeListEnd +{ + my $self = shift; + return 0; +} + +sub writeSetBegin +{ + my $self = shift; + my ($elemType, $size) = @_; + + return + $self->writeByte($elemType) + + $self->writeI32($size); +} + +sub writeSetEnd +{ + my $self = shift; + return 0; +} + +sub writeBool +{ + my $self = shift; + my $value = shift; + + my $data = pack('c', $value ? 1 : 0); + $self->{trans}->write($data, 1); + return 1; +} + +sub writeByte +{ + my $self = shift; + my $value= shift; + + my $data = pack('c', $value); + $self->{trans}->write($data, 1); + return 1; +} + +sub writeI16 +{ + my $self = shift; + my $value= shift; + + my $data = pack('n', $value); + $self->{trans}->write($data, 2); + return 2; +} + +sub writeI32 +{ + my $self = shift; + my $value= shift; + + my $data = pack('N', $value); + $self->{trans}->write($data, 4); + return 4; +} + +sub writeI64 +{ + my $self = shift; + my $value= shift; + my $data; + + my $vec; + #stop annoying error + $vec = Bit::Vector->new_Dec(64, $value); + $data = pack 'NN', $vec->Chunk_Read(32, 32), $vec->Chunk_Read(32, 0); + + $self->{trans}->write($data, 8); + + return 8; +} + + +sub writeDouble +{ + my $self = shift; + my $value= shift; + + my $data = pack('d', $value); + if (IS_BIG_ENDIAN) { + $self->{trans}->write($data, 8); + } + else { + $self->{trans}->write(scalar reverse($data), 8); + } + return 8; +} + +sub writeString{ + my $self = shift; + my $value= shift; + + if( utf8::is_utf8($value) ){ + $value = Encode::encode_utf8($value); + } + + my $len = length($value); + + my $result = $self->writeI32($len); + + if ($len) { + $self->{trans}->write($value,$len); + } + return $result + $len; + } + + +# +#All references +# +sub readMessageBegin +{ + my $self = shift; + my ($name, $type, $seqid) = @_; + + my $version = 0; + my $result = $self->readI32(\$version); + if (($version & VERSION_MASK) > 0) { + if (($version & VERSION_MASK) != VERSION_1) { + die new Thrift::TProtocolException('Missing version identifier', + Thrift::TProtocolException::BAD_VERSION); + } + $$type = $version & 0x000000ff; + return + $result + + $self->readString($name) + + $self->readI32($seqid); + } else { # old client support code + return + $result + + $self->readStringBody($name, $version) + # version here holds the size of the string + $self->readByte($type) + + $self->readI32($seqid); + } +} + +sub readMessageEnd +{ + my $self = shift; + return 0; +} + +sub readStructBegin +{ + my $self = shift; + my $name = shift; + + $$name = ''; + + return 0; +} + +sub readStructEnd +{ + my $self = shift; + return 0; +} + +sub readFieldBegin +{ + my $self = shift; + my ($name, $fieldType, $fieldId) = @_; + + my $result = $self->readByte($fieldType); + + if ($$fieldType == Thrift::TType::STOP) { + $$fieldId = 0; + return $result; + } + + $result += $self->readI16($fieldId); + + return $result; +} + +sub readFieldEnd() { + my $self = shift; + return 0; +} + +sub readMapBegin +{ + my $self = shift; + my ($keyType, $valType, $size) = @_; + + return + $self->readByte($keyType) + + $self->readByte($valType) + + $self->readI32($size); +} + +sub readMapEnd() +{ + my $self = shift; + return 0; +} + +sub readListBegin +{ + my $self = shift; + my ($elemType, $size) = @_; + + return + $self->readByte($elemType) + + $self->readI32($size); +} + +sub readListEnd +{ + my $self = shift; + return 0; +} + +sub readSetBegin +{ + my $self = shift; + my ($elemType, $size) = @_; + + return + $self->readByte($elemType) + + $self->readI32($size); +} + +sub readSetEnd +{ + my $self = shift; + return 0; +} + +sub readBool +{ + my $self = shift; + my $value = shift; + + my $data = $self->{trans}->readAll(1); + my @arr = unpack('c', $data); + $$value = $arr[0] == 1; + return 1; +} + +sub readByte +{ + my $self = shift; + my $value = shift; + + my $data = $self->{trans}->readAll(1); + my @arr = unpack('c', $data); + $$value = $arr[0]; + return 1; +} + +sub readI16 +{ + my $self = shift; + my $value = shift; + + my $data = $self->{trans}->readAll(2); + + my @arr = unpack('n', $data); + + $$value = $arr[0]; + + if ($$value > 0x7fff) { + $$value = 0 - (($$value - 1) ^ 0xffff); + } + + return 2; +} + +sub readI32 +{ + my $self = shift; + my $value= shift; + + my $data = $self->{trans}->readAll(4); + my @arr = unpack('N', $data); + + $$value = $arr[0]; + if ($$value > 0x7fffffff) { + $$value = 0 - (($$value - 1) ^ 0xffffffff); + } + return 4; +} + +sub readI64 +{ + my $self = shift; + my $value = shift; + + my $data = $self->{trans}->readAll(8); + + my ($hi,$lo)=unpack('NN',$data); + + my $vec = new Bit::Vector(64); + + $vec->Chunk_Store(32,32,$hi); + $vec->Chunk_Store(32,0,$lo); + + $$value = $vec->to_Dec(); + + return 8; +} + +sub readDouble +{ + my $self = shift; + my $value = shift; + + my $data; + if (IS_BIG_ENDIAN) { + $data = $self->{trans}->readAll(8); + } + else { + $data = scalar reverse($self->{trans}->readAll(8)); + } + + my @arr = unpack('d', $data); + + $$value = $arr[0]; + + return 8; +} + +sub readString +{ + my $self = shift; + my $value = shift; + + my $len; + my $result = $self->readI32(\$len); + + if ($len) { + $$value = $self->{trans}->readAll($len); + } else { + $$value = ''; + } + + return $result + $len; +} + +sub readStringBody +{ + my $self = shift; + my $value = shift; + my $len = shift; + + if ($len) { + $$value = $self->{trans}->readAll($len); + } else { + $$value = ''; + } + + return $len; +} + +# +# Binary Protocol Factory +# +package Thrift::BinaryProtocolFactory; +use base('Thrift::TProtocolFactory'); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new +{ + my $classname = shift; + my $self = $classname->SUPER::new(); + + return bless($self,$classname); +} + +sub getProtocol{ + my $self = shift; + my $trans = shift; + + return new Thrift::BinaryProtocol($trans); +} + +1; diff --git a/lib/perl/lib/Thrift/BufferedTransport.pm b/lib/perl/lib/Thrift/BufferedTransport.pm new file mode 100644 index 0000000..6b5bf7a --- /dev/null +++ b/lib/perl/lib/Thrift/BufferedTransport.pm @@ -0,0 +1,139 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::Exception; +use Thrift::Transport; + +package Thrift::BufferedTransport; +use base('Thrift::Transport'); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new +{ + my $classname = shift; + my $transport = shift; + my $rBufSize = shift || 512; + my $wBufSize = shift || 512; + + my $self = { + transport => $transport, + rBufSize => $rBufSize, + wBufSize => $wBufSize, + wBuf => '', + rBuf => '', + }; + + return bless($self,$classname); +} + +sub isOpen +{ + my $self = shift; + + return $self->{transport}->isOpen(); +} + +sub open +{ + my $self = shift; + $self->{transport}->open(); +} + +sub close() +{ + my $self = shift; + $self->{transport}->close(); +} + +sub readAll +{ + my $self = shift; + my $len = shift; + + return $self->{transport}->readAll($len); +} + +sub read +{ + my $self = shift; + my $len = shift; + my $ret; + + # Methinks Perl is already buffering these for us + return $self->{transport}->read($len); +} + +sub write +{ + my $self = shift; + my $buf = shift; + + $self->{wBuf} .= $buf; + if (length($self->{wBuf}) >= $self->{wBufSize}) { + $self->{transport}->write($self->{wBuf}); + $self->{wBuf} = ''; + } +} + +sub flush +{ + my $self = shift; + + if (length($self->{wBuf}) > 0) { + $self->{transport}->write($self->{wBuf}); + $self->{wBuf} = ''; + } + $self->{transport}->flush(); +} + + +# +# BufferedTransport factory creates buffered transport objects from transports +# +package Thrift::BufferedTransportFactory; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new { + my $classname = shift; + my $self = {}; + + return bless($self,$classname); +} + +# +# Build a buffered transport from the base transport +# +# @return Thrift::BufferedTransport transport +# +sub getTransport +{ + my $self = shift; + my $trans = shift; + + my $buffered = Thrift::BufferedTransport->new($trans); + return $buffered; +} + + +1; diff --git a/lib/perl/lib/Thrift/Exception.pm b/lib/perl/lib/Thrift/Exception.pm new file mode 100644 index 0000000..5f0d8fb --- /dev/null +++ b/lib/perl/lib/Thrift/Exception.pm @@ -0,0 +1,160 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::Type; + +package Thrift::TException; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +use overload '""' => sub { + return + ref( $_[0] ) + . " error: " + . ( $_[0]->{message} || 'empty message' ) + . " (code " + . ( defined $_[0]->{code} ? $_[0]->{code} : 'undefined' ) . ")"; + }; + +sub new { + my $classname = shift; + my $self = {message => shift, code => shift || 0}; + + return bless($self,$classname); +} + +package Thrift::TApplicationException; +use parent -norequire, 'Thrift::TException'; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +use constant UNKNOWN => 0; +use constant UNKNOWN_METHOD => 1; +use constant INVALID_MESSAGE_TYPE => 2; +use constant WRONG_METHOD_NAME => 3; +use constant BAD_SEQUENCE_ID => 4; +use constant MISSING_RESULT => 5; +use constant INTERNAL_ERROR => 6; +use constant PROTOCOL_ERROR => 7; +use constant INVALID_TRANSFORM => 8; +use constant INVALID_PROTOCOL => 9; +use constant UNSUPPORTED_CLIENT_TYPE => 10; + +sub new { + my $classname = shift; + + my $self = $classname->SUPER::new(@_); + + return bless($self,$classname); +} + +sub read { + my $self = shift; + my $input = shift; + + my $xfer = 0; + my $fname = undef; + my $ftype = 0; + my $fid = 0; + + $xfer += $input->readStructBegin(\$fname); + + while (1) + { + $xfer += $input->readFieldBegin(\$fname, \$ftype, \$fid); + if ($ftype == Thrift::TType::STOP) { + last; next; + } + + SWITCH: for($fid) + { + /1/ && do{ + + if ($ftype == Thrift::TType::STRING) { + $xfer += $input->readString(\$self->{message}); + } else { + $xfer += $input->skip($ftype); + } + + last; + }; + + /2/ && do{ + if ($ftype == Thrift::TType::I32) { + $xfer += $input->readI32(\$self->{code}); + } else { + $xfer += $input->skip($ftype); + } + last; + }; + + $xfer += $input->skip($ftype); + } + + $xfer += $input->readFieldEnd(); + } + $xfer += $input->readStructEnd(); + + return $xfer; +} + +sub write { + my $self = shift; + my $output = shift; + + my $xfer = 0; + + $xfer += $output->writeStructBegin('TApplicationException'); + + if ($self->getMessage()) { + $xfer += $output->writeFieldBegin('message', Thrift::TType::STRING, 1); + $xfer += $output->writeString($self->getMessage()); + $xfer += $output->writeFieldEnd(); + } + + if ($self->getCode()) { + $xfer += $output->writeFieldBegin('type', Thrift::TType::I32, 2); + $xfer += $output->writeI32($self->getCode()); + $xfer += $output->writeFieldEnd(); + } + + $xfer += $output->writeFieldStop(); + $xfer += $output->writeStructEnd(); + + return $xfer; +} + +sub getMessage +{ + my $self = shift; + + return $self->{message}; +} + +sub getCode +{ + my $self = shift; + + return $self->{code}; +} + +1; diff --git a/lib/perl/lib/Thrift/FramedTransport.pm b/lib/perl/lib/Thrift/FramedTransport.pm new file mode 100644 index 0000000..ee842e6 --- /dev/null +++ b/lib/perl/lib/Thrift/FramedTransport.pm @@ -0,0 +1,194 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::Transport; + +# +# Framed transport. Writes and reads data in chunks that are stamped with +# their length. +# +# @package thrift.transport +# +package Thrift::FramedTransport; +use base('Thrift::Transport'); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new +{ + my $classname = shift; + my $transport = shift; + my $read = shift || 1; + my $write = shift || 1; + + my $self = { + transport => $transport, + read => $read, + write => $write, + wBuf => '', + rBuf => '', + }; + + return bless($self,$classname); +} + +sub isOpen +{ + my $self = shift; + return $self->{transport}->isOpen(); +} + +sub open +{ + my $self = shift; + + $self->{transport}->open(); +} + +sub close +{ + my $self = shift; + + if (defined $self->{transport}) { + $self->{transport}->close(); + } +} + +# +# Reads from the buffer. When more data is required reads another entire +# chunk and serves future reads out of that. +# +# @param int $len How much data +# +sub read +{ + + my $self = shift; + my $len = shift; + + if (!$self->{read}) { + return $self->{transport}->read($len); + } + + if (length($self->{rBuf}) == 0) { + $self->_readFrame(); + } + + + # Just return full buff + if ($len > length($self->{rBuf})) { + my $out = $self->{rBuf}; + $self->{rBuf} = ''; + return $out; + } + + # Return substr + my $out = substr($self->{rBuf}, 0, $len); + $self->{rBuf} = substr($self->{rBuf}, $len); + return $out; +} + +# +# Reads a chunk of data into the internal read buffer. +# (private) +sub _readFrame +{ + my $self = shift; + my $buf = $self->{transport}->readAll(4); + my @val = unpack('N', $buf); + my $sz = $val[0]; + + $self->{rBuf} = $self->{transport}->readAll($sz); +} + +# +# Writes some data to the pending output buffer. +# +# @param string $buf The data +# @param int $len Limit of bytes to write +# +sub write +{ + my $self = shift; + my $buf = shift; + my $len = shift; + + unless($self->{write}) { + return $self->{transport}->write($buf, $len); + } + + if ( defined $len && $len < length($buf)) { + $buf = substr($buf, 0, $len); + } + + $self->{wBuf} .= $buf; + } + +# +# Writes the output buffer to the stream in the format of a 4-byte length +# followed by the actual data. +# +sub flush +{ + my $self = shift; + + unless ($self->{write}) { + return $self->{transport}->flush(); + } + + my $out = pack('N', length($self->{wBuf})); + $out .= $self->{wBuf}; + $self->{transport}->write($out); + $self->{transport}->flush(); + $self->{wBuf} = ''; + +} + +# +# FramedTransport factory creates framed transport objects from transports +# +package Thrift::FramedTransportFactory; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new { + my $classname = shift; + my $self = {}; + + return bless($self, $classname); +} + +# +# Build a framed transport from the base transport +# +# @return Thrift::FramedTransport transport +# +sub getTransport +{ + my $self = shift; + my $trans = shift; + + my $buffered = Thrift::FramedTransport->new($trans); + return $buffered; +} + +1; diff --git a/lib/perl/lib/Thrift/HttpClient.pm b/lib/perl/lib/Thrift/HttpClient.pm new file mode 100644 index 0000000..6e6a631 --- /dev/null +++ b/lib/perl/lib/Thrift/HttpClient.pm @@ -0,0 +1,203 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use HTTP::Request; +use IO::String; +use LWP::UserAgent; +use Thrift; +use Thrift::Exception; +use Thrift::Transport; + +package Thrift::HttpClient; +use base('Thrift::Transport'); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new +{ + my $classname = shift; + my $url = shift || 'http://localhost:9090'; + + my $out = IO::String->new; + binmode($out); + + my $self = { + url => $url, + out => $out, + timeout => 100, + handle => undef, + headers => {}, + }; + + return bless($self,$classname); +} + +sub setTimeout +{ + my $self = shift; + my $timeout = shift; + + $self->{timeout} = $timeout; +} + +sub setRecvTimeout +{ + warn "setRecvTimeout is deprecated - use setTimeout instead"; + # note: recvTimeout was never used so we do not need to do anything here +} + +sub setSendTimeout +{ + my $self = shift; + my $timeout = shift; + + warn "setSendTimeout is deprecated - use setTimeout instead"; + + $self->setTimeout($timeout); +} + +sub setHeader +{ + my $self = shift; + my ($name, $value) = @_; + + $self->{headers}->{$name} = $value; +} + +# +# Tests whether this is open +# +# @return bool true if the socket is open +# +sub isOpen +{ + return 1; +} + +sub open {} + +# +# Cleans up the buffer. +# +sub close +{ + my $self = shift; + if (defined($self->{io})) { + close($self->{io}); + $self->{io} = undef; + } +} + +# +# Guarantees that the full amount of data is read. +# +# @return string The data, of exact length +# @throws TTransportException if cannot read data +# +sub readAll +{ + my $self = shift; + my $len = shift; + + my $buf = $self->read($len); + + if (!defined($buf)) { + die new Thrift::TTransportException("TSocket: Could not read $len bytes from input buffer", + Thrift::TTransportException::END_OF_FILE); + } + return $buf; +} + +# +# Read and return string +# +sub read +{ + my $self = shift; + my $len = shift; + + my $buf; + + my $in = $self->{in}; + + if (!defined($in)) { + die new Thrift::TTransportException("Response buffer is empty, no request.", + Thrift::TTransportException::END_OF_FILE); + } + eval { + my $ret = sysread($in, $buf, $len); + if (! defined($ret)) { + die new Thrift::TTransportException("No more data available.", + Thrift::TTransportException::TIMED_OUT); + } + }; if($@){ + die new Thrift::TTransportException("$@", Thrift::TTransportException::UNKNOWN); + } + + return $buf; +} + +# +# Write string +# +sub write +{ + my $self = shift; + my $buf = shift; + $self->{out}->print($buf); +} + +# +# Flush output (do the actual HTTP/HTTPS request) +# +sub flush +{ + my $self = shift; + + my $ua = LWP::UserAgent->new('timeout' => ($self->{timeout} / 1000), + 'agent' => 'Perl/THttpClient' + ); + $ua->default_header('Accept' => 'application/x-thrift'); + $ua->default_header('Content-Type' => 'application/x-thrift'); + $ua->cookie_jar({}); # hash to remember cookies between redirects + + my $out = $self->{out}; + $out->setpos(0); # rewind + my $buf = join('', <$out>); + + my $request = new HTTP::Request(POST => $self->{url}, undef, $buf); + map { $request->header($_ => $self->{headers}->{$_}) } keys %{$self->{headers}}; + my $response = $ua->request($request); + my $content_ref = $response->content_ref; + + my $in = IO::String->new($content_ref); + binmode($in); + $self->{in} = $in; + $in->setpos(0); # rewind + + # reset write buffer + $out = IO::String->new; + binmode($out); + $self->{out} = $out; +} + +1; diff --git a/lib/perl/lib/Thrift/MemoryBuffer.pm b/lib/perl/lib/Thrift/MemoryBuffer.pm new file mode 100644 index 0000000..1e51239 --- /dev/null +++ b/lib/perl/lib/Thrift/MemoryBuffer.pm @@ -0,0 +1,148 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::Transport; + +package Thrift::MemoryBuffer; +use base('Thrift::Transport'); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new +{ + my $classname = shift; + + my $bufferSize= shift || 1024; + + my $self = { + buffer => '', + bufferSize=> $bufferSize, + wPos => 0, + rPos => 0, + }; + + return bless($self,$classname); +} + +sub isOpen +{ + return 1; +} + +sub open +{ + +} + +sub close +{ + +} + +sub peek +{ + my $self = shift; + return($self->{rPos} < $self->{wPos}); +} + + +sub getBuffer +{ + my $self = shift; + return $self->{buffer}; +} + +sub resetBuffer +{ + my $self = shift; + + my $new_buffer = shift || ''; + + $self->{buffer} = $new_buffer; + $self->{bufferSize} = length($new_buffer); + $self->{wPos} = length($new_buffer); + $self->{rPos} = 0; +} + +sub available +{ + my $self = shift; + return ($self->{wPos} - $self->{rPos}); +} + +sub read +{ + my $self = shift; + my $len = shift; + my $ret; + + my $avail = ($self->{wPos} - $self->{rPos}); + return '' if $avail == 0; + + #how much to give + my $give = $len; + $give = $avail if $avail < $len; + + $ret = substr($self->{buffer},$self->{rPos},$give); + + $self->{rPos} += $give; + + return $ret; +} + +sub readAll +{ + my $self = shift; + my $len = shift; + + my $avail = ($self->{wPos} - $self->{rPos}); + if ($avail < $len) { + die new TTransportException("Attempt to readAll($len) found only $avail available", + Thrift::TTransportException::END_OF_FILE); + } + + my $data = ''; + my $got = 0; + + while (($got = length($data)) < $len) { + $data .= $self->read($len - $got); + } + + return $data; +} + +sub write +{ + my $self = shift; + my $buf = shift; + + $self->{buffer} .= $buf; + $self->{wPos} += length($buf); +} + +sub flush +{ + +} + +1; diff --git a/lib/perl/lib/Thrift/MessageType.pm b/lib/perl/lib/Thrift/MessageType.pm new file mode 100644 index 0000000..d25c2f7 --- /dev/null +++ b/lib/perl/lib/Thrift/MessageType.pm @@ -0,0 +1,37 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; + +# +# Message types for RPC +# +package Thrift::TMessageType; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +use constant CALL => 1; +use constant REPLY => 2; +use constant EXCEPTION => 3; +use constant ONEWAY => 4; + +1; diff --git a/lib/perl/lib/Thrift/MultiplexedProcessor.pm b/lib/perl/lib/Thrift/MultiplexedProcessor.pm new file mode 100644 index 0000000..05c4ead --- /dev/null +++ b/lib/perl/lib/Thrift/MultiplexedProcessor.pm @@ -0,0 +1,133 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::MessageType; +use Thrift::MultiplexedProtocol; +use Thrift::Protocol; +use Thrift::ProtocolDecorator; + +package Thrift::StoredMessageProtocol; +use base qw(Thrift::ProtocolDecorator); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new { + my $classname = shift; + my $protocol = shift; + my $fname = shift; + my $mtype = shift; + my $rseqid = shift; + my $self = $classname->SUPER::new($protocol); + + $self->{fname} = $fname; + $self->{mtype} = $mtype; + $self->{rseqid} = $rseqid; + + return bless($self,$classname); +} + +sub readMessageBegin +{ + my $self = shift; + my $name = shift; + my $type = shift; + my $seqid = shift; + + $$name = $self->{fname}; + $$type = $self->{mtype}; + $$seqid = $self->{rseqid}; +} + +package Thrift::MultiplexedProcessor; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new { + my $classname = shift; + my $self = {}; + + $self->{serviceProcessorMap} = {}; + $self->{defaultProcessor} = undef; + + return bless($self,$classname); +} + +sub defaultProcessor { + my $self = shift; + my $processor = shift; + + $self->{defaultProcessor} = $processor; +} + +sub registerProcessor { + my $self = shift; + my $serviceName = shift; + my $processor = shift; + + $self->{serviceProcessorMap}->{$serviceName} = $processor; +} + +sub process { + my $self = shift; + my $input = shift; + my $output = shift; + + # + # Use the actual underlying protocol (e.g. BinaryProtocol) to read the + # message header. This pulls the message "off the wire", which we'll + # deal with at the end of this method. + # + + my ($fname, $mtype, $rseqid); + $input->readMessageBegin(\$fname, \$mtype, \$rseqid); + + if ($mtype ne Thrift::TMessageType::CALL && $mtype ne Thrift::TMessageType::ONEWAY) { + die new Thrift::TException("This should not have happened!?"); + } + + # Extract the service name and the new Message name. + if (index($fname, Thrift::MultiplexedProtocol::SEPARATOR) == -1) { + if (defined $self->{defaultProcessor}) { + return $self->{defaultProcessor}->process( + new Thrift::StoredMessageProtocol($input, $fname, $mtype, $rseqid), $output + ); + } else { + die new Thrift::TException("Service name not found in message name: {$fname} and no default processor defined. Did you " . + "forget to use a MultiplexProtocol in your client?"); + } + } + + (my $serviceName, my $messageName) = split(':', $fname, 2); + + if (!exists($self->{serviceProcessorMap}->{$serviceName})) { + die new Thrift::TException("Service name not found: {$serviceName}. Did you forget " . + "to call registerProcessor()?"); + } + + # Dispatch processing to the stored processor + my $processor = $self->{serviceProcessorMap}->{$serviceName}; + return $processor->process( + new Thrift::StoredMessageProtocol($input, $messageName, $mtype, $rseqid), $output + ); +} + +1; diff --git a/lib/perl/lib/Thrift/MultiplexedProtocol.pm b/lib/perl/lib/Thrift/MultiplexedProtocol.pm new file mode 100644 index 0000000..903211f --- /dev/null +++ b/lib/perl/lib/Thrift/MultiplexedProtocol.pm @@ -0,0 +1,68 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::MessageType; +use Thrift::Protocol; +use Thrift::ProtocolDecorator; + +package Thrift::MultiplexedProtocol; +use base qw(Thrift::ProtocolDecorator); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +use constant SEPARATOR => ':'; + +sub new { + my $classname = shift; + my $protocol = shift; + my $serviceName = shift; + my $self = $classname->SUPER::new($protocol); + + $self->{serviceName} = $serviceName; + + return bless($self,$classname); +} + +# +# Writes the message header. +# Prepends the service name to the function name, separated by MultiplexedProtocol::SEPARATOR. +# +# @param string $name Function name. +# @param int $type Message type. +# @param int $seqid The sequence id of this message. +# +sub writeMessageBegin +{ + my $self = shift; + my ($name, $type, $seqid) = @_; + + if ($type == Thrift::TMessageType::CALL || $type == Thrift::TMessageType::ONEWAY) { + my $nameWithService = $self->{serviceName}.SEPARATOR.$name; + $self->SUPER::writeMessageBegin($nameWithService, $type, $seqid); + } + else { + $self->SUPER::writeMessageBegin($name, $type, $seqid); + } +} + +1; diff --git a/lib/perl/lib/Thrift/Protocol.pm b/lib/perl/lib/Thrift/Protocol.pm new file mode 100644 index 0000000..c681f60 --- /dev/null +++ b/lib/perl/lib/Thrift/Protocol.pm @@ -0,0 +1,549 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::Exception; +use Thrift::Type; + +# +# Protocol exceptions +# +package Thrift::TProtocolException; +use base('Thrift::TException'); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +use constant UNKNOWN => 0; +use constant INVALID_DATA => 1; +use constant NEGATIVE_SIZE => 2; +use constant SIZE_LIMIT => 3; +use constant BAD_VERSION => 4; +use constant NOT_IMPLEMENTED => 5; +use constant DEPTH_LIMIT => 6; + +sub new { + my $classname = shift; + + my $self = $classname->SUPER::new(); + + return bless($self,$classname); +} + +# +# Protocol base class module. +# +package Thrift::Protocol; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new { + my $classname = shift; + my $self = {}; + + my $trans = shift; + $self->{trans}= $trans; + + return bless($self,$classname); +} + +sub getTransport +{ + my $self = shift; + + return $self->{trans}; +} + +# +# Writes the message header +# +# @param string $name Function name +# @param int $type message type TMessageType::CALL or TMessageType::REPLY +# @param int $seqid The sequence id of this message +# +sub writeMessageBegin +{ + my ($name, $type, $seqid); + die "abstract"; +} + +# +# Close the message +# +sub writeMessageEnd { + die "abstract"; +} + +# +# Writes a struct header. +# +# @param string $name Struct name +# @throws TProtocolException on write error +# @return int How many bytes written +# +sub writeStructBegin { + my ($name); + + die "abstract"; +} + +# +# Close a struct. +# +# @throws TProtocolException on write error +# @return int How many bytes written +# +sub writeStructEnd { + die "abstract"; +} + +# +# Starts a field. +# +# @param string $name Field name +# @param int $type Field type +# @param int $fid Field id +# @throws TProtocolException on write error +# @return int How many bytes written +# +sub writeFieldBegin { + my ($fieldName, $fieldType, $fieldId); + + die "abstract"; +} + +sub writeFieldEnd { + die "abstract"; +} + +sub writeFieldStop { + die "abstract"; +} + +sub writeMapBegin { + my ($keyType, $valType, $size); + + die "abstract"; +} + +sub writeMapEnd { + die "abstract"; +} + +sub writeListBegin { + my ($elemType, $size); + die "abstract"; +} + +sub writeListEnd { + die "abstract"; +} + +sub writeSetBegin { + my ($elemType, $size); + die "abstract"; +} + +sub writeSetEnd { + die "abstract"; +} + +sub writeBool { + my ($bool); + die "abstract"; +} + +sub writeByte { + my ($byte); + die "abstract"; +} + +sub writeI16 { + my ($i16); + die "abstract"; +} + +sub writeI32 { + my ($i32); + die "abstract"; +} + +sub writeI64 { + my ($i64); + die "abstract"; +} + +sub writeDouble { + my ($dub); + die "abstract"; +} + +sub writeString +{ + my ($str); + die "abstract"; +} + +# +# Reads the message header +# +# @param string $name Function name +# @param int $type message type TMessageType::CALL or TMessageType::REPLY +# @parem int $seqid The sequence id of this message +# +sub readMessageBegin +{ + my ($name, $type, $seqid); + die "abstract"; +} + +# +# Read the close of message +# +sub readMessageEnd +{ + die "abstract"; +} + +sub readStructBegin +{ + my($name); + + die "abstract"; +} + +sub readStructEnd +{ + die "abstract"; +} + +sub readFieldBegin +{ + my ($name, $fieldType, $fieldId); + die "abstract"; +} + +sub readFieldEnd +{ + die "abstract"; +} + +sub readMapBegin +{ + my ($keyType, $valType, $size); + die "abstract"; +} + +sub readMapEnd +{ + die "abstract"; +} + +sub readListBegin +{ + my ($elemType, $size); + die "abstract"; +} + +sub readListEnd +{ + die "abstract"; +} + +sub readSetBegin +{ + my ($elemType, $size); + die "abstract"; +} + +sub readSetEnd +{ + die "abstract"; +} + +sub readBool +{ + my ($bool); + die "abstract"; +} + +sub readByte +{ + my ($byte); + die "abstract"; +} + +sub readI16 +{ + my ($i16); + die "abstract"; +} + +sub readI32 +{ + my ($i32); + die "abstract"; +} + +sub readI64 +{ + my ($i64); + die "abstract"; +} + +sub readDouble +{ + my ($dub); + die "abstract"; +} + +sub readString +{ + my ($str); + die "abstract"; +} + +# +# The skip function is a utility to parse over unrecognized data without +# causing corruption. +# +# @param TType $type What type is it +# +sub skip +{ + my $self = shift; + my $type = shift; + + my $ref; + my $result; + my $i; + + if($type == Thrift::TType::BOOL) + { + return $self->readBool(\$ref); + } + elsif($type == Thrift::TType::BYTE){ + return $self->readByte(\$ref); + } + elsif($type == Thrift::TType::I16){ + return $self->readI16(\$ref); + } + elsif($type == Thrift::TType::I32){ + return $self->readI32(\$ref); + } + elsif($type == Thrift::TType::I64){ + return $self->readI64(\$ref); + } + elsif($type == Thrift::TType::DOUBLE){ + return $self->readDouble(\$ref); + } + elsif($type == Thrift::TType::STRING) + { + return $self->readString(\$ref); + } + elsif($type == Thrift::TType::STRUCT) + { + $result = $self->readStructBegin(\$ref); + while (1) { + my ($ftype,$fid); + $result += $self->readFieldBegin(\$ref, \$ftype, \$fid); + if ($ftype == Thrift::TType::STOP) { + last; + } + $result += $self->skip($ftype); + $result += $self->readFieldEnd(); + } + $result += $self->readStructEnd(); + return $result; + } + elsif($type == Thrift::TType::MAP) + { + my($keyType,$valType,$size); + $result = $self->readMapBegin(\$keyType, \$valType, \$size); + for ($i = 0; $i < $size; $i++) { + $result += $self->skip($keyType); + $result += $self->skip($valType); + } + $result += $self->readMapEnd(); + return $result; + } + elsif($type == Thrift::TType::SET) + { + my ($elemType,$size); + $result = $self->readSetBegin(\$elemType, \$size); + for ($i = 0; $i < $size; $i++) { + $result += $self->skip($elemType); + } + $result += $self->readSetEnd(); + return $result; + } + elsif($type == Thrift::TType::LIST) + { + my ($elemType,$size); + $result = $self->readListBegin(\$elemType, \$size); + for ($i = 0; $i < $size; $i++) { + $result += $self->skip($elemType); + } + $result += $self->readListEnd(); + return $result; + } + + die new Thrift::TProtocolException("Type $type not recognized --- corrupt data?", + Thrift::TProtocolException::INVALID_DATA); + + } + +# +# Utility for skipping binary data +# +# @param TTransport $itrans TTransport object +# @param int $type Field type +# +sub skipBinary +{ + my $self = shift; + my $itrans = shift; + my $type = shift; + + if($type == Thrift::TType::BOOL) + { + return $itrans->readAll(1); + } + elsif($type == Thrift::TType::BYTE) + { + return $itrans->readAll(1); + } + elsif($type == Thrift::TType::I16) + { + return $itrans->readAll(2); + } + elsif($type == Thrift::TType::I32) + { + return $itrans->readAll(4); + } + elsif($type == Thrift::TType::I64) + { + return $itrans->readAll(8); + } + elsif($type == Thrift::TType::DOUBLE) + { + return $itrans->readAll(8); + } + elsif( $type == Thrift::TType::STRING ) + { + my @len = unpack('N', $itrans->readAll(4)); + my $len = $len[0]; + if ($len > 0x7fffffff) { + $len = 0 - (($len - 1) ^ 0xffffffff); + } + return 4 + $itrans->readAll($len); + } + elsif( $type == Thrift::TType::STRUCT ) + { + my $result = 0; + while (1) { + my $ftype = 0; + my $fid = 0; + my $data = $itrans->readAll(1); + my @arr = unpack('c', $data); + $ftype = $arr[0]; + if ($ftype == Thrift::TType::STOP) { + last; + } + # I16 field id + $result += $itrans->readAll(2); + $result += $self->skipBinary($itrans, $ftype); + } + return $result; + } + elsif($type == Thrift::TType::MAP) + { + # Ktype + my $data = $itrans->readAll(1); + my @arr = unpack('c', $data); + my $ktype = $arr[0]; + # Vtype + $data = $itrans->readAll(1); + @arr = unpack('c', $data); + my $vtype = $arr[0]; + # Size + $data = $itrans->readAll(4); + @arr = unpack('N', $data); + my $size = $arr[0]; + if ($size > 0x7fffffff) { + $size = 0 - (($size - 1) ^ 0xffffffff); + } + my $result = 6; + for (my $i = 0; $i < $size; $i++) { + $result += $self->skipBinary($itrans, $ktype); + $result += $self->skipBinary($itrans, $vtype); + } + return $result; + } + elsif($type == Thrift::TType::SET || $type == Thrift::TType::LIST) + { + # Vtype + my $data = $itrans->readAll(1); + my @arr = unpack('c', $data); + my $vtype = $arr[0]; + # Size + $data = $itrans->readAll(4); + @arr = unpack('N', $data); + my $size = $arr[0]; + if ($size > 0x7fffffff) { + $size = 0 - (($size - 1) ^ 0xffffffff); + } + my $result = 5; + for (my $i = 0; $i < $size; $i++) { + $result += $self->skipBinary($itrans, $vtype); + } + return $result; + } + + die new Thrift::TProtocolException("Type $type not recognized --- corrupt data?", + Thrift::TProtocolException::INVALID_DATA); +} + +# +# Protocol factory creates protocol objects from transports +# +package Thrift::TProtocolFactory; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new { + my $classname = shift; + my $self = {}; + + return bless($self,$classname); +} + +# +# Build a protocol from the base transport +# +# @return TProtcol protocol +# +sub getProtocol +{ + my ($trans); + die "interface"; +} + + +1; diff --git a/lib/perl/lib/Thrift/ProtocolDecorator.pm b/lib/perl/lib/Thrift/ProtocolDecorator.pm new file mode 100644 index 0000000..cc5c9da --- /dev/null +++ b/lib/perl/lib/Thrift/ProtocolDecorator.pm @@ -0,0 +1,363 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::Protocol; + +package Thrift::ProtocolDecorator; +use base qw(Thrift::Protocol); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new { + my $classname = shift; + my $protocol = shift; + my $self = $classname->SUPER::new($protocol->getTransport()); + + $self->{concreteProtocol} = $protocol; + + return bless($self,$classname); +} + +# +# Writes the message header +# +# @param string $name Function name +# @param int $type message type TMessageType::CALL or TMessageType::REPLY +# @param int $seqid The sequence id of this message +# +sub writeMessageBegin { + my $self = shift; + my ($name, $type, $seqid) = @_; + + return $self->{concreteProtocol}->writeMessageBegin($name, $type, $seqid); +} + +# +# Close the message +# +sub writeMessageEnd { + my $self = shift; + + return $self->{concreteProtocol}->writeMessageEnd(); +} + +# +# Writes a struct header. +# +# @param string $name Struct name +# @throws TException on write error +# @return int How many bytes written +# +sub writeStructBegin { + my $self = shift; + my ($name) = @_; + + return $self->{concreteProtocol}->writeStructBegin($name); +} + +# +# Close a struct. +# +# @throws TException on write error +# @return int How many bytes written +# +sub writeStructEnd { + my $self = shift; + + return $self->{concreteProtocol}->writeStructEnd(); +} + +# +# Starts a field. +# +# @param string $name Field name +# @param int $type Field type +# @param int $fid Field id +# @throws TException on write error +# @return int How many bytes written +# +sub writeFieldBegin { + my $self = shift; + my ($fieldName, $fieldType, $fieldId) = @_; + + return $self->{concreteProtocol}->writeFieldBegin($fieldName, $fieldType, $fieldId); +} + +sub writeFieldEnd { + my $self = shift; + + return $self->{concreteProtocol}->writeFieldEnd(); +} + +sub writeFieldStop { + my $self = shift; + + return $self->{concreteProtocol}->writeFieldStop(); +} + +sub writeMapBegin { + my $self = shift; + my ($keyType, $valType, $size) = @_; + + return $self->{concreteProtocol}->writeMapBegin($keyType, $valType, $size); +} + +sub writeMapEnd { + my $self = shift; + + return $self->{concreteProtocol}->writeMapEnd(); +} + +sub writeListBegin { + my $self = shift; + my ($elemType, $size) = @_; + + return $self->{concreteProtocol}->writeListBegin($elemType, $size); +} + +sub writeListEnd { + my $self = shift; + + return $self->{concreteProtocol}->writeListEnd(); +} + +sub writeSetBegin { + my $self = shift; + my ($elemType, $size) = @_; + + return $self->{concreteProtocol}->writeSetBegin($elemType, $size); +} + +sub writeSetEnd { + my $self = shift; + + return $self->{concreteProtocol}->writeListEnd(); +} + +sub writeBool { + my $self = shift; + my $bool = shift; + + return $self->{concreteProtocol}->writeBool($bool); +} + +sub writeByte { + my $self = shift; + my $byte = shift; + + return $self->{concreteProtocol}->writeByte($byte); +} + +sub writeI16 { + my $self = shift; + my $i16 = shift; + + return $self->{concreteProtocol}->writeI16($i16); +} + +sub writeI32 { + my $self = shift; + my ($i32) = @_; + + return $self->{concreteProtocol}->writeI32($i32); + +} + +sub writeI64 { + my $self = shift; + my $i64 = shift; + + return $self->{concreteProtocol}->writeI64($i64); +} + +sub writeDouble { + my $self = shift; + my $dub = shift; + + return $self->{concreteProtocol}->writeDouble($dub); +} + +sub writeString { + my $self = shift; + my $str = shift; + + return $self->{concreteProtocol}->writeString($str); +} + +# +# Reads the message header +# +# @param string $name Function name +# @param int $type message type TMessageType::CALL or TMessageType::REPLY +# @parem int $seqid The sequence id of this message +# +sub readMessageBegin +{ + my $self = shift; + my ($name, $type, $seqid) = @_; + + return $self->{concreteProtocol}->readMessageBegin($name, $type, $seqid); +} + +# +# Read the close of message +# +sub readMessageEnd +{ + my $self = shift; + + return $self->{concreteProtocol}->readMessageEnd(); +} + +sub readStructBegin +{ + my $self = shift; + my $name = shift; + + return $self->{concreteProtocol}->readStructBegin($name); +} + +sub readStructEnd +{ + my $self = shift; + + return $self->{concreteProtocol}->readStructEnd(); +} + +sub readFieldBegin +{ + my $self = shift; + my ($name, $fieldType, $fieldId) = @_; + + return $self->{concreteProtocol}->readFieldBegin($name, $fieldType, $fieldId); +} + +sub readFieldEnd +{ + my $self = shift; + + return $self->{concreteProtocol}->readFieldEnd(); +} + +sub readMapBegin +{ + my $self = shift; + my ($keyType, $valType, $size) = @_; + + return $self->{concreteProtocol}->readMapBegin($keyType, $valType, $size); +} + +sub readMapEnd +{ + my $self = shift; + + return $self->{concreteProtocol}->readMapEnd(); +} + +sub readListBegin +{ + my $self = shift; + my ($elemType, $size) = @_; + + return $self->{concreteProtocol}->readListBegin($elemType, $size); +} + +sub readListEnd +{ + my $self = shift; + + return $self->{concreteProtocol}->readListEnd(); +} + +sub readSetBegin +{ + my $self = shift; + my ($elemType, $size) = @_; + + return $self->{concreteProtocol}->readSetBegin($elemType, $size); +} + +sub readSetEnd +{ + my $self = shift; + + return $self->{concreteProtocol}->readSetEnd(); +} + +sub readBool +{ + my $self = shift; + my $bool = shift; + + return $self->{concreteProtocol}->readBool($bool); +} + +sub readByte +{ + my $self = shift; + my $byte = shift; + + return $self->{concreteProtocol}->readByte($byte); +} + +sub readI16 +{ + my $self = shift; + my $i16 = shift; + + return $self->{concreteProtocol}->readI16($i16); +} + +sub readI32 +{ + my $self = shift; + my $i32 = shift; + + return $self->{concreteProtocol}->readI32($i32); +} + +sub readI64 +{ + my $self = shift; + my $i64 = shift; + + return $self->{concreteProtocol}->readI64($i64); +} + +sub readDouble +{ + my $self = shift; + my $dub = shift; + + return $self->{concreteProtocol}->readDouble($dub); +} + +sub readString +{ + my $self = shift; + my $str = shift; + + return $self->{concreteProtocol}->readString($str); +} + +1; diff --git a/lib/perl/lib/Thrift/SSLServerSocket.pm b/lib/perl/lib/Thrift/SSLServerSocket.pm new file mode 100644 index 0000000..d29671b --- /dev/null +++ b/lib/perl/lib/Thrift/SSLServerSocket.pm @@ -0,0 +1,76 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::SSLSocket; +use Thrift::ServerSocket; + +use IO::Socket::SSL; + +package Thrift::SSLServerSocket; +use base qw( Thrift::ServerSocket ); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +# +# Constructor. +# Takes a hash: +# See Thrift::Socket for base class parameters. +# @param[in] ca certificate authority filename - not required +# @param[in] cert certificate filename; may contain key in which case key is not required +# @param[in] key private key filename for the certificate if it is not inside the cert file +# +sub new +{ + my $classname = shift; + my $self = $classname->SUPER::new(@_); + return bless($self, $classname); +} + +sub __client +{ + return new Thrift::SSLSocket(); +} + +sub __listen +{ + my $self = shift; + my $opts = {Listen => $self->{queue}, + LocalAddr => $self->{host}, + LocalPort => $self->{port}, + Proto => 'tcp', + ReuseAddr => 1}; + + my $verify = IO::Socket::SSL::SSL_VERIFY_PEER | IO::Socket::SSL::SSL_VERIFY_FAIL_IF_NO_PEER_CERT | IO::Socket::SSL::SSL_VERIFY_CLIENT_ONCE; + + $opts->{SSL_ca_file} = $self->{ca} if defined $self->{ca}; + $opts->{SSL_cert_file} = $self->{cert} if defined $self->{cert}; + $opts->{SSL_cipher_list} = $self->{ciphers} if defined $self->{ciphers}; + $opts->{SSL_key_file} = $self->{key} if defined $self->{key}; + $opts->{SSL_use_cert} = (defined $self->{cert}) ? 1 : 0; + $opts->{SSL_verify_mode} = (defined $self->{ca}) ? $verify : IO::Socket::SSL::SSL_VERIFY_NONE; + $opts->{SSL_version} = (defined $self->{version}) ? $self->{version} : 'SSLv23:!SSLv3:!SSLv2'; + + return IO::Socket::SSL->new(%$opts); +} + +1; diff --git a/lib/perl/lib/Thrift/SSLSocket.pm b/lib/perl/lib/Thrift/SSLSocket.pm new file mode 100644 index 0000000..4bdf637 --- /dev/null +++ b/lib/perl/lib/Thrift/SSLSocket.pm @@ -0,0 +1,126 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::Socket; + +use IO::Socket::SSL; + +package Thrift::SSLSocket; +use base qw( Thrift::Socket ); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +# +# Construction and usage +# +# my $opts = {} +# my $socket = new Thrift::SSLSocket(\%opts); +# +# options: +# +# Any option from Socket.pm is valid, and then: +# +# ca => certificate authority file (PEM file) to authenticate the +# server against; if not specified then the server is not +# authenticated +# cert => certificate to use as the client; if not specified then +# the client does not present one but still connects using +# secure protocol +# ciphers => allowed cipher list +# (see http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS) +# key => certificate key for "cert" option +# version => acceptable SSL/TLS versions - if not specified then the +# default is to use SSLv23 handshake but only negotiate +# at TLSv1.0 or later +# + +sub new +{ + my $classname = shift; + my $self = $classname->SUPER::new(@_); + + return bless($self, $classname); +} + +sub __open +{ + my $self = shift; + my $opts = {PeerAddr => $self->{host}, + PeerPort => $self->{port}, + Proto => 'tcp', + Timeout => $self->{sendTimeout} / 1000}; + + my $verify = IO::Socket::SSL::SSL_VERIFY_PEER | IO::Socket::SSL::SSL_VERIFY_FAIL_IF_NO_PEER_CERT | IO::Socket::SSL::SSL_VERIFY_CLIENT_ONCE; + + $opts->{SSL_ca_file} = $self->{ca} if defined $self->{ca}; + $opts->{SSL_cert_file} = $self->{cert} if defined $self->{cert}; + $opts->{SSL_cipher_list} = $self->{ciphers} if defined $self->{ciphers}; + $opts->{SSL_key_file} = $self->{key} if defined $self->{key}; + $opts->{SSL_use_cert} = (defined $self->{cert}) ? 1 : 0; + $opts->{SSL_verify_mode} = (defined $self->{ca}) ? $verify : IO::Socket::SSL::SSL_VERIFY_NONE; + $opts->{SSL_version} = (defined $self->{version}) ? $self->{version} : 'SSLv23:!SSLv3:!SSLv2'; + + return IO::Socket::SSL->new(%$opts); +} + +sub __close +{ + my $self = shift; + my $sock = ($self->{handle}->handles())[0]; + if ($sock) { + $sock->close(SSL_no_shutdown => 1); + } +} + +sub __recv +{ + my $self = shift; + my $sock = shift; + my $len = shift; + my $buf = undef; + if ($sock) { + sysread($sock, $buf, $len); + } + return $buf; +} + +sub __send +{ + my $self = shift; + my $sock = shift; + my $buf = shift; + return syswrite($sock, $buf); +} + +sub __wait +{ + my $self = shift; + my $sock = ($self->{handle}->handles())[0]; + if ($sock and $sock->pending() eq 0) { + return $self->SUPER::__wait(); + } + return $sock; +} + + +1; diff --git a/lib/perl/lib/Thrift/Server.pm b/lib/perl/lib/Thrift/Server.pm new file mode 100644 index 0000000..fc9ca30 --- /dev/null +++ b/lib/perl/lib/Thrift/Server.pm @@ -0,0 +1,300 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::BinaryProtocol; +use Thrift::BufferedTransport; +use Thrift::Exception; + +# +# Server base class module +# +package Thrift::Server; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +# +# 3 possible constructors: +# 1. (processor, serverTransport) +# Uses a BufferedTransportFactory and a BinaryProtocolFactory. +# 2. (processor, serverTransport, transportFactory, protocolFactory) +# Uses the same factory for input and output of each type. +# 3. (processor, serverTransport, +# inputTransportFactory, outputTransportFactory, +# inputProtocolFactory, outputProtocolFactory) +# +sub new +{ + my $classname = shift; + my @args = @_; + + my $self; + + if (scalar @args == 2) + { + $self = _init($args[0], $args[1], + Thrift::BufferedTransportFactory->new(), + Thrift::BufferedTransportFactory->new(), + Thrift::BinaryProtocolFactory->new(), + Thrift::BinaryProtocolFactory->new()); + } + elsif (scalar @args == 4) + { + $self = _init($args[0], $args[1], $args[2], $args[2], $args[3], $args[3]); + } + elsif (scalar @args == 6) + { + $self = _init($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]); + } + else + { + die new Thrift::TException("Thrift::Server expects exactly 2, 4, or 6 args"); + } + + return bless($self,$classname); +} + +sub _init +{ + my $processor = shift; + my $serverTransport = shift; + my $inputTransportFactory = shift; + my $outputTransportFactory = shift; + my $inputProtocolFactory = shift; + my $outputProtocolFactory = shift; + + my $self = { + processor => $processor, + serverTransport => $serverTransport, + inputTransportFactory => $inputTransportFactory, + outputTransportFactory => $outputTransportFactory, + inputProtocolFactory => $inputProtocolFactory, + outputProtocolFactory => $outputProtocolFactory, + }; +} + +sub serve +{ + die "abstract"; +} + +sub _clientBegin +{ + my $self = shift; + my $iprot = shift; + my $oprot = shift; + + if (exists $self->{serverEventHandler} and + defined $self->{serverEventHandler}) + { + $self->{serverEventHandler}->clientBegin($iprot, $oprot); + } +} + +sub _handleException +{ + my $self = shift; + my $e = shift; + + if ($e->isa("Thrift::TException") and exists $e->{message}) { + my $message = $e->{message}; + my $code = $e->{code}; + my $out = $code . ':' . $message; + + $message =~ m/TTransportException/ and die $out; + if ($message =~ m/Socket/) { + # suppress Socket messages + } else { + warn $out; + } + } else { + warn $e; + } +} + +# +# SimpleServer from the Server base class that handles one connection at a time +# +package Thrift::SimpleServer; +use parent -norequire, 'Thrift::Server'; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new +{ + my $classname = shift; + + my $self = $classname->SUPER::new(@_); + + return bless($self,$classname); +} + +sub serve +{ + my $self = shift; + + $self->{serverTransport}->listen(); + while (1) + { + my $client = $self->{serverTransport}->accept(); + my $itrans = $self->{inputTransportFactory}->getTransport($client); + my $otrans = $self->{outputTransportFactory}->getTransport($client); + my $iprot = $self->{inputProtocolFactory}->getProtocol($itrans); + my $oprot = $self->{outputProtocolFactory}->getProtocol($otrans); + eval { + $self->_clientBegin($iprot, $oprot); + while (1) + { + $self->{processor}->process($iprot, $oprot); + } + }; if($@) { + $self->_handleException($@); + } + + $itrans->close(); + $otrans->close(); + } +} + + +# +# ForkingServer that forks a new process for each request +# +package Thrift::ForkingServer; +use parent -norequire, 'Thrift::Server'; +use POSIX ":sys_wait_h"; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new +{ + my $classname = shift; + my @args = @_; + + my $self = $classname->SUPER::new(@args); + return bless($self,$classname); +} + + +sub serve +{ + my $self = shift; + + # THRIFT-3848: without ignoring SIGCHLD, perl ForkingServer goes into a tight loop + $SIG{CHLD} = 'IGNORE'; + + $self->{serverTransport}->listen(); + while (1) + { + my $client = $self->{serverTransport}->accept(); + $self->_client($client); + } +} + +sub _client +{ + my $self = shift; + my $client = shift; + + eval { + my $itrans = $self->{inputTransportFactory}->getTransport($client); + my $otrans = $self->{outputTransportFactory}->getTransport($client); + + my $iprot = $self->{inputProtocolFactory}->getProtocol($itrans); + my $oprot = $self->{outputProtocolFactory}->getProtocol($otrans); + + $self->_clientBegin($iprot, $oprot); + + my $pid = fork(); + + if ($pid) + { + $self->_parent($pid, $itrans, $otrans); + } else { + $self->_child($itrans, $otrans, $iprot, $oprot); + } + }; if($@) { + $self->_handleException($@); + } +} + +sub _parent +{ + my $self = shift; + my $pid = shift; + my $itrans = shift; + my $otrans = shift; + + # Parent must close socket or the connection may not get closed promptly + $self->tryClose($itrans); + $self->tryClose($otrans); +} + +sub _child +{ + my $self = shift; + my $itrans = shift; + my $otrans = shift; + my $iprot = shift; + my $oprot = shift; + + my $ecode = 0; + eval { + # THRIFT-4065 ensure child process has normal signal handling in case thrift handler uses it + $SIG{CHLD} = 'DEFAULT'; + while (1) + { + $self->{processor}->process($iprot, $oprot); + } + }; if($@) { + $ecode = 1; + $self->_handleException($@); + } + + $self->tryClose($itrans); + $self->tryClose($otrans); + + exit($ecode); +} + +sub tryClose +{ + my $self = shift; + my $file = shift; + + eval { + if (defined $file) + { + $file->close(); + } + }; if($@) { + if ($@->isa("Thrift::TException") and exists $@->{message}) { + my $message = $@->{message}; + my $code = $@->{code}; + my $out = $code . ':' . $message; + + warn $out; + } else { + warn $@; + } + } +} + +1; diff --git a/lib/perl/lib/Thrift/ServerSocket.pm b/lib/perl/lib/Thrift/ServerSocket.pm new file mode 100644 index 0000000..51f83b4 --- /dev/null +++ b/lib/perl/lib/Thrift/ServerSocket.pm @@ -0,0 +1,115 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use IO::Socket::INET; +use IO::Select; +use Thrift; +use Thrift::Transport; +use Thrift::Socket; + +package Thrift::ServerSocket; +use base qw( Thrift::ServerTransport ); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +# +# Constructor. +# Legacy construction takes one argument, port number. +# New construction takes a hash: +# @param[in] host host interface to listen on (undef = all interfaces) +# @param[in] port port number to listen on (required) +# @param[in] queue the listen queue size (default if not specified is 128) +# @example my $serversock = new Thrift::ServerSocket(host => undef, port => port) +# +sub new +{ + my $classname = shift; + my $args = shift; + my $self; + + # Support both old-style "port number" construction and newer... + if (ref($args) eq 'HASH') { + $self = $args; + } else { + $self = { port => $args }; + } + + if (not defined $self->{queue}) { + $self->{queue} = 128; + } + + return bless($self, $classname); +} + +sub listen +{ + my $self = shift; + + my $sock = $self->__listen() || do { + my $error = ref($self) . ': Could not bind to ' . '*:' . $self->{port} . ' (' . $! . ')'; + + if ($self->{debug}) { + $self->{debugHandler}->($error); + } + + die new Thrift::TTransportException($error, Thrift::TTransportException::NOT_OPEN); + }; + + $self->{handle} = $sock; +} + +sub accept +{ + my $self = shift; + + if ( exists $self->{handle} and defined $self->{handle} ) + { + my $client = $self->{handle}->accept(); + my $result = $self->__client(); + $result->{handle} = new IO::Select($client); + return $result; + } + + return 0; +} + +### +### Overridable methods +### + +sub __client +{ + return new Thrift::Socket(); +} + +sub __listen +{ + my $self = shift; + return IO::Socket::INET->new(LocalAddr => $self->{host}, + LocalPort => $self->{port}, + Proto => 'tcp', + Listen => $self->{queue}, + ReuseAddr => 1); +} + + +1; diff --git a/lib/perl/lib/Thrift/Socket.pm b/lib/perl/lib/Thrift/Socket.pm new file mode 100644 index 0000000..ae248df --- /dev/null +++ b/lib/perl/lib/Thrift/Socket.pm @@ -0,0 +1,325 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::Exception; +use Thrift::Transport; + +use IO::Socket::INET; +use IO::Select; + +package Thrift::Socket; +use base qw( Thrift::Transport ); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +# +# Construction and usage +# +# my $opts = {} +# my $socket = new Thrift::Socket(\%opts); +# +# options: +# +# host => host to connect to +# port => port to connect to +# sendTimeout => timeout used for send and for connect +# recvTimeout => timeout used for recv +# + +sub new +{ + my $classname = shift; + my $opts = shift; + + # default settings: + my $self = { + host => 'localhost', + port => 9090, + recvTimeout => 10000, + sendTimeout => 10000, + + handle => undef + }; + + if (defined $opts and ref $opts eq ref {}) { + + # argument is a hash of options so override the defaults + $self->{$_} = $opts->{$_} for keys %$opts; + + } else { + + # older style constructor takes 3 arguments, none of which are required + $self->{host} = $opts || 'localhost'; + $self->{port} = shift || 9090; + + } + + return bless($self,$classname); +} + + +sub setSendTimeout +{ + my $self = shift; + my $timeout = shift; + + $self->{sendTimeout} = $timeout; +} + +sub setRecvTimeout +{ + my $self = shift; + my $timeout = shift; + + $self->{recvTimeout} = $timeout; +} + + +# +# Tests whether this is open +# +# @return bool true if the socket is open +# +sub isOpen +{ + my $self = shift; + + if( defined $self->{handle} ){ + return ($self->{handle}->handles())[0]->connected; + } + + return 0; +} + +# +# Connects the socket. +# +sub open +{ + my $self = shift; + + my $sock = $self->__open() || do { + my $error = ref($self).': Could not connect to '.$self->{host}.':'.$self->{port}.' ('.$!.')'; + die new Thrift::TTransportException($error, Thrift::TTransportException::NOT_OPEN); + }; + + $self->{handle} = new IO::Select( $sock ); +} + +# +# Closes the socket. +# +sub close +{ + my $self = shift; + if( defined $self->{handle} ) { + $self->__close(); + } +} + +# +# Uses stream get contents to do the reading +# +# @param int $len How many bytes +# @return string Binary data +# +sub readAll +{ + my $self = shift; + my $len = shift; + + + return unless defined $self->{handle}; + + my $pre = ""; + while (1) { + + my $sock = $self->__wait(); + my $buf = $self->__recv($sock, $len); + + if (!defined $buf || $buf eq '') { + + die new Thrift::TTransportException(ref($self).': Could not read '.$len.' bytes from '. + $self->{host}.':'.$self->{port}, Thrift::TTransportException::END_OF_FILE); + + } elsif ((my $sz = length($buf)) < $len) { + + $pre .= $buf; + $len -= $sz; + + } else { + return $pre.$buf; + } + } +} + +# +# Read from the socket +# +# @param int $len How many bytes +# @return string Binary data +# +sub read +{ + my $self = shift; + my $len = shift; + + return unless defined $self->{handle}; + + my $sock = $self->__wait(); + my $buf = $self->__recv($sock, $len); + + if (!defined $buf || $buf eq '') { + + die new Thrift::TTransportException(ref($self).': Could not read '.$len.' bytes from '. + $self->{host}.':'.$self->{port}, Thrift::TTransportException::END_OF_FILE); + + } + + return $buf; +} + + +# +# Write to the socket. +# +# @param string $buf The data to write +# +sub write +{ + my $self = shift; + my $buf = shift; + + return unless defined $self->{handle}; + + while (length($buf) > 0) { + #check for timeout + my @sockets = $self->{handle}->can_write( $self->{sendTimeout} / 1000 ); + + if(@sockets == 0){ + die new Thrift::TTransportException(ref($self).': timed out writing to bytes from '. + $self->{host}.':'.$self->{port}, Thrift::TTransportException::TIMED_OUT); + } + + my $sent = $self->__send($sockets[0], $buf); + + if (!defined $sent || $sent == 0 ) { + + die new Thrift::TTransportException(ref($self).': Could not write '.length($buf).' bytes '. + $self->{host}.':'.$self->{host}, Thrift::TTransportException::END_OF_FILE); + + } + + $buf = substr($buf, $sent); + } +} + +# +# Flush output to the socket. +# +sub flush +{ + my $self = shift; + + return unless defined $self->{handle}; + + my $ret = ($self->{handle}->handles())[0]->flush; +} + +### +### Overridable methods +### + +# +# Open a connection to a server. +# +sub __open +{ + my $self = shift; + return IO::Socket::INET->new(PeerAddr => $self->{host}, + PeerPort => $self->{port}, + Proto => 'tcp', + Timeout => $self->{sendTimeout} / 1000); +} + +# +# Close the connection +# +sub __close +{ + my $self = shift; + CORE::close(($self->{handle}->handles())[0]); +} + +# +# Read data +# +# @param[in] $sock the socket +# @param[in] $len the length to read +# @returns the data buffer that was read +# +sub __recv +{ + my $self = shift; + my $sock = shift; + my $len = shift; + my $buf = undef; + $sock->recv($buf, $len); + return $buf; +} + +# +# Send data +# +# @param[in] $sock the socket +# @param[in] $buf the data buffer +# @returns the number of bytes written +# +sub __send +{ + my $self = shift; + my $sock = shift; + my $buf = shift; + return $sock->send($buf); +} + +# +# Wait for data to be readable +# +# @returns a socket that can be read +# +sub __wait +{ + my $self = shift; + my @sockets = $self->{handle}->can_read( $self->{recvTimeout} / 1000 ); + + if (@sockets == 0) { + die new Thrift::TTransportException(ref($self).': timed out reading from '. + $self->{host}.':'.$self->{port}, Thrift::TTransportException::TIMED_OUT); + } + + return $sockets[0]; +} + + +1; diff --git a/lib/perl/lib/Thrift/Transport.pm b/lib/perl/lib/Thrift/Transport.pm new file mode 100644 index 0000000..10c8ce2 --- /dev/null +++ b/lib/perl/lib/Thrift/Transport.pm @@ -0,0 +1,180 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::Exception; + +# +# Transport exceptions +# +package Thrift::TTransportException; +use base('Thrift::TException'); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +use constant UNKNOWN => 0; +use constant NOT_OPEN => 1; +use constant ALREADY_OPEN => 2; +use constant TIMED_OUT => 3; +use constant END_OF_FILE => 4; + +sub new { + my $classname = shift; + my $self = $classname->SUPER::new(@_); + + return bless($self,$classname); +} + +package Thrift::Transport; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +# +# Whether this transport is open. +# +# @return boolean true if open +# +sub isOpen +{ + die "abstract"; +} + +# +# Open the transport for reading/writing +# +# @throws TTransportException if cannot open +# +sub open +{ + die "abstract"; +} + +# +# Close the transport. +# +sub close +{ + die "abstract"; +} + +# +# Read some data into the array. +# +# @param int $len How much to read +# @return string The data that has been read +# @throws TTransportException if cannot read any more data +# +sub read +{ + die "abstract"; +} + +# +# Guarantees that the full amount of data is read. +# +# @return string The data, of exact length +# @throws TTransportException if cannot read data +# +sub readAll +{ + my $self = shift; + my $len = shift; + + my $data = ''; + my $got = 0; + + while (($got = length($data)) < $len) { + $data .= $self->read($len - $got); + } + + return $data; +} + +# +# Writes the given data out. +# +# @param string $buf The data to write +# @throws TTransportException if writing fails +# +sub write +{ + die "abstract"; +} + +# +# Flushes any pending data out of a buffer +# +# @throws TTransportException if a writing error occurs +# +sub flush {} + + +# +# TransportFactory creates transport objects from transports +# +package Thrift::TransportFactory; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub new { + my $classname = shift; + my $self = {}; + + return bless($self,$classname); +} + +# +# Build a transport from the base transport +# +# @return Thrift::Transport transport +# +sub getTransport +{ + my $self = shift; + my $trans = shift; + + return $trans; +} + + +# +# ServerTransport base class module +# +package Thrift::ServerTransport; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +sub listen +{ + die "abstract"; +} + +sub accept +{ + die "abstract"; +} + +sub close +{ + die "abstract"; +} + + +1; + diff --git a/lib/perl/lib/Thrift/Type.pm b/lib/perl/lib/Thrift/Type.pm new file mode 100644 index 0000000..ad8da3b --- /dev/null +++ b/lib/perl/lib/Thrift/Type.pm @@ -0,0 +1,50 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; + +# +# Data types that can be sent via Thrift +# +package Thrift::TType; +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +use constant STOP => 0; +use constant VOID => 1; +use constant BOOL => 2; +use constant BYTE => 3; +use constant I08 => 3; +use constant DOUBLE => 4; +use constant I16 => 6; +use constant I32 => 8; +use constant I64 => 10; +use constant STRING => 11; +use constant UTF7 => 11; +use constant STRUCT => 12; +use constant MAP => 13; +use constant SET => 14; +use constant LIST => 15; +use constant UTF8 => 16; +use constant UTF16 => 17; + +1; diff --git a/lib/perl/lib/Thrift/UnixServerSocket.pm b/lib/perl/lib/Thrift/UnixServerSocket.pm new file mode 100644 index 0000000..7b857ce --- /dev/null +++ b/lib/perl/lib/Thrift/UnixServerSocket.pm @@ -0,0 +1,84 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::ServerSocket; +use Thrift::UnixSocket; + +use IO::Socket::UNIX; + +package Thrift::UnixServerSocket; +use base qw( Thrift::ServerSocket ); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +# +# Constructor. +# If a single argument is given that is not a hash, that is the unix domain socket path. +# If a single argument is given that is a hash: +# @param[in] path unix domain socket file name +# @param[in] queue the listen queue size (default is not specified is supplied by ServerSocket) +# @example my $serversock = new Thrift::UnixServerSocket($path); +# @example my $serversock = new Thrift::UnixServerSocket(path => "somepath", queue => 64); +# +sub new +{ + my $classname = shift; + my $args = shift; + my $self; + + if (ref($args) eq 'HASH') { + $self = $classname->SUPER::new($args); + } else { + $self = $classname->SUPER::new(); + $self->{path} = $args; + } + + return bless($self, $classname); +} + +sub __client +{ + return new Thrift::UnixSocket(); +} + +sub __listen +{ + my $self = shift; + + my $sock = IO::Socket::UNIX->new( + Type => IO::Socket::SOCK_STREAM, + Local => $self->{path}, + Listen => $self->{queue}) + || do { + my $error = 'UnixServerSocket: Could not bind to ' . + $self->{path} . ' (' . $! . ')'; + if ($self->{debug}) { + $self->{debugHandler}->($error); + } + die new Thrift::TTransportException($error, Thrift::TTransportException::NOT_OPEN); + }; + + return $sock; +} + +1; diff --git a/lib/perl/lib/Thrift/UnixSocket.pm b/lib/perl/lib/Thrift/UnixSocket.pm new file mode 100644 index 0000000..8b00450 --- /dev/null +++ b/lib/perl/lib/Thrift/UnixSocket.pm @@ -0,0 +1,67 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use 5.10.0; +use strict; +use warnings; + +use Thrift; +use Thrift::Socket; + +use IO::Socket::UNIX; + +package Thrift::UnixSocket; +use base qw( Thrift::Socket ); +use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); + +# +# Constructor. +# Takes a unix domain socket filename. +# See Thrift::Socket for base class parameters. +# @param[in] path path to unix socket file +# @example my $sock = new Thrift::UnixSocket($path); +# +sub new +{ + my $classname = shift; + my $self = $classname->SUPER::new(); + $self->{path} = shift; + return bless($self, $classname); +} + +sub __open +{ + my $self = shift; + + my $sock = IO::Socket::UNIX->new( + Type => IO::Socket::SOCK_STREAM, + Peer => $self->{path}) + || do { + my $error = 'UnixSocket: Could not connect to ' . + $self->{path} . ' (' . $! . ')'; + if ($self->{debug}) { + $self->{debugHandler}->($error); + } + die new Thrift::TTransportException($error, Thrift::TTransportException::NOT_OPEN); + }; + + return $sock; +} + +1; diff --git a/lib/perl/test.pl b/lib/perl/test.pl new file mode 100644 index 0000000..7e06840 --- /dev/null +++ b/lib/perl/test.pl @@ -0,0 +1,25 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use strict; +use warnings; + +use Test::Harness; + +runtests(@ARGV); diff --git a/lib/perl/test/Makefile.am b/lib/perl/test/Makefile.am new file mode 100644 index 0000000..de03971 --- /dev/null +++ b/lib/perl/test/Makefile.am @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +EXTRA_DIST = memory_buffer.t processor.t multiplex.t diff --git a/lib/perl/test/Makefile.in b/lib/perl/test/Makefile.in new file mode 100644 index 0000000..a349c54 --- /dev/null +++ b/lib/perl/test/Makefile.in @@ -0,0 +1,623 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/perl/test +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = memory_buffer.t processor.t multiplex.t +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/perl/test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/perl/test/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/perl/test/memory_buffer.t b/lib/perl/test/memory_buffer.t new file mode 100644 index 0000000..8fa9fd7 --- /dev/null +++ b/lib/perl/test/memory_buffer.t @@ -0,0 +1,53 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use Test::More tests => 6; + +use strict; +use warnings; + +use Data::Dumper; + +use Thrift::BinaryProtocol; +use Thrift::MemoryBuffer; + +use ThriftTest::Types; + + +my $transport = Thrift::MemoryBuffer->new(); +my $protocol = Thrift::BinaryProtocol->new($transport); + +my $a = ThriftTest::Xtruct->new(); +$a->i32_thing(10); +$a->i64_thing(30); +$a->string_thing('Hello, world!'); +$a->write($protocol); + +my $b = ThriftTest::Xtruct->new(); +$b->read($protocol); +is($b->i32_thing, $a->i32_thing); +is($b->i64_thing, $a->i64_thing); +is($b->string_thing, $a->string_thing); + +$b->write($protocol); +my $c = ThriftTest::Xtruct->new(); +$c->read($protocol); +is($c->i32_thing, $a->i32_thing); +is($c->i64_thing, $a->i64_thing); +is($c->string_thing, $a->string_thing); diff --git a/lib/perl/test/multiplex.t b/lib/perl/test/multiplex.t new file mode 100644 index 0000000..90a9b4d --- /dev/null +++ b/lib/perl/test/multiplex.t @@ -0,0 +1,201 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use Test::More tests => 6; + +use strict; +use warnings; + +use Thrift::BinaryProtocol; +use Thrift::FramedTransport; +use Thrift::MemoryBuffer; +use Thrift::MessageType; +use Thrift::MultiplexedProcessor; +use Thrift::Server; +use Thrift::Socket; + +use BenchmarkService; +use Aggr; + +use constant NAME_BENCHMARKSERVICE => 'BenchmarkService'; +use constant NAME_AGGR => 'Aggr'; + +my $buffer = Thrift::MemoryBuffer->new(1024); +my $aggr_protocol = Thrift::MultiplexedProtocol->new(Thrift::BinaryProtocol->new($buffer), NAME_AGGR); +my $aggr_client = AggrClient->new($aggr_protocol); +my $benchmark_protocol = Thrift::MultiplexedProtocol->new(Thrift::BinaryProtocol->new($buffer), NAME_BENCHMARKSERVICE); +my $benchmark_client = BenchmarkServiceClient->new($benchmark_protocol); + +$buffer->open(); + +for(my $i = 1; $i <= 5; $i++) { + $aggr_client->send_addValue($i); + $aggr_client->{seqid}++; +} + +$aggr_client->send_getValues(); + +for(my $i = 1; $i <= 5; $i++) { + $benchmark_client->send_fibonacci($i); + $benchmark_client->{seqid}++; +} +$benchmark_client->{seqid}--; + +my $client_command_binary = $buffer->getBuffer; +$buffer->resetBuffer; + + +# Process by server +my $server_output_binary; +{ + my $benchmark_handler = My::BenchmarkService->new(); + my $benchmark_processor = BenchmarkServiceProcessor->new($benchmark_handler); + my $aggr_handler = My::Aggr->new(); + my $aggr_processor = AggrProcessor->new($aggr_handler); + + my $protocol_factory = Thrift::BinaryProtocolFactory->new(); + + my $input_buffer = Thrift::MemoryBuffer->new(); + $input_buffer->write($client_command_binary); + + my $input_protocol = $protocol_factory->getProtocol($input_buffer); + + my $output_buffer = Thrift::MemoryBuffer->new(); + my $output_protocol = $protocol_factory->getProtocol($output_buffer); + + my $processor = Thrift::MultiplexedProcessor->new(); + + $processor->registerProcessor(NAME_BENCHMARKSERVICE, $benchmark_processor); + $processor->registerProcessor(NAME_AGGR, $aggr_processor); + my $result; + for(my $i = 1; $i <= 11; $i++) { + $result = $processor->process($input_protocol, $output_protocol); + print "process resulted in $result\n"; + } + + $server_output_binary = $output_buffer->getBuffer(); +} + +$buffer->write($server_output_binary); + + + +for(my $i = 1; $i <= 5; $i++) { + my ($function_name, $message_type, $sequence_id); + + $aggr_protocol->readMessageBegin(\$function_name, \$message_type, \$sequence_id); + + if ($message_type == Thrift::TMessageType::EXCEPTION) { + die; + } + + my $aggr_result = Aggr_addValue_result->new(); + $aggr_result->read($aggr_protocol); + $aggr_protocol->readMessageEnd(); +} + +my ($function_name, $message_type, $sequence_id); + +$aggr_protocol->readMessageBegin(\$function_name, \$message_type, \$sequence_id); + +if ($message_type == Thrift::TMessageType::EXCEPTION) { + die; +} + +my $aggr_result = Aggr_getValues_result->new(); +$aggr_result->read($aggr_protocol); +$aggr_protocol->readMessageEnd(); + +is_deeply($aggr_result->success(), [1,2,3,4,5]); + + +foreach my $val((1,2,3,5,8)) { + my ($function_name, $message_type, $sequence_id); + + $benchmark_protocol->readMessageBegin(\$function_name, \$message_type, \$sequence_id); + + if ($message_type == Thrift::TMessageType::EXCEPTION) { + die; + } + my $benchmark_result = BenchmarkService_fibonacci_result->new(); + $benchmark_result->read($benchmark_protocol); + $benchmark_protocol->readMessageEnd(); + + is($benchmark_result->success(), $val); +} + + +package My::Aggr; +use base qw(AggrIf); + +use strict; +use warnings; + +sub new { + my $classname = shift; + my $self = {}; + + $self->{values} = (); + + return bless($self,$classname); +} + +sub addValue{ + my $self = shift; + my $value = shift; + + push (@{$self->{values}}, $value); +} + +sub getValues{ + my $self = shift; + + return $self->{values}; +} + + + +package My::BenchmarkService; +use base qw(BenchmarkServiceIf); + +use strict; +use warnings; + +sub new { + my $class = shift; + return bless {}, $class; +} + +sub fibonacci { + my ($self, $n) = @_; + + my $prev = 0; + my $next; + my $result = 1; + + while ($n > 0) { + $next = $result + $prev; + $prev = $result; + $result = $next; + --$n; + } + + return $result; +} + diff --git a/lib/perl/test/processor.t b/lib/perl/test/processor.t new file mode 100644 index 0000000..f833035 --- /dev/null +++ b/lib/perl/test/processor.t @@ -0,0 +1,104 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use Test::More tests => 2; + +use strict; +use warnings; + +use Thrift::BinaryProtocol; +use Thrift::MemoryBuffer; +use Thrift::MessageType; + +use ThriftTest::ThriftTest; +use ThriftTest::Types; + +use Data::Dumper; + +my $buffer = Thrift::MemoryBuffer->new(1024); +my $protocol = Thrift::BinaryProtocol->new($buffer); +my $client = ThriftTest::ThriftTestClient->new($protocol); + +$buffer->open(); +$client->send_testString("foo"); +$client->{seqid}++; +$client->send_testString("bar"); + +my $client_command_binary = $buffer->getBuffer; +$buffer->resetBuffer; + +# Process by server + +my $server_output_binary; +{ + my $protocol_factory = Thrift::BinaryProtocolFactory->new(); + + my $input_buffer = Thrift::MemoryBuffer->new(); + $input_buffer->write($client_command_binary); + my $input_protocol = $protocol_factory->getProtocol($input_buffer); + + my $output_buffer = Thrift::MemoryBuffer->new(); + my $output_protocol = $protocol_factory->getProtocol($output_buffer); + + my $processor = ThriftTest::ThriftTestProcessor->new( My::ThriftTest->new() ); + my $result = $processor->process($input_protocol, $output_protocol); + print "process resulted in $result\n"; + $result = $processor->process($input_protocol, $output_protocol); + print "process resulted in $result\n"; + $server_output_binary = $output_buffer->getBuffer(); +} + +$buffer->write($server_output_binary); + +foreach my $val (("got foo","got bar")){ + my ($function_name, $message_type, $sequence_id); + + $protocol->readMessageBegin(\$function_name, \$message_type, \$sequence_id); + print " $function_name, $message_type, $sequence_id\n"; + + if ($message_type == Thrift::TMessageType::EXCEPTION) { + die; + } + + my $result = ThriftTest::ThriftTest_testString_result->new(); + $result->read($protocol); + $protocol->readMessageEnd(); + + is($result->success(),$val); +} + + +package My::ThriftTest; + +use strict; +use warnings; +use Data::Dumper; + +sub new { + my $class = shift; + return bless {}, $class; +} + +sub testString { + my ($self, $string) = @_; + + print __PACKAGE__ . "->testString()\n"; + + return "got ".$string; +} diff --git a/lib/php/Makefile.am b/lib/php/Makefile.am new file mode 100755 index 0000000..5aa3be4 --- /dev/null +++ b/lib/php/Makefile.am @@ -0,0 +1,149 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +if WITH_TESTS +SUBDIRS = test +endif + +if WITH_PHP_EXTENSION +%.so: + cd src/ext/thrift_protocol/ && $(MAKE) + +phpconfdir=$(PHP_CONFIG_PREFIX) +phpconf_DATA=thrift_protocol.ini + +phpmoduledir = `php-config --extension-dir` +phpmodule_SCRIPTS = src/ext/thrift_protocol/modules/thrift_protocol.so + +distclean-local: + cd $(phpmodule_SCRIPTS) && $(PHPIZE) --clean + +endif + +phpdir = $(PHP_PREFIX)/Thrift +php_DATA = \ + lib/Thrift/TMultiplexedProcessor.php + +phpbasedir = $(phpdir)/Base +phpbase_DATA = \ + lib/Thrift/Base/TBase.php + +phpclassloaderdir = $(phpdir)/ClassLoader +phpclassloader_DATA = \ + lib/Thrift/ClassLoader/ThriftClassLoader.php + +phpexceptiondir = $(phpdir)/Exception +phpexception_DATA = \ + lib/Thrift/Exception/TApplicationException.php \ + lib/Thrift/Exception/TException.php \ + lib/Thrift/Exception/TProtocolException.php \ + lib/Thrift/Exception/TTransportException.php + +phpfactorydir = $(phpdir)/Factory +phpfactory_DATA = \ + lib/Thrift/Factory/TBinaryProtocolFactory.php \ + lib/Thrift/Factory/TCompactProtocolFactory.php \ + lib/Thrift/Factory/TJSONProtocolFactory.php \ + lib/Thrift/Factory/TProtocolFactory.php \ + lib/Thrift/Factory/TStringFuncFactory.php \ + lib/Thrift/Factory/TTransportFactory.php + +phpprotocoldir = $(phpdir)/Protocol +phpprotocol_DATA = \ + lib/Thrift/Protocol/TBinaryProtocolAccelerated.php \ + lib/Thrift/Protocol/TBinaryProtocol.php \ + lib/Thrift/Protocol/TCompactProtocol.php \ + lib/Thrift/Protocol/TJSONProtocol.php \ + lib/Thrift/Protocol/TMultiplexedProtocol.php \ + lib/Thrift/Protocol/TProtocol.php \ + lib/Thrift/Protocol/TProtocolDecorator.php \ + lib/Thrift/Protocol/TSimpleJSONProtocol.php + +phpprotocoljsondir = $(phpprotocoldir)/JSON +phpprotocoljson_DATA = \ + lib/Thrift/Protocol/JSON/BaseContext.php \ + lib/Thrift/Protocol/JSON/ListContext.php \ + lib/Thrift/Protocol/JSON/LookaheadReader.php \ + lib/Thrift/Protocol/JSON/PairContext.php + +phpprotocolsimplejsondir = $(phpprotocoldir)/SimpleJSON +phpprotocolsimplejson_DATA = \ + lib/Thrift/Protocol/SimpleJSON/CollectionMapKeyException.php \ + lib/Thrift/Protocol/SimpleJSON/Context.php \ + lib/Thrift/Protocol/SimpleJSON/ListContext.php \ + lib/Thrift/Protocol/SimpleJSON/MapContext.php \ + lib/Thrift/Protocol/SimpleJSON/StructContext.php + +phpserializerdir = $(phpdir)/Serializer +phpserializer_DATA = \ + lib/Thrift/Serializer/TBinarySerializer.php + +phpserverdir = $(phpdir)/Server +phpserver_DATA = \ + lib/Thrift/Server/TServerSocket.php \ + lib/Thrift/Server/TForkingServer.php \ + lib/Thrift/Server/TServer.php \ + lib/Thrift/Server/TServerTransport.php \ + lib/Thrift/Server/TSimpleServer.php + +phpstringfuncdir = $(phpdir)/StringFunc +phpstringfunc_DATA = \ + lib/Thrift/StringFunc/Mbstring.php \ + lib/Thrift/StringFunc/Core.php \ + lib/Thrift/StringFunc/TStringFunc.php + +phptransportdir = $(phpdir)/Transport +phptransport_DATA = \ + lib/Thrift/Transport/TBufferedTransport.php \ + lib/Thrift/Transport/TCurlClient.php \ + lib/Thrift/Transport/TFramedTransport.php \ + lib/Thrift/Transport/THttpClient.php \ + lib/Thrift/Transport/TMemoryBuffer.php \ + lib/Thrift/Transport/TNullTransport.php \ + lib/Thrift/Transport/TPhpStream.php \ + lib/Thrift/Transport/TSocket.php \ + lib/Thrift/Transport/TSocketPool.php \ + lib/Thrift/Transport/TTransport.php + +phptypedir = $(phpdir)/Type +phptype_DATA = \ + lib/Thrift/Type/TMessageType.php \ + lib/Thrift/Type/TType.php \ + lib/Thrift/Type/TConstant.php + +EXTRA_DIST = \ + lib \ + src/autoload.php \ + src/ext/thrift_protocol/config.m4 \ + src/ext/thrift_protocol/config.w32 \ + src/ext/thrift_protocol/php_thrift_protocol.cpp \ + src/ext/thrift_protocol/php_thrift_protocol.h \ + src/ext/thrift_protocol/run-tests.php \ + src/Thrift.php \ + src/TStringUtils.php \ + coding_standards.md \ + thrift_protocol.ini \ + README.apache.md \ + README.md + +MAINTAINERCLEANFILES = \ + Makefile \ + Makefile.in + diff --git a/lib/php/Makefile.in b/lib/php/Makefile.in new file mode 100644 index 0000000..1695a06 --- /dev/null +++ b/lib/php/Makefile.in @@ -0,0 +1,1334 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/php +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(phpmoduledir)" "$(DESTDIR)$(phpdir)" \ + "$(DESTDIR)$(phpbasedir)" "$(DESTDIR)$(phpclassloaderdir)" \ + "$(DESTDIR)$(phpconfdir)" "$(DESTDIR)$(phpexceptiondir)" \ + "$(DESTDIR)$(phpfactorydir)" "$(DESTDIR)$(phpprotocoldir)" \ + "$(DESTDIR)$(phpprotocoljsondir)" \ + "$(DESTDIR)$(phpprotocolsimplejsondir)" \ + "$(DESTDIR)$(phpserializerdir)" "$(DESTDIR)$(phpserverdir)" \ + "$(DESTDIR)$(phpstringfuncdir)" "$(DESTDIR)$(phptransportdir)" \ + "$(DESTDIR)$(phptypedir)" +SCRIPTS = $(phpmodule_SCRIPTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +DATA = $(php_DATA) $(phpbase_DATA) $(phpclassloader_DATA) \ + $(phpconf_DATA) $(phpexception_DATA) $(phpfactory_DATA) \ + $(phpprotocol_DATA) $(phpprotocoljson_DATA) \ + $(phpprotocolsimplejson_DATA) $(phpserializer_DATA) \ + $(phpserver_DATA) $(phpstringfunc_DATA) $(phptransport_DATA) \ + $(phptype_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = test +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +@WITH_TESTS_TRUE@SUBDIRS = test +@WITH_PHP_EXTENSION_TRUE@phpconfdir = $(PHP_CONFIG_PREFIX) +@WITH_PHP_EXTENSION_TRUE@phpconf_DATA = thrift_protocol.ini +@WITH_PHP_EXTENSION_TRUE@phpmoduledir = `php-config --extension-dir` +@WITH_PHP_EXTENSION_TRUE@phpmodule_SCRIPTS = src/ext/thrift_protocol/modules/thrift_protocol.so +phpdir = $(PHP_PREFIX)/Thrift +php_DATA = \ + lib/Thrift/TMultiplexedProcessor.php + +phpbasedir = $(phpdir)/Base +phpbase_DATA = \ + lib/Thrift/Base/TBase.php + +phpclassloaderdir = $(phpdir)/ClassLoader +phpclassloader_DATA = \ + lib/Thrift/ClassLoader/ThriftClassLoader.php + +phpexceptiondir = $(phpdir)/Exception +phpexception_DATA = \ + lib/Thrift/Exception/TApplicationException.php \ + lib/Thrift/Exception/TException.php \ + lib/Thrift/Exception/TProtocolException.php \ + lib/Thrift/Exception/TTransportException.php + +phpfactorydir = $(phpdir)/Factory +phpfactory_DATA = \ + lib/Thrift/Factory/TBinaryProtocolFactory.php \ + lib/Thrift/Factory/TCompactProtocolFactory.php \ + lib/Thrift/Factory/TJSONProtocolFactory.php \ + lib/Thrift/Factory/TProtocolFactory.php \ + lib/Thrift/Factory/TStringFuncFactory.php \ + lib/Thrift/Factory/TTransportFactory.php + +phpprotocoldir = $(phpdir)/Protocol +phpprotocol_DATA = \ + lib/Thrift/Protocol/TBinaryProtocolAccelerated.php \ + lib/Thrift/Protocol/TBinaryProtocol.php \ + lib/Thrift/Protocol/TCompactProtocol.php \ + lib/Thrift/Protocol/TJSONProtocol.php \ + lib/Thrift/Protocol/TMultiplexedProtocol.php \ + lib/Thrift/Protocol/TProtocol.php \ + lib/Thrift/Protocol/TProtocolDecorator.php \ + lib/Thrift/Protocol/TSimpleJSONProtocol.php + +phpprotocoljsondir = $(phpprotocoldir)/JSON +phpprotocoljson_DATA = \ + lib/Thrift/Protocol/JSON/BaseContext.php \ + lib/Thrift/Protocol/JSON/ListContext.php \ + lib/Thrift/Protocol/JSON/LookaheadReader.php \ + lib/Thrift/Protocol/JSON/PairContext.php + +phpprotocolsimplejsondir = $(phpprotocoldir)/SimpleJSON +phpprotocolsimplejson_DATA = \ + lib/Thrift/Protocol/SimpleJSON/CollectionMapKeyException.php \ + lib/Thrift/Protocol/SimpleJSON/Context.php \ + lib/Thrift/Protocol/SimpleJSON/ListContext.php \ + lib/Thrift/Protocol/SimpleJSON/MapContext.php \ + lib/Thrift/Protocol/SimpleJSON/StructContext.php + +phpserializerdir = $(phpdir)/Serializer +phpserializer_DATA = \ + lib/Thrift/Serializer/TBinarySerializer.php + +phpserverdir = $(phpdir)/Server +phpserver_DATA = \ + lib/Thrift/Server/TServerSocket.php \ + lib/Thrift/Server/TForkingServer.php \ + lib/Thrift/Server/TServer.php \ + lib/Thrift/Server/TServerTransport.php \ + lib/Thrift/Server/TSimpleServer.php + +phpstringfuncdir = $(phpdir)/StringFunc +phpstringfunc_DATA = \ + lib/Thrift/StringFunc/Mbstring.php \ + lib/Thrift/StringFunc/Core.php \ + lib/Thrift/StringFunc/TStringFunc.php + +phptransportdir = $(phpdir)/Transport +phptransport_DATA = \ + lib/Thrift/Transport/TBufferedTransport.php \ + lib/Thrift/Transport/TCurlClient.php \ + lib/Thrift/Transport/TFramedTransport.php \ + lib/Thrift/Transport/THttpClient.php \ + lib/Thrift/Transport/TMemoryBuffer.php \ + lib/Thrift/Transport/TNullTransport.php \ + lib/Thrift/Transport/TPhpStream.php \ + lib/Thrift/Transport/TSocket.php \ + lib/Thrift/Transport/TSocketPool.php \ + lib/Thrift/Transport/TTransport.php + +phptypedir = $(phpdir)/Type +phptype_DATA = \ + lib/Thrift/Type/TMessageType.php \ + lib/Thrift/Type/TType.php \ + lib/Thrift/Type/TConstant.php + +EXTRA_DIST = \ + lib \ + src/autoload.php \ + src/ext/thrift_protocol/config.m4 \ + src/ext/thrift_protocol/config.w32 \ + src/ext/thrift_protocol/php_thrift_protocol.cpp \ + src/ext/thrift_protocol/php_thrift_protocol.h \ + src/ext/thrift_protocol/run-tests.php \ + src/Thrift.php \ + src/TStringUtils.php \ + coding_standards.md \ + thrift_protocol.ini \ + README.apache.md \ + README.md + +MAINTAINERCLEANFILES = \ + Makefile \ + Makefile.in + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/php/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/php/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-phpmoduleSCRIPTS: $(phpmodule_SCRIPTS) + @$(NORMAL_INSTALL) + @list='$(phpmodule_SCRIPTS)'; test -n "$(phpmoduledir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phpmoduledir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phpmoduledir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(phpmoduledir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(phpmoduledir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-phpmoduleSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(phpmodule_SCRIPTS)'; test -n "$(phpmoduledir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + dir='$(DESTDIR)$(phpmoduledir)'; $(am__uninstall_files_from_dir) + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-phpDATA: $(php_DATA) + @$(NORMAL_INSTALL) + @list='$(php_DATA)'; test -n "$(phpdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phpdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phpdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phpdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phpdir)" || exit $$?; \ + done + +uninstall-phpDATA: + @$(NORMAL_UNINSTALL) + @list='$(php_DATA)'; test -n "$(phpdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phpdir)'; $(am__uninstall_files_from_dir) +install-phpbaseDATA: $(phpbase_DATA) + @$(NORMAL_INSTALL) + @list='$(phpbase_DATA)'; test -n "$(phpbasedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phpbasedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phpbasedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phpbasedir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phpbasedir)" || exit $$?; \ + done + +uninstall-phpbaseDATA: + @$(NORMAL_UNINSTALL) + @list='$(phpbase_DATA)'; test -n "$(phpbasedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phpbasedir)'; $(am__uninstall_files_from_dir) +install-phpclassloaderDATA: $(phpclassloader_DATA) + @$(NORMAL_INSTALL) + @list='$(phpclassloader_DATA)'; test -n "$(phpclassloaderdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phpclassloaderdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phpclassloaderdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phpclassloaderdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phpclassloaderdir)" || exit $$?; \ + done + +uninstall-phpclassloaderDATA: + @$(NORMAL_UNINSTALL) + @list='$(phpclassloader_DATA)'; test -n "$(phpclassloaderdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phpclassloaderdir)'; $(am__uninstall_files_from_dir) +install-phpconfDATA: $(phpconf_DATA) + @$(NORMAL_INSTALL) + @list='$(phpconf_DATA)'; test -n "$(phpconfdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phpconfdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phpconfdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phpconfdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phpconfdir)" || exit $$?; \ + done + +uninstall-phpconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(phpconf_DATA)'; test -n "$(phpconfdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phpconfdir)'; $(am__uninstall_files_from_dir) +install-phpexceptionDATA: $(phpexception_DATA) + @$(NORMAL_INSTALL) + @list='$(phpexception_DATA)'; test -n "$(phpexceptiondir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phpexceptiondir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phpexceptiondir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phpexceptiondir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phpexceptiondir)" || exit $$?; \ + done + +uninstall-phpexceptionDATA: + @$(NORMAL_UNINSTALL) + @list='$(phpexception_DATA)'; test -n "$(phpexceptiondir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phpexceptiondir)'; $(am__uninstall_files_from_dir) +install-phpfactoryDATA: $(phpfactory_DATA) + @$(NORMAL_INSTALL) + @list='$(phpfactory_DATA)'; test -n "$(phpfactorydir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phpfactorydir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phpfactorydir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phpfactorydir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phpfactorydir)" || exit $$?; \ + done + +uninstall-phpfactoryDATA: + @$(NORMAL_UNINSTALL) + @list='$(phpfactory_DATA)'; test -n "$(phpfactorydir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phpfactorydir)'; $(am__uninstall_files_from_dir) +install-phpprotocolDATA: $(phpprotocol_DATA) + @$(NORMAL_INSTALL) + @list='$(phpprotocol_DATA)'; test -n "$(phpprotocoldir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phpprotocoldir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phpprotocoldir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phpprotocoldir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phpprotocoldir)" || exit $$?; \ + done + +uninstall-phpprotocolDATA: + @$(NORMAL_UNINSTALL) + @list='$(phpprotocol_DATA)'; test -n "$(phpprotocoldir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phpprotocoldir)'; $(am__uninstall_files_from_dir) +install-phpprotocoljsonDATA: $(phpprotocoljson_DATA) + @$(NORMAL_INSTALL) + @list='$(phpprotocoljson_DATA)'; test -n "$(phpprotocoljsondir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phpprotocoljsondir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phpprotocoljsondir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phpprotocoljsondir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phpprotocoljsondir)" || exit $$?; \ + done + +uninstall-phpprotocoljsonDATA: + @$(NORMAL_UNINSTALL) + @list='$(phpprotocoljson_DATA)'; test -n "$(phpprotocoljsondir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phpprotocoljsondir)'; $(am__uninstall_files_from_dir) +install-phpprotocolsimplejsonDATA: $(phpprotocolsimplejson_DATA) + @$(NORMAL_INSTALL) + @list='$(phpprotocolsimplejson_DATA)'; test -n "$(phpprotocolsimplejsondir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phpprotocolsimplejsondir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phpprotocolsimplejsondir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phpprotocolsimplejsondir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phpprotocolsimplejsondir)" || exit $$?; \ + done + +uninstall-phpprotocolsimplejsonDATA: + @$(NORMAL_UNINSTALL) + @list='$(phpprotocolsimplejson_DATA)'; test -n "$(phpprotocolsimplejsondir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phpprotocolsimplejsondir)'; $(am__uninstall_files_from_dir) +install-phpserializerDATA: $(phpserializer_DATA) + @$(NORMAL_INSTALL) + @list='$(phpserializer_DATA)'; test -n "$(phpserializerdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phpserializerdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phpserializerdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phpserializerdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phpserializerdir)" || exit $$?; \ + done + +uninstall-phpserializerDATA: + @$(NORMAL_UNINSTALL) + @list='$(phpserializer_DATA)'; test -n "$(phpserializerdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phpserializerdir)'; $(am__uninstall_files_from_dir) +install-phpserverDATA: $(phpserver_DATA) + @$(NORMAL_INSTALL) + @list='$(phpserver_DATA)'; test -n "$(phpserverdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phpserverdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phpserverdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phpserverdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phpserverdir)" || exit $$?; \ + done + +uninstall-phpserverDATA: + @$(NORMAL_UNINSTALL) + @list='$(phpserver_DATA)'; test -n "$(phpserverdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phpserverdir)'; $(am__uninstall_files_from_dir) +install-phpstringfuncDATA: $(phpstringfunc_DATA) + @$(NORMAL_INSTALL) + @list='$(phpstringfunc_DATA)'; test -n "$(phpstringfuncdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phpstringfuncdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phpstringfuncdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phpstringfuncdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phpstringfuncdir)" || exit $$?; \ + done + +uninstall-phpstringfuncDATA: + @$(NORMAL_UNINSTALL) + @list='$(phpstringfunc_DATA)'; test -n "$(phpstringfuncdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phpstringfuncdir)'; $(am__uninstall_files_from_dir) +install-phptransportDATA: $(phptransport_DATA) + @$(NORMAL_INSTALL) + @list='$(phptransport_DATA)'; test -n "$(phptransportdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phptransportdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phptransportdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phptransportdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phptransportdir)" || exit $$?; \ + done + +uninstall-phptransportDATA: + @$(NORMAL_UNINSTALL) + @list='$(phptransport_DATA)'; test -n "$(phptransportdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phptransportdir)'; $(am__uninstall_files_from_dir) +install-phptypeDATA: $(phptype_DATA) + @$(NORMAL_INSTALL) + @list='$(phptype_DATA)'; test -n "$(phptypedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(phptypedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(phptypedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(phptypedir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(phptypedir)" || exit $$?; \ + done + +uninstall-phptypeDATA: + @$(NORMAL_UNINSTALL) + @list='$(phptype_DATA)'; test -n "$(phptypedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(phptypedir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(SCRIPTS) $(DATA) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(phpmoduledir)" "$(DESTDIR)$(phpdir)" "$(DESTDIR)$(phpbasedir)" "$(DESTDIR)$(phpclassloaderdir)" "$(DESTDIR)$(phpconfdir)" "$(DESTDIR)$(phpexceptiondir)" "$(DESTDIR)$(phpfactorydir)" "$(DESTDIR)$(phpprotocoldir)" "$(DESTDIR)$(phpprotocoljsondir)" "$(DESTDIR)$(phpprotocolsimplejsondir)" "$(DESTDIR)$(phpserializerdir)" "$(DESTDIR)$(phpserverdir)" "$(DESTDIR)$(phpstringfuncdir)" "$(DESTDIR)$(phptransportdir)" "$(DESTDIR)$(phptypedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +@WITH_PHP_EXTENSION_FALSE@distclean-local: +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-local \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-phpDATA install-phpbaseDATA \ + install-phpclassloaderDATA install-phpconfDATA \ + install-phpexceptionDATA install-phpfactoryDATA \ + install-phpmoduleSCRIPTS install-phpprotocolDATA \ + install-phpprotocoljsonDATA install-phpprotocolsimplejsonDATA \ + install-phpserializerDATA install-phpserverDATA \ + install-phpstringfuncDATA install-phptransportDATA \ + install-phptypeDATA + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +style: style-recursive + +style-am: style-local + +uninstall-am: uninstall-phpDATA uninstall-phpbaseDATA \ + uninstall-phpclassloaderDATA uninstall-phpconfDATA \ + uninstall-phpexceptionDATA uninstall-phpfactoryDATA \ + uninstall-phpmoduleSCRIPTS uninstall-phpprotocolDATA \ + uninstall-phpprotocoljsonDATA \ + uninstall-phpprotocolsimplejsonDATA \ + uninstall-phpserializerDATA uninstall-phpserverDATA \ + uninstall-phpstringfuncDATA uninstall-phptransportDATA \ + uninstall-phptypeDATA + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-local distclean-tags distdir dvi dvi-am html html-am \ + info info-am install install-am install-data install-data-am \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-phpDATA \ + install-phpbaseDATA install-phpclassloaderDATA \ + install-phpconfDATA install-phpexceptionDATA \ + install-phpfactoryDATA install-phpmoduleSCRIPTS \ + install-phpprotocolDATA install-phpprotocoljsonDATA \ + install-phpprotocolsimplejsonDATA install-phpserializerDATA \ + install-phpserverDATA install-phpstringfuncDATA \ + install-phptransportDATA install-phptypeDATA install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags tags-am uninstall uninstall-am uninstall-phpDATA \ + uninstall-phpbaseDATA uninstall-phpclassloaderDATA \ + uninstall-phpconfDATA uninstall-phpexceptionDATA \ + uninstall-phpfactoryDATA uninstall-phpmoduleSCRIPTS \ + uninstall-phpprotocolDATA uninstall-phpprotocoljsonDATA \ + uninstall-phpprotocolsimplejsonDATA \ + uninstall-phpserializerDATA uninstall-phpserverDATA \ + uninstall-phpstringfuncDATA uninstall-phptransportDATA \ + uninstall-phptypeDATA + +.PRECIOUS: Makefile + + +@WITH_PHP_EXTENSION_TRUE@%.so: +@WITH_PHP_EXTENSION_TRUE@ cd src/ext/thrift_protocol/ && $(MAKE) + +@WITH_PHP_EXTENSION_TRUE@distclean-local: +@WITH_PHP_EXTENSION_TRUE@ cd $(phpmodule_SCRIPTS) && $(PHPIZE) --clean + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/php/README.apache.md b/lib/php/README.apache.md new file mode 100644 index 0000000..5e92589 --- /dev/null +++ b/lib/php/README.apache.md @@ -0,0 +1,74 @@ +Thrift PHP/Apache Integration + +License +======= + +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + +Building PHP Thrift Services with Apache +======================================== + +Thrift can be embedded in the Apache webserver with PHP installed. Sample +code is provided below. Note that to make requests to this type of server +you must use a THttpClient transport. + +Sample Code +=========== + +registerNamespace('Thrift', $THRIFT_ROOT); +$loader->registerDefinition('Thrift', $THRIFT_ROOT . '/packages'); +$loader->register(); + +use Thrift\Transport\TPhpStream; +use Thrift\Protocol\TBinaryProtocol; + +/** + * Example of how to build a Thrift server in Apache/PHP + */ + +class ServiceHandler implements ServiceIf { + // Implement your interface and methods here +} + +header('Content-Type: application/x-thrift'); + +$handler = new ServiceHandler(); +$processor = new ServiceProcessor($handler); + +// Use the TPhpStream transport to read/write directly from HTTP +$transport = new TPhpStream(TPhpStream::MODE_R | TPhpStream::MODE_W); +$protocol = new TBinaryProtocol($transport); + +$transport->open(); +$processor->process($protocol, $protocol); +$transport->close(); diff --git a/lib/php/README.md b/lib/php/README.md new file mode 100644 index 0000000..c24ee2c --- /dev/null +++ b/lib/php/README.md @@ -0,0 +1,53 @@ +Thrift PHP Software Library + +License +======= + +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + +Using Thrift with PHP +===================== + +Thrift requires PHP 5. Thrift makes as few assumptions about your PHP +environment as possible while trying to make some more advanced PHP +features (i.e. APC cacheing using asbolute path URLs) as simple as possible. + +To use Thrift in your PHP codebase, take the following steps: + +#1) Copy all of thrift/lib/php/lib into your PHP codebase +#2) Configure Symfony Autoloader (or whatever you usually use) + +After that, you have to manually include the Thrift package +created by the compiler: + +require_once 'packages/Service/Service.php'; +require_once 'packages/Service/Types.php'; + +Dependencies +============ + +PHP_INT_SIZE + + This built-in signals whether your architecture is 32 or 64 bit and is + used by the TBinaryProtocol to properly use pack() and unpack() to + serialize data. + +apc_fetch(), apc_store() + + APC cache is used by the TSocketPool class. If you do not have APC installed, + Thrift will fill in null stub function definitions. diff --git a/lib/php/coding_standards.md b/lib/php/coding_standards.md new file mode 100644 index 0000000..fa0390b --- /dev/null +++ b/lib/php/coding_standards.md @@ -0,0 +1 @@ +Please follow [General Coding Standards](/doc/coding_standards.md) diff --git a/lib/php/lib/Thrift/Base/TBase.php b/lib/php/lib/Thrift/Base/TBase.php new file mode 100644 index 0000000..4195f75 --- /dev/null +++ b/lib/php/lib/Thrift/Base/TBase.php @@ -0,0 +1,380 @@ + 'Bool', + TType::BYTE => 'Byte', + TType::I16 => 'I16', + TType::I32 => 'I32', + TType::I64 => 'I64', + TType::DOUBLE => 'Double', + TType::STRING => 'String'); + + abstract public function read($input); + + abstract public function write($output); + + public function __construct($spec=null, $vals=null) + { + if (is_array($spec) && is_array($vals)) { + foreach ($spec as $fid => $fspec) { + $var = $fspec['var']; + if (isset($vals[$var])) { + $this->$var = $vals[$var]; + } + } + } + } + + public function __wakeup() + { + $this->__construct(get_object_vars($this)); + } + + private function _readMap(&$var, $spec, $input) + { + $xfer = 0; + $ktype = $spec['ktype']; + $vtype = $spec['vtype']; + $kread = $vread = null; + if (isset(TBase::$tmethod[$ktype])) { + $kread = 'read'.TBase::$tmethod[$ktype]; + } else { + $kspec = $spec['key']; + } + if (isset(TBase::$tmethod[$vtype])) { + $vread = 'read'.TBase::$tmethod[$vtype]; + } else { + $vspec = $spec['val']; + } + $var = array(); + $_ktype = $_vtype = $size = 0; + $xfer += $input->readMapBegin($_ktype, $_vtype, $size); + for ($i = 0; $i < $size; ++$i) { + $key = $val = null; + if ($kread !== null) { + $xfer += $input->$kread($key); + } else { + switch ($ktype) { + case TType::STRUCT: + $class = $kspec['class']; + $key = new $class(); + $xfer += $key->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($key, $kspec, $input); + break; + case TType::LST: + $xfer += $this->_readList($key, $kspec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($key, $kspec, $input, true); + break; + } + } + if ($vread !== null) { + $xfer += $input->$vread($val); + } else { + switch ($vtype) { + case TType::STRUCT: + $class = $vspec['class']; + $val = new $class(); + $xfer += $val->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($val, $vspec, $input); + break; + case TType::LST: + $xfer += $this->_readList($val, $vspec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($val, $vspec, $input, true); + break; + } + } + $var[$key] = $val; + } + $xfer += $input->readMapEnd(); + + return $xfer; + } + + private function _readList(&$var, $spec, $input, $set=false) + { + $xfer = 0; + $etype = $spec['etype']; + $eread = $vread = null; + if (isset(TBase::$tmethod[$etype])) { + $eread = 'read'.TBase::$tmethod[$etype]; + } else { + $espec = $spec['elem']; + } + $var = array(); + $_etype = $size = 0; + if ($set) { + $xfer += $input->readSetBegin($_etype, $size); + } else { + $xfer += $input->readListBegin($_etype, $size); + } + for ($i = 0; $i < $size; ++$i) { + $elem = null; + if ($eread !== null) { + $xfer += $input->$eread($elem); + } else { + $espec = $spec['elem']; + switch ($etype) { + case TType::STRUCT: + $class = $espec['class']; + $elem = new $class(); + $xfer += $elem->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($elem, $espec, $input); + break; + case TType::LST: + $xfer += $this->_readList($elem, $espec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($elem, $espec, $input, true); + break; + } + } + if ($set) { + $var[$elem] = true; + } else { + $var []= $elem; + } + } + if ($set) { + $xfer += $input->readSetEnd(); + } else { + $xfer += $input->readListEnd(); + } + + return $xfer; + } + + protected function _read($class, $spec, $input) + { + $xfer = 0; + $fname = null; + $ftype = 0; + $fid = 0; + $xfer += $input->readStructBegin($fname); + while (true) { + $xfer += $input->readFieldBegin($fname, $ftype, $fid); + if ($ftype == TType::STOP) { + break; + } + if (isset($spec[$fid])) { + $fspec = $spec[$fid]; + $var = $fspec['var']; + if ($ftype == $fspec['type']) { + $xfer = 0; + if (isset(TBase::$tmethod[$ftype])) { + $func = 'read'.TBase::$tmethod[$ftype]; + $xfer += $input->$func($this->$var); + } else { + switch ($ftype) { + case TType::STRUCT: + $class = $fspec['class']; + $this->$var = new $class(); + $xfer += $this->$var->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($this->$var, $fspec, $input); + break; + case TType::LST: + $xfer += $this->_readList($this->$var, $fspec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($this->$var, $fspec, $input, true); + break; + } + } + } else { + $xfer += $input->skip($ftype); + } + } else { + $xfer += $input->skip($ftype); + } + $xfer += $input->readFieldEnd(); + } + $xfer += $input->readStructEnd(); + + return $xfer; + } + + private function _writeMap($var, $spec, $output) + { + $xfer = 0; + $ktype = $spec['ktype']; + $vtype = $spec['vtype']; + $kwrite = $vwrite = null; + if (isset(TBase::$tmethod[$ktype])) { + $kwrite = 'write'.TBase::$tmethod[$ktype]; + } else { + $kspec = $spec['key']; + } + if (isset(TBase::$tmethod[$vtype])) { + $vwrite = 'write'.TBase::$tmethod[$vtype]; + } else { + $vspec = $spec['val']; + } + $xfer += $output->writeMapBegin($ktype, $vtype, count($var)); + foreach ($var as $key => $val) { + if (isset($kwrite)) { + $xfer += $output->$kwrite($key); + } else { + switch ($ktype) { + case TType::STRUCT: + $xfer += $key->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($key, $kspec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($key, $kspec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($key, $kspec, $output, true); + break; + } + } + if (isset($vwrite)) { + $xfer += $output->$vwrite($val); + } else { + switch ($vtype) { + case TType::STRUCT: + $xfer += $val->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($val, $vspec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($val, $vspec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($val, $vspec, $output, true); + break; + } + } + } + $xfer += $output->writeMapEnd(); + + return $xfer; + } + + private function _writeList($var, $spec, $output, $set=false) + { + $xfer = 0; + $etype = $spec['etype']; + $ewrite = null; + if (isset(TBase::$tmethod[$etype])) { + $ewrite = 'write'.TBase::$tmethod[$etype]; + } else { + $espec = $spec['elem']; + } + if ($set) { + $xfer += $output->writeSetBegin($etype, count($var)); + } else { + $xfer += $output->writeListBegin($etype, count($var)); + } + foreach ($var as $key => $val) { + $elem = $set ? $key : $val; + if (isset($ewrite)) { + $xfer += $output->$ewrite($elem); + } else { + switch ($etype) { + case TType::STRUCT: + $xfer += $elem->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($elem, $espec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($elem, $espec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($elem, $espec, $output, true); + break; + } + } + } + if ($set) { + $xfer += $output->writeSetEnd(); + } else { + $xfer += $output->writeListEnd(); + } + + return $xfer; + } + + protected function _write($class, $spec, $output) + { + $xfer = 0; + $xfer += $output->writeStructBegin($class); + foreach ($spec as $fid => $fspec) { + $var = $fspec['var']; + if ($this->$var !== null) { + $ftype = $fspec['type']; + $xfer += $output->writeFieldBegin($var, $ftype, $fid); + if (isset(TBase::$tmethod[$ftype])) { + $func = 'write'.TBase::$tmethod[$ftype]; + $xfer += $output->$func($this->$var); + } else { + switch ($ftype) { + case TType::STRUCT: + $xfer += $this->$var->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($this->$var, $fspec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($this->$var, $fspec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($this->$var, $fspec, $output, true); + break; + } + } + $xfer += $output->writeFieldEnd(); + } + } + $xfer += $output->writeFieldStop(); + $xfer += $output->writeStructEnd(); + + return $xfer; + } +} diff --git a/lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php b/lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php new file mode 100644 index 0000000..67575ce --- /dev/null +++ b/lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php @@ -0,0 +1,210 @@ +apc = $apc; + $this->apc_prefix = $apc_prefix; + } + + /** + * Registers a namespace. + * + * @param string $namespace The namespace + * @param array|string $paths The location(s) of the namespace + */ + public function registerNamespace($namespace, $paths) + { + $this->namespaces[$namespace] = (array) $paths; + } + + /** + * Registers a Thrift definition namespace. + * + * @param string $namespace The definition namespace + * @param array|string $paths The location(s) of the definition namespace + */ + public function registerDefinition($namespace, $paths) + { + $this->definitions[$namespace] = (array) $paths; + } + + /** + * Registers this instance as an autoloader. + * + * @param Boolean $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Loads the given class, definition or interface. + * + * @param string $class The name of the class + */ + public function loadClass($class) + { + if ( + (true === $this->apc && ($file = $this->findFileInApc($class))) or + ($file = $this->findFile($class)) + ) + { + require_once $file; + } + } + + /** + * Loads the given class or interface in APC. + * @param string $class The name of the class + * @return string + */ + protected function findFileInApc($class) + { + if (false === $file = apc_fetch($this->apc_prefix.$class)) { + apc_store($this->apc_prefix.$class, $file = $this->findFile($class)); + } + + return $file; + } + + /** + * Find class in namespaces or definitions directories + * @param string $class + * @return string + */ + public function findFile($class) + { + // Remove first backslash + if ('\\' == $class[0]) { + $class = substr($class, 1); + } + + if (false !== $pos = strrpos($class, '\\')) { + // Namespaced class name + $namespace = substr($class, 0, $pos); + + // Iterate in normal namespaces + foreach ($this->namespaces as $ns => $dirs) { + //Don't interfere with other autoloaders + if (0 !== strpos($namespace, $ns)) { + continue; + } + + foreach ($dirs as $dir) { + $className = substr($class, $pos + 1); + + $file = $dir.DIRECTORY_SEPARATOR. + str_replace('\\', DIRECTORY_SEPARATOR, $namespace). + DIRECTORY_SEPARATOR. + $className.'.php'; + + if (file_exists($file)) { + return $file; + } + } + } + + // Iterate in Thrift namespaces + + // Remove first part of namespace + $m = explode('\\', $class); + + // Ignore wrong call + if (count($m) <= 1) { + return; + } + + $class = array_pop($m); + $namespace = implode('\\', $m); + + foreach ($this->definitions as $ns => $dirs) { + //Don't interfere with other autoloaders + if (0 !== strpos($namespace, $ns)) { + continue; + } + + foreach ($dirs as $dir) { + /** + * Available in service: Interface, Client, Processor, Rest + * And every service methods (_.+) + */ + if( + 0 === preg_match('#(.+)(if|client|processor|rest)$#i', $class, $n) and + 0 === preg_match('#(.+)_[a-z0-9]+_(args|result)$#i', $class, $n) + ) + { + $className = 'Types'; + } else { + $className = $n[1]; + } + + $file = $dir.DIRECTORY_SEPARATOR . + str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . + DIRECTORY_SEPARATOR . + $className . '.php'; + + if (file_exists($file)) { + return $file; + } + } + } + } + } +} diff --git a/lib/php/lib/Thrift/Exception/TApplicationException.php b/lib/php/lib/Thrift/Exception/TApplicationException.php new file mode 100644 index 0000000..b1689fc --- /dev/null +++ b/lib/php/lib/Thrift/Exception/TApplicationException.php @@ -0,0 +1,76 @@ + array('var' => 'message', + 'type' => TType::STRING), + 2 => array('var' => 'code', + 'type' => TType::I32)); + + const UNKNOWN = 0; + const UNKNOWN_METHOD = 1; + const INVALID_MESSAGE_TYPE = 2; + const WRONG_METHOD_NAME = 3; + const BAD_SEQUENCE_ID = 4; + const MISSING_RESULT = 5; + const INTERNAL_ERROR = 6; + const PROTOCOL_ERROR = 7; + const INVALID_TRANSFORM = 8; + const INVALID_PROTOCOL = 9; + const UNSUPPORTED_CLIENT_TYPE = 10; + + public function __construct($message=null, $code=0) + { + parent::__construct($message, $code); + } + + public function read($output) + { + return $this->_read('TApplicationException', self::$_TSPEC, $output); + } + + public function write($output) + { + $xfer = 0; + $xfer += $output->writeStructBegin('TApplicationException'); + if ($message = $this->getMessage()) { + $xfer += $output->writeFieldBegin('message', TType::STRING, 1); + $xfer += $output->writeString($message); + $xfer += $output->writeFieldEnd(); + } + if ($code = $this->getCode()) { + $xfer += $output->writeFieldBegin('type', TType::I32, 2); + $xfer += $output->writeI32($code); + $xfer += $output->writeFieldEnd(); + } + $xfer += $output->writeFieldStop(); + $xfer += $output->writeStructEnd(); + + return $xfer; + } +} diff --git a/lib/php/lib/Thrift/Exception/TException.php b/lib/php/lib/Thrift/Exception/TException.php new file mode 100644 index 0000000..5c06843 --- /dev/null +++ b/lib/php/lib/Thrift/Exception/TException.php @@ -0,0 +1,383 @@ + $fspec) { + $var = $fspec['var']; + if (isset($vals[$var])) { + $this->$var = $vals[$var]; + } + } + } else { + parent::__construct($p1, $p2); + } + } + + static $tmethod = array(TType::BOOL => 'Bool', + TType::BYTE => 'Byte', + TType::I16 => 'I16', + TType::I32 => 'I32', + TType::I64 => 'I64', + TType::DOUBLE => 'Double', + TType::STRING => 'String'); + + private function _readMap(&$var, $spec, $input) + { + $xfer = 0; + $ktype = $spec['ktype']; + $vtype = $spec['vtype']; + $kread = $vread = null; + if (isset(TBase::$tmethod[$ktype])) { + $kread = 'read'.TBase::$tmethod[$ktype]; + } else { + $kspec = $spec['key']; + } + if (isset(TBase::$tmethod[$vtype])) { + $vread = 'read'.TBase::$tmethod[$vtype]; + } else { + $vspec = $spec['val']; + } + $var = array(); + $_ktype = $_vtype = $size = 0; + $xfer += $input->readMapBegin($_ktype, $_vtype, $size); + for ($i = 0; $i < $size; ++$i) { + $key = $val = null; + if ($kread !== null) { + $xfer += $input->$kread($key); + } else { + switch ($ktype) { + case TType::STRUCT: + $class = $kspec['class']; + $key = new $class(); + $xfer += $key->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($key, $kspec, $input); + break; + case TType::LST: + $xfer += $this->_readList($key, $kspec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($key, $kspec, $input, true); + break; + } + } + if ($vread !== null) { + $xfer += $input->$vread($val); + } else { + switch ($vtype) { + case TType::STRUCT: + $class = $vspec['class']; + $val = new $class(); + $xfer += $val->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($val, $vspec, $input); + break; + case TType::LST: + $xfer += $this->_readList($val, $vspec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($val, $vspec, $input, true); + break; + } + } + $var[$key] = $val; + } + $xfer += $input->readMapEnd(); + + return $xfer; + } + + private function _readList(&$var, $spec, $input, $set=false) + { + $xfer = 0; + $etype = $spec['etype']; + $eread = $vread = null; + if (isset(TBase::$tmethod[$etype])) { + $eread = 'read'.TBase::$tmethod[$etype]; + } else { + $espec = $spec['elem']; + } + $var = array(); + $_etype = $size = 0; + if ($set) { + $xfer += $input->readSetBegin($_etype, $size); + } else { + $xfer += $input->readListBegin($_etype, $size); + } + for ($i = 0; $i < $size; ++$i) { + $elem = null; + if ($eread !== null) { + $xfer += $input->$eread($elem); + } else { + $espec = $spec['elem']; + switch ($etype) { + case TType::STRUCT: + $class = $espec['class']; + $elem = new $class(); + $xfer += $elem->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($elem, $espec, $input); + break; + case TType::LST: + $xfer += $this->_readList($elem, $espec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($elem, $espec, $input, true); + break; + } + } + if ($set) { + $var[$elem] = true; + } else { + $var []= $elem; + } + } + if ($set) { + $xfer += $input->readSetEnd(); + } else { + $xfer += $input->readListEnd(); + } + + return $xfer; + } + + protected function _read($class, $spec, $input) + { + $xfer = 0; + $fname = null; + $ftype = 0; + $fid = 0; + $xfer += $input->readStructBegin($fname); + while (true) { + $xfer += $input->readFieldBegin($fname, $ftype, $fid); + if ($ftype == TType::STOP) { + break; + } + if (isset($spec[$fid])) { + $fspec = $spec[$fid]; + $var = $fspec['var']; + if ($ftype == $fspec['type']) { + $xfer = 0; + if (isset(TBase::$tmethod[$ftype])) { + $func = 'read'.TBase::$tmethod[$ftype]; + $xfer += $input->$func($this->$var); + } else { + switch ($ftype) { + case TType::STRUCT: + $class = $fspec['class']; + $this->$var = new $class(); + $xfer += $this->$var->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($this->$var, $fspec, $input); + break; + case TType::LST: + $xfer += $this->_readList($this->$var, $fspec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($this->$var, $fspec, $input, true); + break; + } + } + } else { + $xfer += $input->skip($ftype); + } + } else { + $xfer += $input->skip($ftype); + } + $xfer += $input->readFieldEnd(); + } + $xfer += $input->readStructEnd(); + + return $xfer; + } + + private function _writeMap($var, $spec, $output) + { + $xfer = 0; + $ktype = $spec['ktype']; + $vtype = $spec['vtype']; + $kwrite = $vwrite = null; + if (isset(TBase::$tmethod[$ktype])) { + $kwrite = 'write'.TBase::$tmethod[$ktype]; + } else { + $kspec = $spec['key']; + } + if (isset(TBase::$tmethod[$vtype])) { + $vwrite = 'write'.TBase::$tmethod[$vtype]; + } else { + $vspec = $spec['val']; + } + $xfer += $output->writeMapBegin($ktype, $vtype, count($var)); + foreach ($var as $key => $val) { + if (isset($kwrite)) { + $xfer += $output->$kwrite($key); + } else { + switch ($ktype) { + case TType::STRUCT: + $xfer += $key->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($key, $kspec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($key, $kspec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($key, $kspec, $output, true); + break; + } + } + if (isset($vwrite)) { + $xfer += $output->$vwrite($val); + } else { + switch ($vtype) { + case TType::STRUCT: + $xfer += $val->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($val, $vspec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($val, $vspec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($val, $vspec, $output, true); + break; + } + } + } + $xfer += $output->writeMapEnd(); + + return $xfer; + } + + private function _writeList($var, $spec, $output, $set=false) + { + $xfer = 0; + $etype = $spec['etype']; + $ewrite = null; + if (isset(TBase::$tmethod[$etype])) { + $ewrite = 'write'.TBase::$tmethod[$etype]; + } else { + $espec = $spec['elem']; + } + if ($set) { + $xfer += $output->writeSetBegin($etype, count($var)); + } else { + $xfer += $output->writeListBegin($etype, count($var)); + } + foreach ($var as $key => $val) { + $elem = $set ? $key : $val; + if (isset($ewrite)) { + $xfer += $output->$ewrite($elem); + } else { + switch ($etype) { + case TType::STRUCT: + $xfer += $elem->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($elem, $espec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($elem, $espec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($elem, $espec, $output, true); + break; + } + } + } + if ($set) { + $xfer += $output->writeSetEnd(); + } else { + $xfer += $output->writeListEnd(); + } + + return $xfer; + } + + protected function _write($class, $spec, $output) + { + $xfer = 0; + $xfer += $output->writeStructBegin($class); + foreach ($spec as $fid => $fspec) { + $var = $fspec['var']; + if ($this->$var !== null) { + $ftype = $fspec['type']; + $xfer += $output->writeFieldBegin($var, $ftype, $fid); + if (isset(TBase::$tmethod[$ftype])) { + $func = 'write'.TBase::$tmethod[$ftype]; + $xfer += $output->$func($this->$var); + } else { + switch ($ftype) { + case TType::STRUCT: + $xfer += $this->$var->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($this->$var, $fspec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($this->$var, $fspec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($this->$var, $fspec, $output, true); + break; + } + } + $xfer += $output->writeFieldEnd(); + } + } + $xfer += $output->writeFieldStop(); + $xfer += $output->writeStructEnd(); + + return $xfer; + } + +} diff --git a/lib/php/lib/Thrift/Exception/TProtocolException.php b/lib/php/lib/Thrift/Exception/TProtocolException.php new file mode 100644 index 0000000..ba7135c --- /dev/null +++ b/lib/php/lib/Thrift/Exception/TProtocolException.php @@ -0,0 +1,50 @@ +strictRead_ = $strictRead; + $this->strictWrite_ = $strictWrite; + } + + public function getProtocol($trans) + { + return new TBinaryProtocol($trans, $this->strictRead_, $this->strictWrite_); + } +} diff --git a/lib/php/lib/Thrift/Factory/TCompactProtocolFactory.php b/lib/php/lib/Thrift/Factory/TCompactProtocolFactory.php new file mode 100644 index 0000000..f4b4fe3 --- /dev/null +++ b/lib/php/lib/Thrift/Factory/TCompactProtocolFactory.php @@ -0,0 +1,40 @@ +p_ = $p; + } + + public function write() + { + if ($this->first_) { + $this->first_ = false; + } else { + $this->p_->getTransport()->write(TJSONProtocol::COMMA); + } + } + + public function read() + { + if ($this->first_) { + $this->first_ = false; + } else { + $this->p_->readJSONSyntaxChar(TJSONProtocol::COMMA); + } + } +} diff --git a/lib/php/lib/Thrift/Protocol/JSON/LookaheadReader.php b/lib/php/lib/Thrift/Protocol/JSON/LookaheadReader.php new file mode 100644 index 0000000..0b18c40 --- /dev/null +++ b/lib/php/lib/Thrift/Protocol/JSON/LookaheadReader.php @@ -0,0 +1,57 @@ +p_ = $p; + } + + public function read() + { + if ($this->hasData_) { + $this->hasData_ = false; + } else { + $this->data_ = $this->p_->getTransport()->readAll(1); + } + + return substr($this->data_, 0, 1); + } + + public function peek() + { + if (!$this->hasData_) { + $this->data_ = $this->p_->getTransport()->readAll(1); + } + + $this->hasData_ = true; + + return substr($this->data_, 0, 1); + } +} diff --git a/lib/php/lib/Thrift/Protocol/JSON/PairContext.php b/lib/php/lib/Thrift/Protocol/JSON/PairContext.php new file mode 100644 index 0000000..7b353c4 --- /dev/null +++ b/lib/php/lib/Thrift/Protocol/JSON/PairContext.php @@ -0,0 +1,64 @@ +p_ = $p; + } + + public function write() + { + if ($this->first_) { + $this->first_ = false; + $this->colon_ = true; + } else { + $this->p_->getTransport()->write($this->colon_ ? TJSONProtocol::COLON : TJSONProtocol::COMMA); + $this->colon_ = !$this->colon_; + } + } + + public function read() + { + if ($this->first_) { + $this->first_ = false; + $this->colon_ = true; + } else { + $this->p_->readJSONSyntaxChar($this->colon_ ? TJSONProtocol::COLON : TJSONProtocol::COMMA); + $this->colon_ = !$this->colon_; + } + } + + public function escapeNum() + { + return $this->colon_; + } +} diff --git a/lib/php/lib/Thrift/Protocol/SimpleJSON/CollectionMapKeyException.php b/lib/php/lib/Thrift/Protocol/SimpleJSON/CollectionMapKeyException.php new file mode 100644 index 0000000..522b85a --- /dev/null +++ b/lib/php/lib/Thrift/Protocol/SimpleJSON/CollectionMapKeyException.php @@ -0,0 +1,33 @@ +p_ = $p; + } + + public function write() + { + if ($this->first_) { + $this->first_ = false; + } else { + $this->p_->getTransport()->write(TSimpleJSONProtocol::COMMA); + } + } +} diff --git a/lib/php/lib/Thrift/Protocol/SimpleJSON/MapContext.php b/lib/php/lib/Thrift/Protocol/SimpleJSON/MapContext.php new file mode 100644 index 0000000..bb9a04d --- /dev/null +++ b/lib/php/lib/Thrift/Protocol/SimpleJSON/MapContext.php @@ -0,0 +1,51 @@ +isKey = !$this->isKey; + } + + public function isMapKey() + { + // we want to coerce map keys to json strings regardless + // of their type + return $this->isKey; + } +} + + diff --git a/lib/php/lib/Thrift/Protocol/SimpleJSON/StructContext.php b/lib/php/lib/Thrift/Protocol/SimpleJSON/StructContext.php new file mode 100644 index 0000000..8162f2b --- /dev/null +++ b/lib/php/lib/Thrift/Protocol/SimpleJSON/StructContext.php @@ -0,0 +1,53 @@ +p_ = $p; + } + + public function write() + { + if ($this->first_) { + $this->first_ = false; + $this->colon_ = true; + } else { + $this->p_->getTransport()->write( + $this->colon_ ? + TSimpleJSONProtocol::COLON : + TSimpleJSONProtocol::COMMA + ); + $this->colon_ = !$this->colon_; + } + } +} + diff --git a/lib/php/lib/Thrift/Protocol/TBinaryProtocol.php b/lib/php/lib/Thrift/Protocol/TBinaryProtocol.php new file mode 100644 index 0000000..fe6a103 --- /dev/null +++ b/lib/php/lib/Thrift/Protocol/TBinaryProtocol.php @@ -0,0 +1,453 @@ +strictRead_ = $strictRead; + $this->strictWrite_ = $strictWrite; + } + + public function writeMessageBegin($name, $type, $seqid) + { + if ($this->strictWrite_) { + $version = self::VERSION_1 | $type; + + return + $this->writeI32($version) + + $this->writeString($name) + + $this->writeI32($seqid); + } else { + return + $this->writeString($name) + + $this->writeByte($type) + + $this->writeI32($seqid); + } + } + + public function writeMessageEnd() + { + return 0; + } + + public function writeStructBegin($name) + { + return 0; + } + + public function writeStructEnd() + { + return 0; + } + + public function writeFieldBegin($fieldName, $fieldType, $fieldId) + { + return + $this->writeByte($fieldType) + + $this->writeI16($fieldId); + } + + public function writeFieldEnd() + { + return 0; + } + + public function writeFieldStop() + { + return + $this->writeByte(TType::STOP); + } + + public function writeMapBegin($keyType, $valType, $size) + { + return + $this->writeByte($keyType) + + $this->writeByte($valType) + + $this->writeI32($size); + } + + public function writeMapEnd() + { + return 0; + } + + public function writeListBegin($elemType, $size) + { + return + $this->writeByte($elemType) + + $this->writeI32($size); + } + + public function writeListEnd() + { + return 0; + } + + public function writeSetBegin($elemType, $size) + { + return + $this->writeByte($elemType) + + $this->writeI32($size); + } + + public function writeSetEnd() + { + return 0; + } + + public function writeBool($value) + { + $data = pack('c', $value ? 1 : 0); + $this->trans_->write($data, 1); + + return 1; + } + + public function writeByte($value) + { + $data = pack('c', $value); + $this->trans_->write($data, 1); + + return 1; + } + + public function writeI16($value) + { + $data = pack('n', $value); + $this->trans_->write($data, 2); + + return 2; + } + + public function writeI32($value) + { + $data = pack('N', $value); + $this->trans_->write($data, 4); + + return 4; + } + + public function writeI64($value) + { + // If we are on a 32bit architecture we have to explicitly deal with + // 64-bit twos-complement arithmetic since PHP wants to treat all ints + // as signed and any int over 2^31 - 1 as a float + if (PHP_INT_SIZE == 4) { + $neg = $value < 0; + + if ($neg) { + $value *= -1; + } + + $hi = (int) ($value / 4294967296); + $lo = (int) $value; + + if ($neg) { + $hi = ~$hi; + $lo = ~$lo; + if (($lo & (int) 0xffffffff) == (int) 0xffffffff) { + $lo = 0; + $hi++; + } else { + $lo++; + } + } + $data = pack('N2', $hi, $lo); + + } else { + $hi = $value >> 32; + $lo = $value & 0xFFFFFFFF; + $data = pack('N2', $hi, $lo); + } + + $this->trans_->write($data, 8); + + return 8; + } + + public function writeDouble($value) + { + $data = pack('d', $value); + $this->trans_->write(strrev($data), 8); + + return 8; + } + + public function writeString($value) + { + $len = TStringFuncFactory::create()->strlen($value); + $result = $this->writeI32($len); + if ($len) { + $this->trans_->write($value, $len); + } + + return $result + $len; + } + + public function readMessageBegin(&$name, &$type, &$seqid) + { + $result = $this->readI32($sz); + if ($sz < 0) { + $version = (int) ($sz & self::VERSION_MASK); + if ($version != (int) self::VERSION_1) { + throw new TProtocolException('Bad version identifier: '.$sz, TProtocolException::BAD_VERSION); + } + $type = $sz & 0x000000ff; + $result += + $this->readString($name) + + $this->readI32($seqid); + } else { + if ($this->strictRead_) { + throw new TProtocolException('No version identifier, old protocol client?', TProtocolException::BAD_VERSION); + } else { + // Handle pre-versioned input + $name = $this->trans_->readAll($sz); + $result += + $sz + + $this->readByte($type) + + $this->readI32($seqid); + } + } + + return $result; + } + + public function readMessageEnd() + { + return 0; + } + + public function readStructBegin(&$name) + { + $name = ''; + + return 0; + } + + public function readStructEnd() + { + return 0; + } + + public function readFieldBegin(&$name, &$fieldType, &$fieldId) + { + $result = $this->readByte($fieldType); + if ($fieldType == TType::STOP) { + $fieldId = 0; + + return $result; + } + $result += $this->readI16($fieldId); + + return $result; + } + + public function readFieldEnd() + { + return 0; + } + + public function readMapBegin(&$keyType, &$valType, &$size) + { + return + $this->readByte($keyType) + + $this->readByte($valType) + + $this->readI32($size); + } + + public function readMapEnd() + { + return 0; + } + + public function readListBegin(&$elemType, &$size) + { + return + $this->readByte($elemType) + + $this->readI32($size); + } + + public function readListEnd() + { + return 0; + } + + public function readSetBegin(&$elemType, &$size) + { + return + $this->readByte($elemType) + + $this->readI32($size); + } + + public function readSetEnd() + { + return 0; + } + + public function readBool(&$value) + { + $data = $this->trans_->readAll(1); + $arr = unpack('c', $data); + $value = $arr[1] == 1; + + return 1; + } + + public function readByte(&$value) + { + $data = $this->trans_->readAll(1); + $arr = unpack('c', $data); + $value = $arr[1]; + + return 1; + } + + public function readI16(&$value) + { + $data = $this->trans_->readAll(2); + $arr = unpack('n', $data); + $value = $arr[1]; + if ($value > 0x7fff) { + $value = 0 - (($value - 1) ^ 0xffff); + } + + return 2; + } + + public function readI32(&$value) + { + $data = $this->trans_->readAll(4); + $arr = unpack('N', $data); + $value = $arr[1]; + if ($value > 0x7fffffff) { + $value = 0 - (($value - 1) ^ 0xffffffff); + } + + return 4; + } + + public function readI64(&$value) + { + $data = $this->trans_->readAll(8); + + $arr = unpack('N2', $data); + + // If we are on a 32bit architecture we have to explicitly deal with + // 64-bit twos-complement arithmetic since PHP wants to treat all ints + // as signed and any int over 2^31 - 1 as a float + if (PHP_INT_SIZE == 4) { + + $hi = $arr[1]; + $lo = $arr[2]; + $isNeg = $hi < 0; + + // Check for a negative + if ($isNeg) { + $hi = ~$hi & (int) 0xffffffff; + $lo = ~$lo & (int) 0xffffffff; + + if ($lo == (int) 0xffffffff) { + $hi++; + $lo = 0; + } else { + $lo++; + } + } + + // Force 32bit words in excess of 2G to pe positive - we deal wigh sign + // explicitly below + + if ($hi & (int) 0x80000000) { + $hi &= (int) 0x7fffffff; + $hi += 0x80000000; + } + + if ($lo & (int) 0x80000000) { + $lo &= (int) 0x7fffffff; + $lo += 0x80000000; + } + + $value = $hi * 4294967296 + $lo; + + if ($isNeg) { + $value = 0 - $value; + } + } else { + + // Upcast negatives in LSB bit + if ($arr[2] & 0x80000000) { + $arr[2] = $arr[2] & 0xffffffff; + } + + // Check for a negative + if ($arr[1] & 0x80000000) { + $arr[1] = $arr[1] & 0xffffffff; + $arr[1] = $arr[1] ^ 0xffffffff; + $arr[2] = $arr[2] ^ 0xffffffff; + $value = 0 - $arr[1]*4294967296 - $arr[2] - 1; + } else { + $value = $arr[1]*4294967296 + $arr[2]; + } + } + + return 8; + } + + public function readDouble(&$value) + { + $data = strrev($this->trans_->readAll(8)); + $arr = unpack('d', $data); + $value = $arr[1]; + + return 8; + } + + public function readString(&$value) + { + $result = $this->readI32($len); + if ($len) { + $value = $this->trans_->readAll($len); + } else { + $value = ''; + } + + return $result + $len; + } +} diff --git a/lib/php/lib/Thrift/Protocol/TBinaryProtocolAccelerated.php b/lib/php/lib/Thrift/Protocol/TBinaryProtocolAccelerated.php new file mode 100644 index 0000000..f0e0bb9 --- /dev/null +++ b/lib/php/lib/Thrift/Protocol/TBinaryProtocolAccelerated.php @@ -0,0 +1,65 @@ +strictRead_; + } + public function isStrictWrite() + { + return $this->strictWrite_; + } +} diff --git a/lib/php/lib/Thrift/Protocol/TCompactProtocol.php b/lib/php/lib/Thrift/Protocol/TCompactProtocol.php new file mode 100644 index 0000000..c25b050 --- /dev/null +++ b/lib/php/lib/Thrift/Protocol/TCompactProtocol.php @@ -0,0 +1,739 @@ + TCompactProtocol::COMPACT_STOP, + TType::BOOL => TCompactProtocol::COMPACT_TRUE, // used for collection + TType::BYTE => TCompactProtocol::COMPACT_BYTE, + TType::I16 => TCompactProtocol::COMPACT_I16, + TType::I32 => TCompactProtocol::COMPACT_I32, + TType::I64 => TCompactProtocol::COMPACT_I64, + TType::DOUBLE => TCompactProtocol::COMPACT_DOUBLE, + TType::STRING => TCompactProtocol::COMPACT_BINARY, + TType::STRUCT => TCompactProtocol::COMPACT_STRUCT, + TType::LST => TCompactProtocol::COMPACT_LIST, + TType::SET => TCompactProtocol::COMPACT_SET, + TType::MAP => TCompactProtocol::COMPACT_MAP, + ); + + protected static $ttypes = array( + TCompactProtocol::COMPACT_STOP => TType::STOP , + TCompactProtocol::COMPACT_TRUE => TType::BOOL, // used for collection + TCompactProtocol::COMPACT_FALSE => TType::BOOL, + TCompactProtocol::COMPACT_BYTE => TType::BYTE, + TCompactProtocol::COMPACT_I16 => TType::I16, + TCompactProtocol::COMPACT_I32 => TType::I32, + TCompactProtocol::COMPACT_I64 => TType::I64, + TCompactProtocol::COMPACT_DOUBLE => TType::DOUBLE, + TCompactProtocol::COMPACT_BINARY => TType::STRING, + TCompactProtocol::COMPACT_STRUCT => TType::STRUCT, + TCompactProtocol::COMPACT_LIST => TType::LST, + TCompactProtocol::COMPACT_SET => TType::SET, + TCompactProtocol::COMPACT_MAP => TType::MAP, + ); + + protected $state = TCompactProtocol::STATE_CLEAR; + protected $lastFid = 0; + protected $boolFid = null; + protected $boolValue = null; + protected $structs = array(); + protected $containers = array(); + + // Some varint / zigzag helper methods + public function toZigZag($n, $bits) + { + return ($n << 1) ^ ($n >> ($bits - 1)); + } + + public function fromZigZag($n) + { + return ($n >> 1) ^ -($n & 1); + } + + public function getVarint($data) + { + $out = ""; + while (true) { + if (($data & ~0x7f) === 0) { + $out .= chr($data); + break; + } else { + $out .= chr(($data & 0xff) | 0x80); + $data = $data >> 7; + } + } + + return $out; + } + + public function writeVarint($data) + { + $out = $this->getVarint($data); + $result = TStringFuncFactory::create()->strlen($out); + $this->trans_->write($out, $result); + + return $result; + } + + public function readVarint(&$result) + { + $idx = 0; + $shift = 0; + $result = 0; + while (true) { + $x = $this->trans_->readAll(1); + $arr = unpack('C', $x); + $byte = $arr[1]; + $idx += 1; + $result |= ($byte & 0x7f) << $shift; + if (($byte >> 7) === 0) { + return $idx; + } + $shift += 7; + } + + return $idx; + } + + public function __construct($trans) + { + parent::__construct($trans); + } + + public function writeMessageBegin($name, $type, $seqid) + { + $written = + $this->writeUByte(TCompactProtocol::PROTOCOL_ID) + + $this->writeUByte(TCompactProtocol::VERSION | + ($type << TCompactProtocol::TYPE_SHIFT_AMOUNT)) + + $this->writeVarint($seqid) + + $this->writeString($name); + $this->state = TCompactProtocol::STATE_VALUE_WRITE; + + return $written; + } + + public function writeMessageEnd() + { + $this->state = TCompactProtocol::STATE_CLEAR; + + return 0; + } + + public function writeStructBegin($name) + { + $this->structs[] = array($this->state, $this->lastFid); + $this->state = TCompactProtocol::STATE_FIELD_WRITE; + $this->lastFid = 0; + + return 0; + } + + public function writeStructEnd() + { + $old_values = array_pop($this->structs); + $this->state = $old_values[0]; + $this->lastFid = $old_values[1]; + + return 0; + } + + public function writeFieldStop() + { + return $this->writeByte(0); + } + + public function writeFieldHeader($type, $fid) + { + $written = 0; + $delta = $fid - $this->lastFid; + if (0 < $delta && $delta <= 15) { + $written = $this->writeUByte(($delta << 4) | $type); + } else { + $written = $this->writeByte($type) + + $this->writeI16($fid); + } + $this->lastFid = $fid; + + return $written; + } + + public function writeFieldBegin($field_name, $field_type, $field_id) + { + if ($field_type == TTYPE::BOOL) { + $this->state = TCompactProtocol::STATE_BOOL_WRITE; + $this->boolFid = $field_id; + + return 0; + } else { + $this->state = TCompactProtocol::STATE_VALUE_WRITE; + + return $this->writeFieldHeader(self::$ctypes[$field_type], $field_id); + } + } + + public function writeFieldEnd() + { + $this->state = TCompactProtocol::STATE_FIELD_WRITE; + + return 0; + } + + public function writeCollectionBegin($etype, $size) + { + $written = 0; + if ($size <= 14) { + $written = $this->writeUByte($size << 4 | + self::$ctypes[$etype]); + } else { + $written = $this->writeUByte(0xf0 | + self::$ctypes[$etype]) + + $this->writeVarint($size); + } + $this->containers[] = $this->state; + $this->state = TCompactProtocol::STATE_CONTAINER_WRITE; + + return $written; + } + + public function writeMapBegin($key_type, $val_type, $size) + { + $written = 0; + if ($size == 0) { + $written = $this->writeByte(0); + } else { + $written = $this->writeVarint($size) + + $this->writeUByte(self::$ctypes[$key_type] << 4 | + self::$ctypes[$val_type]); + } + $this->containers[] = $this->state; + + return $written; + } + + public function writeCollectionEnd() + { + $this->state = array_pop($this->containers); + + return 0; + } + + public function writeMapEnd() + { + return $this->writeCollectionEnd(); + } + + public function writeListBegin($elem_type, $size) + { + return $this->writeCollectionBegin($elem_type, $size); + } + + public function writeListEnd() + { + return $this->writeCollectionEnd(); + } + + public function writeSetBegin($elem_type, $size) + { + return $this->writeCollectionBegin($elem_type, $size); + } + + public function writeSetEnd() + { + return $this->writeCollectionEnd(); + } + + public function writeBool($value) + { + if ($this->state == TCompactProtocol::STATE_BOOL_WRITE) { + $ctype = TCompactProtocol::COMPACT_FALSE; + if ($value) { + $ctype = TCompactProtocol::COMPACT_TRUE; + } + + return $this->writeFieldHeader($ctype, $this->boolFid); + } elseif ($this->state == TCompactProtocol::STATE_CONTAINER_WRITE) { + return $this->writeByte($value ? 1 : 0); + } else { + throw new TProtocolException('Invalid state in compact protocol'); + } + } + + public function writeByte($value) + { + $data = pack('c', $value); + $this->trans_->write($data, 1); + + return 1; + } + + public function writeUByte($byte) + { + $this->trans_->write(pack('C', $byte), 1); + + return 1; + } + + public function writeI16($value) + { + $thing = $this->toZigZag($value, 16); + + return $this->writeVarint($thing); + } + + public function writeI32($value) + { + $thing = $this->toZigZag($value, 32); + + return $this->writeVarint($thing); + } + + public function writeDouble($value) + { + $data = pack('d', $value); + $this->trans_->write($data, 8); + + return 8; + } + + public function writeString($value) + { + $len = TStringFuncFactory::create()->strlen($value); + $result = $this->writeVarint($len); + if ($len) { + $this->trans_->write($value, $len); + } + + return $result + $len; + } + + public function readFieldBegin(&$name, &$field_type, &$field_id) + { + $result = $this->readUByte($compact_type_and_delta); + + $compact_type = $compact_type_and_delta & 0x0f; + + if ($compact_type == TType::STOP) { + $field_type = $compact_type; + $field_id = 0; + + return $result; + } + $delta = $compact_type_and_delta >> 4; + if ($delta == 0) { + $result += $this->readI16($field_id); + } else { + $field_id = $this->lastFid + $delta; + } + $this->lastFid = $field_id; + $field_type = $this->getTType($compact_type); + + if ($compact_type == TCompactProtocol::COMPACT_TRUE) { + $this->state = TCompactProtocol::STATE_BOOL_READ; + $this->boolValue = true; + } elseif ($compact_type == TCompactProtocol::COMPACT_FALSE) { + $this->state = TCompactProtocol::STATE_BOOL_READ; + $this->boolValue = false; + } else { + $this->state = TCompactProtocol::STATE_VALUE_READ; + } + + return $result; + } + + public function readFieldEnd() + { + $this->state = TCompactProtocol::STATE_FIELD_READ; + + return 0; + } + + public function readUByte(&$value) + { + $data = $this->trans_->readAll(1); + $arr = unpack('C', $data); + $value = $arr[1]; + + return 1; + } + + public function readByte(&$value) + { + $data = $this->trans_->readAll(1); + $arr = unpack('c', $data); + $value = $arr[1]; + + return 1; + } + + public function readZigZag(&$value) + { + $result = $this->readVarint($value); + $value = $this->fromZigZag($value); + + return $result; + } + + public function readMessageBegin(&$name, &$type, &$seqid) + { + $protoId = 0; + $result = $this->readUByte($protoId); + if ($protoId != TCompactProtocol::PROTOCOL_ID) { + throw new TProtocolException('Bad protocol id in TCompact message'); + } + $verType = 0; + $result += $this->readUByte($verType); + $type = ($verType >> TCompactProtocol::TYPE_SHIFT_AMOUNT) & TCompactProtocol::TYPE_BITS; + $version = $verType & TCompactProtocol::VERSION_MASK; + if ($version != TCompactProtocol::VERSION) { + throw new TProtocolException('Bad version in TCompact message'); + } + $result += $this->readVarint($seqid); + $result += $this->readString($name); + + return $result; + } + + public function readMessageEnd() + { + return 0; + } + + public function readStructBegin(&$name) + { + $name = ''; // unused + $this->structs[] = array($this->state, $this->lastFid); + $this->state = TCompactProtocol::STATE_FIELD_READ; + $this->lastFid = 0; + + return 0; + } + + public function readStructEnd() + { + $last = array_pop($this->structs); + $this->state = $last[0]; + $this->lastFid = $last[1]; + + return 0; + } + + public function readCollectionBegin(&$type, &$size) + { + $sizeType = 0; + $result = $this->readUByte($sizeType); + $size = $sizeType >> 4; + $type = $this->getTType($sizeType); + if ($size == 15) { + $result += $this->readVarint($size); + } + $this->containers[] = $this->state; + $this->state = TCompactProtocol::STATE_CONTAINER_READ; + + return $result; + } + + public function readMapBegin(&$key_type, &$val_type, &$size) + { + $result = $this->readVarint($size); + $types = 0; + if ($size > 0) { + $result += $this->readUByte($types); + } + $val_type = $this->getTType($types); + $key_type = $this->getTType($types >> 4); + $this->containers[] = $this->state; + $this->state = TCompactProtocol::STATE_CONTAINER_READ; + + return $result; + } + + public function readCollectionEnd() + { + $this->state = array_pop($this->containers); + + return 0; + } + + public function readMapEnd() + { + return $this->readCollectionEnd(); + } + + public function readListBegin(&$elem_type, &$size) + { + return $this->readCollectionBegin($elem_type, $size); + } + + public function readListEnd() + { + return $this->readCollectionEnd(); + } + + public function readSetBegin(&$elem_type, &$size) + { + return $this->readCollectionBegin($elem_type, $size); + } + + public function readSetEnd() + { + return $this->readCollectionEnd(); + } + + public function readBool(&$value) + { + if ($this->state == TCompactProtocol::STATE_BOOL_READ) { + $value = $this->boolValue; + + return 0; + } elseif ($this->state == TCompactProtocol::STATE_CONTAINER_READ) { + return $this->readByte($value); + } else { + throw new TProtocolException('Invalid state in compact protocol'); + } + } + + public function readI16(&$value) + { + return $this->readZigZag($value); + } + + public function readI32(&$value) + { + return $this->readZigZag($value); + } + + public function readDouble(&$value) + { + $data = $this->trans_->readAll(8); + $arr = unpack('d', $data); + $value = $arr[1]; + + return 8; + } + + public function readString(&$value) + { + $result = $this->readVarint($len); + if ($len) { + $value = $this->trans_->readAll($len); + } else { + $value = ''; + } + + return $result + $len; + } + + public function getTType($byte) + { + return self::$ttypes[$byte & 0x0f]; + } + + // If we are on a 32bit architecture we have to explicitly deal with + // 64-bit twos-complement arithmetic since PHP wants to treat all ints + // as signed and any int over 2^31 - 1 as a float + + // Read and write I64 as two 32 bit numbers $hi and $lo + + public function readI64(&$value) + { + // Read varint from wire + $hi = 0; + $lo = 0; + + $idx = 0; + $shift = 0; + + while (true) { + $x = $this->trans_->readAll(1); + $arr = unpack('C', $x); + $byte = $arr[1]; + $idx += 1; + // Shift hi and lo together. + if ($shift < 28) { + $lo |= (($byte & 0x7f) << $shift); + } elseif ($shift == 28) { + $lo |= (($byte & 0x0f) << 28); + $hi |= (($byte & 0x70) >> 4); + } else { + $hi |= (($byte & 0x7f) << ($shift - 32)); + } + if (($byte >> 7) === 0) { + break; + } + $shift += 7; + } + + // Now, unzig it. + $xorer = 0; + if ($lo & 1) { + $xorer = 0xffffffff; + } + $lo = ($lo >> 1) & 0x7fffffff; + $lo = $lo | (($hi & 1) << 31); + $hi = ($hi >> 1) ^ $xorer; + $lo = $lo ^ $xorer; + + // Now put $hi and $lo back together + $isNeg = $hi < 0 || $hi & 0x80000000; + + // Check for a negative + if ($isNeg) { + $hi = ~$hi & (int) 0xffffffff; + $lo = ~$lo & (int) 0xffffffff; + + if ($lo == (int) 0xffffffff) { + $hi++; + $lo = 0; + } else { + $lo++; + } + } + + // Force 32bit words in excess of 2G to be positive - we deal with sign + // explicitly below + + if ($hi & (int) 0x80000000) { + $hi &= (int) 0x7fffffff; + $hi += 0x80000000; + } + + if ($lo & (int) 0x80000000) { + $lo &= (int) 0x7fffffff; + $lo += 0x80000000; + } + + // Create as negative value first, since we can store -2^63 but not 2^63 + $value = -$hi * 4294967296 - $lo; + + if (!$isNeg) { + $value = -$value; + } + + return $idx; + } + + public function writeI64($value) + { + // If we are in an I32 range, use the easy method below. + if (($value > 4294967296) || ($value < -4294967296)) { + // Convert $value to $hi and $lo + $neg = $value < 0; + + if ($neg) { + $value *= -1; + } + + $hi = (int) $value >> 32; + $lo = (int) $value & 0xffffffff; + + if ($neg) { + $hi = ~$hi; + $lo = ~$lo; + if (($lo & (int) 0xffffffff) == (int) 0xffffffff) { + $lo = 0; + $hi++; + } else { + $lo++; + } + } + + // Now do the zigging and zagging. + $xorer = 0; + if ($neg) { + $xorer = 0xffffffff; + } + $lowbit = ($lo >> 31) & 1; + $hi = ($hi << 1) | $lowbit; + $lo = ($lo << 1); + $lo = ($lo ^ $xorer) & 0xffffffff; + $hi = ($hi ^ $xorer) & 0xffffffff; + + // now write out the varint, ensuring we shift both hi and lo + $out = ""; + while (true) { + if (($lo & ~0x7f) === 0 && + $hi === 0) { + $out .= chr($lo); + break; + } else { + $out .= chr(($lo & 0xff) | 0x80); + $lo = $lo >> 7; + $lo = $lo | ($hi << 25); + $hi = $hi >> 7; + // Right shift carries sign, but we don't want it to. + $hi = $hi & (127 << 25); + } + } + + $ret = TStringFuncFactory::create()->strlen($out); + $this->trans_->write($out, $ret); + + return $ret; + } else { + return $this->writeVarint($this->toZigZag($value, 64)); + } + } +} diff --git a/lib/php/lib/Thrift/Protocol/TJSONProtocol.php b/lib/php/lib/Thrift/Protocol/TJSONProtocol.php new file mode 100644 index 0000000..6d8e81f --- /dev/null +++ b/lib/php/lib/Thrift/Protocol/TJSONProtocol.php @@ -0,0 +1,807 @@ + 1) { + switch (substr($name, 0, 1)) { + case 'd': + $result = TType::DOUBLE; + break; + case 'i': + switch (substr($name, 1, 1)) { + case '8': + $result = TType::BYTE; + break; + case '1': + $result = TType::I16; + break; + case '3': + $result = TType::I32; + break; + case '6': + $result = TType::I64; + break; + } + break; + case 'l': + $result = TType::LST; + break; + case 'm': + $result = TType::MAP; + break; + case 'r': + $result = TType::STRUCT; + break; + case 's': + if (substr($name, 1, 1) == 't') { + $result = TType::STRING; + } elseif (substr($name, 1, 1) == 'e') { + $result = TType::SET; + } + break; + case 't': + $result = TType::BOOL; + break; + } + } + if ($result == TType::STOP) { + throw new TProtocolException("Unrecognized type", TProtocolException::INVALID_DATA); + } + + return $result; + } + + public $contextStack_ = array(); + public $context_; + public $reader_; + + private function pushContext($c) + { + array_push($this->contextStack_, $this->context_); + $this->context_ = $c; + } + + private function popContext() + { + $this->context_ = array_pop($this->contextStack_); + } + + public function __construct($trans) + { + parent::__construct($trans); + $this->context_ = new BaseContext(); + $this->reader_ = new LookaheadReader($this); + } + + public function reset() + { + $this->contextStack_ = array(); + $this->context_ = new BaseContext(); + $this->reader_ = new LookaheadReader($this); + } + + private $tmpbuf_ = array(4); + + public function readJSONSyntaxChar($b) + { + $ch = $this->reader_->read(); + + if (substr($ch, 0, 1) != $b) { + throw new TProtocolException("Unexpected character: " . $ch, TProtocolException::INVALID_DATA); + } + } + + private function hexVal($s) + { + for ($i = 0; $i < strlen($s); $i++) { + $ch = substr($s, $i, 1); + + if (!($ch >= "a" && $ch <= "f") && !($ch >= "0" && $ch <= "9")) { + throw new TProtocolException("Expected hex character " . $ch, TProtocolException::INVALID_DATA); + } + } + + return hexdec($s); + } + + private function hexChar($val) + { + return dechex($val); + } + + private function hasJSONUnescapedUnicode() + { + if (PHP_MAJOR_VERSION > 5 + || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4)) + return true; + + return false; + } + + private function unescapedUnicode($str) + { + if ($this->hasJSONUnescapedUnicode()) { + return json_encode($str, JSON_UNESCAPED_UNICODE); + } + + $json = json_encode($str); + + /* + * Unescaped character outside the Basic Multilingual Plane + * High surrogate: 0xD800 - 0xDBFF + * Low surrogate: 0xDC00 - 0xDFFF + */ + $json = preg_replace_callback('/\\\\u(d[89ab][0-9a-f]{2})\\\\u(d[cdef][0-9a-f]{2})/i', + function ($matches) { + return mb_convert_encoding(pack('H*', $matches[1].$matches[2]), 'UTF-8', 'UTF-16BE'); + }, $json); + + /* + * Unescaped characters within the Basic Multilingual Plane + */ + $json = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', + function ($matches) { + return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UTF-16BE'); + }, $json); + + return $json; + } + + private function writeJSONString($b) + { + $this->context_->write(); + + if (is_numeric($b) && $this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + + $this->trans_->write($this->unescapedUnicode($b)); + + if (is_numeric($b) && $this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + } + + private function writeJSONInteger($num) + { + $this->context_->write(); + + if ($this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + + $this->trans_->write($num); + + if ($this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + } + + private function writeJSONDouble($num) + { + $this->context_->write(); + + if ($this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + + $this->trans_->write(json_encode($num)); + + if ($this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + } + + private function writeJSONBase64($data) + { + $this->context_->write(); + $this->trans_->write(self::QUOTE); + $this->trans_->write(json_encode(base64_encode($data))); + $this->trans_->write(self::QUOTE); + } + + private function writeJSONObjectStart() + { + $this->context_->write(); + $this->trans_->write(self::LBRACE); + $this->pushContext(new PairContext($this)); + } + + private function writeJSONObjectEnd() + { + $this->popContext(); + $this->trans_->write(self::RBRACE); + } + + private function writeJSONArrayStart() + { + $this->context_->write(); + $this->trans_->write(self::LBRACKET); + $this->pushContext(new ListContext($this)); + } + + private function writeJSONArrayEnd() + { + $this->popContext(); + $this->trans_->write(self::RBRACKET); + } + + private function readJSONString($skipContext) + { + if (!$skipContext) { + $this->context_->read(); + } + + $jsonString = ''; + $lastChar = null; + while (true) { + $ch = $this->reader_->read(); + $jsonString .= $ch; + if ($ch == self::QUOTE && + $lastChar !== NULL && + $lastChar !== self::ESCSEQ) { + break; + } + if ($ch == self::ESCSEQ && $lastChar == self::ESCSEQ) { + $lastChar = self::DOUBLEESC; + } else { + $lastChar = $ch; + } + } + + return json_decode($jsonString); + } + + private function isJSONNumeric($b) + { + switch ($b) { + case '+': + case '-': + case '.': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'E': + case 'e': + return true; + } + + return false; + } + + private function readJSONNumericChars() + { + $strbld = array(); + + while (true) { + $ch = $this->reader_->peek(); + + if (!$this->isJSONNumeric($ch)) { + break; + } + + $strbld[] = $this->reader_->read(); + } + + return implode("", $strbld); + } + + private function readJSONInteger() + { + $this->context_->read(); + + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + $str = $this->readJSONNumericChars(); + + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + if (!is_numeric($str)) { + throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA); + } + + return intval($str); + } + + /** + * Identical to readJSONInteger but without the final cast. + * Needed for proper handling of i64 on 32 bit machines. Why a + * separate function? So we don't have to force the rest of the + * use cases through the extra conditional. + */ + private function readJSONIntegerAsString() + { + $this->context_->read(); + + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + $str = $this->readJSONNumericChars(); + + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + if (!is_numeric($str)) { + throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA); + } + + return $str; + } + + private function readJSONDouble() + { + $this->context_->read(); + + if (substr($this->reader_->peek(), 0, 1) == self::QUOTE) { + $arr = $this->readJSONString(true); + + if ($arr == "NaN") { + return NAN; + } elseif ($arr == "Infinity") { + return INF; + } elseif (!$this->context_->escapeNum()) { + throw new TProtocolException("Numeric data unexpectedly quoted " . $arr, + TProtocolException::INVALID_DATA); + } + + return floatval($arr); + } else { + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + return floatval($this->readJSONNumericChars()); + } + } + + private function readJSONBase64() + { + $arr = $this->readJSONString(false); + $data = base64_decode($arr, true); + + if ($data === false) { + throw new TProtocolException("Invalid base64 data " . $arr, TProtocolException::INVALID_DATA); + } + + return $data; + } + + private function readJSONObjectStart() + { + $this->context_->read(); + $this->readJSONSyntaxChar(self::LBRACE); + $this->pushContext(new PairContext($this)); + } + + private function readJSONObjectEnd() + { + $this->readJSONSyntaxChar(self::RBRACE); + $this->popContext(); + } + + private function readJSONArrayStart() + { + $this->context_->read(); + $this->readJSONSyntaxChar(self::LBRACKET); + $this->pushContext(new ListContext($this)); + } + + private function readJSONArrayEnd() + { + $this->readJSONSyntaxChar(self::RBRACKET); + $this->popContext(); + } + + /** + * Writes the message header + * + * @param string $name Function name + * @param int $type message type TMessageType::CALL or TMessageType::REPLY + * @param int $seqid The sequence id of this message + */ + public function writeMessageBegin($name, $type, $seqid) + { + $this->writeJSONArrayStart(); + $this->writeJSONInteger(self::VERSION); + $this->writeJSONString($name); + $this->writeJSONInteger($type); + $this->writeJSONInteger($seqid); + } + + /** + * Close the message + */ + public function writeMessageEnd() + { + $this->writeJSONArrayEnd(); + } + + /** + * Writes a struct header. + * + * @param string $name Struct name + * @throws TException on write error + * @return int How many bytes written + */ + public function writeStructBegin($name) + { + $this->writeJSONObjectStart(); + } + + /** + * Close a struct. + * + * @throws TException on write error + * @return int How many bytes written + */ + public function writeStructEnd() + { + $this->writeJSONObjectEnd(); + } + + public function writeFieldBegin($fieldName, $fieldType, $fieldId) + { + $this->writeJSONInteger($fieldId); + $this->writeJSONObjectStart(); + $this->writeJSONString($this->getTypeNameForTypeID($fieldType)); + } + + public function writeFieldEnd() + { + $this->writeJsonObjectEnd(); + } + + public function writeFieldStop() + { + } + + public function writeMapBegin($keyType, $valType, $size) + { + $this->writeJSONArrayStart(); + $this->writeJSONString($this->getTypeNameForTypeID($keyType)); + $this->writeJSONString($this->getTypeNameForTypeID($valType)); + $this->writeJSONInteger($size); + $this->writeJSONObjectStart(); + } + + public function writeMapEnd() + { + $this->writeJSONObjectEnd(); + $this->writeJSONArrayEnd(); + } + + public function writeListBegin($elemType, $size) + { + $this->writeJSONArrayStart(); + $this->writeJSONString($this->getTypeNameForTypeID($elemType)); + $this->writeJSONInteger($size); + } + + public function writeListEnd() + { + $this->writeJSONArrayEnd(); + } + + public function writeSetBegin($elemType, $size) + { + $this->writeJSONArrayStart(); + $this->writeJSONString($this->getTypeNameForTypeID($elemType)); + $this->writeJSONInteger($size); + } + + public function writeSetEnd() + { + $this->writeJSONArrayEnd(); + } + + public function writeBool($bool) + { + $this->writeJSONInteger($bool ? 1 : 0); + } + + public function writeByte($byte) + { + $this->writeJSONInteger($byte); + } + + public function writeI16($i16) + { + $this->writeJSONInteger($i16); + } + + public function writeI32($i32) + { + $this->writeJSONInteger($i32); + } + + public function writeI64($i64) + { + $this->writeJSONInteger($i64); + } + + public function writeDouble($dub) + { + $this->writeJSONDouble($dub); + } + + public function writeString($str) + { + $this->writeJSONString($str); + } + + /** + * Reads the message header + * + * @param string $name Function name + * @param int $type message type TMessageType::CALL or TMessageType::REPLY + * @parem int $seqid The sequence id of this message + */ + public function readMessageBegin(&$name, &$type, &$seqid) + { + $this->readJSONArrayStart(); + + if ($this->readJSONInteger() != self::VERSION) { + throw new TProtocolException("Message contained bad version", TProtocolException::BAD_VERSION); + } + + $name = $this->readJSONString(false); + $type = $this->readJSONInteger(); + $seqid = $this->readJSONInteger(); + + return true; + } + + /** + * Read the close of message + */ + public function readMessageEnd() + { + $this->readJSONArrayEnd(); + } + + public function readStructBegin(&$name) + { + $this->readJSONObjectStart(); + + return 0; + } + + public function readStructEnd() + { + $this->readJSONObjectEnd(); + } + + public function readFieldBegin(&$name, &$fieldType, &$fieldId) + { + $ch = $this->reader_->peek(); + $name = ""; + + if (substr($ch, 0, 1) == self::RBRACE) { + $fieldType = TType::STOP; + } else { + $fieldId = $this->readJSONInteger(); + $this->readJSONObjectStart(); + $fieldType = $this->getTypeIDForTypeName($this->readJSONString(false)); + } + } + + public function readFieldEnd() + { + $this->readJSONObjectEnd(); + } + + public function readMapBegin(&$keyType, &$valType, &$size) + { + $this->readJSONArrayStart(); + $keyType = $this->getTypeIDForTypeName($this->readJSONString(false)); + $valType = $this->getTypeIDForTypeName($this->readJSONString(false)); + $size = $this->readJSONInteger(); + $this->readJSONObjectStart(); + } + + public function readMapEnd() + { + $this->readJSONObjectEnd(); + $this->readJSONArrayEnd(); + } + + public function readListBegin(&$elemType, &$size) + { + $this->readJSONArrayStart(); + $elemType = $this->getTypeIDForTypeName($this->readJSONString(false)); + $size = $this->readJSONInteger(); + + return true; + } + + public function readListEnd() + { + $this->readJSONArrayEnd(); + } + + public function readSetBegin(&$elemType, &$size) + { + $this->readJSONArrayStart(); + $elemType = $this->getTypeIDForTypeName($this->readJSONString(false)); + $size = $this->readJSONInteger(); + + return true; + } + + public function readSetEnd() + { + $this->readJSONArrayEnd(); + } + + public function readBool(&$bool) + { + $bool = $this->readJSONInteger() == 0 ? false : true; + + return true; + } + + public function readByte(&$byte) + { + $byte = $this->readJSONInteger(); + + return true; + } + + public function readI16(&$i16) + { + $i16 = $this->readJSONInteger(); + + return true; + } + + public function readI32(&$i32) + { + $i32 = $this->readJSONInteger(); + + return true; + } + + public function readI64(&$i64) + { + if (PHP_INT_SIZE === 4) { + $i64 = $this->readJSONIntegerAsString(); + } else { + $i64 = $this->readJSONInteger(); + } + + return true; + } + + public function readDouble(&$dub) + { + $dub = $this->readJSONDouble(); + + return true; + } + + public function readString(&$str) + { + $str = $this->readJSONString(false); + + return true; + } +} diff --git a/lib/php/lib/Thrift/Protocol/TMultiplexedProtocol.php b/lib/php/lib/Thrift/Protocol/TMultiplexedProtocol.php new file mode 100644 index 0000000..d579c09 --- /dev/null +++ b/lib/php/lib/Thrift/Protocol/TMultiplexedProtocol.php @@ -0,0 +1,85 @@ +TMultiplexedProtocol is a protocol-independent concrete decorator + * that allows a Thrift client to communicate with a multiplexing Thrift server, + * by prepending the service name to the function name during function calls. + * + * @package Thrift\Protocol + */ +class TMultiplexedProtocol extends TProtocolDecorator +{ + /** + * Separator between service name and function name. + * Should be the same as used at multiplexed Thrift server. + * + * @var string + */ + const SEPARATOR = ":"; + + /** + * The name of service. + * + * @var string + */ + private $serviceName_; + + /** + * Constructor of TMultiplexedProtocol class. + * + * Wrap the specified protocol, allowing it to be used to communicate with a + * multiplexing server. The $serviceName is required as it is + * prepended to the message header so that the multiplexing server can broker + * the function call to the proper service. + * + * @param TProtocol $protocol + * @param string $serviceName The name of service. + */ + public function __construct(TProtocol $protocol, $serviceName) + { + parent::__construct($protocol); + $this->serviceName_ = $serviceName; + } + + /** + * Writes the message header. + * Prepends the service name to the function name, separated by TMultiplexedProtocol::SEPARATOR. + * + * @param string $name Function name. + * @param int $type Message type. + * @param int $seqid The sequence id of this message. + */ + public function writeMessageBegin($name, $type, $seqid) + { + if ($type == TMessageType::CALL || $type == TMessageType::ONEWAY) { + $nameWithService = $this->serviceName_ . self::SEPARATOR . $name; + parent::writeMessageBegin($nameWithService, $type, $seqid); + } else { + parent::writeMessageBegin($name, $type, $seqid); + } + } +} diff --git a/lib/php/lib/Thrift/Protocol/TProtocol.php b/lib/php/lib/Thrift/Protocol/TProtocol.php new file mode 100644 index 0000000..0e3bc0d --- /dev/null +++ b/lib/php/lib/Thrift/Protocol/TProtocol.php @@ -0,0 +1,352 @@ +trans_ = $trans; + } + + /** + * Accessor for transport + * + * @return TTransport + */ + public function getTransport() + { + return $this->trans_; + } + + /** + * Writes the message header + * + * @param string $name Function name + * @param int $type message type TMessageType::CALL or TMessageType::REPLY + * @param int $seqid The sequence id of this message + */ + abstract public function writeMessageBegin($name, $type, $seqid); + + /** + * Close the message + */ + abstract public function writeMessageEnd(); + + /** + * Writes a struct header. + * + * @param string $name Struct name + * @throws TException on write error + * @return int How many bytes written + */ + abstract public function writeStructBegin($name); + + /** + * Close a struct. + * + * @throws TException on write error + * @return int How many bytes written + */ + abstract public function writeStructEnd(); + + /* + * Starts a field. + * + * @param string $name Field name + * @param int $type Field type + * @param int $fid Field id + * @throws TException on write error + * @return int How many bytes written + */ + abstract public function writeFieldBegin($fieldName, $fieldType, $fieldId); + + abstract public function writeFieldEnd(); + + abstract public function writeFieldStop(); + + abstract public function writeMapBegin($keyType, $valType, $size); + + abstract public function writeMapEnd(); + + abstract public function writeListBegin($elemType, $size); + + abstract public function writeListEnd(); + + abstract public function writeSetBegin($elemType, $size); + + abstract public function writeSetEnd(); + + abstract public function writeBool($bool); + + abstract public function writeByte($byte); + + abstract public function writeI16($i16); + + abstract public function writeI32($i32); + + abstract public function writeI64($i64); + + abstract public function writeDouble($dub); + + abstract public function writeString($str); + + /** + * Reads the message header + * + * @param string $name Function name + * @param int $type message type TMessageType::CALL or TMessageType::REPLY + * @parem int $seqid The sequence id of this message + */ + abstract public function readMessageBegin(&$name, &$type, &$seqid); + + /** + * Read the close of message + */ + abstract public function readMessageEnd(); + + abstract public function readStructBegin(&$name); + + abstract public function readStructEnd(); + + abstract public function readFieldBegin(&$name, &$fieldType, &$fieldId); + + abstract public function readFieldEnd(); + + abstract public function readMapBegin(&$keyType, &$valType, &$size); + + abstract public function readMapEnd(); + + abstract public function readListBegin(&$elemType, &$size); + + abstract public function readListEnd(); + + abstract public function readSetBegin(&$elemType, &$size); + + abstract public function readSetEnd(); + + abstract public function readBool(&$bool); + + abstract public function readByte(&$byte); + + abstract public function readI16(&$i16); + + abstract public function readI32(&$i32); + + abstract public function readI64(&$i64); + + abstract public function readDouble(&$dub); + + abstract public function readString(&$str); + + /** + * The skip function is a utility to parse over unrecognized date without + * causing corruption. + * + * @param TType $type What type is it + */ + public function skip($type) + { + switch ($type) { + case TType::BOOL: + return $this->readBool($bool); + case TType::BYTE: + return $this->readByte($byte); + case TType::I16: + return $this->readI16($i16); + case TType::I32: + return $this->readI32($i32); + case TType::I64: + return $this->readI64($i64); + case TType::DOUBLE: + return $this->readDouble($dub); + case TType::STRING: + return $this->readString($str); + case TType::STRUCT: + { + $result = $this->readStructBegin($name); + while (true) { + $result += $this->readFieldBegin($name, $ftype, $fid); + if ($ftype == TType::STOP) { + break; + } + $result += $this->skip($ftype); + $result += $this->readFieldEnd(); + } + $result += $this->readStructEnd(); + + return $result; + } + case TType::MAP: + { + $result = $this->readMapBegin($keyType, $valType, $size); + for ($i = 0; $i < $size; $i++) { + $result += $this->skip($keyType); + $result += $this->skip($valType); + } + $result += $this->readMapEnd(); + + return $result; + } + case TType::SET: + { + $result = $this->readSetBegin($elemType, $size); + for ($i = 0; $i < $size; $i++) { + $result += $this->skip($elemType); + } + $result += $this->readSetEnd(); + + return $result; + } + case TType::LST: + { + $result = $this->readListBegin($elemType, $size); + for ($i = 0; $i < $size; $i++) { + $result += $this->skip($elemType); + } + $result += $this->readListEnd(); + + return $result; + } + default: + throw new TProtocolException('Unknown field type: '.$type, + TProtocolException::INVALID_DATA); + } + } + + /** + * Utility for skipping binary data + * + * @param TTransport $itrans TTransport object + * @param int $type Field type + */ + public static function skipBinary($itrans, $type) + { + switch ($type) { + case TType::BOOL: + return $itrans->readAll(1); + case TType::BYTE: + return $itrans->readAll(1); + case TType::I16: + return $itrans->readAll(2); + case TType::I32: + return $itrans->readAll(4); + case TType::I64: + return $itrans->readAll(8); + case TType::DOUBLE: + return $itrans->readAll(8); + case TType::STRING: + $len = unpack('N', $itrans->readAll(4)); + $len = $len[1]; + if ($len > 0x7fffffff) { + $len = 0 - (($len - 1) ^ 0xffffffff); + } + + return 4 + $itrans->readAll($len); + case TType::STRUCT: + { + $result = 0; + while (true) { + $ftype = 0; + $fid = 0; + $data = $itrans->readAll(1); + $arr = unpack('c', $data); + $ftype = $arr[1]; + if ($ftype == TType::STOP) { + break; + } + // I16 field id + $result += $itrans->readAll(2); + $result += self::skipBinary($itrans, $ftype); + } + + return $result; + } + case TType::MAP: + { + // Ktype + $data = $itrans->readAll(1); + $arr = unpack('c', $data); + $ktype = $arr[1]; + // Vtype + $data = $itrans->readAll(1); + $arr = unpack('c', $data); + $vtype = $arr[1]; + // Size + $data = $itrans->readAll(4); + $arr = unpack('N', $data); + $size = $arr[1]; + if ($size > 0x7fffffff) { + $size = 0 - (($size - 1) ^ 0xffffffff); + } + $result = 6; + for ($i = 0; $i < $size; $i++) { + $result += self::skipBinary($itrans, $ktype); + $result += self::skipBinary($itrans, $vtype); + } + + return $result; + } + case TType::SET: + case TType::LST: + { + // Vtype + $data = $itrans->readAll(1); + $arr = unpack('c', $data); + $vtype = $arr[1]; + // Size + $data = $itrans->readAll(4); + $arr = unpack('N', $data); + $size = $arr[1]; + if ($size > 0x7fffffff) { + $size = 0 - (($size - 1) ^ 0xffffffff); + } + $result = 5; + for ($i = 0; $i < $size; $i++) { + $result += self::skipBinary($itrans, $vtype); + } + + return $result; + } + default: + throw new TProtocolException('Unknown field type: '.$type, + TProtocolException::INVALID_DATA); + } + } +} diff --git a/lib/php/lib/Thrift/Protocol/TProtocolDecorator.php b/lib/php/lib/Thrift/Protocol/TProtocolDecorator.php new file mode 100644 index 0000000..c08c4d5 --- /dev/null +++ b/lib/php/lib/Thrift/Protocol/TProtocolDecorator.php @@ -0,0 +1,284 @@ +TProtocolDecorator forwards all requests to an enclosed + * TProtocol instance, providing a way to author concise + * concrete decorator subclasses. While it has no abstract methods, it + * is marked abstract as a reminder that by itself, it does not modify + * the behaviour of the enclosed TProtocol. + * + * @package Thrift\Protocol + */ +abstract class TProtocolDecorator extends TProtocol +{ + /** + * Instance of protocol, to which all operations will be forwarded. + * + * @var TProtocol + */ + private $concreteProtocol_; + + /** + * Constructor of TProtocolDecorator class. + * Encloses the specified protocol. + * + * @param TProtocol $protocol All operations will be forward to this instance. Must be non-null. + */ + protected function __construct(TProtocol $protocol) + { + parent::__construct($protocol->getTransport()); + $this->concreteProtocol_ = $protocol; + } + + /** + * Writes the message header. + * + * @param string $name Function name + * @param int $type message type TMessageType::CALL or TMessageType::REPLY + * @param int $seqid The sequence id of this message + */ + public function writeMessageBegin($name, $type, $seqid) + { + return $this->concreteProtocol_->writeMessageBegin($name, $type, $seqid); + } + + /** + * Closes the message. + */ + public function writeMessageEnd() + { + return $this->concreteProtocol_->writeMessageEnd(); + } + + /** + * Writes a struct header. + * + * @param string $name Struct name + * + * @throws TException on write error + * @return int How many bytes written + */ + public function writeStructBegin($name) + { + return $this->concreteProtocol_->writeStructBegin($name); + } + + /** + * Close a struct. + * + * @throws TException on write error + * @return int How many bytes written + */ + public function writeStructEnd() + { + return $this->concreteProtocol_->writeStructEnd(); + } + + public function writeFieldBegin($fieldName, $fieldType, $fieldId) + { + return $this->concreteProtocol_->writeFieldBegin($fieldName, $fieldType, $fieldId); + } + + public function writeFieldEnd() + { + return $this->concreteProtocol_->writeFieldEnd(); + } + + public function writeFieldStop() + { + return $this->concreteProtocol_->writeFieldStop(); + } + + public function writeMapBegin($keyType, $valType, $size) + { + return $this->concreteProtocol_->writeMapBegin($keyType, $valType, $size); + } + + public function writeMapEnd() + { + return $this->concreteProtocol_->writeMapEnd(); + } + + public function writeListBegin($elemType, $size) + { + return $this->concreteProtocol_->writeListBegin($elemType, $size); + } + + public function writeListEnd() + { + return $this->concreteProtocol_->writeListEnd(); + } + + public function writeSetBegin($elemType, $size) + { + return $this->concreteProtocol_->writeSetBegin($elemType, $size); + } + + public function writeSetEnd() + { + return $this->concreteProtocol_->writeSetEnd(); + } + + public function writeBool($bool) + { + return $this->concreteProtocol_->writeBool($bool); + } + + public function writeByte($byte) + { + return $this->concreteProtocol_->writeByte($byte); + } + + public function writeI16($i16) + { + return $this->concreteProtocol_->writeI16($i16); + } + + public function writeI32($i32) + { + return $this->concreteProtocol_->writeI32($i32); + } + + public function writeI64($i64) + { + return $this->concreteProtocol_->writeI64($i64); + } + + public function writeDouble($dub) + { + return $this->concreteProtocol_->writeDouble($dub); + } + + public function writeString($str) + { + return $this->concreteProtocol_->writeString($str); + } + + /** + * Reads the message header + * + * @param string $name Function name + * @param int $type message type TMessageType::CALL or TMessageType::REPLY + * @param int $seqid The sequence id of this message + */ + public function readMessageBegin(&$name, &$type, &$seqid) + { + return $this->concreteProtocol_->readMessageBegin($name, $type, $seqid); + } + + /** + * Read the close of message + */ + public function readMessageEnd() + { + return $this->concreteProtocol_->readMessageEnd(); + } + + public function readStructBegin(&$name) + { + return $this->concreteProtocol_->readStructBegin($name); + } + + public function readStructEnd() + { + return $this->concreteProtocol_->readStructEnd(); + } + + public function readFieldBegin(&$name, &$fieldType, &$fieldId) + { + return $this->concreteProtocol_->readFieldBegin($name, $fieldType, $fieldId); + } + + public function readFieldEnd() + { + return $this->concreteProtocol_->readFieldEnd(); + } + + public function readMapBegin(&$keyType, &$valType, &$size) + { + $this->concreteProtocol_->readMapBegin($keyType, $valType, $size); + } + + public function readMapEnd() + { + return $this->concreteProtocol_->readMapEnd(); + } + + public function readListBegin(&$elemType, &$size) + { + $this->concreteProtocol_->readListBegin($elemType, $size); + } + + public function readListEnd() + { + return $this->concreteProtocol_->readListEnd(); + } + + public function readSetBegin(&$elemType, &$size) + { + return $this->concreteProtocol_->readSetBegin($elemType, $size); + } + + public function readSetEnd() + { + return $this->concreteProtocol_->readSetEnd(); + } + + public function readBool(&$bool) + { + return $this->concreteProtocol_->readBool($bool); + } + + public function readByte(&$byte) + { + return $this->concreteProtocol_->readByte($byte); + } + + public function readI16(&$i16) + { + return $this->concreteProtocol_->readI16($i16); + } + + public function readI32(&$i32) + { + return $this->concreteProtocol_->readI32($i32); + } + + public function readI64(&$i64) + { + return $this->concreteProtocol_->readI64($i64); + } + + public function readDouble(&$dub) + { + return $this->concreteProtocol_->readDouble($dub); + } + + public function readString(&$str) + { + return $this->concreteProtocol_->readString($str); + } +} diff --git a/lib/php/lib/Thrift/Protocol/TSimpleJSONProtocol.php b/lib/php/lib/Thrift/Protocol/TSimpleJSONProtocol.php new file mode 100644 index 0000000..9cf90bd --- /dev/null +++ b/lib/php/lib/Thrift/Protocol/TSimpleJSONProtocol.php @@ -0,0 +1,371 @@ +writeContextStack_[] = $this->writeContext_; + $this->writeContext_ = $c; + } + + /** + * Pop the last write context off the stack + */ + protected function popWriteContext() { + $this->writeContext_ = array_pop($this->writeContextStack_); + } + + /** + * Used to make sure that we are not encountering a map whose keys are containers + */ + protected function assertContextIsNotMapKey($invalidKeyType) { + if ($this->writeContext_->isMapKey()) { + throw new CollectionMapKeyException( + "Cannot serialize a map with keys that are of type " . + $invalidKeyType + ); + } + } + + private function writeJSONString($b) + { + $this->writeContext_->write(); + + $this->trans_->write(json_encode((string)$b)); + } + + private function writeJSONInteger($num) + { + $isMapKey = $this->writeContext_->isMapKey(); + + $this->writeContext_->write(); + + if ($isMapKey) { + $this->trans_->write(self::QUOTE); + } + + $this->trans_->write((int)$num); + + if ($isMapKey) { + $this->trans_->write(self::QUOTE); + } + } + + private function writeJSONDouble($num) + { + $isMapKey = $this->writeContext_->isMapKey(); + + $this->writeContext_->write(); + + if ($isMapKey) { + $this->trans_->write(self::QUOTE); + } + + $this->trans_->write(json_encode((float)$num)); + + if ($isMapKey) { + $this->trans_->write(self::QUOTE); + } + } + + /** + * Constructor + */ + public function __construct($trans) + { + parent::__construct($trans); + $this->writeContext_ = new Context(); + } + + /** + * Writes the message header + * + * @param string $name Function name + * @param int $type message type TMessageType::CALL or TMessageType::REPLY + * @param int $seqid The sequence id of this message + */ + public function writeMessageBegin($name, $type, $seqid) + { + $this->trans_->write(self::LBRACKET); + $this->pushWriteContext(new ListContext($this)); + $this->writeJSONString($name); + $this->writeJSONInteger($type); + $this->writeJSONInteger($seqid); + } + + /** + * Close the message + */ + public function writeMessageEnd() + { + $this->popWriteContext(); + $this->trans_->write(self::RBRACKET); + } + + /** + * Writes a struct header. + * + * @param string $name Struct name + */ + public function writeStructBegin($name) + { + $this->writeContext_->write(); + $this->trans_->write(self::LBRACE); + $this->pushWriteContext(new StructContext($this)); + } + + /** + * Close a struct. + */ + public function writeStructEnd() + { + $this->popWriteContext(); + $this->trans_->write(self::RBRACE); + } + + public function writeFieldBegin($fieldName, $fieldType, $fieldId) + { + $this->writeJSONString($fieldName); + } + + public function writeFieldEnd() + { + } + + public function writeFieldStop() + { + } + + public function writeMapBegin($keyType, $valType, $size) + { + $this->assertContextIsNotMapKey(self::NAME_MAP); + $this->writeContext_->write(); + $this->trans_->write(self::LBRACE); + $this->pushWriteContext(new MapContext($this)); + } + + public function writeMapEnd() + { + $this->popWriteContext(); + $this->trans_->write(self::RBRACE); + } + + public function writeListBegin($elemType, $size) + { + $this->assertContextIsNotMapKey(self::NAME_LIST); + $this->writeContext_->write(); + $this->trans_->write(self::LBRACKET); + $this->pushWriteContext(new ListContext($this)); + // No metadata! + } + + public function writeListEnd() + { + $this->popWriteContext(); + $this->trans_->write(self::RBRACKET); + } + + public function writeSetBegin($elemType, $size) + { + $this->assertContextIsNotMapKey(self::NAME_SET); + $this->writeContext_->write(); + $this->trans_->write(self::LBRACKET); + $this->pushWriteContext(new ListContext($this)); + // No metadata! + } + + public function writeSetEnd() + { + $this->popWriteContext(); + $this->trans_->write(self::RBRACKET); + } + + public function writeBool($bool) + { + $this->writeJSONInteger($bool ? 1 : 0); + } + + public function writeByte($byte) + { + $this->writeJSONInteger($byte); + } + + public function writeI16($i16) + { + $this->writeJSONInteger($i16); + } + + public function writeI32($i32) + { + $this->writeJSONInteger($i32); + } + + public function writeI64($i64) + { + $this->writeJSONInteger($i64); + } + + public function writeDouble($dub) + { + $this->writeJSONDouble($dub); + } + + public function writeString($str) + { + $this->writeJSONString($str); + } + + /** + * Reading methods. + * + * simplejson is not meant to be read back into thrift + * - see http://wiki.apache.org/thrift/ThriftUsageJava + * - use JSON instead + */ + + public function readMessageBegin(&$name, &$type, &$seqid) + { + throw new TException("Not implemented"); + } + + public function readMessageEnd() + { + throw new TException("Not implemented"); + } + + public function readStructBegin(&$name) + { + throw new TException("Not implemented"); + } + + public function readStructEnd() + { + throw new TException("Not implemented"); + } + + public function readFieldBegin(&$name, &$fieldType, &$fieldId) + { + throw new TException("Not implemented"); + } + + public function readFieldEnd() + { + throw new TException("Not implemented"); + } + + public function readMapBegin(&$keyType, &$valType, &$size) + { + throw new TException("Not implemented"); + } + + public function readMapEnd() + { + throw new TException("Not implemented"); + } + + public function readListBegin(&$elemType, &$size) + { + throw new TException("Not implemented"); + } + + public function readListEnd() + { + throw new TException("Not implemented"); + } + + public function readSetBegin(&$elemType, &$size) + { + throw new TException("Not implemented"); + } + + public function readSetEnd() + { + throw new TException("Not implemented"); + } + + public function readBool(&$bool) + { + throw new TException("Not implemented"); + } + + public function readByte(&$byte) + { + throw new TException("Not implemented"); + } + + public function readI16(&$i16) + { + throw new TException("Not implemented"); + } + + public function readI32(&$i32) + { + throw new TException("Not implemented"); + } + + public function readI64(&$i64) + { + throw new TException("Not implemented"); + } + + public function readDouble(&$dub) + { + throw new TException("Not implemented"); + } + + public function readString(&$str) + { + throw new TException("Not implemented"); + } +} diff --git a/lib/php/lib/Thrift/Serializer/TBinarySerializer.php b/lib/php/lib/Thrift/Serializer/TBinarySerializer.php new file mode 100644 index 0000000..aa2f71b --- /dev/null +++ b/lib/php/lib/Thrift/Serializer/TBinarySerializer.php @@ -0,0 +1,85 @@ +getName(), + TMessageType::REPLY, $object, + 0, $protocol->isStrictWrite()); + + $protocol->readMessageBegin($unused_name, $unused_type, + $unused_seqid); + } else { + $object->write($protocol); + } + $protocol->getTransport()->flush(); + + return $transport->getBuffer(); + } + + public static function deserialize($string_object, $class_name, $buffer_size = 8192) + { + $transport = new TMemoryBuffer(); + $protocol = new TBinaryProtocolAccelerated($transport); + if (function_exists('thrift_protocol_read_binary')) { + // NOTE (t.heintz) TBinaryProtocolAccelerated internally wraps our TMemoryBuffer in a + // TBufferedTransport, so we have to retrieve it again or risk losing data when writing + // less than 512 bytes to the transport (see the comment there as well). + // @see THRIFT-1579 + $protocol->writeMessageBegin('', TMessageType::REPLY, 0); + $protocolTransport = $protocol->getTransport(); + $protocolTransport->write($string_object); + $protocolTransport->flush(); + + return thrift_protocol_read_binary($protocol, $class_name, + $protocol->isStrictRead(), + $buffer_size); + } else { + $transport->write($string_object); + $object = new $class_name(); + $object->read($protocol); + + return $object; + } + } +} diff --git a/lib/php/lib/Thrift/Server/TForkingServer.php b/lib/php/lib/Thrift/Server/TForkingServer.php new file mode 100644 index 0000000..7f6e541 --- /dev/null +++ b/lib/php/lib/Thrift/Server/TForkingServer.php @@ -0,0 +1,120 @@ +transport_->listen(); + + while (!$this->stop_) { + try { + $transport = $this->transport_->accept(); + + if ($transport != null) { + $pid = pcntl_fork(); + + if ($pid > 0) { + $this->handleParent($transport, $pid); + } elseif ($pid === 0) { + $this->handleChild($transport); + } else { + throw new TException('Failed to fork'); + } + } + } catch (TTransportException $e) { } + + $this->collectChildren(); + } + } + + /** + * Code run by the parent + * + * @param TTransport $transport + * @param int $pid + * @return void + */ + private function handleParent(TTransport $transport, $pid) + { + $this->children_[$pid] = $transport; + } + + /** + * Code run by the child. + * + * @param TTransport $transport + * @return void + */ + private function handleChild(TTransport $transport) + { + try { + $inputTransport = $this->inputTransportFactory_->getTransport($transport); + $outputTransport = $this->outputTransportFactory_->getTransport($transport); + $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport); + $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport); + while ($this->processor_->process($inputProtocol, $outputProtocol)) { } + @$transport->close(); + } catch (TTransportException $e) { } + + exit(0); + } + + /** + * Collects any children we may have + * + * @return void + */ + private function collectChildren() + { + foreach ($this->children_ as $pid => $transport) { + if (pcntl_waitpid($pid, $status, WNOHANG) > 0) { + unset($this->children_[$pid]); + if ($transport) @$transport->close(); + } + } + } + + /** + * Stops the server running. Kills the transport + * and then stops the main serving loop + * + * @return void + */ + public function stop() + { + $this->transport_->close(); + $this->stop_ = true; + } +} diff --git a/lib/php/lib/Thrift/Server/TSSLServerSocket.php b/lib/php/lib/Thrift/Server/TSSLServerSocket.php new file mode 100644 index 0000000..dfc4704 --- /dev/null +++ b/lib/php/lib/Thrift/Server/TSSLServerSocket.php @@ -0,0 +1,94 @@ +getSSLHost($host); + parent::__construct($ssl_host, $port); + $this->context_ = $context; + } + + public function getSSLHost($host) + { + $transport_protocol_loc = strpos($host, "://"); + if ($transport_protocol_loc === false) { + $host = 'ssl://'.$host; + } + return $host; + } + + /** + * Opens a new socket server handle + * + * @return void + */ + public function listen() + { + $this->listener_ = @stream_socket_server( + $this->host_ . ':' . $this->port_, + $errno, + $errstr, + STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, + $this->context_); + } + + /** + * Implementation of accept. If not client is accepted in the given time + * + * @return TSocket + */ + protected function acceptImpl() + { + $handle = @stream_socket_accept($this->listener_, $this->acceptTimeout_ / 1000.0); + if(!$handle) return null; + + $socket = new TSSLSocket(); + $socket->setHandle($handle); + + return $socket; + } +} diff --git a/lib/php/lib/Thrift/Server/TServer.php b/lib/php/lib/Thrift/Server/TServer.php new file mode 100644 index 0000000..f4d76cc --- /dev/null +++ b/lib/php/lib/Thrift/Server/TServer.php @@ -0,0 +1,100 @@ +processor_ = $processor; + $this->transport_ = $transport; + $this->inputTransportFactory_ = $inputTransportFactory; + $this->outputTransportFactory_ = $outputTransportFactory; + $this->inputProtocolFactory_ = $inputProtocolFactory; + $this->outputProtocolFactory_ = $outputProtocolFactory; + } + + /** + * Serves the server. This should never return + * unless a problem permits it to do so or it + * is interrupted intentionally + * + * @abstract + * @return void + */ + abstract public function serve(); + + /** + * Stops the server serving + * + * @abstract + * @return void + */ + abstract public function stop(); +} diff --git a/lib/php/lib/Thrift/Server/TServerSocket.php b/lib/php/lib/Thrift/Server/TServerSocket.php new file mode 100644 index 0000000..da8e226 --- /dev/null +++ b/lib/php/lib/Thrift/Server/TServerSocket.php @@ -0,0 +1,122 @@ +host_ = $host; + $this->port_ = $port; + } + + /** + * Sets the accept timeout + * + * @param int $acceptTimeout + * @return void + */ + public function setAcceptTimeout($acceptTimeout) + { + $this->acceptTimeout_ = $acceptTimeout; + } + + /** + * Opens a new socket server handle + * + * @return void + */ + public function listen() + { + $this->listener_ = stream_socket_server('tcp://' . $this->host_ . ':' . $this->port_); + } + + /** + * Closes the socket server handle + * + * @return void + */ + public function close() + { + @fclose($this->listener_); + $this->listener_ = null; + } + + /** + * Implementation of accept. If not client is accepted in the given time + * + * @return TSocket + */ + protected function acceptImpl() + { + $handle = @stream_socket_accept($this->listener_, $this->acceptTimeout_ / 1000.0); + if(!$handle) return null; + + $socket = new TSocket(); + $socket->setHandle($handle); + + return $socket; + } +} diff --git a/lib/php/lib/Thrift/Server/TServerTransport.php b/lib/php/lib/Thrift/Server/TServerTransport.php new file mode 100644 index 0000000..f82d06d --- /dev/null +++ b/lib/php/lib/Thrift/Server/TServerTransport.php @@ -0,0 +1,56 @@ +acceptImpl(); + + if ($transport == null) { + throw new TTransportException("accept() may not return NULL"); + } + + return $transport; + } +} diff --git a/lib/php/lib/Thrift/Server/TSimpleServer.php b/lib/php/lib/Thrift/Server/TSimpleServer.php new file mode 100644 index 0000000..e277700 --- /dev/null +++ b/lib/php/lib/Thrift/Server/TSimpleServer.php @@ -0,0 +1,58 @@ +transport_->listen(); + + while (!$this->stop_) { + try { + $transport = $this->transport_->accept(); + + if ($transport != null) { + $inputTransport = $this->inputTransportFactory_->getTransport($transport); + $outputTransport = $this->outputTransportFactory_->getTransport($transport); + $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport); + $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport); + while ($this->processor_->process($inputProtocol, $outputProtocol)) { } + } + } catch (TTransportException $e) { } + } + } + + /** + * Stops the server running. Kills the transport + * and then stops the main serving loop + * + * @return void + */ + public function stop() + { + $this->transport_->close(); + $this->stop_ = true; + } +} diff --git a/lib/php/lib/Thrift/StringFunc/Core.php b/lib/php/lib/Thrift/StringFunc/Core.php new file mode 100644 index 0000000..39a75b3 --- /dev/null +++ b/lib/php/lib/Thrift/StringFunc/Core.php @@ -0,0 +1,40 @@ +strlen($str) - $start; + } + + return mb_substr($str, $start, $length, '8bit'); + } + + public function strlen($str) + { + return mb_strlen($str, '8bit'); + } +} diff --git a/lib/php/lib/Thrift/StringFunc/TStringFunc.php b/lib/php/lib/Thrift/StringFunc/TStringFunc.php new file mode 100644 index 0000000..dea497f --- /dev/null +++ b/lib/php/lib/Thrift/StringFunc/TStringFunc.php @@ -0,0 +1,28 @@ +TMultiplexedProcessor is a Processor allowing + * a single TServer to provide multiple services. + * + *

To do so, you instantiate the processor and then register additional + * processors with it, as shown in the following example:

+ * + *
+ * $processor = new TMultiplexedProcessor(); + * + * processor->registerProcessor( + * "Calculator", + * new \tutorial\CalculatorProcessor(new CalculatorHandler())); + * + * processor->registerProcessor( + * "WeatherReport", + * new \tutorial\WeatherReportProcessor(new WeatherReportHandler())); + * + * $processor->process($protocol, $protocol); + *
+ */ + +class TMultiplexedProcessor +{ + private $serviceProcessorMap_; + + /** + * 'Register' a service with this TMultiplexedProcessor. This + * allows us to broker requests to individual services by using the service + * name to select them at request time. + * + * @param serviceName Name of a service, has to be identical to the name + * declared in the Thrift IDL, e.g. "WeatherReport". + * @param processor Implementation of a service, usually referred to + * as "handlers", e.g. WeatherReportHandler implementing WeatherReport.Iface. + */ + public function registerProcessor($serviceName, $processor) + { + $this->serviceProcessorMap_[$serviceName] = $processor; + } + + /** + * This implementation of process performs the following steps: + * + *
    + *
  1. Read the beginning of the message.
  2. + *
  3. Extract the service name from the message.
  4. + *
  5. Using the service name to locate the appropriate processor.
  6. + *
  7. Dispatch to the processor, with a decorated instance of TProtocol + * that allows readMessageBegin() to return the original Message.
  8. + *
+ * + * @throws TException If the message type is not CALL or ONEWAY, if + * the service name was not found in the message, or if the service + * name was not found in the service map. + */ + public function process(TProtocol $input, TProtocol $output) + { + /* + Use the actual underlying protocol (e.g. TBinaryProtocol) to read the + message header. This pulls the message "off the wire", which we'll + deal with at the end of this method. + */ + $input->readMessageBegin($fname, $mtype, $rseqid); + + if ($mtype !== TMessageType::CALL && $mtype != TMessageType::ONEWAY) { + throw new TException("This should not have happened!?"); + } + + // Extract the service name and the new Message name. + if (strpos($fname, TMultiplexedProtocol::SEPARATOR) === false) { + throw new TException("Service name not found in message name: {$fname}. Did you " . + "forget to use a TMultiplexProtocol in your client?"); + } + list($serviceName, $messageName) = explode(':', $fname, 2); + if (!array_key_exists($serviceName, $this->serviceProcessorMap_)) { + throw new TException("Service name not found: {$serviceName}. Did you forget " . + "to call registerProcessor()?"); + } + + // Dispatch processing to the stored processor + $processor = $this->serviceProcessorMap_[$serviceName]; + + return $processor->process( + new StoredMessageProtocol($input, $messageName, $mtype, $rseqid), $output + ); + } +} + +/** + * Our goal was to work with any protocol. In order to do that, we needed + * to allow them to call readMessageBegin() and get the Message in exactly + * the standard format, without the service name prepended to the Message name. + */ +class StoredMessageProtocol extends TProtocolDecorator +{ + private $fname_, $mtype_, $rseqid_; + + public function __construct(TProtocol $protocol, $fname, $mtype, $rseqid) + { + parent::__construct($protocol); + $this->fname_ = $fname; + $this->mtype_ = $mtype; + $this->rseqid_ = $rseqid; + } + + public function readMessageBegin(&$name, &$type, &$seqid) + { + $name = $this->fname_; + $type = $this->mtype_; + $seqid = $this->rseqid_; + } +} diff --git a/lib/php/lib/Thrift/Transport/TBufferedTransport.php b/lib/php/lib/Thrift/Transport/TBufferedTransport.php new file mode 100644 index 0000000..f654ad3 --- /dev/null +++ b/lib/php/lib/Thrift/Transport/TBufferedTransport.php @@ -0,0 +1,181 @@ +transport_ = $transport; + $this->rBufSize_ = $rBufSize; + $this->wBufSize_ = $wBufSize; + } + + /** + * The underlying transport + * + * @var TTransport + */ + protected $transport_ = null; + + /** + * The receive buffer size + * + * @var int + */ + protected $rBufSize_ = 512; + + /** + * The write buffer size + * + * @var int + */ + protected $wBufSize_ = 512; + + /** + * The write buffer. + * + * @var string + */ + protected $wBuf_ = ''; + + /** + * The read buffer. + * + * @var string + */ + protected $rBuf_ = ''; + + public function isOpen() + { + return $this->transport_->isOpen(); + } + + public function open() + { + $this->transport_->open(); + } + + public function close() + { + $this->transport_->close(); + } + + public function putBack($data) + { + if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { + $this->rBuf_ = $data; + } else { + $this->rBuf_ = ($data . $this->rBuf_); + } + } + + /** + * The reason that we customize readAll here is that the majority of PHP + * streams are already internally buffered by PHP. The socket stream, for + * example, buffers internally and blocks if you call read with $len greater + * than the amount of data available, unlike recv() in C. + * + * Therefore, use the readAll method of the wrapped transport inside + * the buffered readAll. + */ + public function readAll($len) + { + $have = TStringFuncFactory::create()->strlen($this->rBuf_); + if ($have == 0) { + $data = $this->transport_->readAll($len); + } elseif ($have < $len) { + $data = $this->rBuf_; + $this->rBuf_ = ''; + $data .= $this->transport_->readAll($len - $have); + } elseif ($have == $len) { + $data = $this->rBuf_; + $this->rBuf_ = ''; + } elseif ($have > $len) { + $data = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len); + $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len); + } + + return $data; + } + + public function read($len) + { + if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { + $this->rBuf_ = $this->transport_->read($this->rBufSize_); + } + + if (TStringFuncFactory::create()->strlen($this->rBuf_) <= $len) { + $ret = $this->rBuf_; + $this->rBuf_ = ''; + + return $ret; + } + + $ret = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len); + $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len); + + return $ret; + } + + public function write($buf) + { + $this->wBuf_ .= $buf; + if (TStringFuncFactory::create()->strlen($this->wBuf_) >= $this->wBufSize_) { + $out = $this->wBuf_; + + // Note that we clear the internal wBuf_ prior to the underlying write + // to ensure we're in a sane state (i.e. internal buffer cleaned) + // if the underlying write throws up an exception + $this->wBuf_ = ''; + $this->transport_->write($out); + } + } + + public function flush() + { + if (TStringFuncFactory::create()->strlen($this->wBuf_) > 0) { + $out = $this->wBuf_; + + // Note that we clear the internal wBuf_ prior to the underlying write + // to ensure we're in a sane state (i.e. internal buffer cleaned) + // if the underlying write throws up an exception + $this->wBuf_ = ''; + $this->transport_->write($out); + } + $this->transport_->flush(); + } + +} diff --git a/lib/php/lib/Thrift/Transport/TCurlClient.php b/lib/php/lib/Thrift/Transport/TCurlClient.php new file mode 100644 index 0000000..c761cd0 --- /dev/null +++ b/lib/php/lib/Thrift/Transport/TCurlClient.php @@ -0,0 +1,249 @@ +strlen($uri) > 0) && ($uri{0} != '/')) { + $uri = '/'.$uri; + } + $this->scheme_ = $scheme; + $this->host_ = $host; + $this->port_ = $port; + $this->uri_ = $uri; + $this->request_ = ''; + $this->response_ = null; + $this->timeout_ = null; + $this->headers_ = array(); + } + + /** + * Set read timeout + * + * @param float $timeout + */ + public function setTimeoutSecs($timeout) + { + $this->timeout_ = $timeout; + } + + /** + * Whether this transport is open. + * + * @return boolean true if open + */ + public function isOpen() + { + return true; + } + + /** + * Open the transport for reading/writing + * + * @throws TTransportException if cannot open + */ + public function open() + { + } + + /** + * Close the transport. + */ + public function close() + { + $this->request_ = ''; + $this->response_ = null; + } + + /** + * Read some data into the array. + * + * @param int $len How much to read + * @return string The data that has been read + * @throws TTransportException if cannot read any more data + */ + public function read($len) + { + if ($len >= strlen($this->response_)) { + return $this->response_; + } else { + $ret = substr($this->response_, 0, $len); + $this->response_ = substr($this->response_, $len); + + return $ret; + } + } + + /** + * Writes some data into the pending buffer + * + * @param string $buf The data to write + * @throws TTransportException if writing fails + */ + public function write($buf) + { + $this->request_ .= $buf; + } + + /** + * Opens and sends the actual request over the HTTP connection + * + * @throws TTransportException if a writing error occurs + */ + public function flush() + { + if (!self::$curlHandle) { + register_shutdown_function(array('Thrift\\Transport\\TCurlClient', 'closeCurlHandle')); + self::$curlHandle = curl_init(); + curl_setopt(self::$curlHandle, CURLOPT_RETURNTRANSFER, true); + curl_setopt(self::$curlHandle, CURLOPT_BINARYTRANSFER, true); + curl_setopt(self::$curlHandle, CURLOPT_USERAGENT, 'PHP/TCurlClient'); + curl_setopt(self::$curlHandle, CURLOPT_CUSTOMREQUEST, 'POST'); + curl_setopt(self::$curlHandle, CURLOPT_FOLLOWLOCATION, true); + curl_setopt(self::$curlHandle, CURLOPT_MAXREDIRS, 1); + } + // God, PHP really has some esoteric ways of doing simple things. + $host = $this->host_.($this->port_ != 80 ? ':'.$this->port_ : ''); + $fullUrl = $this->scheme_."://".$host.$this->uri_; + + $headers = array(); + $defaultHeaders = array('Accept' => 'application/x-thrift', + 'Content-Type' => 'application/x-thrift', + 'Content-Length' => TStringFuncFactory::create()->strlen($this->request_)); + foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) { + $headers[] = "$key: $value"; + } + + curl_setopt(self::$curlHandle, CURLOPT_HTTPHEADER, $headers); + + if ($this->timeout_ > 0) { + curl_setopt(self::$curlHandle, CURLOPT_TIMEOUT, $this->timeout_); + } + curl_setopt(self::$curlHandle, CURLOPT_POSTFIELDS, $this->request_); + $this->request_ = ''; + + curl_setopt(self::$curlHandle, CURLOPT_URL, $fullUrl); + $this->response_ = curl_exec(self::$curlHandle); + + // Connect failed? + if (!$this->response_) { + curl_close(self::$curlHandle); + self::$curlHandle = null; + $error = 'TCurlClient: Could not connect to '.$fullUrl; + throw new TTransportException($error, TTransportException::NOT_OPEN); + } + } + + public static function closeCurlHandle() + { + try { + if (self::$curlHandle) { + curl_close(self::$curlHandle); + self::$curlHandle = null; + } + } catch (\Exception $x) { + error_log('There was an error closing the curl handle: ' . $x->getMessage()); + } + } + + public function addHeaders($headers) + { + $this->headers_ = array_merge($this->headers_, $headers); + } + +} diff --git a/lib/php/lib/Thrift/Transport/TFramedTransport.php b/lib/php/lib/Thrift/Transport/TFramedTransport.php new file mode 100644 index 0000000..b8a64a9 --- /dev/null +++ b/lib/php/lib/Thrift/Transport/TFramedTransport.php @@ -0,0 +1,193 @@ +transport_ = $transport; + $this->read_ = $read; + $this->write_ = $write; + } + + public function isOpen() + { + return $this->transport_->isOpen(); + } + + public function open() + { + $this->transport_->open(); + } + + public function close() + { + $this->transport_->close(); + } + + /** + * Reads from the buffer. When more data is required reads another entire + * chunk and serves future reads out of that. + * + * @param int $len How much data + */ + public function read($len) + { + if (!$this->read_) { + return $this->transport_->read($len); + } + + if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { + $this->readFrame(); + } + + // Just return full buff + if ($len >= TStringFuncFactory::create()->strlen($this->rBuf_)) { + $out = $this->rBuf_; + $this->rBuf_ = null; + + return $out; + } + + // Return TStringFuncFactory::create()->substr + $out = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len); + $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len); + + return $out; + } + + /** + * Put previously read data back into the buffer + * + * @param string $data data to return + */ + public function putBack($data) + { + if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { + $this->rBuf_ = $data; + } else { + $this->rBuf_ = ($data . $this->rBuf_); + } + } + + /** + * Reads a chunk of data into the internal read buffer. + */ + private function readFrame() + { + $buf = $this->transport_->readAll(4); + $val = unpack('N', $buf); + $sz = $val[1]; + + $this->rBuf_ = $this->transport_->readAll($sz); + } + + /** + * Writes some data to the pending output buffer. + * + * @param string $buf The data + * @param int $len Limit of bytes to write + */ + public function write($buf, $len=null) + { + if (!$this->write_) { + return $this->transport_->write($buf, $len); + } + + if ($len !== null && $len < TStringFuncFactory::create()->strlen($buf)) { + $buf = TStringFuncFactory::create()->substr($buf, 0, $len); + } + $this->wBuf_ .= $buf; + } + + /** + * Writes the output buffer to the stream in the format of a 4-byte length + * followed by the actual data. + */ + public function flush() + { + if (!$this->write_ || TStringFuncFactory::create()->strlen($this->wBuf_) == 0) { + return $this->transport_->flush(); + } + + $out = pack('N', TStringFuncFactory::create()->strlen($this->wBuf_)); + $out .= $this->wBuf_; + + // Note that we clear the internal wBuf_ prior to the underlying write + // to ensure we're in a sane state (i.e. internal buffer cleaned) + // if the underlying write throws up an exception + $this->wBuf_ = ''; + $this->transport_->write($out); + $this->transport_->flush(); + } + +} diff --git a/lib/php/lib/Thrift/Transport/THttpClient.php b/lib/php/lib/Thrift/Transport/THttpClient.php new file mode 100644 index 0000000..b372ab7 --- /dev/null +++ b/lib/php/lib/Thrift/Transport/THttpClient.php @@ -0,0 +1,229 @@ +strlen($uri) > 0) && ($uri{0} != '/')) { + $uri = '/'.$uri; + } + $this->scheme_ = $scheme; + $this->host_ = $host; + $this->port_ = $port; + $this->uri_ = $uri; + $this->buf_ = ''; + $this->handle_ = null; + $this->timeout_ = null; + $this->headers_ = array(); + } + + /** + * Set read timeout + * + * @param float $timeout + */ + public function setTimeoutSecs($timeout) + { + $this->timeout_ = $timeout; + } + + /** + * Whether this transport is open. + * + * @return boolean true if open + */ + public function isOpen() + { + return true; + } + + /** + * Open the transport for reading/writing + * + * @throws TTransportException if cannot open + */ + public function open() {} + + /** + * Close the transport. + */ + public function close() + { + if ($this->handle_) { + @fclose($this->handle_); + $this->handle_ = null; + } + } + + /** + * Read some data into the array. + * + * @param int $len How much to read + * @return string The data that has been read + * @throws TTransportException if cannot read any more data + */ + public function read($len) + { + $data = @fread($this->handle_, $len); + if ($data === FALSE || $data === '') { + $md = stream_get_meta_data($this->handle_); + if ($md['timed_out']) { + throw new TTransportException('THttpClient: timed out reading '.$len.' bytes from '.$this->host_.':'.$this->port_.$this->uri_, TTransportException::TIMED_OUT); + } else { + throw new TTransportException('THttpClient: Could not read '.$len.' bytes from '.$this->host_.':'.$this->port_.$this->uri_, TTransportException::UNKNOWN); + } + } + + return $data; + } + + /** + * Writes some data into the pending buffer + * + * @param string $buf The data to write + * @throws TTransportException if writing fails + */ + public function write($buf) + { + $this->buf_ .= $buf; + } + + /** + * Opens and sends the actual request over the HTTP connection + * + * @throws TTransportException if a writing error occurs + */ + public function flush() + { + // God, PHP really has some esoteric ways of doing simple things. + $host = $this->host_.($this->port_ != 80 ? ':'.$this->port_ : ''); + + $headers = array(); + $defaultHeaders = array('Host' => $host, + 'Accept' => 'application/x-thrift', + 'User-Agent' => 'PHP/THttpClient', + 'Content-Type' => 'application/x-thrift', + 'Content-Length' => TStringFuncFactory::create()->strlen($this->buf_)); + foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) { + $headers[] = "$key: $value"; + } + + $options = array('method' => 'POST', + 'header' => implode("\r\n", $headers), + 'max_redirects' => 1, + 'content' => $this->buf_); + if ($this->timeout_ > 0) { + $options['timeout'] = $this->timeout_; + } + $this->buf_ = ''; + + $contextid = stream_context_create(array('http' => $options)); + $this->handle_ = @fopen($this->scheme_.'://'.$host.$this->uri_, 'r', false, $contextid); + + // Connect failed? + if ($this->handle_ === FALSE) { + $this->handle_ = null; + $error = 'THttpClient: Could not connect to '.$host.$this->uri_; + throw new TTransportException($error, TTransportException::NOT_OPEN); + } + } + + public function addHeaders($headers) + { + $this->headers_ = array_merge($this->headers_, $headers); + } + +} diff --git a/lib/php/lib/Thrift/Transport/TMemoryBuffer.php b/lib/php/lib/Thrift/Transport/TMemoryBuffer.php new file mode 100644 index 0000000..ca31c57 --- /dev/null +++ b/lib/php/lib/Thrift/Transport/TMemoryBuffer.php @@ -0,0 +1,100 @@ +buf_ = $buf; + } + + protected $buf_ = ''; + + public function isOpen() + { + return true; + } + + public function open() {} + + public function close() {} + + public function write($buf) + { + $this->buf_ .= $buf; + } + + public function read($len) + { + $bufLength = TStringFuncFactory::create()->strlen($this->buf_); + + if ($bufLength === 0) { + throw new TTransportException('TMemoryBuffer: Could not read ' . + $len . ' bytes from buffer.', + TTransportException::UNKNOWN); + } + + if ($bufLength <= $len) { + $ret = $this->buf_; + $this->buf_ = ''; + + return $ret; + } + + $ret = TStringFuncFactory::create()->substr($this->buf_, 0, $len); + $this->buf_ = TStringFuncFactory::create()->substr($this->buf_, $len); + + return $ret; + } + + public function getBuffer() + { + return $this->buf_; + } + + public function available() + { + return TStringFuncFactory::create()->strlen($this->buf_); + } + + public function putBack($data) + { + $this->buf_ = $data.$this->buf_; + } +} diff --git a/lib/php/lib/Thrift/Transport/TNullTransport.php b/lib/php/lib/Thrift/Transport/TNullTransport.php new file mode 100644 index 0000000..feeb7a4 --- /dev/null +++ b/lib/php/lib/Thrift/Transport/TNullTransport.php @@ -0,0 +1,51 @@ +read_ = $mode & self::MODE_R; + $this->write_ = $mode & self::MODE_W; + } + + public function open() + { + if ($this->read_) { + $this->inStream_ = @fopen(self::inStreamName(), 'r'); + if (!is_resource($this->inStream_)) { + throw new TException('TPhpStream: Could not open php://input'); + } + } + if ($this->write_) { + $this->outStream_ = @fopen('php://output', 'w'); + if (!is_resource($this->outStream_)) { + throw new TException('TPhpStream: Could not open php://output'); + } + } + } + + public function close() + { + if ($this->read_) { + @fclose($this->inStream_); + $this->inStream_ = null; + } + if ($this->write_) { + @fclose($this->outStream_); + $this->outStream_ = null; + } + } + + public function isOpen() + { + return + (!$this->read_ || is_resource($this->inStream_)) && + (!$this->write_ || is_resource($this->outStream_)); + } + + public function read($len) + { + $data = @fread($this->inStream_, $len); + if ($data === FALSE || $data === '') { + throw new TException('TPhpStream: Could not read '.$len.' bytes'); + } + + return $data; + } + + public function write($buf) + { + while (TStringFuncFactory::create()->strlen($buf) > 0) { + $got = @fwrite($this->outStream_, $buf); + if ($got === 0 || $got === FALSE) { + throw new TException('TPhpStream: Could not write '.TStringFuncFactory::create()->strlen($buf).' bytes'); + } + $buf = TStringFuncFactory::create()->substr($buf, $got); + } + } + + public function flush() + { + @fflush($this->outStream_); + } + + private static function inStreamName() + { + if (php_sapi_name() == 'cli') { + return 'php://stdin'; + } + + return 'php://input'; + } + +} diff --git a/lib/php/lib/Thrift/Transport/TSSLSocket.php b/lib/php/lib/Thrift/Transport/TSSLSocket.php new file mode 100644 index 0000000..533b7bb --- /dev/null +++ b/lib/php/lib/Thrift/Transport/TSSLSocket.php @@ -0,0 +1,112 @@ +host_ = $this->getSSLHost($host); + $this->port_ = $port; + $this->context_ = $context; + $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log'; + } + + /** + * Creates a host name with SSL transport protocol + * if no transport protocol already specified in + * the host name. + * + * @param string $host Host to listen on + * @return string $host Host name with transport protocol + */ + private function getSSLHost($host) + { + $transport_protocol_loc = strpos($host, "://"); + if ($transport_protocol_loc === false) { + $host = 'ssl://'.$host; + } + return $host; + } + + /** + * Connects the socket. + */ + public function open() + { + if ($this->isOpen()) { + throw new TTransportException('Socket already connected', TTransportException::ALREADY_OPEN); + } + + if (empty($this->host_)) { + throw new TTransportException('Cannot open null host', TTransportException::NOT_OPEN); + } + + if ($this->port_ <= 0) { + throw new TTransportException('Cannot open without port', TTransportException::NOT_OPEN); + } + + $this->handle_ = @stream_socket_client($this->host_.':'.$this->port_, + $errno, + $errstr, + $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000), + STREAM_CLIENT_CONNECT, + $this->context_); + + // Connect failed? + if ($this->handle_ === FALSE) { + $error = 'TSocket: Could not connect to '.$this->host_.':'.$this->port_.' ('.$errstr.' ['.$errno.'])'; + if ($this->debug_) { + call_user_func($this->debugHandler_, $error); + } + throw new TException($error); + } + } +} diff --git a/lib/php/lib/Thrift/Transport/TSocket.php b/lib/php/lib/Thrift/Transport/TSocket.php new file mode 100644 index 0000000..a1872b9 --- /dev/null +++ b/lib/php/lib/Thrift/Transport/TSocket.php @@ -0,0 +1,340 @@ +host_ = $host; + $this->port_ = $port; + $this->persist_ = $persist; + $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log'; + } + + /** + * @param resource $handle + * @return void + */ + public function setHandle($handle) + { + $this->handle_ = $handle; + } + + /** + * Sets the send timeout. + * + * @param int $timeout Timeout in milliseconds. + */ + public function setSendTimeout($timeout) + { + $this->sendTimeoutSec_ = floor($timeout / 1000); + $this->sendTimeoutUsec_ = + ($timeout - ($this->sendTimeoutSec_ * 1000)) * 1000; + } + + /** + * Sets the receive timeout. + * + * @param int $timeout Timeout in milliseconds. + */ + public function setRecvTimeout($timeout) + { + $this->recvTimeoutSec_ = floor($timeout / 1000); + $this->recvTimeoutUsec_ = + ($timeout - ($this->recvTimeoutSec_ * 1000)) * 1000; + } + + /** + * Sets debugging output on or off + * + * @param bool $debug + */ + public function setDebug($debug) + { + $this->debug_ = $debug; + } + + /** + * Get the host that this socket is connected to + * + * @return string host + */ + public function getHost() + { + return $this->host_; + } + + /** + * Get the remote port that this socket is connected to + * + * @return int port + */ + public function getPort() + { + return $this->port_; + } + + /** + * Tests whether this is open + * + * @return bool true if the socket is open + */ + public function isOpen() + { + return is_resource($this->handle_); + } + + /** + * Connects the socket. + */ + public function open() + { + if ($this->isOpen()) { + throw new TTransportException('Socket already connected', TTransportException::ALREADY_OPEN); + } + + if (empty($this->host_)) { + throw new TTransportException('Cannot open null host', TTransportException::NOT_OPEN); + } + + if ($this->port_ <= 0) { + throw new TTransportException('Cannot open without port', TTransportException::NOT_OPEN); + } + + if ($this->persist_) { + $this->handle_ = @pfsockopen($this->host_, + $this->port_, + $errno, + $errstr, + $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000)); + } else { + $this->handle_ = @fsockopen($this->host_, + $this->port_, + $errno, + $errstr, + $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000)); + } + + // Connect failed? + if ($this->handle_ === FALSE) { + $error = 'TSocket: Could not connect to '.$this->host_.':'.$this->port_.' ('.$errstr.' ['.$errno.'])'; + if ($this->debug_) { + call_user_func($this->debugHandler_, $error); + } + throw new TException($error); + } + + if (function_exists('socket_import_stream') && function_exists('socket_set_option')) { + $socket = socket_import_stream($this->handle_); + socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); + } + } + + /** + * Closes the socket. + */ + public function close() + { + @fclose($this->handle_); + $this->handle_ = null; + } + + /** + * Read from the socket at most $len bytes. + * + * This method will not wait for all the requested data, it will return as + * soon as any data is received. + * + * @param int $len Maximum number of bytes to read. + * @return string Binary data + */ + public function read($len) + { + $null = null; + $read = array($this->handle_); + $readable = @stream_select($read, $null, $null, $this->recvTimeoutSec_, $this->recvTimeoutUsec_); + + if ($readable > 0) { + $data = fread($this->handle_, $len); + if ($data === false) { + throw new TTransportException('TSocket: Could not read '.$len.' bytes from '. + $this->host_.':'.$this->port_); + } elseif ($data == '' && feof($this->handle_)) { + throw new TTransportException('TSocket read 0 bytes'); + } + + return $data; + } elseif ($readable === 0) { + throw new TTransportException('TSocket: timed out reading '.$len.' bytes from '. + $this->host_.':'.$this->port_); + } else { + throw new TTransportException('TSocket: Could not read '.$len.' bytes from '. + $this->host_.':'.$this->port_); + } + } + + /** + * Write to the socket. + * + * @param string $buf The data to write + */ + public function write($buf) + { + $null = null; + $write = array($this->handle_); + + // keep writing until all the data has been written + while (TStringFuncFactory::create()->strlen($buf) > 0) { + // wait for stream to become available for writing + $writable = @stream_select($null, $write, $null, $this->sendTimeoutSec_, $this->sendTimeoutUsec_); + if ($writable > 0) { + // write buffer to stream + $written = fwrite($this->handle_, $buf); + if ($written === -1 || $written === false) { + throw new TTransportException('TSocket: Could not write '.TStringFuncFactory::create()->strlen($buf).' bytes '. + $this->host_.':'.$this->port_); + } + // determine how much of the buffer is left to write + $buf = TStringFuncFactory::create()->substr($buf, $written); + } elseif ($writable === 0) { + throw new TTransportException('TSocket: timed out writing '.TStringFuncFactory::create()->strlen($buf).' bytes from '. + $this->host_.':'.$this->port_); + } else { + throw new TTransportException('TSocket: Could not write '.TStringFuncFactory::create()->strlen($buf).' bytes '. + $this->host_.':'.$this->port_); + } + } + } + + /** + * Flush output to the socket. + * + * Since read(), readAll() and write() operate on the sockets directly, + * this is a no-op + * + * If you wish to have flushable buffering behaviour, wrap this TSocket + * in a TBufferedTransport. + */ + public function flush() + { + // no-op + } + } diff --git a/lib/php/lib/Thrift/Transport/TSocketPool.php b/lib/php/lib/Thrift/Transport/TSocketPool.php new file mode 100644 index 0000000..18ffd8d --- /dev/null +++ b/lib/php/lib/Thrift/Transport/TSocketPool.php @@ -0,0 +1,300 @@ + $val) { + $ports[$key] = $port; + } + } + + foreach ($hosts as $key => $host) { + $this->servers_ []= array('host' => $host, + 'port' => $ports[$key]); + } + } + + /** + * Add a server to the pool + * + * This function does not prevent you from adding a duplicate server entry. + * + * @param string $host hostname or IP + * @param int $port port + */ + public function addServer($host, $port) + { + $this->servers_[] = array('host' => $host, 'port' => $port); + } + + /** + * Sets how many time to keep retrying a host in the connect function. + * + * @param int $numRetries + */ + public function setNumRetries($numRetries) + { + $this->numRetries_ = $numRetries; + } + + /** + * Sets how long to wait until retrying a host if it was marked down + * + * @param int $numRetries + */ + public function setRetryInterval($retryInterval) + { + $this->retryInterval_ = $retryInterval; + } + + /** + * Sets how many time to keep retrying a host before marking it as down. + * + * @param int $numRetries + */ + public function setMaxConsecutiveFailures($maxConsecutiveFailures) + { + $this->maxConsecutiveFailures_ = $maxConsecutiveFailures; + } + + /** + * Turns randomization in connect order on or off. + * + * @param bool $randomize + */ + public function setRandomize($randomize) + { + $this->randomize_ = $randomize; + } + + /** + * Whether to always try the last server. + * + * @param bool $alwaysTryLast + */ + public function setAlwaysTryLast($alwaysTryLast) + { + $this->alwaysTryLast_ = $alwaysTryLast; + } + + /** + * Connects the socket by iterating through all the servers in the pool + * and trying to find one that works. + */ + public function open() + { + // Check if we want order randomization + if ($this->randomize_) { + shuffle($this->servers_); + } + + // Count servers to identify the "last" one + $numServers = count($this->servers_); + + for ($i = 0; $i < $numServers; ++$i) { + + // This extracts the $host and $port variables + extract($this->servers_[$i]); + + // Check APC cache for a record of this server being down + $failtimeKey = 'thrift_failtime:'.$host.':'.$port.'~'; + + // Cache miss? Assume it's OK + $lastFailtime = apc_fetch($failtimeKey); + if ($lastFailtime === FALSE) { + $lastFailtime = 0; + } + + $retryIntervalPassed = false; + + // Cache hit...make sure enough the retry interval has elapsed + if ($lastFailtime > 0) { + $elapsed = time() - $lastFailtime; + if ($elapsed > $this->retryInterval_) { + $retryIntervalPassed = true; + if ($this->debug_) { + call_user_func($this->debugHandler_, + 'TSocketPool: retryInterval '. + '('.$this->retryInterval_.') '. + 'has passed for host '.$host.':'.$port); + } + } + } + + // Only connect if not in the middle of a fail interval, OR if this + // is the LAST server we are trying, just hammer away on it + $isLastServer = false; + if ($this->alwaysTryLast_) { + $isLastServer = ($i == ($numServers - 1)); + } + + if (($lastFailtime === 0) || + ($isLastServer) || + ($lastFailtime > 0 && $retryIntervalPassed)) { + + // Set underlying TSocket params to this one + $this->host_ = $host; + $this->port_ = $port; + + // Try up to numRetries_ connections per server + for ($attempt = 0; $attempt < $this->numRetries_; $attempt++) { + try { + // Use the underlying TSocket open function + parent::open(); + + // Only clear the failure counts if required to do so + if ($lastFailtime > 0) { + apc_store($failtimeKey, 0); + } + + // Successful connection, return now + return; + + } catch (TException $tx) { + // Connection failed + } + } + + // Mark failure of this host in the cache + $consecfailsKey = 'thrift_consecfails:'.$host.':'.$port.'~'; + + // Ignore cache misses + $consecfails = apc_fetch($consecfailsKey); + if ($consecfails === FALSE) { + $consecfails = 0; + } + + // Increment by one + $consecfails++; + + // Log and cache this failure + if ($consecfails >= $this->maxConsecutiveFailures_) { + if ($this->debug_) { + call_user_func($this->debugHandler_, + 'TSocketPool: marking '.$host.':'.$port. + ' as down for '.$this->retryInterval_.' secs '. + 'after '.$consecfails.' failed attempts.'); + } + // Store the failure time + apc_store($failtimeKey, time()); + + // Clear the count of consecutive failures + apc_store($consecfailsKey, 0); + } else { + apc_store($consecfailsKey, $consecfails); + } + } + } + + // Oh no; we failed them all. The system is totally ill! + $error = 'TSocketPool: All hosts in pool are down. '; + $hosts = array(); + foreach ($this->servers_ as $server) { + $hosts []= $server['host'].':'.$server['port']; + } + $hostlist = implode(',', $hosts); + $error .= '('.$hostlist.')'; + if ($this->debug_) { + call_user_func($this->debugHandler_, $error); + } + throw new TException($error); + } +} diff --git a/lib/php/lib/Thrift/Transport/TTransport.php b/lib/php/lib/Thrift/Transport/TTransport.php new file mode 100644 index 0000000..99c39ff --- /dev/null +++ b/lib/php/lib/Thrift/Transport/TTransport.php @@ -0,0 +1,95 @@ +read($len); + + $data = ''; + $got = 0; + while (($got = TStringFuncFactory::create()->strlen($data)) < $len) { + $data .= $this->read($len - $got); + } + + return $data; + } + + /** + * Writes the given data out. + * + * @param string $buf The data to write + * @throws TTransportException if writing fails + */ + abstract public function write($buf); + + /** + * Flushes any pending data out of a buffer + * + * @throws TTransportException if a writing error occurs + */ + public function flush() {} +} diff --git a/lib/php/lib/Thrift/Type/TConstant.php b/lib/php/lib/Thrift/Type/TConstant.php new file mode 100644 index 0000000..7c8eceb --- /dev/null +++ b/lib/php/lib/Thrift/Type/TConstant.php @@ -0,0 +1,50 @@ +strlen($str) - $start; + } + + return mb_substr($str, $start, $length, '8bit'); + } + + public function strlen($str) + { + return mb_strlen($str, '8bit'); + } +} + +class TStringFuncFactory +{ + private static $_instance; + + /** + * Get the Singleton instance of TStringFunc implementation that is + * compatible with the current system's mbstring.func_overload settings. + * + * @return TStringFunc + */ + public static function create() + { + if (!self::$_instance) { + self::_setInstance(); + } + + return self::$_instance; + } + + private static function _setInstance() + { + /** + * Cannot use str* functions for byte counting because multibyte + * characters will be read a single bytes. + * + * See: http://us.php.net/manual/en/mbstring.overload.php + */ + if (ini_get('mbstring.func_overload') & 2) { + self::$_instance = new TStringFunc_Mbstring(); + } + /** + * mbstring is not installed or does not have function overloading + * of the str* functions enabled so use PHP core str* functions for + * byte counting. + */ + else { + self::$_instance = new TStringFunc_Core(); + } + } +} diff --git a/lib/php/src/Thrift.php b/lib/php/src/Thrift.php new file mode 100644 index 0000000..4fe4392 --- /dev/null +++ b/lib/php/src/Thrift.php @@ -0,0 +1,821 @@ + $fspec) { + $var = $fspec['var']; + if (isset($vals[$var])) { + $this->$var = $vals[$var]; + } + } + } else { + parent::__construct($p1, $p2); + } + } + + static $tmethod = array(TType::BOOL => 'Bool', + TType::BYTE => 'Byte', + TType::I16 => 'I16', + TType::I32 => 'I32', + TType::I64 => 'I64', + TType::DOUBLE => 'Double', + TType::STRING => 'String'); + + private function _readMap(&$var, $spec, $input) + { + $xfer = 0; + $ktype = $spec['ktype']; + $vtype = $spec['vtype']; + $kread = $vread = null; + if (isset(TBase::$tmethod[$ktype])) { + $kread = 'read'.TBase::$tmethod[$ktype]; + } else { + $kspec = $spec['key']; + } + if (isset(TBase::$tmethod[$vtype])) { + $vread = 'read'.TBase::$tmethod[$vtype]; + } else { + $vspec = $spec['val']; + } + $var = array(); + $_ktype = $_vtype = $size = 0; + $xfer += $input->readMapBegin($_ktype, $_vtype, $size); + for ($i = 0; $i < $size; ++$i) { + $key = $val = null; + if ($kread !== null) { + $xfer += $input->$kread($key); + } else { + switch ($ktype) { + case TType::STRUCT: + $class = $kspec['class']; + $key = new $class(); + $xfer += $key->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($key, $kspec, $input); + break; + case TType::LST: + $xfer += $this->_readList($key, $kspec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($key, $kspec, $input, true); + break; + } + } + if ($vread !== null) { + $xfer += $input->$vread($val); + } else { + switch ($vtype) { + case TType::STRUCT: + $class = $vspec['class']; + $val = new $class(); + $xfer += $val->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($val, $vspec, $input); + break; + case TType::LST: + $xfer += $this->_readList($val, $vspec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($val, $vspec, $input, true); + break; + } + } + $var[$key] = $val; + } + $xfer += $input->readMapEnd(); + + return $xfer; + } + + private function _readList(&$var, $spec, $input, $set=false) + { + $xfer = 0; + $etype = $spec['etype']; + $eread = $vread = null; + if (isset(TBase::$tmethod[$etype])) { + $eread = 'read'.TBase::$tmethod[$etype]; + } else { + $espec = $spec['elem']; + } + $var = array(); + $_etype = $size = 0; + if ($set) { + $xfer += $input->readSetBegin($_etype, $size); + } else { + $xfer += $input->readListBegin($_etype, $size); + } + for ($i = 0; $i < $size; ++$i) { + $elem = null; + if ($eread !== null) { + $xfer += $input->$eread($elem); + } else { + $espec = $spec['elem']; + switch ($etype) { + case TType::STRUCT: + $class = $espec['class']; + $elem = new $class(); + $xfer += $elem->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($elem, $espec, $input); + break; + case TType::LST: + $xfer += $this->_readList($elem, $espec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($elem, $espec, $input, true); + break; + } + } + if ($set) { + $var[$elem] = true; + } else { + $var []= $elem; + } + } + if ($set) { + $xfer += $input->readSetEnd(); + } else { + $xfer += $input->readListEnd(); + } + + return $xfer; + } + + protected function _read($class, $spec, $input) + { + $xfer = 0; + $fname = null; + $ftype = 0; + $fid = 0; + $xfer += $input->readStructBegin($fname); + while (true) { + $xfer += $input->readFieldBegin($fname, $ftype, $fid); + if ($ftype == TType::STOP) { + break; + } + if (isset($spec[$fid])) { + $fspec = $spec[$fid]; + $var = $fspec['var']; + if ($ftype == $fspec['type']) { + $xfer = 0; + if (isset(TBase::$tmethod[$ftype])) { + $func = 'read'.TBase::$tmethod[$ftype]; + $xfer += $input->$func($this->$var); + } else { + switch ($ftype) { + case TType::STRUCT: + $class = $fspec['class']; + $this->$var = new $class(); + $xfer += $this->$var->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($this->$var, $fspec, $input); + break; + case TType::LST: + $xfer += $this->_readList($this->$var, $fspec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($this->$var, $fspec, $input, true); + break; + } + } + } else { + $xfer += $input->skip($ftype); + } + } else { + $xfer += $input->skip($ftype); + } + $xfer += $input->readFieldEnd(); + } + $xfer += $input->readStructEnd(); + + return $xfer; + } + + private function _writeMap($var, $spec, $output) + { + $xfer = 0; + $ktype = $spec['ktype']; + $vtype = $spec['vtype']; + $kwrite = $vwrite = null; + if (isset(TBase::$tmethod[$ktype])) { + $kwrite = 'write'.TBase::$tmethod[$ktype]; + } else { + $kspec = $spec['key']; + } + if (isset(TBase::$tmethod[$vtype])) { + $vwrite = 'write'.TBase::$tmethod[$vtype]; + } else { + $vspec = $spec['val']; + } + $xfer += $output->writeMapBegin($ktype, $vtype, count($var)); + foreach ($var as $key => $val) { + if (isset($kwrite)) { + $xfer += $output->$kwrite($key); + } else { + switch ($ktype) { + case TType::STRUCT: + $xfer += $key->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($key, $kspec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($key, $kspec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($key, $kspec, $output, true); + break; + } + } + if (isset($vwrite)) { + $xfer += $output->$vwrite($val); + } else { + switch ($vtype) { + case TType::STRUCT: + $xfer += $val->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($val, $vspec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($val, $vspec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($val, $vspec, $output, true); + break; + } + } + } + $xfer += $output->writeMapEnd(); + + return $xfer; + } + + private function _writeList($var, $spec, $output, $set=false) + { + $xfer = 0; + $etype = $spec['etype']; + $ewrite = null; + if (isset(TBase::$tmethod[$etype])) { + $ewrite = 'write'.TBase::$tmethod[$etype]; + } else { + $espec = $spec['elem']; + } + if ($set) { + $xfer += $output->writeSetBegin($etype, count($var)); + } else { + $xfer += $output->writeListBegin($etype, count($var)); + } + foreach ($var as $key => $val) { + $elem = $set ? $key : $val; + if (isset($ewrite)) { + $xfer += $output->$ewrite($elem); + } else { + switch ($etype) { + case TType::STRUCT: + $xfer += $elem->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($elem, $espec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($elem, $espec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($elem, $espec, $output, true); + break; + } + } + } + if ($set) { + $xfer += $output->writeSetEnd(); + } else { + $xfer += $output->writeListEnd(); + } + + return $xfer; + } + + protected function _write($class, $spec, $output) + { + $xfer = 0; + $xfer += $output->writeStructBegin($class); + foreach ($spec as $fid => $fspec) { + $var = $fspec['var']; + if ($this->$var !== null) { + $ftype = $fspec['type']; + $xfer += $output->writeFieldBegin($var, $ftype, $fid); + if (isset(TBase::$tmethod[$ftype])) { + $func = 'write'.TBase::$tmethod[$ftype]; + $xfer += $output->$func($this->$var); + } else { + switch ($ftype) { + case TType::STRUCT: + $xfer += $this->$var->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($this->$var, $fspec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($this->$var, $fspec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($this->$var, $fspec, $output, true); + break; + } + } + $xfer += $output->writeFieldEnd(); + } + } + $xfer += $output->writeFieldStop(); + $xfer += $output->writeStructEnd(); + + return $xfer; + } + +} + +/** + * Base class from which other Thrift structs extend. This is so that we can + * cut back on the size of the generated code which is turning out to have a + * nontrivial cost just to load thanks to the wondrously abysmal implementation + * of PHP. Note that code is intentionally duplicated in here to avoid making + * function calls for every field or member of a container.. + */ +abstract class TBase +{ + static $tmethod = array(TType::BOOL => 'Bool', + TType::BYTE => 'Byte', + TType::I16 => 'I16', + TType::I32 => 'I32', + TType::I64 => 'I64', + TType::DOUBLE => 'Double', + TType::STRING => 'String'); + + abstract public function read($input); + + abstract public function write($output); + + public function __construct($spec=null, $vals=null) + { + if (is_array($spec) && is_array($vals)) { + foreach ($spec as $fid => $fspec) { + $var = $fspec['var']; + if (isset($vals[$var])) { + $this->$var = $vals[$var]; + } + } + } + } + + private function _readMap(&$var, $spec, $input) + { + $xfer = 0; + $ktype = $spec['ktype']; + $vtype = $spec['vtype']; + $kread = $vread = null; + if (isset(TBase::$tmethod[$ktype])) { + $kread = 'read'.TBase::$tmethod[$ktype]; + } else { + $kspec = $spec['key']; + } + if (isset(TBase::$tmethod[$vtype])) { + $vread = 'read'.TBase::$tmethod[$vtype]; + } else { + $vspec = $spec['val']; + } + $var = array(); + $_ktype = $_vtype = $size = 0; + $xfer += $input->readMapBegin($_ktype, $_vtype, $size); + for ($i = 0; $i < $size; ++$i) { + $key = $val = null; + if ($kread !== null) { + $xfer += $input->$kread($key); + } else { + switch ($ktype) { + case TType::STRUCT: + $class = $kspec['class']; + $key = new $class(); + $xfer += $key->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($key, $kspec, $input); + break; + case TType::LST: + $xfer += $this->_readList($key, $kspec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($key, $kspec, $input, true); + break; + } + } + if ($vread !== null) { + $xfer += $input->$vread($val); + } else { + switch ($vtype) { + case TType::STRUCT: + $class = $vspec['class']; + $val = new $class(); + $xfer += $val->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($val, $vspec, $input); + break; + case TType::LST: + $xfer += $this->_readList($val, $vspec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($val, $vspec, $input, true); + break; + } + } + $var[$key] = $val; + } + $xfer += $input->readMapEnd(); + + return $xfer; + } + + private function _readList(&$var, $spec, $input, $set=false) + { + $xfer = 0; + $etype = $spec['etype']; + $eread = $vread = null; + if (isset(TBase::$tmethod[$etype])) { + $eread = 'read'.TBase::$tmethod[$etype]; + } else { + $espec = $spec['elem']; + } + $var = array(); + $_etype = $size = 0; + if ($set) { + $xfer += $input->readSetBegin($_etype, $size); + } else { + $xfer += $input->readListBegin($_etype, $size); + } + for ($i = 0; $i < $size; ++$i) { + $elem = null; + if ($eread !== null) { + $xfer += $input->$eread($elem); + } else { + $espec = $spec['elem']; + switch ($etype) { + case TType::STRUCT: + $class = $espec['class']; + $elem = new $class(); + $xfer += $elem->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($elem, $espec, $input); + break; + case TType::LST: + $xfer += $this->_readList($elem, $espec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($elem, $espec, $input, true); + break; + } + } + if ($set) { + $var[$elem] = true; + } else { + $var []= $elem; + } + } + if ($set) { + $xfer += $input->readSetEnd(); + } else { + $xfer += $input->readListEnd(); + } + + return $xfer; + } + + protected function _read($class, $spec, $input) + { + $xfer = 0; + $fname = null; + $ftype = 0; + $fid = 0; + $xfer += $input->readStructBegin($fname); + while (true) { + $xfer += $input->readFieldBegin($fname, $ftype, $fid); + if ($ftype == TType::STOP) { + break; + } + if (isset($spec[$fid])) { + $fspec = $spec[$fid]; + $var = $fspec['var']; + if ($ftype == $fspec['type']) { + $xfer = 0; + if (isset(TBase::$tmethod[$ftype])) { + $func = 'read'.TBase::$tmethod[$ftype]; + $xfer += $input->$func($this->$var); + } else { + switch ($ftype) { + case TType::STRUCT: + $class = $fspec['class']; + $this->$var = new $class(); + $xfer += $this->$var->read($input); + break; + case TType::MAP: + $xfer += $this->_readMap($this->$var, $fspec, $input); + break; + case TType::LST: + $xfer += $this->_readList($this->$var, $fspec, $input, false); + break; + case TType::SET: + $xfer += $this->_readList($this->$var, $fspec, $input, true); + break; + } + } + } else { + $xfer += $input->skip($ftype); + } + } else { + $xfer += $input->skip($ftype); + } + $xfer += $input->readFieldEnd(); + } + $xfer += $input->readStructEnd(); + + return $xfer; + } + + private function _writeMap($var, $spec, $output) + { + $xfer = 0; + $ktype = $spec['ktype']; + $vtype = $spec['vtype']; + $kwrite = $vwrite = null; + if (isset(TBase::$tmethod[$ktype])) { + $kwrite = 'write'.TBase::$tmethod[$ktype]; + } else { + $kspec = $spec['key']; + } + if (isset(TBase::$tmethod[$vtype])) { + $vwrite = 'write'.TBase::$tmethod[$vtype]; + } else { + $vspec = $spec['val']; + } + $xfer += $output->writeMapBegin($ktype, $vtype, count($var)); + foreach ($var as $key => $val) { + if (isset($kwrite)) { + $xfer += $output->$kwrite($key); + } else { + switch ($ktype) { + case TType::STRUCT: + $xfer += $key->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($key, $kspec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($key, $kspec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($key, $kspec, $output, true); + break; + } + } + if (isset($vwrite)) { + $xfer += $output->$vwrite($val); + } else { + switch ($vtype) { + case TType::STRUCT: + $xfer += $val->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($val, $vspec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($val, $vspec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($val, $vspec, $output, true); + break; + } + } + } + $xfer += $output->writeMapEnd(); + + return $xfer; + } + + private function _writeList($var, $spec, $output, $set=false) + { + $xfer = 0; + $etype = $spec['etype']; + $ewrite = null; + if (isset(TBase::$tmethod[$etype])) { + $ewrite = 'write'.TBase::$tmethod[$etype]; + } else { + $espec = $spec['elem']; + } + if ($set) { + $xfer += $output->writeSetBegin($etype, count($var)); + } else { + $xfer += $output->writeListBegin($etype, count($var)); + } + foreach ($var as $key => $val) { + $elem = $set ? $key : $val; + if (isset($ewrite)) { + $xfer += $output->$ewrite($elem); + } else { + switch ($etype) { + case TType::STRUCT: + $xfer += $elem->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($elem, $espec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($elem, $espec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($elem, $espec, $output, true); + break; + } + } + } + if ($set) { + $xfer += $output->writeSetEnd(); + } else { + $xfer += $output->writeListEnd(); + } + + return $xfer; + } + + protected function _write($class, $spec, $output) + { + $xfer = 0; + $xfer += $output->writeStructBegin($class); + foreach ($spec as $fid => $fspec) { + $var = $fspec['var']; + if ($this->$var !== null) { + $ftype = $fspec['type']; + $xfer += $output->writeFieldBegin($var, $ftype, $fid); + if (isset(TBase::$tmethod[$ftype])) { + $func = 'write'.TBase::$tmethod[$ftype]; + $xfer += $output->$func($this->$var); + } else { + switch ($ftype) { + case TType::STRUCT: + $xfer += $this->$var->write($output); + break; + case TType::MAP: + $xfer += $this->_writeMap($this->$var, $fspec, $output); + break; + case TType::LST: + $xfer += $this->_writeList($this->$var, $fspec, $output, false); + break; + case TType::SET: + $xfer += $this->_writeList($this->$var, $fspec, $output, true); + break; + } + } + $xfer += $output->writeFieldEnd(); + } + } + $xfer += $output->writeFieldStop(); + $xfer += $output->writeStructEnd(); + + return $xfer; + } +} + +class TApplicationException extends TException +{ + static $_TSPEC = + array(1 => array('var' => 'message', + 'type' => TType::STRING), + 2 => array('var' => 'code', + 'type' => TType::I32)); + + const UNKNOWN = 0; + const UNKNOWN_METHOD = 1; + const INVALID_MESSAGE_TYPE = 2; + const WRONG_METHOD_NAME = 3; + const BAD_SEQUENCE_ID = 4; + const MISSING_RESULT = 5; + const INTERNAL_ERROR = 6; + const PROTOCOL_ERROR = 7; + + public function __construct($message=null, $code=0) + { + parent::__construct($message, $code); + } + + public function read($output) + { + return $this->_read('TApplicationException', self::$_TSPEC, $output); + } + + public function write($output) + { + $xfer = 0; + $xfer += $output->writeStructBegin('TApplicationException'); + if ($message = $this->getMessage()) { + $xfer += $output->writeFieldBegin('message', TType::STRING, 1); + $xfer += $output->writeString($message); + $xfer += $output->writeFieldEnd(); + } + if ($code = $this->getCode()) { + $xfer += $output->writeFieldBegin('type', TType::I32, 2); + $xfer += $output->writeI32($code); + $xfer += $output->writeFieldEnd(); + } + $xfer += $output->writeFieldStop(); + $xfer += $output->writeStructEnd(); + + return $xfer; + } +} + +/** + * Set global THRIFT ROOT automatically via inclusion here + */ +if (!isset($GLOBALS['THRIFT_ROOT'])) { + $GLOBALS['THRIFT_ROOT'] = dirname(__FILE__); +} +include_once $GLOBALS['THRIFT_ROOT'].'/protocol/TProtocol.php'; +include_once $GLOBALS['THRIFT_ROOT'].'/transport/TTransport.php'; +include_once $GLOBALS['THRIFT_ROOT'].'/TStringUtils.php'; diff --git a/lib/php/src/autoload.php b/lib/php/src/autoload.php new file mode 100644 index 0000000..85bd797 --- /dev/null +++ b/lib/php/src/autoload.php @@ -0,0 +1,51 @@ += 70000 + +#include +#include + +#include +#include +#include + +#ifndef bswap_64 +#define bswap_64(x) (((uint64_t)(x) << 56) | \ + (((uint64_t)(x) << 40) & 0xff000000000000ULL) | \ + (((uint64_t)(x) << 24) & 0xff0000000000ULL) | \ + (((uint64_t)(x) << 8) & 0xff00000000ULL) | \ + (((uint64_t)(x) >> 8) & 0xff000000ULL) | \ + (((uint64_t)(x) >> 24) & 0xff0000ULL) | \ + (((uint64_t)(x) >> 40) & 0xff00ULL) | \ + ((uint64_t)(x) >> 56)) +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define htonll(x) bswap_64(x) +#define ntohll(x) bswap_64(x) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define htonll(x) x +#define ntohll(x) x +#else +#error Unknown __BYTE_ORDER +#endif + +enum TType { + T_STOP = 0, + T_VOID = 1, + T_BOOL = 2, + T_BYTE = 3, + T_I08 = 3, + T_I16 = 6, + T_I32 = 8, + T_U64 = 9, + T_I64 = 10, + T_DOUBLE = 4, + T_STRING = 11, + T_UTF7 = 11, + T_STRUCT = 12, + T_MAP = 13, + T_SET = 14, + T_LIST = 15, + T_UTF8 = 16, + T_UTF16 = 17 +}; + +const int32_t VERSION_MASK = 0xffff0000; +const int32_t VERSION_1 = 0x80010000; +const int8_t T_CALL = 1; +const int8_t T_REPLY = 2; +const int8_t T_EXCEPTION = 3; +// tprotocolexception +const int INVALID_DATA = 1; +const int BAD_VERSION = 4; + +static zend_function_entry thrift_protocol_functions[] = { + PHP_FE(thrift_protocol_write_binary, nullptr) + PHP_FE(thrift_protocol_read_binary, nullptr) + PHP_FE(thrift_protocol_read_binary_after_message_begin, nullptr) + {nullptr, nullptr, nullptr} +}; + +zend_module_entry thrift_protocol_module_entry = { + STANDARD_MODULE_HEADER, + "thrift_protocol", + thrift_protocol_functions, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + "1.0", + STANDARD_MODULE_PROPERTIES +}; + +#ifdef COMPILE_DL_THRIFT_PROTOCOL +ZEND_GET_MODULE(thrift_protocol) +#endif + +class PHPExceptionWrapper : public std::exception { +public: + PHPExceptionWrapper(zval* _ex) throw() { + ZVAL_COPY(&ex, _ex); + snprintf(_what, 40, "PHP exception zval=%p", _ex); + } + + PHPExceptionWrapper(zend_object* _exobj) throw() { + ZVAL_OBJ(&ex, _exobj); + snprintf(_what, 40, "PHP exception zval=%p", _exobj); + } + ~PHPExceptionWrapper() throw() { + zval_dtor(&ex); + } + + const char* what() const throw() { + return _what; + } + operator zval*() const throw() { + return const_cast(&ex); + } // Zend API doesn't do 'const'... +protected: + zval ex; + char _what[40]; +} ; + +class PHPTransport { +protected: + PHPTransport(zval* _p, size_t _buffer_size) { + assert(Z_TYPE_P(_p) == IS_OBJECT); + + ZVAL_UNDEF(&t); + + buffer = reinterpret_cast(emalloc(_buffer_size)); + buffer_ptr = buffer; + buffer_used = 0; + buffer_size = _buffer_size; + + // Get the transport for the passed protocol + zval gettransport; + ZVAL_STRING(&gettransport, "getTransport"); + call_user_function(nullptr, _p, &gettransport, &t, 0, nullptr); + + zval_dtor(&gettransport); + + if (EG(exception)) { + zend_object *ex = EG(exception); + EG(exception) = nullptr; + throw PHPExceptionWrapper(ex); + } + + assert(Z_TYPE(t) == IS_OBJECT); + } + + ~PHPTransport() { + efree(buffer); + zval_dtor(&t); + } + + char* buffer; + char* buffer_ptr; + size_t buffer_used; + size_t buffer_size; + + zval t; +}; + + +class PHPOutputTransport : public PHPTransport { +public: + PHPOutputTransport(zval* _p, size_t _buffer_size = 8192) : PHPTransport(_p, _buffer_size) { } + ~PHPOutputTransport() { } + + void write(const char* data, size_t len) { + if ((len + buffer_used) > buffer_size) { + internalFlush(); + } + if (len > buffer_size) { + directWrite(data, len); + } else { + memcpy(buffer_ptr, data, len); + buffer_used += len; + buffer_ptr += len; + } + } + + void writeI64(int64_t i) { + i = htonll(i); + write((const char*)&i, 8); + } + + void writeU32(uint32_t i) { + i = htonl(i); + write((const char*)&i, 4); + } + + void writeI32(int32_t i) { + i = htonl(i); + write((const char*)&i, 4); + } + + void writeI16(int16_t i) { + i = htons(i); + write((const char*)&i, 2); + } + + void writeI8(int8_t i) { + write((const char*)&i, 1); + } + + void writeString(const char* str, size_t len) { + writeU32(len); + write(str, len); + } + + void flush() { + internalFlush(); + directFlush(); + } + +protected: + void internalFlush() { + if (buffer_used) { + directWrite(buffer, buffer_used); + buffer_ptr = buffer; + buffer_used = 0; + } + } + void directFlush() { + zval ret, flushfn; + ZVAL_NULL(&ret); + ZVAL_STRING(&flushfn, "flush"); + + call_user_function(EG(function_table), &(this->t), &flushfn, &ret, 0, nullptr); + zval_dtor(&flushfn); + zval_dtor(&ret); + if (EG(exception)) { + zend_object *ex = EG(exception); + EG(exception) = nullptr; + throw PHPExceptionWrapper(ex); + } + } + void directWrite(const char* data, size_t len) { + zval args[1], ret, writefn; + + ZVAL_STRING(&writefn, "write"); + ZVAL_STRINGL(&args[0], data, len); + + ZVAL_NULL(&ret); + call_user_function(EG(function_table), &(this->t), &writefn, &ret, 1, args); + + zval_dtor(&writefn); + zval_dtor(&ret); + zval_dtor(&args[0]); + + if (EG(exception)) { + zend_object *ex = EG(exception); + EG(exception) = nullptr; + throw PHPExceptionWrapper(ex); + } + } +}; + +class PHPInputTransport : public PHPTransport { +public: + PHPInputTransport(zval* _p, size_t _buffer_size = 8192) : PHPTransport(_p, _buffer_size) { + } + + ~PHPInputTransport() { + put_back(); + } + + void put_back() { + if (buffer_used) { + zval args[1], ret, putbackfn; + ZVAL_STRINGL(&args[0], buffer_ptr, buffer_used); + ZVAL_STRING(&putbackfn, "putBack"); + ZVAL_NULL(&ret); + + call_user_function(EG(function_table), &(this->t), &putbackfn, &ret, 1, args); + + zval_dtor(&putbackfn); + zval_dtor(&ret); + zval_dtor(&args[0]); + if (EG(exception)) { + zend_object *ex = EG(exception); + EG(exception) = nullptr; + throw PHPExceptionWrapper(ex); + } + } + buffer_used = 0; + buffer_ptr = buffer; + } + + void skip(size_t len) { + while (len) { + size_t chunk_size = std::min(len, buffer_used); + if (chunk_size) { + buffer_ptr = reinterpret_cast(buffer_ptr) + chunk_size; + buffer_used -= chunk_size; + len -= chunk_size; + } + if (! len) break; + refill(); + } + } + + void readBytes(void* buf, size_t len) { + while (len) { + size_t chunk_size = std::min(len, buffer_used); + if (chunk_size) { + memcpy(buf, buffer_ptr, chunk_size); + buffer_ptr = reinterpret_cast(buffer_ptr) + chunk_size; + buffer_used -= chunk_size; + buf = reinterpret_cast(buf) + chunk_size; + len -= chunk_size; + } + if (! len) break; + refill(); + } + } + + int8_t readI8() { + int8_t c; + readBytes(&c, 1); + return c; + } + + int16_t readI16() { + int16_t c; + readBytes(&c, 2); + return (int16_t)ntohs(c); + } + + uint32_t readU32() { + uint32_t c; + readBytes(&c, 4); + return (uint32_t)ntohl(c); + } + + int32_t readI32() { + int32_t c; + readBytes(&c, 4); + return (int32_t)ntohl(c); + } + +protected: + void refill() { + assert(buffer_used == 0); + zval retval; + zval args[1]; + zval funcname; + + ZVAL_NULL(&retval); + ZVAL_LONG(&args[0], buffer_size); + + ZVAL_STRING(&funcname, "read"); + + call_user_function(EG(function_table), &(this->t), &funcname, &retval, 1, args); + zval_dtor(&args[0]); + zval_dtor(&funcname); + + if (EG(exception)) { + zval_dtor(&retval); + + zend_object *ex = EG(exception); + EG(exception) = nullptr; + throw PHPExceptionWrapper(ex); + } + + buffer_used = Z_STRLEN(retval); + memcpy(buffer, Z_STRVAL(retval), buffer_used); + + zval_dtor(&retval); + + buffer_ptr = buffer; + } + +}; + +static +void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTable* spec); +static +void binary_serialize_spec(zval* zthis, PHPOutputTransport& transport, HashTable* spec); +static +void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, zval* value, HashTable* fieldspec); +static inline +bool ttype_is_scalar(int8_t t); + +// Create a PHP object given a typename and call the ctor, optionally passing up to 2 arguments +static +void createObject(const char* obj_typename, zval* return_value, int nargs = 0, zval* arg1 = nullptr, zval* arg2 = nullptr) { + /* is there a better way to do that on the stack ? */ + zend_string *obj_name = zend_string_init(obj_typename, strlen(obj_typename), 0); + zend_class_entry* ce = zend_fetch_class(obj_name, ZEND_FETCH_CLASS_DEFAULT); + zend_string_release(obj_name); + + if (! ce) { + php_error_docref(nullptr, E_ERROR, "Class %s does not exist", obj_typename); + RETURN_NULL(); + } + + object_and_properties_init(return_value, ce, nullptr); + zend_function* constructor = zend_std_get_constructor(Z_OBJ_P(return_value)); + zval ctor_rv; + zend_call_method(return_value, ce, &constructor, NULL, 0, &ctor_rv, nargs, arg1, arg2); + zval_dtor(&ctor_rv); + if (EG(exception)) { + zend_object *ex = EG(exception); + EG(exception) = nullptr; + throw PHPExceptionWrapper(ex); + } +} + +static +void throw_tprotocolexception(const char* what, long errorcode) { + zval zwhat, zerrorcode; + + ZVAL_STRING(&zwhat, what); + ZVAL_LONG(&zerrorcode, errorcode); + + zval ex; + createObject("\\Thrift\\Exception\\TProtocolException", &ex, 2, &zwhat, &zerrorcode); + + zval_dtor(&zwhat); + zval_dtor(&zerrorcode); + + throw PHPExceptionWrapper(&ex); +} + +// Sets EG(exception), call this and then RETURN_NULL(); +static +void throw_zend_exception_from_std_exception(const std::exception& ex) { + zend_throw_exception(zend_exception_get_default(), const_cast(ex.what()), 0); +} + +static +void skip_element(long thrift_typeID, PHPInputTransport& transport) { + switch (thrift_typeID) { + case T_STOP: + case T_VOID: + return; + case T_STRUCT: + while (true) { + int8_t ttype = transport.readI8(); // get field type + if (ttype == T_STOP) break; + transport.skip(2); // skip field number, I16 + skip_element(ttype, transport); // skip field payload + } + return; + case T_BOOL: + case T_BYTE: + transport.skip(1); + return; + case T_I16: + transport.skip(2); + return; + case T_I32: + transport.skip(4); + return; + case T_U64: + case T_I64: + case T_DOUBLE: + transport.skip(8); + return; + //case T_UTF7: // aliases T_STRING + case T_UTF8: + case T_UTF16: + case T_STRING: { + uint32_t len = transport.readU32(); + transport.skip(len); + } return; + case T_MAP: { + int8_t keytype = transport.readI8(); + int8_t valtype = transport.readI8(); + uint32_t size = transport.readU32(); + for (uint32_t i = 0; i < size; ++i) { + skip_element(keytype, transport); + skip_element(valtype, transport); + } + } return; + case T_LIST: + case T_SET: { + int8_t valtype = transport.readI8(); + uint32_t size = transport.readU32(); + for (uint32_t i = 0; i < size; ++i) { + skip_element(valtype, transport); + } + } return; + }; + + char errbuf[128]; + sprintf(errbuf, "Unknown thrift typeID %ld", thrift_typeID); + throw_tprotocolexception(errbuf, INVALID_DATA); +} + +static inline +bool zval_is_bool(zval* v) { + return Z_TYPE_P(v) == IS_TRUE || Z_TYPE_P(v) == IS_FALSE; +} + +static +void binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport, zval* return_value, HashTable* fieldspec) { + ZVAL_NULL(return_value); + + switch (thrift_typeID) { + case T_STOP: + case T_VOID: + RETURN_NULL(); + return; + case T_STRUCT: { + zval* val_ptr = zend_hash_str_find(fieldspec, "class", sizeof("class")-1); + if (val_ptr == nullptr) { + throw_tprotocolexception("no class type in spec", INVALID_DATA); + skip_element(T_STRUCT, transport); + RETURN_NULL(); + } + + char* structType = Z_STRVAL_P(val_ptr); + // Create an object in PHP userland based on our spec + createObject(structType, return_value); + if (Z_TYPE_P(return_value) == IS_NULL) { + // unable to create class entry + skip_element(T_STRUCT, transport); + RETURN_NULL(); + } + + zval* spec = zend_read_static_property(Z_OBJCE_P(return_value), "_TSPEC", sizeof("_TSPEC")-1, false); + if (EG(exception)) { + zend_object *ex = EG(exception); + EG(exception) = nullptr; + throw PHPExceptionWrapper(ex); + } + if (Z_TYPE_P(spec) != IS_ARRAY) { + char errbuf[128]; + snprintf(errbuf, 128, "spec for %s is wrong type: %d\n", structType, Z_TYPE_P(spec)); + throw_tprotocolexception(errbuf, INVALID_DATA); + RETURN_NULL(); + } + binary_deserialize_spec(return_value, transport, Z_ARRVAL_P(spec)); + return; + } break; + case T_BOOL: { + uint8_t c; + transport.readBytes(&c, 1); + RETURN_BOOL(c != 0); + } + //case T_I08: // same numeric value as T_BYTE + case T_BYTE: { + uint8_t c; + transport.readBytes(&c, 1); + RETURN_LONG((int8_t)c); + } + case T_I16: { + uint16_t c; + transport.readBytes(&c, 2); + RETURN_LONG((int16_t)ntohs(c)); + } + case T_I32: { + uint32_t c; + transport.readBytes(&c, 4); + RETURN_LONG((int32_t)ntohl(c)); + } + case T_U64: + case T_I64: { + uint64_t c; + transport.readBytes(&c, 8); + RETURN_LONG((int64_t)ntohll(c)); + } + case T_DOUBLE: { + union { + uint64_t c; + double d; + } a; + transport.readBytes(&(a.c), 8); + a.c = ntohll(a.c); + RETURN_DOUBLE(a.d); + } + //case T_UTF7: // aliases T_STRING + case T_UTF8: + case T_UTF16: + case T_STRING: { + uint32_t size = transport.readU32(); + if (size) { + char strbuf[size+1]; + transport.readBytes(strbuf, size); + strbuf[size] = '\0'; + ZVAL_STRINGL(return_value, strbuf, size); + } else { + ZVAL_EMPTY_STRING(return_value); + } + return; + } + case T_MAP: { // array of key -> value + uint8_t types[2]; + transport.readBytes(types, 2); + uint32_t size = transport.readU32(); + array_init(return_value); + + zval *val_ptr; + val_ptr = zend_hash_str_find(fieldspec, "key", sizeof("key")-1); + HashTable* keyspec = Z_ARRVAL_P(val_ptr); + val_ptr = zend_hash_str_find(fieldspec, "val", sizeof("val")-1); + HashTable* valspec = Z_ARRVAL_P(val_ptr); + + for (uint32_t s = 0; s < size; ++s) { + zval key, value; + + binary_deserialize(types[0], transport, &key, keyspec); + binary_deserialize(types[1], transport, &value, valspec); + if (Z_TYPE(key) == IS_LONG) { + zend_hash_index_update(Z_ARR_P(return_value), Z_LVAL(key), &value); + } else { + if (Z_TYPE(key) != IS_STRING) convert_to_string(&key); + zend_symtable_update(Z_ARR_P(return_value), Z_STR(key), &value); + } + zval_dtor(&key); + } + return; // return_value already populated + } + case T_LIST: { // array with autogenerated numeric keys + int8_t type = transport.readI8(); + uint32_t size = transport.readU32(); + zval *val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1); + HashTable* elemspec = Z_ARRVAL_P(val_ptr); + + array_init(return_value); + for (uint32_t s = 0; s < size; ++s) { + zval value; + binary_deserialize(type, transport, &value, elemspec); + zend_hash_next_index_insert(Z_ARR_P(return_value), &value); + } + return; + } + case T_SET: { // array of key -> TRUE + uint8_t type; + uint32_t size; + transport.readBytes(&type, 1); + transport.readBytes(&size, 4); + size = ntohl(size); + zval *val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1); + HashTable* elemspec = Z_ARRVAL_P(val_ptr); + + array_init(return_value); + + for (uint32_t s = 0; s < size; ++s) { + zval key, value; + ZVAL_TRUE(&value); + + binary_deserialize(type, transport, &key, elemspec); + + if (Z_TYPE(key) == IS_LONG) { + zend_hash_index_update(Z_ARR_P(return_value), Z_LVAL(key), &value); + } else { + if (Z_TYPE(key) != IS_STRING) convert_to_string(&key); + zend_symtable_update(Z_ARR_P(return_value), Z_STR(key), &value); + } + zval_dtor(&key); + } + return; + } + }; + + char errbuf[128]; + sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID); + throw_tprotocolexception(errbuf, INVALID_DATA); +} + +static +void binary_serialize_hashtable_key(int8_t keytype, PHPOutputTransport& transport, HashTable* ht, HashPosition& ht_pos, HashTable* spec) { + bool keytype_is_numeric = (!((keytype == T_STRING) || (keytype == T_UTF8) || (keytype == T_UTF16))); + + zend_string* key; + uint key_len; + long index = 0; + + zval z; + + int res = zend_hash_get_current_key_ex(ht, &key, (zend_ulong*)&index, &ht_pos); + if (res == HASH_KEY_IS_STRING) { + ZVAL_STR_COPY(&z, key); + } else { + ZVAL_LONG(&z, index); + } + binary_serialize(keytype, transport, &z, spec); + zval_dtor(&z); +} + +static +void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, zval* value, HashTable* fieldspec) { + // At this point the typeID (and field num, if applicable) should've already been written to the output so all we need to do is write the payload. + switch (thrift_typeID) { + case T_STOP: + case T_VOID: + return; + case T_STRUCT: { + if (Z_TYPE_P(value) != IS_OBJECT) { + throw_tprotocolexception("Attempt to send non-object type as a T_STRUCT", INVALID_DATA); + } + zval* spec = zend_read_static_property(Z_OBJCE_P(value), "_TSPEC", sizeof("_TSPEC")-1, true); + if (!spec || Z_TYPE_P(spec) != IS_ARRAY) { + throw_tprotocolexception("Attempt to send non-Thrift object as a T_STRUCT", INVALID_DATA); + } + binary_serialize_spec(value, transport, Z_ARRVAL_P(spec)); + } return; + case T_BOOL: + if (!zval_is_bool(value)) convert_to_boolean(value); + transport.writeI8(Z_TYPE_INFO_P(value) == IS_TRUE ? 1 : 0); + return; + case T_BYTE: + if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value); + transport.writeI8(Z_LVAL_P(value)); + return; + case T_I16: + if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value); + transport.writeI16(Z_LVAL_P(value)); + return; + case T_I32: + if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value); + transport.writeI32(Z_LVAL_P(value)); + return; + case T_I64: + case T_U64: { + int64_t l_data; +#if defined(_LP64) || defined(_WIN64) + if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value); + l_data = Z_LVAL_P(value); +#else + if (Z_TYPE_P(value) != IS_DOUBLE) convert_to_double(value); + l_data = (int64_t)Z_DVAL_P(value); +#endif + transport.writeI64(l_data); + } return; + case T_DOUBLE: { + union { + int64_t c; + double d; + } a; + if (Z_TYPE_P(value) != IS_DOUBLE) convert_to_double(value); + a.d = Z_DVAL_P(value); + transport.writeI64(a.c); + } return; + case T_UTF8: + case T_UTF16: + case T_STRING: + if (Z_TYPE_P(value) != IS_STRING) convert_to_string(value); + transport.writeString(Z_STRVAL_P(value), Z_STRLEN_P(value)); + return; + case T_MAP: { + if (Z_TYPE_P(value) != IS_ARRAY) convert_to_array(value); + if (Z_TYPE_P(value) != IS_ARRAY) { + throw_tprotocolexception("Attempt to send an incompatible type as an array (T_MAP)", INVALID_DATA); + } + HashTable* ht = Z_ARRVAL_P(value); + zval* val_ptr; + + val_ptr = zend_hash_str_find(fieldspec, "ktype", sizeof("ktype")-1); + if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr); + uint8_t keytype = Z_LVAL_P(val_ptr); + transport.writeI8(keytype); + val_ptr = zend_hash_str_find(fieldspec, "vtype", sizeof("vtype")-1); + if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr); + uint8_t valtype = Z_LVAL_P(val_ptr); + transport.writeI8(valtype); + + val_ptr = zend_hash_str_find(fieldspec, "val", sizeof("val")-1); + HashTable* valspec = Z_ARRVAL_P(val_ptr); + HashTable* keyspec = Z_ARRVAL_P(zend_hash_str_find(fieldspec, "key", sizeof("key")-1)); + + transport.writeI32(zend_hash_num_elements(ht)); + HashPosition key_ptr; + for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); + (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr; + zend_hash_move_forward_ex(ht, &key_ptr)) { + binary_serialize_hashtable_key(keytype, transport, ht, key_ptr, keyspec); + binary_serialize(valtype, transport, val_ptr, valspec); + } + } return; + case T_LIST: { + if (Z_TYPE_P(value) != IS_ARRAY) convert_to_array(value); + if (Z_TYPE_P(value) != IS_ARRAY) { + throw_tprotocolexception("Attempt to send an incompatible type as an array (T_LIST)", INVALID_DATA); + } + HashTable* ht = Z_ARRVAL_P(value); + zval* val_ptr; + + val_ptr = zend_hash_str_find(fieldspec, "etype", sizeof("etype")-1); + if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr); + uint8_t valtype = Z_LVAL_P(val_ptr); + transport.writeI8(valtype); + + val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1); + HashTable* valspec = Z_ARRVAL_P(val_ptr); + + transport.writeI32(zend_hash_num_elements(ht)); + HashPosition key_ptr; + for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); + (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr; + zend_hash_move_forward_ex(ht, &key_ptr)) { + binary_serialize(valtype, transport, val_ptr, valspec); + } + } return; + case T_SET: { + if (Z_TYPE_P(value) != IS_ARRAY) convert_to_array(value); + if (Z_TYPE_P(value) != IS_ARRAY) { + throw_tprotocolexception("Attempt to send an incompatible type as an array (T_SET)", INVALID_DATA); + } + HashTable* ht = Z_ARRVAL_P(value); + zval* val_ptr; + + val_ptr = zend_hash_str_find(fieldspec, "etype", sizeof("etype")-1); + HashTable* spec = Z_ARRVAL_P(zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1)); + if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr); + uint8_t keytype = Z_LVAL_P(val_ptr); + transport.writeI8(keytype); + + transport.writeI32(zend_hash_num_elements(ht)); + HashPosition key_ptr; + if(ttype_is_scalar(keytype)){ + for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); + (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr; + zend_hash_move_forward_ex(ht, &key_ptr)) { + binary_serialize_hashtable_key(keytype, transport, ht, key_ptr, spec); + } + } else { + for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); + (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr; + zend_hash_move_forward_ex(ht, &key_ptr)) { + binary_serialize(keytype, transport, val_ptr, spec); + } + } + } return; + }; + + char errbuf[128]; + snprintf(errbuf, 128, "Unknown thrift typeID %d", thrift_typeID); + throw_tprotocolexception(errbuf, INVALID_DATA); +} + +static +void protocol_writeMessageBegin(zval* transport, zend_string* method_name, int32_t msgtype, int32_t seqID) { + zval args[3]; + zval ret; + zval writeMessagefn; + + ZVAL_STR_COPY(&args[0], method_name); + ZVAL_LONG(&args[1], msgtype); + ZVAL_LONG(&args[2], seqID); + ZVAL_NULL(&ret); + ZVAL_STRING(&writeMessagefn, "writeMessageBegin"); + + call_user_function(EG(function_table), transport, &writeMessagefn, &ret, 3, args); + + zval_dtor(&writeMessagefn); + zval_dtor(&args[2]); zval_dtor(&args[1]); zval_dtor(&args[0]); + zval_dtor(&ret); + if (EG(exception)) { + zend_object *ex = EG(exception); + EG(exception) = nullptr; + throw PHPExceptionWrapper(ex); + } +} + +static inline +bool ttype_is_int(int8_t t) { + return ((t == T_BYTE) || ((t >= T_I16) && (t <= T_I64))); +} +static inline +bool ttype_is_scalar(int8_t t) { + return !((t == T_STRUCT) || ( t== T_MAP) || (t == T_SET) || (t == T_LIST)); +} + +static inline +bool ttypes_are_compatible(int8_t t1, int8_t t2) { + // Integer types of different widths are considered compatible; + // otherwise the typeID must match. + return ((t1 == t2) || (ttype_is_int(t1) && ttype_is_int(t2))); +} + +//is used to validate objects before serialization and after deserialization. For now, only required fields are validated. +static +void validate_thrift_object(zval* object) { + zend_class_entry* object_class_entry = Z_OBJCE_P(object); + zval* is_validate = zend_read_static_property(object_class_entry, "isValidate", sizeof("isValidate")-1, true); + zval* spec = zend_read_static_property(object_class_entry, "_TSPEC", sizeof("_TSPEC")-1, true); + HashPosition key_ptr; + zval* val_ptr; + + if (is_validate && Z_TYPE_INFO_P(is_validate) == IS_TRUE) { + for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(spec), &key_ptr); + (val_ptr = zend_hash_get_current_data_ex(Z_ARRVAL_P(spec), &key_ptr)) != nullptr; + zend_hash_move_forward_ex(Z_ARRVAL_P(spec), &key_ptr)) { + + zend_ulong fieldno; + if (zend_hash_get_current_key_ex(Z_ARRVAL_P(spec), nullptr, &fieldno, &key_ptr) != HASH_KEY_IS_LONG) { + throw_tprotocolexception("Bad keytype in TSPEC (expected 'long')", INVALID_DATA); + return; + } + HashTable* fieldspec = Z_ARRVAL_P(val_ptr); + + // field name + zval* zvarname = zend_hash_str_find(fieldspec, "var", sizeof("var")-1); + char* varname = Z_STRVAL_P(zvarname); + + zval* is_required = zend_hash_str_find(fieldspec, "isRequired", sizeof("isRequired")-1); + zval rv; + zval* prop = zend_read_property(object_class_entry, object, varname, strlen(varname), false, &rv); + + if (Z_TYPE_INFO_P(is_required) == IS_TRUE && Z_TYPE_P(prop) == IS_NULL) { + char errbuf[128]; + snprintf(errbuf, 128, "Required field %s.%s is unset!", ZSTR_VAL(object_class_entry->name), varname); + throw_tprotocolexception(errbuf, INVALID_DATA); + } + } + } +} + +static +void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTable* spec) { + // SET and LIST have 'elem' => array('type', [optional] 'class') + // MAP has 'val' => array('type', [optiona] 'class') + zend_class_entry* ce = Z_OBJCE_P(zthis); + while (true) { + int8_t ttype = transport.readI8(); + if (ttype == T_STOP) { + validate_thrift_object(zthis); + return; + } + + int16_t fieldno = transport.readI16(); + zval* val_ptr = zend_hash_index_find(spec, fieldno); + if (val_ptr != nullptr) { + HashTable* fieldspec = Z_ARRVAL_P(val_ptr); + // pull the field name + val_ptr = zend_hash_str_find(fieldspec, "var", sizeof("var")-1); + char* varname = Z_STRVAL_P(val_ptr); + + // and the type + val_ptr = zend_hash_str_find(fieldspec, "type", sizeof("type")-1); + if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr); + int8_t expected_ttype = Z_LVAL_P(val_ptr); + + if (ttypes_are_compatible(ttype, expected_ttype)) { + zval rv; + ZVAL_UNDEF(&rv); + + binary_deserialize(ttype, transport, &rv, fieldspec); + zend_update_property(ce, zthis, varname, strlen(varname), &rv); + + zval_ptr_dtor(&rv); + } else { + skip_element(ttype, transport); + } + } else { + skip_element(ttype, transport); + } + } +} + +static +void binary_serialize_spec(zval* zthis, PHPOutputTransport& transport, HashTable* spec) { + + validate_thrift_object(zthis); + + HashPosition key_ptr; + zval* val_ptr; + + for (zend_hash_internal_pointer_reset_ex(spec, &key_ptr); + (val_ptr = zend_hash_get_current_data_ex(spec, &key_ptr)) != nullptr; + zend_hash_move_forward_ex(spec, &key_ptr)) { + + zend_ulong fieldno; + if (zend_hash_get_current_key_ex(spec, nullptr, &fieldno, &key_ptr) != HASH_KEY_IS_LONG) { + throw_tprotocolexception("Bad keytype in TSPEC (expected 'long')", INVALID_DATA); + return; + } + HashTable* fieldspec = Z_ARRVAL_P(val_ptr); + + // field name + val_ptr = zend_hash_str_find(fieldspec, "var", sizeof("var")-1); + char* varname = Z_STRVAL_P(val_ptr); + + // thrift type + val_ptr = zend_hash_str_find(fieldspec, "type", sizeof("type")-1); + if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr); + int8_t ttype = Z_LVAL_P(val_ptr); + + zval rv; + zval* prop = zend_read_property(Z_OBJCE_P(zthis), zthis, varname, strlen(varname), false, &rv); + + if (Z_TYPE_P(prop) == IS_REFERENCE){ + ZVAL_UNREF(prop); + } + if (Z_TYPE_P(prop) != IS_NULL) { + transport.writeI8(ttype); + transport.writeI16(fieldno); + binary_serialize(ttype, transport, prop, fieldspec); + } + } + transport.writeI8(T_STOP); // struct end +} + +// 6 params: $transport $method_name $ttype $request_struct $seqID $strict_write +PHP_FUNCTION(thrift_protocol_write_binary) { + zval *protocol; + zval *request_struct; + zend_string *method_name; + long msgtype, seqID; + zend_bool strict_write; + + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "oSlolb", + &protocol, &method_name, &msgtype, + &request_struct, &seqID, &strict_write) == FAILURE) { + return; + } + + try { + zval* spec = zend_read_static_property(Z_OBJCE_P(request_struct), "_TSPEC", sizeof("_TSPEC")-1, true); + + if (!spec || Z_TYPE_P(spec) != IS_ARRAY) { + throw_tprotocolexception("Attempt serialize from non-Thrift object", INVALID_DATA); + } + + PHPOutputTransport transport(protocol); + protocol_writeMessageBegin(protocol, method_name, (int32_t) msgtype, (int32_t) seqID); + binary_serialize_spec(request_struct, transport, Z_ARRVAL_P(spec)); + transport.flush(); + + } catch (const PHPExceptionWrapper& ex) { + // ex will be destructed, so copy to a zval that zend_throw_exception_object can take ownership of + zval myex; + ZVAL_COPY(&myex, ex); + zend_throw_exception_object(&myex); + RETURN_NULL(); + } catch (const std::exception& ex) { + throw_zend_exception_from_std_exception(ex); + RETURN_NULL(); + } +} + + +// 4 params: $transport $response_Typename $strict_read $buffer_size +PHP_FUNCTION(thrift_protocol_read_binary) { + zval *protocol; + zend_string *obj_typename; + zend_bool strict_read; + size_t buffer_size = 8192; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "oSb|l", &protocol, &obj_typename, &strict_read, &buffer_size) == FAILURE) { + return; + } + + try { + PHPInputTransport transport(protocol, buffer_size); + int8_t messageType = 0; + int32_t sz = transport.readI32(); + + if (sz < 0) { + // Check for correct version number + int32_t version = sz & VERSION_MASK; + if (version != VERSION_1) { + throw_tprotocolexception("Bad version identifier", BAD_VERSION); + } + messageType = (sz & 0x000000ff); + int32_t namelen = transport.readI32(); + // skip the name string and the sequence ID, we don't care about those + transport.skip(namelen + 4); + } else { + if (strict_read) { + throw_tprotocolexception("No version identifier... old protocol client in strict mode?", BAD_VERSION); + } else { + // Handle pre-versioned input + transport.skip(sz); // skip string body + messageType = transport.readI8(); + transport.skip(4); // skip sequence number + } + } + + if (messageType == T_EXCEPTION) { + zval ex; + createObject("\\Thrift\\Exception\\TApplicationException", &ex); + zval* spec = zend_read_static_property(Z_OBJCE(ex), "_TSPEC", sizeof("_TPSEC")-1, false); + if (EG(exception)) { + zend_object *ex = EG(exception); + EG(exception) = nullptr; + throw PHPExceptionWrapper(ex); + } + binary_deserialize_spec(&ex, transport, Z_ARRVAL_P(spec)); + throw PHPExceptionWrapper(&ex); + } + + createObject(ZSTR_VAL(obj_typename), return_value); + zval* spec = zend_read_static_property(Z_OBJCE_P(return_value), "_TSPEC", sizeof("_TSPEC")-1, true); + if (!spec || Z_TYPE_P(spec) != IS_ARRAY) { + throw_tprotocolexception("Attempt deserialize to non-Thrift object", INVALID_DATA); + } + binary_deserialize_spec(return_value, transport, Z_ARRVAL_P(spec)); + } catch (const PHPExceptionWrapper& ex) { + // ex will be destructed, so copy to a zval that zend_throw_exception_object can ownership of + zval myex; + ZVAL_COPY(&myex, ex); + zval_dtor(return_value); + zend_throw_exception_object(&myex); + RETURN_NULL(); + } catch (const std::exception& ex) { + throw_zend_exception_from_std_exception(ex); + RETURN_NULL(); + } +} + +// 4 params: $transport $response_Typename $strict_read $buffer_size +PHP_FUNCTION(thrift_protocol_read_binary_after_message_begin) { + zval *protocol; + zend_string *obj_typename; + zend_bool strict_read; + size_t buffer_size = 8192; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "oSb|l", &protocol, &obj_typename, &strict_read, &buffer_size) == FAILURE) { + return; + } + + try { + PHPInputTransport transport(protocol, buffer_size); + + createObject(ZSTR_VAL(obj_typename), return_value); + zval* spec = zend_read_static_property(Z_OBJCE_P(return_value), "_TSPEC", sizeof("_TSPEC")-1, false); + binary_deserialize_spec(return_value, transport, Z_ARRVAL_P(spec)); + } catch (const PHPExceptionWrapper& ex) { + // ex will be destructed, so copy to a zval that zend_throw_exception_object can take ownership of + zval myex; + ZVAL_COPY(&myex, ex); + zend_throw_exception_object(&myex); + RETURN_NULL(); + } catch (const std::exception& ex) { + throw_zend_exception_from_std_exception(ex); + RETURN_NULL(); + } +} + +#endif /* PHP_VERSION_ID >= 70000 */ diff --git a/lib/php/src/ext/thrift_protocol/php_thrift_protocol.h b/lib/php/src/ext/thrift_protocol/php_thrift_protocol.h new file mode 100644 index 0000000..0420997 --- /dev/null +++ b/lib/php/src/ext/thrift_protocol/php_thrift_protocol.h @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#pragma once + +PHP_FUNCTION(thrift_protocol_write_binary); +PHP_FUNCTION(thrift_protocol_read_binary); +PHP_FUNCTION(thrift_protocol_read_binary_after_message_begin); + +extern zend_module_entry thrift_protocol_module_entry; +#define phpext_thrift_protocol_ptr &thrift_protocol_module_entry + diff --git a/lib/php/src/ext/thrift_protocol/run-tests.php b/lib/php/src/ext/thrift_protocol/run-tests.php new file mode 100644 index 0000000..1ffc9e5 --- /dev/null +++ b/lib/php/src/ext/thrift_protocol/run-tests.php @@ -0,0 +1,2928 @@ +#!/usr/bin/env php + | + | Preston L. Bannister | + | Marcus Boerger | + | Derick Rethans | + | Sander Roobol | + | (based on version by: Stig Bakken ) | + | (based on the PHP 3 test framework by Rasmus Lerdorf) | + +----------------------------------------------------------------------+ + */ + +/* $Id: f2568036579435fa181c7ed1c8c3064360174ccd $ */ + +/* Sanity check to ensure that pcre extension needed by this script is available. + * In the event it is not, print a nice error message indicating that this script will + * not run without it. + */ + +if (!extension_loaded('pcre')) { + echo <<'; + save_text($info_file, $php_info); + $info_params = array(); + settings2array($ini_overwrites, $info_params); + settings2params($info_params); + $php_info = `$php $pass_options $info_params $no_file_cache "$info_file"`; + define('TESTED_PHP_VERSION', `$php -n -r "echo PHP_VERSION;"`); + + if ($php_cgi && $php != $php_cgi) { + $php_info_cgi = `$php_cgi $pass_options $info_params $no_file_cache -q "$info_file"`; + $php_info_sep = "\n---------------------------------------------------------------------"; + $php_cgi_info = "$php_info_sep\nPHP : $php_cgi $php_info_cgi$php_info_sep"; + } else { + $php_cgi_info = ''; + } + + if ($phpdbg) { + $phpdbg_info = `$phpdbg $pass_options $info_params $no_file_cache -qrr "$info_file"`; + $php_info_sep = "\n---------------------------------------------------------------------"; + $phpdbg_info = "$php_info_sep\nPHP : $phpdbg $phpdbg_info$php_info_sep"; + } else { + $phpdbg_info = ''; + } + + @unlink($info_file); + + // load list of enabled extensions + save_text($info_file, ''); + $exts_to_test = explode(',',`$php $pass_options $info_params $no_file_cache "$info_file"`); + // check for extensions that need special handling and regenerate + $info_params_ex = array( + 'session' => array('session.auto_start=0'), + 'tidy' => array('tidy.clean_output=0'), + 'zlib' => array('zlib.output_compression=Off'), + 'xdebug' => array('xdebug.default_enable=0'), + 'mbstring' => array('mbstring.func_overload=0'), + ); + + foreach($info_params_ex as $ext => $ini_overwrites_ex) { + if (in_array($ext, $exts_to_test)) { + $ini_overwrites = array_merge($ini_overwrites, $ini_overwrites_ex); + } + } + + @unlink($info_file); + + // Write test context information. + echo " +===================================================================== +PHP : $php $php_info $php_cgi_info $phpdbg_info +CWD : $cwd +Extra dirs : "; + foreach ($user_tests as $test_dir) { + echo "{$test_dir}\n "; + } + echo " +VALGRIND : " . ($leak_check ? $valgrind_header : 'Not used') . " +===================================================================== +"; +} + +define('PHP_QA_EMAIL', 'qa-reports@lists.php.net'); +define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php'); +define('QA_REPORTS_PAGE', 'http://qa.php.net/reports'); +define('TRAVIS_CI' , (bool) getenv('TRAVIS')); + +function save_or_mail_results() +{ + global $sum_results, $just_save_results, $failed_test_summary, + $PHP_FAILED_TESTS, $CUR_DIR, $php, $output_file, $compression; + + /* We got failed Tests, offer the user to send an e-mail to QA team, unless NO_INTERACTION is set */ + if (!getenv('NO_INTERACTION') && !TRAVIS_CI) { + $fp = fopen("php://stdin", "r+"); + if ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['WARNED'] || $sum_results['LEAKED']) { + echo "\nYou may have found a problem in PHP."; + } + echo "\nThis report can be automatically sent to the PHP QA team at\n"; + echo QA_REPORTS_PAGE . " and http://news.php.net/php.qa.reports\n"; + echo "This gives us a better understanding of PHP's behavior.\n"; + echo "If you don't want to send the report immediately you can choose\n"; + echo "option \"s\" to save it. You can then email it to ". PHP_QA_EMAIL . " later.\n"; + echo "Do you want to send this report now? [Yns]: "; + flush(); + + $user_input = fgets($fp, 10); + $just_save_results = (strtolower($user_input[0]) == 's'); + } + + if ($just_save_results || !getenv('NO_INTERACTION') || TRAVIS_CI) { + if ($just_save_results || TRAVIS_CI || strlen(trim($user_input)) == 0 || strtolower($user_input[0]) == 'y') { + /* + * Collect information about the host system for our report + * Fetch phpinfo() output so that we can see the PHP environment + * Make an archive of all the failed tests + * Send an email + */ + if ($just_save_results) { + $user_input = 's'; + } + + /* Ask the user to provide an email address, so that QA team can contact the user */ + if (TRAVIS_CI) { + $user_email = 'travis at php dot net'; + } elseif (!strncasecmp($user_input, 'y', 1) || strlen(trim($user_input)) == 0) { + echo "\nPlease enter your email address.\n(Your address will be mangled so that it will not go out on any\nmailinglist in plain text): "; + flush(); + $user_email = trim(fgets($fp, 1024)); + $user_email = str_replace("@", " at ", str_replace(".", " dot ", $user_email)); + } + + $failed_tests_data = ''; + $sep = "\n" . str_repeat('=', 80) . "\n"; + $failed_tests_data .= $failed_test_summary . "\n"; + $failed_tests_data .= get_summary(true, false) . "\n"; + + if ($sum_results['FAILED']) { + foreach ($PHP_FAILED_TESTS['FAILED'] as $test_info) { + $failed_tests_data .= $sep . $test_info['name'] . $test_info['info']; + $failed_tests_data .= $sep . file_get_contents(realpath($test_info['output']), FILE_BINARY); + $failed_tests_data .= $sep . file_get_contents(realpath($test_info['diff']), FILE_BINARY); + $failed_tests_data .= $sep . "\n\n"; + } + $status = "failed"; + } else { + $status = "success"; + } + + $failed_tests_data .= "\n" . $sep . 'BUILD ENVIRONMENT' . $sep; + $failed_tests_data .= "OS:\n" . PHP_OS . " - " . php_uname() . "\n\n"; + $ldd = $autoconf = $sys_libtool = $libtool = $compiler = 'N/A'; + + if (substr(PHP_OS, 0, 3) != "WIN") { + /* If PHP_AUTOCONF is set, use it; otherwise, use 'autoconf'. */ + if (getenv('PHP_AUTOCONF')) { + $autoconf = shell_exec(getenv('PHP_AUTOCONF') . ' --version'); + } else { + $autoconf = shell_exec('autoconf --version'); + } + + /* Always use the generated libtool - Mac OSX uses 'glibtool' */ + $libtool = shell_exec($CUR_DIR . '/libtool --version'); + + /* Use shtool to find out if there is glibtool present (MacOSX) */ + $sys_libtool_path = shell_exec(__DIR__ . '/build/shtool path glibtool libtool'); + + if ($sys_libtool_path) { + $sys_libtool = shell_exec(str_replace("\n", "", $sys_libtool_path) . ' --version'); + } + + /* Try the most common flags for 'version' */ + $flags = array('-v', '-V', '--version'); + $cc_status = 0; + + foreach($flags AS $flag) { + system(getenv('CC') . " $flag >/dev/null 2>&1", $cc_status); + if ($cc_status == 0) { + $compiler = shell_exec(getenv('CC') . " $flag 2>&1"); + break; + } + } + + $ldd = shell_exec("ldd $php 2>/dev/null"); + } + + $failed_tests_data .= "Autoconf:\n$autoconf\n"; + $failed_tests_data .= "Bundled Libtool:\n$libtool\n"; + $failed_tests_data .= "System Libtool:\n$sys_libtool\n"; + $failed_tests_data .= "Compiler:\n$compiler\n"; + $failed_tests_data .= "Bison:\n". shell_exec('bison --version 2>/dev/null') . "\n"; + $failed_tests_data .= "Libraries:\n$ldd\n"; + $failed_tests_data .= "\n"; + + if (isset($user_email)) { + $failed_tests_data .= "User's E-mail: " . $user_email . "\n\n"; + } + + $failed_tests_data .= $sep . "PHPINFO" . $sep; + $failed_tests_data .= shell_exec($php . ' -ddisplay_errors=stderr -dhtml_errors=0 -i 2> /dev/null'); + + if ($just_save_results || !mail_qa_team($failed_tests_data, $compression, $status) && !TRAVIS_CI) { + file_put_contents($output_file, $failed_tests_data); + + if (!$just_save_results) { + echo "\nThe test script was unable to automatically send the report to PHP's QA Team\n"; + } + + echo "Please send " . $output_file . " to " . PHP_QA_EMAIL . " manually, thank you.\n"; + } elseif (!getenv('NO_INTERACTION') && !TRAVIS_CI) { + fwrite($fp, "\nThank you for helping to make PHP better.\n"); + fclose($fp); + } + } + } +} + +// Determine the tests to be run. + +$test_files = array(); +$redir_tests = array(); +$test_results = array(); +$PHP_FAILED_TESTS = array('BORKED' => array(), 'FAILED' => array(), 'WARNED' => array(), 'LEAKED' => array(), 'XFAILED' => array()); + +// If parameters given assume they represent selected tests to run. +$failed_tests_file= false; +$pass_option_n = false; +$pass_options = ''; + +$compression = 0; +$output_file = $CUR_DIR . '/php_test_results_' . date('Ymd_Hi') . '.txt'; + +if ($compression && in_array("compress.zlib", stream_get_filters())) { + $output_file = 'compress.zlib://' . $output_file . '.gz'; +} + +$just_save_results = false; +$leak_check = false; +$html_output = false; +$html_file = null; +$temp_source = null; +$temp_target = null; +$temp_urlbase = null; +$conf_passed = null; +$no_clean = false; + +$cfgtypes = array('show', 'keep'); +$cfgfiles = array('skip', 'php', 'clean', 'out', 'diff', 'exp'); +$cfg = array(); + +foreach($cfgtypes as $type) { + $cfg[$type] = array(); + + foreach($cfgfiles as $file) { + $cfg[$type][$file] = false; + } +} + +if (getenv('TEST_PHP_ARGS')) { + + if (!isset($argc) || !$argc || !isset($argv)) { + $argv = array(__FILE__); + } + + $argv = array_merge($argv, explode(' ', getenv('TEST_PHP_ARGS'))); + $argc = count($argv); +} + +if (isset($argc) && $argc > 1) { + + for ($i=1; $i<$argc; $i++) { + $is_switch = false; + $switch = substr($argv[$i],1,1); + $repeat = substr($argv[$i],0,1) == '-'; + + while ($repeat) { + + if (!$is_switch) { + $switch = substr($argv[$i],1,1); + } + + $is_switch = true; + + if ($repeat) { + foreach($cfgtypes as $type) { + if (strpos($switch, '--' . $type) === 0) { + foreach($cfgfiles as $file) { + if ($switch == '--' . $type . '-' . $file) { + $cfg[$type][$file] = true; + $is_switch = false; + break; + } + } + } + } + } + + if (!$is_switch) { + $is_switch = true; + break; + } + + $repeat = false; + + switch($switch) { + case 'r': + case 'l': + $test_list = file($argv[++$i]); + if ($test_list) { + foreach($test_list as $test) { + $matches = array(); + if (preg_match('/^#.*\[(.*)\]\:\s+(.*)$/', $test, $matches)) { + $redir_tests[] = array($matches[1], $matches[2]); + } else if (strlen($test)) { + $test_files[] = trim($test); + } + } + } + if ($switch != 'l') { + break; + } + $i--; + // break left intentionally + case 'w': + $failed_tests_file = fopen($argv[++$i], 'w+t'); + break; + case 'a': + $failed_tests_file = fopen($argv[++$i], 'a+t'); + break; + case 'c': + $conf_passed = $argv[++$i]; + break; + case 'd': + $ini_overwrites[] = $argv[++$i]; + break; + case 'g': + $SHOW_ONLY_GROUPS = explode(",", $argv[++$i]); + break; + //case 'h' + case '--keep-all': + foreach($cfgfiles as $file) { + $cfg['keep'][$file] = true; + } + break; + //case 'l' + case 'm': + $leak_check = true; + $valgrind_cmd = "valgrind --version"; + $valgrind_header = system_with_timeout($valgrind_cmd, $environment); + $replace_count = 0; + if (!$valgrind_header) { + error("Valgrind returned no version info, cannot proceed.\nPlease check if Valgrind is installed."); + } else { + $valgrind_version = preg_replace("/valgrind-(\d+)\.(\d+)\.(\d+)([.\w_-]+)?(\s+)/", '$1.$2.$3', $valgrind_header, 1, $replace_count); + if ($replace_count != 1) { + error("Valgrind returned invalid version info (\"$valgrind_header\"), cannot proceed."); + } + $valgrind_header = trim($valgrind_header); + } + break; + case 'n': + if (!$pass_option_n) { + $pass_options .= ' -n'; + } + $pass_option_n = true; + break; + case 'e': + $pass_options .= ' -e'; + break; + case '--no-clean': + $no_clean = true; + break; + case 'p': + $php = $argv[++$i]; + putenv("TEST_PHP_EXECUTABLE=$php"); + $environment['TEST_PHP_EXECUTABLE'] = $php; + break; + case 'P': + if(constant('PHP_BINARY')) { + $php = PHP_BINARY; + } else { + break; + } + putenv("TEST_PHP_EXECUTABLE=$php"); + $environment['TEST_PHP_EXECUTABLE'] = $php; + break; + case 'q': + putenv('NO_INTERACTION=1'); + break; + //case 'r' + case 's': + $output_file = $argv[++$i]; + $just_save_results = true; + break; + case '--set-timeout': + $environment['TEST_TIMEOUT'] = $argv[++$i]; + break; + case '--show-all': + foreach($cfgfiles as $file) { + $cfg['show'][$file] = true; + } + break; + case '--temp-source': + $temp_source = $argv[++$i]; + break; + case '--temp-target': + $temp_target = $argv[++$i]; + if ($temp_urlbase) { + $temp_urlbase = $temp_target; + } + break; + case '--temp-urlbase': + $temp_urlbase = $argv[++$i]; + break; + case 'v': + case '--verbose': + $DETAILED = true; + break; + case 'x': + $environment['SKIP_SLOW_TESTS'] = 1; + break; + case '--offline': + $environment['SKIP_ONLINE_TESTS'] = 1; + break; + //case 'w' + case '-': + // repeat check with full switch + $switch = $argv[$i]; + if ($switch != '-') { + $repeat = true; + } + break; + case '--html': + $html_file = fopen($argv[++$i], 'wt'); + $html_output = is_resource($html_file); + break; + case '--version': + echo '$Id: f2568036579435fa181c7ed1c8c3064360174ccd $' . "\n"; + exit(1); + + default: + echo "Illegal switch '$switch' specified!\n"; + case 'h': + case '-help': + case '--help': + echo << Read the testfiles to be executed from . After the test + has finished all failed tests are written to the same . + If the list is empty and no further test is specified then + all tests are executed (same as: -r -w ). + + -r Read the testfiles to be executed from . + + -w Write a list of all failed tests to . + + -a Same as -w but append rather then truncating . + + -c Look for php.ini in directory or use as ini. + + -n Pass -n option to the php binary (Do not use a php.ini). + + -d foo=bar Pass -d option to the php binary (Define INI entry foo + with value 'bar'). + + -g Comma separated list of groups to show during test run + (possible values: PASS, FAIL, XFAIL, SKIP, BORK, WARN, LEAK, REDIRECT). + + -m Test for memory leaks with Valgrind. + + -p Specify PHP executable to run. + + -P Use PHP_BINARY as PHP executable to run. + + -q Quiet, no user interaction (same as environment NO_INTERACTION). + + -s Write output to . + + -x Sets 'SKIP_SLOW_TESTS' environmental variable. + + --offline Sets 'SKIP_ONLINE_TESTS' environmental variable. + + --verbose + -v Verbose mode. + + --help + -h This Help. + + --html Generate HTML output. + + --temp-source --temp-target [--temp-urlbase ] + Write temporary files to by replacing from the + filenames to generate with . If --html is being used and + given then the generated links are relative and prefixed + with the given url. In general you want to make the path + to your source files and some pach in your web page + hierarchy with pointing to . + + --keep-[all|php|skip|clean] + Do not delete 'all' files, 'php' test file, 'skip' or 'clean' + file. + + --set-timeout [n] + Set timeout for individual tests, where [n] is the number of + seconds. The default value is 60 seconds, or 300 seconds when + testing for memory leaks. + + --show-[all|php|skip|clean|exp|diff|out] + Show 'all' files, 'php' test file, 'skip' or 'clean' file. You + can also use this to show the output 'out', the expected result + 'exp' or the difference between them 'diff'. The result types + get written independent of the log format, however 'diff' only + exists when a test fails. + + --no-clean Do not execute clean section if any. + +HELP; + exit(1); + } + } + + if (!$is_switch) { + $testfile = realpath($argv[$i]); + + if (!$testfile && strpos($argv[$i], '*') !== false && function_exists('glob')) { + + if (preg_match("/\.phpt$/", $argv[$i])) { + $pattern_match = glob($argv[$i]); + } else if (preg_match("/\*$/", $argv[$i])) { + $pattern_match = glob($argv[$i] . '.phpt'); + } else { + die("bogus test name " . $argv[$i] . "\n"); + } + + if (is_array($pattern_match)) { + $test_files = array_merge($test_files, $pattern_match); + } + + } else if (is_dir($testfile)) { + find_files($testfile); + } else if (preg_match("/\.phpt$/", $testfile)) { + $test_files[] = $testfile; + } else { + die("bogus test name " . $argv[$i] . "\n"); + } + } + } + + if (strlen($conf_passed)) { + if (substr(PHP_OS, 0, 3) == "WIN") { + $pass_options .= " -c " . escapeshellarg($conf_passed); + } else { + $pass_options .= " -c '$conf_passed'"; + } + } + + $test_files = array_unique($test_files); + $test_files = array_merge($test_files, $redir_tests); + + // Run selected tests. + $test_cnt = count($test_files); + + if ($test_cnt) { + putenv('NO_INTERACTION=1'); + verify_config(); + write_information($html_output); + usort($test_files, "test_sort"); + $start_time = time(); + + if (!$html_output) { + echo "Running selected tests.\n"; + } else { + show_start($start_time); + } + + $test_idx = 0; + run_all_tests($test_files, $environment); + $end_time = time(); + + if ($html_output) { + show_end($end_time); + } + + if ($failed_tests_file) { + fclose($failed_tests_file); + } + + compute_summary(); + if ($html_output) { + fwrite($html_file, "
\n" . get_summary(false, true)); + } + echo "====================================================================="; + echo get_summary(false, false); + + if ($html_output) { + fclose($html_file); + } + + if ($output_file != '' && $just_save_results) { + save_or_mail_results(); + } + + junit_save_xml(); + + if (getenv('REPORT_EXIT_STATUS') == 1 && ($sum_results['FAILED'] || $sum_results['BORKED'])) { + exit(1); + } + + exit(0); + } +} + +verify_config(); +write_information($html_output); + +// Compile a list of all test files (*.phpt). +$test_files = array(); +$exts_tested = count($exts_to_test); +$exts_skipped = 0; +$ignored_by_ext = 0; +sort($exts_to_test); +$test_dirs = array(); +$optionals = array('tests', 'ext', 'Zend', 'sapi'); + +foreach($optionals as $dir) { + if (@filetype($dir) == 'dir') { + $test_dirs[] = $dir; + } +} + +// Convert extension names to lowercase +foreach ($exts_to_test as $key => $val) { + $exts_to_test[$key] = strtolower($val); +} + +foreach ($test_dirs as $dir) { + find_files("{$cwd}/{$dir}", ($dir == 'ext')); +} + +foreach ($user_tests as $dir) { + find_files($dir, ($dir == 'ext')); +} + +function find_files($dir, $is_ext_dir = false, $ignore = false) +{ + global $test_files, $exts_to_test, $ignored_by_ext, $exts_skipped, $exts_tested; + + $o = opendir($dir) or error("cannot open directory: $dir"); + + while (($name = readdir($o)) !== false) { + + if (is_dir("{$dir}/{$name}") && !in_array($name, array('.', '..', '.svn'))) { + $skip_ext = ($is_ext_dir && !in_array(strtolower($name), $exts_to_test)); + if ($skip_ext) { + $exts_skipped++; + } + find_files("{$dir}/{$name}", false, $ignore || $skip_ext); + } + + // Cleanup any left-over tmp files from last run. + if (substr($name, -4) == '.tmp') { + @unlink("$dir/$name"); + continue; + } + + // Otherwise we're only interested in *.phpt files. + if (substr($name, -5) == '.phpt') { + if ($ignore) { + $ignored_by_ext++; + } else { + $testfile = realpath("{$dir}/{$name}"); + $test_files[] = $testfile; + } + } + } + + closedir($o); +} + +function test_name($name) +{ + if (is_array($name)) { + return $name[0] . ':' . $name[1]; + } else { + return $name; + } +} + +function test_sort($a, $b) +{ + global $cwd; + + $a = test_name($a); + $b = test_name($b); + + $ta = strpos($a, "{$cwd}/tests") === 0 ? 1 + (strpos($a, "{$cwd}/tests/run-test") === 0 ? 1 : 0) : 0; + $tb = strpos($b, "{$cwd}/tests") === 0 ? 1 + (strpos($b, "{$cwd}/tests/run-test") === 0 ? 1 : 0) : 0; + + if ($ta == $tb) { + return strcmp($a, $b); + } else { + return $tb - $ta; + } +} + +$test_files = array_unique($test_files); +usort($test_files, "test_sort"); + +$start_time = time(); +show_start($start_time); + +$test_cnt = count($test_files); +$test_idx = 0; +run_all_tests($test_files, $environment); +$end_time = time(); + +if ($failed_tests_file) { + fclose($failed_tests_file); +} + +// Summarize results + +if (0 == count($test_results)) { + echo "No tests were run.\n"; + return; +} + +compute_summary(); + +show_end($end_time); +show_summary(); + +if ($html_output) { + fclose($html_file); +} + +save_or_mail_results(); + +junit_save_xml(); + +if (getenv('REPORT_EXIT_STATUS') == 1 && ($sum_results['FAILED'] || $sum_results['BORKED'])) { + exit(1); +} +exit(0); + +// +// Send Email to QA Team +// + +function mail_qa_team($data, $compression, $status = false) +{ + $url_bits = parse_url(QA_SUBMISSION_PAGE); + + if (($proxy = getenv('http_proxy'))) { + $proxy = parse_url($proxy); + $path = $url_bits['host'].$url_bits['path']; + $host = $proxy['host']; + if (empty($proxy['port'])) { + $proxy['port'] = 80; + } + $port = $proxy['port']; + } else { + $path = $url_bits['path']; + $host = $url_bits['host']; + $port = empty($url_bits['port']) ? 80 : $port = $url_bits['port']; + } + + $data = "php_test_data=" . urlencode(base64_encode(str_replace("\00", '[0x0]', $data))); + $data_length = strlen($data); + + $fs = fsockopen($host, $port, $errno, $errstr, 10); + + if (!$fs) { + return false; + } + + $php_version = urlencode(TESTED_PHP_VERSION); + + echo "\nPosting to ". QA_SUBMISSION_PAGE . "\n"; + fwrite($fs, "POST " . $path . "?status=$status&version=$php_version HTTP/1.1\r\n"); + fwrite($fs, "Host: " . $host . "\r\n"); + fwrite($fs, "User-Agent: QA Browser 0.1\r\n"); + fwrite($fs, "Content-Type: application/x-www-form-urlencoded\r\n"); + fwrite($fs, "Content-Length: " . $data_length . "\r\n\r\n"); + fwrite($fs, $data); + fwrite($fs, "\r\n\r\n"); + fclose($fs); + + return 1; +} + + +// +// Write the given text to a temporary file, and return the filename. +// + +function save_text($filename, $text, $filename_copy = null) +{ + global $DETAILED; + + if ($filename_copy && $filename_copy != $filename) { + if (file_put_contents($filename_copy, $text, FILE_BINARY) === false) { + error("Cannot open file '" . $filename_copy . "' (save_text)"); + } + } + + if (file_put_contents($filename, $text, FILE_BINARY) === false) { + error("Cannot open file '" . $filename . "' (save_text)"); + } + + if (1 < $DETAILED) echo " +FILE $filename {{{ +$text +}}} +"; +} + +// +// Write an error in a format recognizable to Emacs or MSVC. +// + +function error_report($testname, $logname, $tested) +{ + $testname = realpath($testname); + $logname = realpath($logname); + + switch (strtoupper(getenv('TEST_PHP_ERROR_STYLE'))) { + case 'MSVC': + echo $testname . "(1) : $tested\n"; + echo $logname . "(1) : $tested\n"; + break; + case 'EMACS': + echo $testname . ":1: $tested\n"; + echo $logname . ":1: $tested\n"; + break; + } +} + +function system_with_timeout($commandline, $env = null, $stdin = null) +{ + global $leak_check, $cwd; + + $data = ''; + + $bin_env = array(); + foreach((array)$env as $key => $value) { + $bin_env[$key] = $value; + } + + $proc = proc_open($commandline, array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w') + ), $pipes, $cwd, $bin_env, array('suppress_errors' => true, 'binary_pipes' => true)); + + if (!$proc) { + return false; + } + + if (!is_null($stdin)) { + fwrite($pipes[0], $stdin); + } + fclose($pipes[0]); + unset($pipes[0]); + + $timeout = $leak_check ? 300 : (isset($env['TEST_TIMEOUT']) ? $env['TEST_TIMEOUT'] : 60); + + while (true) { + /* hide errors from interrupted syscalls */ + $r = $pipes; + $w = null; + $e = null; + + $n = @stream_select($r, $w, $e, $timeout); + + if ($n === false) { + break; + } else if ($n === 0) { + /* timed out */ + $data .= "\n ** ERROR: process timed out **\n"; + proc_terminate($proc, 9); + return $data; + } else if ($n > 0) { + $line = fread($pipes[1], 8192); + if (strlen($line) == 0) { + /* EOF */ + break; + } + $data .= $line; + } + } + + $stat = proc_get_status($proc); + + if ($stat['signaled']) { + $data .= "\nTermsig=" . $stat['stopsig'] . "\n"; + } + if ($stat["exitcode"] > 128 && $stat["exitcode"] < 160) { + $data .= "\nTermsig=" . ($stat["exitcode"] - 128) . "\n"; + } + + $code = proc_close($proc); + return $data; +} + +function run_all_tests($test_files, $env, $redir_tested = null) +{ + global $test_results, $failed_tests_file, $php, $test_cnt, $test_idx; + + foreach($test_files as $name) { + + if (is_array($name)) { + $index = "# $name[1]: $name[0]"; + + if ($redir_tested) { + $name = $name[0]; + } + } else if ($redir_tested) { + $index = "# $redir_tested: $name"; + } else { + $index = $name; + } + $test_idx++; + $result = run_test($php, $name, $env); + + if (!is_array($name) && $result != 'REDIR') { + $test_results[$index] = $result; + if ($failed_tests_file && ($result == 'XFAILED' || $result == 'FAILED' || $result == 'WARNED' || $result == 'LEAKED')) { + fwrite($failed_tests_file, "$index\n"); + } + } + } +} + +// +// Show file or result block +// +function show_file_block($file, $block, $section = null) +{ + global $cfg; + + if ($cfg['show'][$file]) { + + if (is_null($section)) { + $section = strtoupper($file); + } + + echo "\n========" . $section . "========\n"; + echo rtrim($block); + echo "\n========DONE========\n"; + } +} + +// +// Run an individual test case. +// +function run_test($php, $file, $env) +{ + global $log_format, $info_params, $ini_overwrites, $cwd, $PHP_FAILED_TESTS; + global $pass_options, $DETAILED, $IN_REDIRECT, $test_cnt, $test_idx; + global $leak_check, $temp_source, $temp_target, $cfg, $environment; + global $no_clean; + global $valgrind_version; + global $JUNIT; + global $SHOW_ONLY_GROUPS; + global $no_file_cache; + $temp_filenames = null; + $org_file = $file; + + if (isset($env['TEST_PHP_CGI_EXECUTABLE'])) { + $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE']; + } + + if (isset($env['TEST_PHPDBG_EXECUTABLE'])) { + $phpdbg = $env['TEST_PHPDBG_EXECUTABLE']; + } + + if (is_array($file)) { + $file = $file[0]; + } + + if ($DETAILED) echo " +================= +TEST $file +"; + + // Load the sections of the test file. + $section_text = array('TEST' => ''); + + $fp = fopen($file, "rb") or error("Cannot open test file: $file"); + + $borked = false; + $bork_info = ''; + + if (!feof($fp)) { + $line = fgets($fp); + + if ($line === false) { + $bork_info = "cannot read test"; + $borked = true; + } + } else { + $bork_info = "empty test [$file]"; + $borked = true; + } + if (!$borked && strncmp('--TEST--', $line, 8)) { + $bork_info = "tests must start with --TEST-- [$file]"; + $borked = true; + } + + $section = 'TEST'; + $secfile = false; + $secdone = false; + + while (!feof($fp)) { + $line = fgets($fp); + + if ($line === false) { + break; + } + + // Match the beginning of a section. + if (preg_match('/^--([_A-Z]+)--/', $line, $r)) { + $section = $r[1]; + settype($section, 'string'); + + if (isset($section_text[$section])) { + $bork_info = "duplicated $section section"; + $borked = true; + } + + $section_text[$section] = ''; + $secfile = $section == 'FILE' || $section == 'FILEEOF' || $section == 'FILE_EXTERNAL'; + $secdone = false; + continue; + } + + // Add to the section text. + if (!$secdone) { + $section_text[$section] .= $line; + } + + // End of actual test? + if ($secfile && preg_match('/^===DONE===\s*$/', $line)) { + $secdone = true; + } + } + + // the redirect section allows a set of tests to be reused outside of + // a given test dir + if (!$borked) { + if (@count($section_text['REDIRECTTEST']) == 1) { + + if ($IN_REDIRECT) { + $borked = true; + $bork_info = "Can't redirect a test from within a redirected test"; + } else { + $borked = false; + } + + } else { + + if (!isset($section_text['PHPDBG']) && @count($section_text['FILE']) + @count($section_text['FILEEOF']) + @count($section_text['FILE_EXTERNAL']) != 1) { + $bork_info = "missing section --FILE--"; + $borked = true; + } + + if (@count($section_text['FILEEOF']) == 1) { + $section_text['FILE'] = preg_replace("/[\r\n]+$/", '', $section_text['FILEEOF']); + unset($section_text['FILEEOF']); + } + + foreach (array( 'FILE', 'EXPECT', 'EXPECTF', 'EXPECTREGEX' ) as $prefix) { + $key = $prefix . '_EXTERNAL'; + + if (@count($section_text[$key]) == 1) { + // don't allow tests to retrieve files from anywhere but this subdirectory + $section_text[$key] = dirname($file) . '/' . trim(str_replace('..', '', $section_text[$key])); + + if (file_exists($section_text[$key])) { + $section_text[$prefix] = file_get_contents($section_text[$key], FILE_BINARY); + unset($section_text[$key]); + } else { + $bork_info = "could not load --" . $key . "-- " . dirname($file) . '/' . trim($section_text[$key]); + $borked = true; + } + } + } + + if ((@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX'])) != 1) { + $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--"; + $borked = true; + } + } + } + fclose($fp); + + $shortname = str_replace($cwd . '/', '', $file); + $tested_file = $shortname; + + if ($borked) { + show_result("BORK", $bork_info, $tested_file); + $PHP_FAILED_TESTS['BORKED'][] = array ( + 'name' => $file, + 'test_name' => '', + 'output' => '', + 'diff' => '', + 'info' => "$bork_info [$file]", + ); + + junit_mark_test_as('BORK', $shortname, $tested_file, 0, $bork_info); + return 'BORKED'; + } + + $tested = trim($section_text['TEST']); + + /* For GET/POST/PUT tests, check if cgi sapi is available and if it is, use it. */ + if (!empty($section_text['GET']) || !empty($section_text['POST']) || !empty($section_text['GZIP_POST']) || !empty($section_text['DEFLATE_POST']) || !empty($section_text['POST_RAW']) || !empty($section_text['PUT']) || !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) { + if (isset($php_cgi)) { + $old_php = $php; + $php = $php_cgi . ' -C '; + } else if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/php-cgi.exe")) { + $old_php = $php; + $php = realpath(dirname($php) . "/php-cgi.exe") . ' -C '; + } else { + if (file_exists(dirname($php) . "/../../sapi/cgi/php-cgi")) { + $old_php = $php; + $php = realpath(dirname($php) . "/../../sapi/cgi/php-cgi") . ' -C '; + } else if (file_exists("./sapi/cgi/php-cgi")) { + $old_php = $php; + $php = realpath("./sapi/cgi/php-cgi") . ' -C '; + } else if (file_exists(dirname($php) . "/php-cgi")) { + $old_php = $php; + $php = realpath(dirname($php) . "/php-cgi") . ' -C '; + } else { + show_result('SKIP', $tested, $tested_file, "reason: CGI not available"); + + junit_init_suite(junit_get_suitename_for($shortname)); + junit_mark_test_as('SKIP', $shortname, $tested, 0, 'CGI not available'); + return 'SKIPPED'; + } + } + } + + /* For phpdbg tests, check if phpdbg sapi is available and if it is, use it. */ + if (array_key_exists('PHPDBG', $section_text)) { + if (!isset($section_text['STDIN'])) { + $section_text['STDIN'] = $section_text['PHPDBG']."\n"; + } + + if (isset($phpdbg)) { + $old_php = $php; + $php = $phpdbg . ' -qIb'; + } else { + show_result('SKIP', $tested, $tested_file, "reason: phpdbg not available"); + + junit_init_suite(junit_get_suitename_for($shortname)); + junit_mark_test_as('SKIP', $shortname, $tested, 0, 'phpdbg not available'); + return 'SKIPPED'; + } + } + + if (!$SHOW_ONLY_GROUPS) { + show_test($test_idx, $shortname); + } + + if (is_array($IN_REDIRECT)) { + $temp_dir = $test_dir = $IN_REDIRECT['dir']; + } else { + $temp_dir = $test_dir = realpath(dirname($file)); + } + + if ($temp_source && $temp_target) { + $temp_dir = str_replace($temp_source, $temp_target, $temp_dir); + } + + $main_file_name = basename($file,'phpt'); + + $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'diff'; + $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'log'; + $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'exp'; + $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'out'; + $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'mem'; + $sh_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'sh'; + $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php'; + $test_file = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php'; + $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php'; + $test_skipif = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php'; + $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php'; + $test_clean = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php'; + $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('/phpt.'); + $tmp_relative_file = str_replace(__DIR__ . DIRECTORY_SEPARATOR, '', $test_file) . 't'; + + if ($temp_source && $temp_target) { + $temp_skipif .= 's'; + $temp_file .= 's'; + $temp_clean .= 's'; + $copy_file = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file) . '.phps'; + + if (!is_dir(dirname($copy_file))) { + mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file)); + } + + if (isset($section_text['FILE'])) { + save_text($copy_file, $section_text['FILE']); + } + + $temp_filenames = array( + 'file' => $copy_file, + 'diff' => $diff_filename, + 'log' => $log_filename, + 'exp' => $exp_filename, + 'out' => $output_filename, + 'mem' => $memcheck_filename, + 'sh' => $sh_filename, + 'php' => $temp_file, + 'skip' => $temp_skipif, + 'clean'=> $temp_clean); + } + + if (is_array($IN_REDIRECT)) { + $tested = $IN_REDIRECT['prefix'] . ' ' . trim($section_text['TEST']); + $tested_file = $tmp_relative_file; + } + + // unlink old test results + @unlink($diff_filename); + @unlink($log_filename); + @unlink($exp_filename); + @unlink($output_filename); + @unlink($memcheck_filename); + @unlink($sh_filename); + @unlink($temp_file); + @unlink($test_file); + @unlink($temp_skipif); + @unlink($test_skipif); + @unlink($tmp_post); + @unlink($temp_clean); + @unlink($test_clean); + + // Reset environment from any previous test. + $env['REDIRECT_STATUS'] = ''; + $env['QUERY_STRING'] = ''; + $env['PATH_TRANSLATED'] = ''; + $env['SCRIPT_FILENAME'] = ''; + $env['REQUEST_METHOD'] = ''; + $env['CONTENT_TYPE'] = ''; + $env['CONTENT_LENGTH'] = ''; + $env['TZ'] = ''; + + if (!empty($section_text['ENV'])) { + + foreach(explode("\n", trim($section_text['ENV'])) as $e) { + $e = explode('=', trim($e), 2); + + if (!empty($e[0]) && isset($e[1])) { + $env[$e[0]] = $e[1]; + } + } + } + + // Default ini settings + $ini_settings = array(); + + // Additional required extensions + if (array_key_exists('EXTENSIONS', $section_text)) { + $ext_dir=`$php -r 'echo ini_get("extension_dir");'`; + $extensions = preg_split("/[\n\r]+/", trim($section_text['EXTENSIONS'])); + $loaded = explode(",", `$php -n -r 'echo join(",", get_loaded_extensions());'`); + foreach ($extensions as $req_ext) { + if (!in_array($req_ext, $loaded)) { + if ($req_ext == 'opcache') { + $ini_settings['zend_extension'][] = $ext_dir . DIRECTORY_SEPARATOR . $req_ext . '.' . PHP_SHLIB_SUFFIX; + } else { + $ini_settings['extension'][] = $ext_dir . DIRECTORY_SEPARATOR . $req_ext . '.' . PHP_SHLIB_SUFFIX; + } + } + } + } + + // additional ini overwrites + //$ini_overwrites[] = 'setting=value'; + settings2array($ini_overwrites, $ini_settings); + + // Any special ini settings + // these may overwrite the test defaults... + if (array_key_exists('INI', $section_text)) { + if (strpos($section_text['INI'], '{PWD}') !== false) { + $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']); + } + settings2array(preg_split( "/[\n\r]+/", $section_text['INI']), $ini_settings); + } + + settings2params($ini_settings); + + // Check if test should be skipped. + $info = ''; + $warn = false; + + if (array_key_exists('SKIPIF', $section_text)) { + + if (trim($section_text['SKIPIF'])) { + show_file_block('skip', $section_text['SKIPIF']); + save_text($test_skipif, $section_text['SKIPIF'], $temp_skipif); + $extra = substr(PHP_OS, 0, 3) !== "WIN" ? + "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": ""; + + if ($leak_check) { + $env['USE_ZEND_ALLOC'] = '0'; + $env['ZEND_DONT_UNLOAD_MODULES'] = 1; + } else { + $env['USE_ZEND_ALLOC'] = '1'; + $env['ZEND_DONT_UNLOAD_MODULES'] = 0; + } + + junit_start_timer($shortname); + + $output = system_with_timeout("$extra $php $pass_options -q $ini_settings $no_file_cache -d display_errors=0 \"$test_skipif\"", $env); + + junit_finish_timer($shortname); + + if (!$cfg['keep']['skip']) { + @unlink($test_skipif); + } + + if (!strncasecmp('skip', ltrim($output), 4)) { + + if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) { + show_result('SKIP', $tested, $tested_file, "reason: $m[1]", $temp_filenames); + } else { + show_result('SKIP', $tested, $tested_file, '', $temp_filenames); + } + + if (isset($old_php)) { + $php = $old_php; + } + + if (!$cfg['keep']['skip']) { + @unlink($test_skipif); + } + + $message = !empty($m[1]) ? $m[1] : ''; + junit_mark_test_as('SKIP', $shortname, $tested, null, $message); + return 'SKIPPED'; + } + + if (!strncasecmp('info', ltrim($output), 4)) { + if (preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) { + $info = " (info: $m[1])"; + } + } + + if (!strncasecmp('warn', ltrim($output), 4)) { + if (preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) { + $warn = true; /* only if there is a reason */ + $info = " (warn: $m[1])"; + } + } + } + } + + if (!extension_loaded("zlib") + && ( array_key_exists("GZIP_POST", $section_text) + || array_key_exists("DEFLATE_POST", $section_text)) + ) { + $message = "ext/zlib required"; + show_result('SKIP', $tested, $tested_file, "reason: $message", $temp_filenames); + junit_mark_test_as('SKIP', $shortname, $tested, null, $message); + return 'SKIPPED'; + } + + if (@count($section_text['REDIRECTTEST']) == 1) { + $test_files = array(); + + $IN_REDIRECT = eval($section_text['REDIRECTTEST']); + $IN_REDIRECT['via'] = "via [$shortname]\n\t"; + $IN_REDIRECT['dir'] = realpath(dirname($file)); + $IN_REDIRECT['prefix'] = trim($section_text['TEST']); + + if (count($IN_REDIRECT['TESTS']) == 1) { + + if (is_array($org_file)) { + $test_files[] = $org_file[1]; + } else { + $GLOBALS['test_files'] = $test_files; + find_files($IN_REDIRECT['TESTS']); + + foreach($GLOBALS['test_files'] as $f) { + $test_files[] = array($f, $file); + } + } + $test_cnt += @count($test_files) - 1; + $test_idx--; + + show_redirect_start($IN_REDIRECT['TESTS'], $tested, $tested_file); + + // set up environment + $redirenv = array_merge($environment, $IN_REDIRECT['ENV']); + $redirenv['REDIR_TEST_DIR'] = realpath($IN_REDIRECT['TESTS']) . DIRECTORY_SEPARATOR; + + usort($test_files, "test_sort"); + run_all_tests($test_files, $redirenv, $tested); + + show_redirect_ends($IN_REDIRECT['TESTS'], $tested, $tested_file); + + // a redirected test never fails + $IN_REDIRECT = false; + + junit_mark_test_as('PASS', $shortname, $tested); + return 'REDIR'; + + } else { + + $bork_info = "Redirect info must contain exactly one TEST string to be used as redirect directory."; + show_result("BORK", $bork_info, '', $temp_filenames); + $PHP_FAILED_TESTS['BORKED'][] = array ( + 'name' => $file, + 'test_name' => '', + 'output' => '', + 'diff' => '', + 'info' => "$bork_info [$file]", + ); + } + } + + if (is_array($org_file) || @count($section_text['REDIRECTTEST']) == 1) { + + if (is_array($org_file)) { + $file = $org_file[0]; + } + + $bork_info = "Redirected test did not contain redirection info"; + show_result("BORK", $bork_info, '', $temp_filenames); + $PHP_FAILED_TESTS['BORKED'][] = array ( + 'name' => $file, + 'test_name' => '', + 'output' => '', + 'diff' => '', + 'info' => "$bork_info [$file]", + ); + + junit_mark_test_as('BORK', $shortname, $tested, null, $bork_info); + + return 'BORKED'; + } + + // We've satisfied the preconditions - run the test! + if (isset($section_text['FILE'])) { + show_file_block('php', $section_text['FILE'], 'TEST'); + save_text($test_file, $section_text['FILE'], $temp_file); + } else { + $test_file = $temp_file = ""; + } + + if (array_key_exists('GET', $section_text)) { + $query_string = trim($section_text['GET']); + } else { + $query_string = ''; + } + + $env['REDIRECT_STATUS'] = '1'; + if (empty($env['QUERY_STRING'])) { + $env['QUERY_STRING'] = $query_string; + } + if (empty($env['PATH_TRANSLATED'])) { + $env['PATH_TRANSLATED'] = $test_file; + } + if (empty($env['SCRIPT_FILENAME'])) { + $env['SCRIPT_FILENAME'] = $test_file; + } + + if (array_key_exists('COOKIE', $section_text)) { + $env['HTTP_COOKIE'] = trim($section_text['COOKIE']); + } else { + $env['HTTP_COOKIE'] = ''; + } + + $args = isset($section_text['ARGS']) ? ' -- ' . $section_text['ARGS'] : ''; + + if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) { + + $post = trim($section_text['POST_RAW']); + $raw_lines = explode("\n", $post); + + $request = ''; + $started = false; + + foreach ($raw_lines as $line) { + + if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) { + $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); + continue; + } + + if ($started) { + $request .= "\n"; + } + + $started = true; + $request .= $line; + } + + $env['CONTENT_LENGTH'] = strlen($request); + $env['REQUEST_METHOD'] = 'POST'; + + if (empty($request)) { + junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request'); + return 'BORKED'; + } + + save_text($tmp_post, $request); + $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\""; + + } elseif (array_key_exists('PUT', $section_text) && !empty($section_text['PUT'])) { + + $post = trim($section_text['PUT']); + $raw_lines = explode("\n", $post); + + $request = ''; + $started = false; + + foreach ($raw_lines as $line) { + + if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) { + $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); + continue; + } + + if ($started) { + $request .= "\n"; + } + + $started = true; + $request .= $line; + } + + $env['CONTENT_LENGTH'] = strlen($request); + $env['REQUEST_METHOD'] = 'PUT'; + + if (empty($request)) { + junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request'); + return 'BORKED'; + } + + save_text($tmp_post, $request); + $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\""; + + } else if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { + + $post = trim($section_text['POST']); + $content_length = strlen($post); + save_text($tmp_post, $post); + + $env['REQUEST_METHOD'] = 'POST'; + if (empty($env['CONTENT_TYPE'])) { + $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; + } + + if (empty($env['CONTENT_LENGTH'])) { + $env['CONTENT_LENGTH'] = $content_length; + } + + $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\""; + + } else if (array_key_exists('GZIP_POST', $section_text) && !empty($section_text['GZIP_POST'])) { + + $post = trim($section_text['GZIP_POST']); + $post = gzencode($post, 9, FORCE_GZIP); + $env['HTTP_CONTENT_ENCODING'] = 'gzip'; + + save_text($tmp_post, $post); + $content_length = strlen($post); + + $env['REQUEST_METHOD'] = 'POST'; + $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; + $env['CONTENT_LENGTH'] = $content_length; + + $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\""; + + } else if (array_key_exists('DEFLATE_POST', $section_text) && !empty($section_text['DEFLATE_POST'])) { + $post = trim($section_text['DEFLATE_POST']); + $post = gzcompress($post, 9); + $env['HTTP_CONTENT_ENCODING'] = 'deflate'; + save_text($tmp_post, $post); + $content_length = strlen($post); + + $env['REQUEST_METHOD'] = 'POST'; + $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; + $env['CONTENT_LENGTH'] = $content_length; + + $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\""; + + } else { + + $env['REQUEST_METHOD'] = 'GET'; + $env['CONTENT_TYPE'] = ''; + $env['CONTENT_LENGTH'] = ''; + + $cmd = "$php $pass_options $ini_settings -f \"$test_file\" $args 2>&1"; + } + + if ($leak_check) { + $env['USE_ZEND_ALLOC'] = '0'; + $env['ZEND_DONT_UNLOAD_MODULES'] = 1; + + /* --vex-iropt-register-updates=allregs-at-mem-access is necessary for phpdbg watchpoint tests */ + if (version_compare($valgrind_version, '3.8.0', '>=')) { + /* valgrind 3.3.0+ doesn't have --log-file-exactly option */ + $cmd = "valgrind -q --tool=memcheck --trace-children=yes --vex-iropt-register-updates=allregs-at-mem-access --log-file=$memcheck_filename $cmd"; + } elseif (version_compare($valgrind_version, '3.3.0', '>=')) { + $cmd = "valgrind -q --tool=memcheck --trace-children=yes --vex-iropt-precise-memory-exns=yes --log-file=$memcheck_filename $cmd"; + } else { + $cmd = "valgrind -q --tool=memcheck --trace-children=yes --vex-iropt-precise-memory-exns=yes --log-file-exactly=$memcheck_filename $cmd"; + } + + } else { + $env['USE_ZEND_ALLOC'] = '1'; + $env['ZEND_DONT_UNLOAD_MODULES'] = 0; + } + + if ($DETAILED) echo " +CONTENT_LENGTH = " . $env['CONTENT_LENGTH'] . " +CONTENT_TYPE = " . $env['CONTENT_TYPE'] . " +PATH_TRANSLATED = " . $env['PATH_TRANSLATED'] . " +QUERY_STRING = " . $env['QUERY_STRING'] . " +REDIRECT_STATUS = " . $env['REDIRECT_STATUS'] . " +REQUEST_METHOD = " . $env['REQUEST_METHOD'] . " +SCRIPT_FILENAME = " . $env['SCRIPT_FILENAME'] . " +HTTP_COOKIE = " . $env['HTTP_COOKIE'] . " +COMMAND $cmd +"; + + junit_start_timer($shortname); + + $out = system_with_timeout($cmd, $env, isset($section_text['STDIN']) ? $section_text['STDIN'] : null); + + junit_finish_timer($shortname); + + if (array_key_exists('CLEAN', $section_text) && (!$no_clean || $cfg['keep']['clean'])) { + + if (trim($section_text['CLEAN'])) { + show_file_block('clean', $section_text['CLEAN']); + save_text($test_clean, trim($section_text['CLEAN']), $temp_clean); + + if (!$no_clean) { + $clean_params = array(); + settings2array($ini_overwrites, $clean_params); + settings2params($clean_params); + $extra = substr(PHP_OS, 0, 3) !== "WIN" ? + "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": ""; + system_with_timeout("$extra $php $pass_options -q $clean_params $no_file_cache \"$test_clean\"", $env); + } + + if (!$cfg['keep']['clean']) { + @unlink($test_clean); + } + } + } + + @unlink($tmp_post); + + $leaked = false; + $passed = false; + + if ($leak_check) { // leak check + $leaked = filesize($memcheck_filename) > 0; + + if (!$leaked) { + @unlink($memcheck_filename); + } + } + + // Does the output match what is expected? + $output = preg_replace("/\r\n/", "\n", trim($out)); + + /* when using CGI, strip the headers from the output */ + $headers = ""; + + if (isset($old_php) && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) { + $output = trim($match[2]); + $rh = preg_split("/[\n\r]+/", $match[1]); + $headers = array(); + + foreach ($rh as $line) { + if (strpos($line, ':') !== false) { + $line = explode(':', $line, 2); + $headers[trim($line[0])] = trim($line[1]); + } + } + } + + $failed_headers = false; + + if (isset($section_text['EXPECTHEADERS'])) { + $want = array(); + $wanted_headers = array(); + $lines = preg_split("/[\n\r]+/", $section_text['EXPECTHEADERS']); + + foreach($lines as $line) { + if (strpos($line, ':') !== false) { + $line = explode(':', $line, 2); + $want[trim($line[0])] = trim($line[1]); + $wanted_headers[] = trim($line[0]) . ': ' . trim($line[1]); + } + } + + $org_headers = $headers; + $headers = array(); + $output_headers = array(); + + foreach($want as $k => $v) { + + if (isset($org_headers[$k])) { + $headers = $org_headers[$k]; + $output_headers[] = $k . ': ' . $org_headers[$k]; + } + + if (!isset($org_headers[$k]) || $org_headers[$k] != $v) { + $failed_headers = true; + } + } + + ksort($wanted_headers); + $wanted_headers = join("\n", $wanted_headers); + ksort($output_headers); + $output_headers = join("\n", $output_headers); + } + + show_file_block('out', $output); + + if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) { + + if (isset($section_text['EXPECTF'])) { + $wanted = trim($section_text['EXPECTF']); + } else { + $wanted = trim($section_text['EXPECTREGEX']); + } + + show_file_block('exp', $wanted); + $wanted_re = preg_replace('/\r\n/', "\n", $wanted); + + if (isset($section_text['EXPECTF'])) { + + // do preg_quote, but miss out any %r delimited sections + $temp = ""; + $r = "%r"; + $startOffset = 0; + $length = strlen($wanted_re); + while($startOffset < $length) { + $start = strpos($wanted_re, $r, $startOffset); + if ($start !== false) { + // we have found a start tag + $end = strpos($wanted_re, $r, $start+2); + if ($end === false) { + // unbalanced tag, ignore it. + $end = $start = $length; + } + } else { + // no more %r sections + $start = $end = $length; + } + // quote a non re portion of the string + $temp = $temp . preg_quote(substr($wanted_re, $startOffset, ($start - $startOffset)), '/'); + // add the re unquoted. + if ($end > $start) { + $temp = $temp . '(' . substr($wanted_re, $start+2, ($end - $start-2)). ')'; + } + $startOffset = $end + 2; + } + $wanted_re = $temp; + + $wanted_re = str_replace( + array('%binary_string_optional%'), + 'string', + $wanted_re + ); + $wanted_re = str_replace( + array('%unicode_string_optional%'), + 'string', + $wanted_re + ); + $wanted_re = str_replace( + array('%unicode\|string%', '%string\|unicode%'), + 'string', + $wanted_re + ); + $wanted_re = str_replace( + array('%u\|b%', '%b\|u%'), + '', + $wanted_re + ); + // Stick to basics + $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re); + $wanted_re = str_replace('%s', '[^\r\n]+', $wanted_re); + $wanted_re = str_replace('%S', '[^\r\n]*', $wanted_re); + $wanted_re = str_replace('%a', '.+', $wanted_re); + $wanted_re = str_replace('%A', '.*', $wanted_re); + $wanted_re = str_replace('%w', '\s*', $wanted_re); + $wanted_re = str_replace('%i', '[+-]?\d+', $wanted_re); + $wanted_re = str_replace('%d', '\d+', $wanted_re); + $wanted_re = str_replace('%x', '[0-9a-fA-F]+', $wanted_re); + $wanted_re = str_replace('%f', '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?', $wanted_re); + $wanted_re = str_replace('%c', '.', $wanted_re); + // %f allows two points "-.0.0" but that is the best *simple* expression + } +/* DEBUG YOUR REGEX HERE + var_dump($wanted_re); + print(str_repeat('=', 80) . "\n"); + var_dump($output); +*/ + if (preg_match("/^$wanted_re\$/s", $output)) { + $passed = true; + if (!$cfg['keep']['php']) { + @unlink($test_file); + } + if (isset($old_php)) { + $php = $old_php; + } + + if (!$leaked && !$failed_headers) { + if (isset($section_text['XFAIL'] )) { + $warn = true; + $info = " (warn: XFAIL section but test passes)"; + }else { + show_result("PASS", $tested, $tested_file, '', $temp_filenames); + junit_mark_test_as('PASS', $shortname, $tested); + return 'PASSED'; + } + } + } + + } else { + + $wanted = trim($section_text['EXPECT']); + $wanted = preg_replace('/\r\n/',"\n", $wanted); + show_file_block('exp', $wanted); + + // compare and leave on success + if (!strcmp($output, $wanted)) { + $passed = true; + + if (!$cfg['keep']['php']) { + @unlink($test_file); + } + + if (isset($old_php)) { + $php = $old_php; + } + + if (!$leaked && !$failed_headers) { + if (isset($section_text['XFAIL'] )) { + $warn = true; + $info = " (warn: XFAIL section but test passes)"; + }else { + show_result("PASS", $tested, $tested_file, '', $temp_filenames); + junit_mark_test_as('PASS', $shortname, $tested); + return 'PASSED'; + } + } + } + + $wanted_re = null; + } + + // Test failed so we need to report details. + if ($failed_headers) { + $passed = false; + $wanted = $wanted_headers . "\n--HEADERS--\n" . $wanted; + $output = $output_headers . "\n--HEADERS--\n" . $output; + + if (isset($wanted_re)) { + $wanted_re = preg_quote($wanted_headers . "\n--HEADERS--\n", '/') . $wanted_re; + } + } + + if ($leaked) { + $restype[] = 'LEAK'; + } + + if ($warn) { + $restype[] = 'WARN'; + } + + if (!$passed) { + if (isset($section_text['XFAIL'])) { + $restype[] = 'XFAIL'; + $info = ' XFAIL REASON: ' . rtrim($section_text['XFAIL']); + } else { + $restype[] = 'FAIL'; + } + } + + if (!$passed) { + + // write .exp + if (strpos($log_format, 'E') !== false && file_put_contents($exp_filename, $wanted, FILE_BINARY) === false) { + error("Cannot create expected test output - $exp_filename"); + } + + // write .out + if (strpos($log_format, 'O') !== false && file_put_contents($output_filename, $output, FILE_BINARY) === false) { + error("Cannot create test output - $output_filename"); + } + + // write .diff + $diff = generate_diff($wanted, $wanted_re, $output); + if (is_array($IN_REDIRECT)) { + $diff = "# original source file: $shortname\n" . $diff; + } + show_file_block('diff', $diff); + if (strpos($log_format, 'D') !== false && file_put_contents($diff_filename, $diff, FILE_BINARY) === false) { + error("Cannot create test diff - $diff_filename"); + } + + // write .sh + if (strpos($log_format, 'S') !== false && file_put_contents($sh_filename, "#!/bin/sh + +{$cmd} +", FILE_BINARY) === false) { + error("Cannot create test shell script - $sh_filename"); + } + chmod($sh_filename, 0755); + + // write .log + if (strpos($log_format, 'L') !== false && file_put_contents($log_filename, " +---- EXPECTED OUTPUT +$wanted +---- ACTUAL OUTPUT +$output +---- FAILED +", FILE_BINARY) === false) { + error("Cannot create test log - $log_filename"); + error_report($file, $log_filename, $tested); + } + } + + show_result(implode('&', $restype), $tested, $tested_file, $info, $temp_filenames); + + foreach ($restype as $type) { + $PHP_FAILED_TESTS[$type.'ED'][] = array ( + 'name' => $file, + 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]", + 'output' => $output_filename, + 'diff' => $diff_filename, + 'info' => $info, + ); + } + + if (isset($old_php)) { + $php = $old_php; + } + + $diff = empty($diff) ? '' : preg_replace('/\e/', '', $diff); + + junit_mark_test_as($restype, str_replace($cwd . '/', '', $tested_file), $tested, null, $info, $diff); + + return $restype[0] . 'ED'; +} + +function comp_line($l1, $l2, $is_reg) +{ + if ($is_reg) { + return preg_match('/^'. $l1 . '$/s', $l2); + } else { + return !strcmp($l1, $l2); + } +} + +function count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2, $cnt1, $cnt2, $steps) +{ + $equal = 0; + + while ($idx1 < $cnt1 && $idx2 < $cnt2 && comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) { + $idx1++; + $idx2++; + $equal++; + $steps--; + } + if (--$steps > 0) { + $eq1 = 0; + $st = $steps / 2; + + for ($ofs1 = $idx1 + 1; $ofs1 < $cnt1 && $st-- > 0; $ofs1++) { + $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $ofs1, $idx2, $cnt1, $cnt2, $st); + + if ($eq > $eq1) { + $eq1 = $eq; + } + } + + $eq2 = 0; + $st = $steps; + + for ($ofs2 = $idx2 + 1; $ofs2 < $cnt2 && $st-- > 0; $ofs2++) { + $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $ofs2, $cnt1, $cnt2, $st); + if ($eq > $eq2) { + $eq2 = $eq; + } + } + + if ($eq1 > $eq2) { + $equal += $eq1; + } else if ($eq2 > 0) { + $equal += $eq2; + } + } + + return $equal; +} + +function generate_array_diff($ar1, $ar2, $is_reg, $w) +{ + $idx1 = 0; $ofs1 = 0; $cnt1 = @count($ar1); + $idx2 = 0; $ofs2 = 0; $cnt2 = @count($ar2); + $diff = array(); + $old1 = array(); + $old2 = array(); + + while ($idx1 < $cnt1 && $idx2 < $cnt2) { + + if (comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) { + $idx1++; + $idx2++; + continue; + } else { + + $c1 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1+1, $idx2, $cnt1, $cnt2, 10); + $c2 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2+1, $cnt1, $cnt2, 10); + + if ($c1 > $c2) { + $old1[$idx1] = sprintf("%03d- ", $idx1+1) . $w[$idx1++]; + $last = 1; + } else if ($c2 > 0) { + $old2[$idx2] = sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++]; + $last = 2; + } else { + $old1[$idx1] = sprintf("%03d- ", $idx1+1) . $w[$idx1++]; + $old2[$idx2] = sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++]; + } + } + } + + reset($old1); $k1 = key($old1); $l1 = -2; + reset($old2); $k2 = key($old2); $l2 = -2; + + while ($k1 !== null || $k2 !== null) { + + if ($k1 == $l1 + 1 || $k2 === null) { + $l1 = $k1; + $diff[] = current($old1); + $k1 = next($old1) ? key($old1) : null; + } else if ($k2 == $l2 + 1 || $k1 === null) { + $l2 = $k2; + $diff[] = current($old2); + $k2 = next($old2) ? key($old2) : null; + } else if ($k1 < $k2) { + $l1 = $k1; + $diff[] = current($old1); + $k1 = next($old1) ? key($old1) : null; + } else { + $l2 = $k2; + $diff[] = current($old2); + $k2 = next($old2) ? key($old2) : null; + } + } + + while ($idx1 < $cnt1) { + $diff[] = sprintf("%03d- ", $idx1 + 1) . $w[$idx1++]; + } + + while ($idx2 < $cnt2) { + $diff[] = sprintf("%03d+ ", $idx2 + 1) . $ar2[$idx2++]; + } + + return $diff; +} + +function generate_diff($wanted, $wanted_re, $output) +{ + $w = explode("\n", $wanted); + $o = explode("\n", $output); + $r = is_null($wanted_re) ? $w : explode("\n", $wanted_re); + $diff = generate_array_diff($r, $o, !is_null($wanted_re), $w); + + return implode("\r\n", $diff); +} + +function error($message) +{ + echo "ERROR: {$message}\n"; + exit(1); +} + +function settings2array($settings, &$ini_settings) +{ + foreach($settings as $setting) { + + if (strpos($setting, '=') !== false) { + $setting = explode("=", $setting, 2); + $name = trim($setting[0]); + $value = trim($setting[1]); + + if ($name == 'extension' || $name == 'zend_extension') { + + if (!isset($ini_settings[$name])) { + $ini_settings[$name] = array(); + } + + $ini_settings[$name][] = $value; + + } else { + $ini_settings[$name] = $value; + } + } + } +} + +function settings2params(&$ini_settings) +{ + $settings = ''; + + foreach($ini_settings as $name => $value) { + + if (is_array($value)) { + foreach($value as $val) { + $val = addslashes($val); + $settings .= " -d \"$name=$val\""; + } + } else { + if (substr(PHP_OS, 0, 3) == "WIN" && !empty($value) && $value{0} == '"') { + $len = strlen($value); + + if ($value{$len - 1} == '"') { + $value{0} = "'"; + $value{$len - 1} = "'"; + } + } else { + $value = addslashes($value); + } + + $settings .= " -d \"$name=$value\""; + } + } + + $ini_settings = $settings; +} + +function compute_summary() +{ + global $n_total, $test_results, $ignored_by_ext, $sum_results, $percent_results; + + $n_total = count($test_results); + $n_total += $ignored_by_ext; + $sum_results = array( + 'PASSED' => 0, + 'WARNED' => 0, + 'SKIPPED' => 0, + 'FAILED' => 0, + 'BORKED' => 0, + 'LEAKED' => 0, + 'XFAILED' => 0 + ); + + foreach ($test_results as $v) { + $sum_results[$v]++; + } + + $sum_results['SKIPPED'] += $ignored_by_ext; + $percent_results = array(); + + while (list($v, $n) = each($sum_results)) { + $percent_results[$v] = (100.0 * $n) / $n_total; + } +} + +function get_summary($show_ext_summary, $show_html) +{ + global $exts_skipped, $exts_tested, $n_total, $sum_results, $percent_results, $end_time, $start_time, $failed_test_summary, $PHP_FAILED_TESTS, $leak_check; + + $x_total = $n_total - $sum_results['SKIPPED'] - $sum_results['BORKED']; + + if ($x_total) { + $x_warned = (100.0 * $sum_results['WARNED']) / $x_total; + $x_failed = (100.0 * $sum_results['FAILED']) / $x_total; + $x_xfailed = (100.0 * $sum_results['XFAILED']) / $x_total; + $x_leaked = (100.0 * $sum_results['LEAKED']) / $x_total; + $x_passed = (100.0 * $sum_results['PASSED']) / $x_total; + } else { + $x_warned = $x_failed = $x_passed = $x_leaked = $x_xfailed = 0; + } + + $summary = ''; + + if ($show_html) { + $summary .= "
\n";
+	}
+
+	if ($show_ext_summary) {
+		$summary .= '
+=====================================================================
+TEST RESULT SUMMARY
+---------------------------------------------------------------------
+Exts skipped    : ' . sprintf('%4d', $exts_skipped) . '
+Exts tested     : ' . sprintf('%4d', $exts_tested) . '
+---------------------------------------------------------------------
+';
+	}
+
+	$summary .= '
+Number of tests : ' . sprintf('%4d', $n_total) . '          ' . sprintf('%8d', $x_total);
+
+	if ($sum_results['BORKED']) {
+		$summary .= '
+Tests borked    : ' . sprintf('%4d (%5.1f%%)', $sum_results['BORKED'], $percent_results['BORKED']) . ' --------';
+	}
+
+	$summary .= '
+Tests skipped   : ' . sprintf('%4d (%5.1f%%)', $sum_results['SKIPPED'], $percent_results['SKIPPED']) . ' --------
+Tests warned    : ' . sprintf('%4d (%5.1f%%)', $sum_results['WARNED'], $percent_results['WARNED']) . ' ' . sprintf('(%5.1f%%)', $x_warned) . '
+Tests failed    : ' . sprintf('%4d (%5.1f%%)', $sum_results['FAILED'], $percent_results['FAILED']) . ' ' . sprintf('(%5.1f%%)', $x_failed) . '
+Expected fail   : ' . sprintf('%4d (%5.1f%%)', $sum_results['XFAILED'], $percent_results['XFAILED']) . ' ' . sprintf('(%5.1f%%)', $x_xfailed);
+
+	if ($leak_check) {
+		$summary .= '
+Tests leaked    : ' . sprintf('%4d (%5.1f%%)', $sum_results['LEAKED'], $percent_results['LEAKED']) . ' ' . sprintf('(%5.1f%%)', $x_leaked);
+	}
+
+	$summary .= '
+Tests passed    : ' . sprintf('%4d (%5.1f%%)', $sum_results['PASSED'], $percent_results['PASSED']) . ' ' . sprintf('(%5.1f%%)', $x_passed) . '
+---------------------------------------------------------------------
+Time taken      : ' . sprintf('%4d seconds', $end_time - $start_time) . '
+=====================================================================
+';
+	$failed_test_summary = '';
+
+	if (count($PHP_FAILED_TESTS['XFAILED'])) {
+		$failed_test_summary .= '
+=====================================================================
+EXPECTED FAILED TEST SUMMARY
+---------------------------------------------------------------------
+';
+		foreach ($PHP_FAILED_TESTS['XFAILED'] as $failed_test_data) {
+			$failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
+		}
+		$failed_test_summary .=  "=====================================================================\n";
+	}
+
+	if (count($PHP_FAILED_TESTS['BORKED'])) {
+		$failed_test_summary .= '
+=====================================================================
+BORKED TEST SUMMARY
+---------------------------------------------------------------------
+';
+		foreach ($PHP_FAILED_TESTS['BORKED'] as $failed_test_data) {
+			$failed_test_summary .= $failed_test_data['info'] . "\n";
+		}
+
+		$failed_test_summary .=  "=====================================================================\n";
+	}
+
+	if (count($PHP_FAILED_TESTS['FAILED'])) {
+		$failed_test_summary .= '
+=====================================================================
+FAILED TEST SUMMARY
+---------------------------------------------------------------------
+';
+		foreach ($PHP_FAILED_TESTS['FAILED'] as $failed_test_data) {
+			$failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
+		}
+		$failed_test_summary .=  "=====================================================================\n";
+	}
+	if (count($PHP_FAILED_TESTS['WARNED'])) {
+		$failed_test_summary .= '
+=====================================================================
+WARNED TEST SUMMARY
+---------------------------------------------------------------------
+';
+		foreach ($PHP_FAILED_TESTS['WARNED'] as $failed_test_data) {
+			$failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
+		}
+
+		$failed_test_summary .=  "=====================================================================\n";
+	}
+
+	if (count($PHP_FAILED_TESTS['LEAKED'])) {
+		$failed_test_summary .= '
+=====================================================================
+LEAKED TEST SUMMARY
+---------------------------------------------------------------------
+';
+		foreach ($PHP_FAILED_TESTS['LEAKED'] as $failed_test_data) {
+			$failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
+		}
+
+		$failed_test_summary .=  "=====================================================================\n";
+	}
+
+	if ($failed_test_summary && !getenv('NO_PHPTEST_SUMMARY')) {
+		$summary .= $failed_test_summary;
+	}
+
+	if ($show_html) {
+		$summary .= "
"; + } + + return $summary; +} + +function show_start($start_time) +{ + global $html_output, $html_file; + + if ($html_output) { + fwrite($html_file, "

Time Start: " . date('Y-m-d H:i:s', $start_time) . "

\n"); + fwrite($html_file, "\n"); + } + + echo "TIME START " . date('Y-m-d H:i:s', $start_time) . "\n=====================================================================\n"; +} + +function show_end($end_time) +{ + global $html_output, $html_file; + + if ($html_output) { + fwrite($html_file, "
\n"); + fwrite($html_file, "

Time End: " . date('Y-m-d H:i:s', $end_time) . "

\n"); + } + + echo "=====================================================================\nTIME END " . date('Y-m-d H:i:s', $end_time) . "\n"; +} + +function show_summary() +{ + global $html_output, $html_file; + + if ($html_output) { + fwrite($html_file, "
\n" . get_summary(true, true)); + } + + echo get_summary(true, false); +} + +function show_redirect_start($tests, $tested, $tested_file) +{ + global $html_output, $html_file, $line_length, $SHOW_ONLY_GROUPS; + + if ($html_output) { + fwrite($html_file, "---> $tests ($tested [$tested_file]) begin\n"); + } + + if (!$SHOW_ONLY_GROUPS || in_array('REDIRECT', $SHOW_ONLY_GROUPS)) { + echo "REDIRECT $tests ($tested [$tested_file]) begin\n"; + } else { + // Write over the last line to avoid random trailing chars on next echo + echo str_repeat(" ", $line_length), "\r"; + } +} + +function show_redirect_ends($tests, $tested, $tested_file) +{ + global $html_output, $html_file, $line_length, $SHOW_ONLY_GROUPS; + + if ($html_output) { + fwrite($html_file, "---> $tests ($tested [$tested_file]) done\n"); + } + + if (!$SHOW_ONLY_GROUPS || in_array('REDIRECT', $SHOW_ONLY_GROUPS)) { + echo "REDIRECT $tests ($tested [$tested_file]) done\n"; + } else { + // Write over the last line to avoid random trailing chars on next echo + echo str_repeat(" ", $line_length), "\r"; + } +} + +function show_test($test_idx, $shortname) +{ + global $test_cnt; + global $line_length; + + $str = "TEST $test_idx/$test_cnt [$shortname]\r"; + $line_length = strlen($str); + echo $str; + flush(); +} + +function show_result($result, $tested, $tested_file, $extra = '', $temp_filenames = null) +{ + global $html_output, $html_file, $temp_target, $temp_urlbase, $line_length, $SHOW_ONLY_GROUPS; + + if (!$SHOW_ONLY_GROUPS || in_array($result, $SHOW_ONLY_GROUPS)) { + echo "$result $tested [$tested_file] $extra\n"; + } else if (!$SHOW_ONLY_GROUPS) { + // Write over the last line to avoid random trailing chars on next echo + echo str_repeat(" ", $line_length), "\r"; + } + + if ($html_output) { + + if (isset($temp_filenames['file']) && file_exists($temp_filenames['file'])) { + $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['file']); + $tested = "$tested"; + } + + if (isset($temp_filenames['skip']) && file_exists($temp_filenames['skip'])) { + + if (empty($extra)) { + $extra = "skipif"; + } + + $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['skip']); + $extra = "$extra"; + + } else if (empty($extra)) { + $extra = " "; + } + + if (isset($temp_filenames['diff']) && file_exists($temp_filenames['diff'])) { + $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['diff']); + $diff = "diff"; + } else { + $diff = " "; + } + + if (isset($temp_filenames['mem']) && file_exists($temp_filenames['mem'])) { + $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['mem']); + $mem = "leaks"; + } else { + $mem = " "; + } + + fwrite($html_file, + "" . + "$result" . + "$tested" . + "$extra" . + "$diff" . + "$mem" . + "\n"); + } +} + +function junit_init() { + // Check whether a junit log is wanted. + $JUNIT = getenv('TEST_PHP_JUNIT'); + if (empty($JUNIT)) { + $JUNIT = FALSE; + } elseif (!$fp = fopen($JUNIT, 'w')) { + error("Failed to open $JUNIT for writing."); + } else { + $JUNIT = array( + 'fp' => $fp, + 'name' => 'php-src', + 'test_total' => 0, + 'test_pass' => 0, + 'test_fail' => 0, + 'test_error' => 0, + 'test_skip' => 0, + 'test_warn' => 0, + 'execution_time'=> 0, + 'suites' => array(), + 'files' => array() + ); + } + + $GLOBALS['JUNIT'] = $JUNIT; +} + +function junit_save_xml() { + global $JUNIT; + if (!junit_enabled()) return; + + $xml = ''. PHP_EOL . + '' . PHP_EOL; + $xml .= junit_get_suite_xml(); + $xml .= ''; + fwrite($JUNIT['fp'], $xml); +} + +function junit_get_suite_xml($suite_name = '') { + global $JUNIT; + + $suite = $suite_name ? $JUNIT['suites'][$suite_name] : $JUNIT; + + $result = sprintf( + '' . PHP_EOL, + $suite['name'], $suite['test_total'], $suite['test_fail'], $suite['test_error'], $suite['test_skip'], + $suite['execution_time'] + ); + + foreach($suite['suites'] as $sub_suite) { + $result .= junit_get_suite_xml($sub_suite['name']); + } + + // Output files only in subsuites + if (!empty($suite_name)) { + foreach($suite['files'] as $file) { + $result .= $JUNIT['files'][$file]['xml']; + } + } + + $result .= '' . PHP_EOL; + + return $result; +} + +function junit_enabled() { + global $JUNIT; + return !empty($JUNIT); +} + +/** + * @param array|string $type + * @param string $file_name + * @param string $test_name + * @param int|string $time + * @param string $message + * @param string $details + * @return void + */ +function junit_mark_test_as($type, $file_name, $test_name, $time = null, $message = '', $details = '') { + global $JUNIT; + if (!junit_enabled()) return; + + $suite = junit_get_suitename_for($file_name); + + junit_suite_record($suite, 'test_total'); + + $time = null !== $time ? $time : junit_get_timer($file_name); + junit_suite_record($suite, 'execution_time', $time); + + $escaped_details = htmlspecialchars($details, ENT_QUOTES, 'UTF-8'); + $escaped_details = preg_replace_callback('/[\0-\x08\x0B\x0C\x0E-\x1F]/', function ($c) { + return sprintf('[[0x%02x]]', ord($c[0])); + }, $escaped_details); + $escaped_message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); + + $escaped_test_name = basename($file_name) . ' - ' . htmlspecialchars($test_name, ENT_QUOTES); + $JUNIT['files'][$file_name]['xml'] = "\n"; + + if (is_array($type)) { + $output_type = $type[0] . 'ED'; + $temp = array_intersect(array('XFAIL', 'FAIL', 'WARN'), $type); + $type = reset($temp); + } else { + $output_type = $type . 'ED'; + } + + if ('PASS' == $type || 'XFAIL' == $type) { + junit_suite_record($suite, 'test_pass'); + } elseif ('BORK' == $type) { + junit_suite_record($suite, 'test_error'); + $JUNIT['files'][$file_name]['xml'] .= "\n"; + } elseif ('SKIP' == $type) { + junit_suite_record($suite, 'test_skip'); + $JUNIT['files'][$file_name]['xml'] .= "$escaped_message\n"; + } elseif ('WARN' == $type) { + junit_suite_record($suite, 'test_warn'); + $JUNIT['files'][$file_name]['xml'] .= "$escaped_message\n"; + } elseif('FAIL' == $type) { + junit_suite_record($suite, 'test_fail'); + $JUNIT['files'][$file_name]['xml'] .= "$escaped_details\n"; + } else { + junit_suite_record($suite, 'test_error'); + $JUNIT['files'][$file_name]['xml'] .= "$escaped_details\n"; + } + + $JUNIT['files'][$file_name]['xml'] .= "\n"; + +} + +function junit_suite_record($suite, $param, $value = 1) { + global $JUNIT; + + $JUNIT[$param] += $value; + $JUNIT['suites'][$suite][$param] += $value; +} + +function junit_get_timer($file_name) { + global $JUNIT; + if (!junit_enabled()) return 0; + + if (isset($JUNIT['files'][$file_name]['total'])) { + return number_format($JUNIT['files'][$file_name]['total'], 4); + } + + return 0; +} + +function junit_start_timer($file_name) { + global $JUNIT; + if (!junit_enabled()) return; + + if (!isset($JUNIT['files'][$file_name]['start'])) { + $JUNIT['files'][$file_name]['start'] = microtime(true); + + $suite = junit_get_suitename_for($file_name); + junit_init_suite($suite); + $JUNIT['suites'][$suite]['files'][$file_name] = $file_name; + } +} + +function junit_get_suitename_for($file_name) { + return junit_path_to_classname(dirname($file_name)); +} + +function junit_path_to_classname($file_name) { + global $JUNIT; + return $JUNIT['name'] . '.' . str_replace(DIRECTORY_SEPARATOR, '.', $file_name); +} + +function junit_init_suite($suite_name) { + global $JUNIT; + if (!junit_enabled()) return; + + if (!empty($JUNIT['suites'][$suite_name])) { + return; + } + + $JUNIT['suites'][$suite_name] = array( + 'name' => $suite_name, + 'test_total' => 0, + 'test_pass' => 0, + 'test_fail' => 0, + 'test_error' => 0, + 'test_skip' => 0, + 'suites' => array(), + 'files' => array(), + 'execution_time'=> 0, + ); +} + +function junit_finish_timer($file_name) { + global $JUNIT; + if (!junit_enabled()) return; + + if (!isset($JUNIT['files'][$file_name]['start'])) { + error("Timer for $file_name was not started!"); + } + + if (!isset($JUNIT['files'][$file_name]['total'])) { + $JUNIT['files'][$file_name]['total'] = 0; + } + + $start = $JUNIT['files'][$file_name]['start']; + $JUNIT['files'][$file_name]['total'] += microtime(true) - $start; + unset($JUNIT['files'][$file_name]['start']); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim: noet sw=4 ts=4 + */ +?> diff --git a/lib/php/test/Makefile.am b/lib/php/test/Makefile.am new file mode 100755 index 0000000..c872b1a --- /dev/null +++ b/lib/php/test/Makefile.am @@ -0,0 +1,59 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +stubs: ../../../test/ThriftTest.thrift TestValidators.thrift + mkdir -p ./packages + $(THRIFT) --gen php -r --out ./packages ../../../test/ThriftTest.thrift + mkdir -p ./packages/phpv + mkdir -p ./packages/phpvo + mkdir -p ./packages/phpjs + $(THRIFT) --gen php:validate -r --out ./packages/phpv TestValidators.thrift + $(THRIFT) --gen php:validate,oop -r --out ./packages/phpvo TestValidators.thrift + $(THRIFT) --gen php:json -r --out ./packages/phpjs TestValidators.thrift + +check-json-serializer: stubs +if HAVE_PHPUNIT + $(PHPUNIT) --log-junit=TEST-json-serializer.xml Test/Thrift/JsonSerialize/ +endif + +check-validator: stubs + php Test/Thrift/TestValidators.php + php Test/Thrift/TestValidators.php -oop + +check-protocol: stubs +if HAVE_PHPUNIT + $(PHPUNIT) --log-junit=TEST-log-json-protocol.xml Test/Thrift/Protocol/TestTJSONProtocol.php + $(PHPUNIT) --log-junit=TEST-binary-serializer.xml Test/Thrift/Protocol/TestBinarySerializer.php + $(PHPUNIT) --log-junit=TEST-log-simple-json-protocol.xml Test/Thrift/Protocol/TestTSimpleJSONProtocol.php +endif + +check: stubs \ + check-protocol \ + check-validator \ + check-json-serializer + +clean-local: + $(RM) -r ./packages + $(RM) TEST-*.xml + +EXTRA_DIST = \ + Test \ + TestValidators.thrift + + diff --git a/lib/php/test/Makefile.in b/lib/php/test/Makefile.in new file mode 100644 index 0000000..f3cca0e --- /dev/null +++ b/lib/php/test/Makefile.in @@ -0,0 +1,657 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/php/test +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + Test \ + TestValidators.thrift + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/php/test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/php/test/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +stubs: ../../../test/ThriftTest.thrift TestValidators.thrift + mkdir -p ./packages + $(THRIFT) --gen php -r --out ./packages ../../../test/ThriftTest.thrift + mkdir -p ./packages/phpv + mkdir -p ./packages/phpvo + mkdir -p ./packages/phpjs + $(THRIFT) --gen php:validate -r --out ./packages/phpv TestValidators.thrift + $(THRIFT) --gen php:validate,oop -r --out ./packages/phpvo TestValidators.thrift + $(THRIFT) --gen php:json -r --out ./packages/phpjs TestValidators.thrift + +check-json-serializer: stubs +@HAVE_PHPUNIT_TRUE@ $(PHPUNIT) --log-junit=TEST-json-serializer.xml Test/Thrift/JsonSerialize/ + +check-validator: stubs + php Test/Thrift/TestValidators.php + php Test/Thrift/TestValidators.php -oop + +check-protocol: stubs +@HAVE_PHPUNIT_TRUE@ $(PHPUNIT) --log-junit=TEST-log-json-protocol.xml Test/Thrift/Protocol/TestTJSONProtocol.php +@HAVE_PHPUNIT_TRUE@ $(PHPUNIT) --log-junit=TEST-binary-serializer.xml Test/Thrift/Protocol/TestBinarySerializer.php +@HAVE_PHPUNIT_TRUE@ $(PHPUNIT) --log-junit=TEST-log-simple-json-protocol.xml Test/Thrift/Protocol/TestTSimpleJSONProtocol.php + +check: stubs \ + check-protocol \ + check-validator \ + check-json-serializer + +clean-local: + $(RM) -r ./packages + $(RM) TEST-*.xml + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/php/test/Test/Thrift/Fixtures.php b/lib/php/test/Test/Thrift/Fixtures.php new file mode 100644 index 0000000..2c60a08 --- /dev/null +++ b/lib/php/test/Test/Thrift/Fixtures.php @@ -0,0 +1,194 @@ +<><"; + + self::$testArgs['testString3'] = + "string that ends in double-backslash \\\\"; + + self::$testArgs['testUnicodeStringWithNonBMP'] = + "สวัสดี/𝒯"; + + self::$testArgs['testDouble'] = 3.1415926535898; + + // TODO: add testBinary() call + + self::$testArgs['testByte'] = 0x01; + + self::$testArgs['testI32'] = pow( 2, 30 ); + + if (PHP_INT_SIZE == 8) { + self::$testArgs['testI64'] = pow( 2, 60 ); + } else { + self::$testArgs['testI64'] = "1152921504606847000"; + } + + self::$testArgs['testStruct'] = + new Xtruct( + array( + 'string_thing' => 'worked', + 'byte_thing' => 0x01, + 'i32_thing' => pow( 2, 30 ), + 'i64_thing' => self::$testArgs['testI64'] + ) + ); + + self::$testArgs['testNestNested'] = + new Xtruct( + array( + 'string_thing' => 'worked', + 'byte_thing' => 0x01, + 'i32_thing' => pow( 2, 30 ), + 'i64_thing' => self::$testArgs['testI64'] + ) + ); + + self::$testArgs['testNest'] = + new Xtruct2( + array( + 'byte_thing' => 0x01, + 'struct_thing' => self::$testArgs['testNestNested'], + 'i32_thing' => pow( 2, 15 ) + ) + ); + + self::$testArgs['testMap'] = + array( + 7 => 77, + 8 => 88, + 9 => 99 + ); + + self::$testArgs['testStringMap'] = + array( + "a" => "123", + "a b" => "with spaces ", + "same" => "same", + "0" => "numeric key", + "longValue" => self::$testArgs['testString1'], + self::$testArgs['testString1'] => "long key" + ); + + self::$testArgs['testSet'] = array( 1 => true, 5 => true, 6 => true ); + + self::$testArgs['testList'] = array( 1, 2, 3 ); + + self::$testArgs['testEnum'] = Numberz::ONE; + + self::$testArgs['testTypedef'] = 69; + + self::$testArgs['testMapMapExpectedResult'] = + array( + 4 => array( + 1 => 1, + 2 => 2, + 3 => 3, + 4 => 4, + ), + -4 => array( + -4 => -4, + -3 => -3, + -2 => -2, + -1 => -1 + ) + ); + + // testInsanity ... takes a few steps to set up! + + $xtruct1 = + new Xtruct( + array( + 'string_thing' => 'Goodbye4', + 'byte_thing' => 4, + 'i32_thing' => 4, + 'i64_thing' => 4 + ) + ); + + $xtruct2 = + new Xtruct( + array( + 'string_thing' => 'Hello2', + 'byte_thing' =>2, + 'i32_thing' => 2, + 'i64_thing' => 2 + ) + ); + + $userMap = + array( + Numberz::FIVE => 5, + Numberz::EIGHT => 8 + ); + + $insanity2 = + new Insanity( + array( + 'userMap' => $userMap, + 'xtructs' => array($xtruct1,$xtruct2) + ) + ); + + $insanity3 = $insanity2; + + $insanity6 = + new Insanity( + array( + 'userMap' => null, + 'xtructs' => null + ) + ); + + self::$testArgs['testInsanityExpectedResult'] = + array( + "1" => array( + Numberz::TWO => $insanity2, + Numberz::THREE => $insanity3 + ), + "2" => array( + Numberz::SIX => $insanity6 + ) + ); + + } +} diff --git a/lib/php/test/Test/Thrift/JsonSerialize/JsonSerializeTest.php b/lib/php/test/Test/Thrift/JsonSerialize/JsonSerializeTest.php new file mode 100644 index 0000000..2471b52 --- /dev/null +++ b/lib/php/test/Test/Thrift/JsonSerialize/JsonSerializeTest.php @@ -0,0 +1,116 @@ +registerNamespace('Thrift', __DIR__ . '/../../../../lib'); +$loader->registerNamespace('Test', __DIR__ . '/../../..'); +$loader->registerDefinition('ThriftTest', __DIR__ . '/../../../packages/phpjs'); +$loader->register(); + +class JsonSerializeTest extends \PHPUnit_Framework_TestCase +{ + protected function setUp() { + if (version_compare(phpversion(), '5.4', '<')) { + $this->markTestSkipped('Requires PHP 5.4 or newer!'); + } + } + + public function testEmptyStruct() + { + $empty = new \ThriftTest\EmptyStruct(array('non_existing_key' => 'bar')); + $this->assertEquals(new stdClass(), json_decode(json_encode($empty))); + } + + public function testStringsAndInts() + { + $input = array( + 'string_thing' => 'foo', + 'i64_thing' => 1234567890, + ); + $xtruct = new \ThriftTest\Xtruct($input); + + // Xtruct's 'i32_thing' and 'byte_thing' fields should not be present here! + $expected = new stdClass(); + $expected->string_thing = $input['string_thing']; + $expected->i64_thing = $input['i64_thing']; + $this->assertEquals($expected, json_decode(json_encode($xtruct))); + } + + public function testNestedStructs() + { + $xtruct2 = new \ThriftTest\Xtruct2(array( + 'byte_thing' => 42, + 'struct_thing' => new \ThriftTest\Xtruct(array( + 'i32_thing' => 123456, + )), + )); + + $expected = new stdClass(); + $expected->byte_thing = $xtruct2->byte_thing; + $expected->struct_thing = new stdClass(); + $expected->struct_thing->i32_thing = $xtruct2->struct_thing->i32_thing; + $this->assertEquals($expected, json_decode(json_encode($xtruct2))); + } + + public function testInsanity() + { + $xinput = array('string_thing' => 'foo'); + $xtruct = new \ThriftTest\Xtruct($xinput); + $insanity = new \ThriftTest\Insanity(array( + 'xtructs' => array($xtruct, $xtruct, $xtruct) + )); + $expected = new stdClass(); + $expected->xtructs = array((object) $xinput, (object) $xinput, (object) $xinput); + $this->assertEquals($expected, json_decode(json_encode($insanity))); + } + + public function testNestedLists() + { + $bonk = new \ThriftTest\Bonk(array('message' => 'foo')); + $nested = new \ThriftTest\NestedListsBonk(array('bonk' => array(array(array($bonk))))); + $expected = new stdClass(); + $expected->bonk = array(array(array((object) array('message' => 'foo')))); + $this->assertEquals($expected, json_decode(json_encode($nested))); + } + + public function testMaps() + { + $intmap = new \ThriftTest\ThriftTest_testMap_args(['thing' => [0 => 'zero']]); + $emptymap = new \ThriftTest\ThriftTest_testMap_args([]); + $this->assertEquals('{"thing":{"0":"zero"}}', json_encode($intmap)); + $this->assertEquals('{}', json_encode($emptymap)); + } + + public function testScalarTypes() + { + $b = new \ThriftTest\Bools(['im_true' => '1', 'im_false' => '0']); + $this->assertEquals('{"im_true":true,"im_false":false}', json_encode($b)); + $s = new \ThriftTest\StructA(['s' => 42]); + $this->assertEquals('{"s":"42"}', json_encode($s)); + } + +} diff --git a/lib/php/test/Test/Thrift/Protocol/TestBinarySerializer.php b/lib/php/test/Test/Thrift/Protocol/TestBinarySerializer.php new file mode 100644 index 0000000..a983216 --- /dev/null +++ b/lib/php/test/Test/Thrift/Protocol/TestBinarySerializer.php @@ -0,0 +1,64 @@ +registerNamespace('Thrift', __DIR__ . '/../../../../lib'); +$loader->registerNamespace('Test', __DIR__ . '/../../..'); +$loader->registerDefinition('ThriftTest', __DIR__ . '/../../../packages'); +$loader->register(); + +/*** + * This test suite depends on running the compiler against the + * standard ThriftTest.thrift file: + * + * lib/php/test$ ../../../compiler/cpp/thrift --gen php -r \ + * --out ./packages ../../../test/ThriftTest.thrift + */ + +class TestBinarySerializer extends \PHPUnit_Framework_TestCase +{ + + public function setUp() + { + } + + /** + * We try to serialize and deserialize a random object to make sure no exceptions are thrown. + * @see THRIFT-1579 + */ + public function testBinarySerializer() + { + $struct = new \ThriftTest\Xtruct(array('string_thing' => 'abc')); + $serialized = TBinarySerializer::serialize($struct, 'ThriftTest\\Xtruct'); + $deserialized = TBinarySerializer::deserialize($serialized, 'ThriftTest\\Xtruct'); + $this->assertEquals($struct, $deserialized); + } + +} diff --git a/lib/php/test/Test/Thrift/Protocol/TestTJSONProtocol.php b/lib/php/test/Test/Thrift/Protocol/TestTJSONProtocol.php new file mode 100755 index 0000000..a4ca9d5 --- /dev/null +++ b/lib/php/test/Test/Thrift/Protocol/TestTJSONProtocol.php @@ -0,0 +1,583 @@ +registerNamespace('Thrift', __DIR__ . '/../../../../lib'); +$loader->registerNamespace('Test', __DIR__ . '/../../..'); +$loader->registerDefinition('ThriftTest', __DIR__ . '/../../../packages'); +$loader->register(); + +/*** + * This test suite depends on running the compiler against the + * standard ThriftTest.thrift file: + * + * lib/php/test$ ../../../compiler/cpp/thrift --gen php -r \ + * --out ./packages ../../../test/ThriftTest.thrift + */ + +class TestTJSONProtocol extends \PHPUnit_Framework_TestCase +{ + private $transport; + private $protocol; + + public static function setUpBeforeClass() + { + Fixtures::populateTestArgs(); + TestTJSONProtocol_Fixtures::populateTestArgsJSON(); + } + + public function setUp() + { + $this->transport = new TMemoryBuffer(); + $this->protocol = new TJSONProtocol($this->transport); + $this->transport->open(); + } + + /*** + * WRITE TESTS + */ + + public function testVoid_Write() + { + $args = new \ThriftTest\ThriftTest_testVoid_args(); + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testVoid']; + + $this->assertEquals( $expected, $actual ); + } + + public function testString1_Write() + { + $args = new \ThriftTest\ThriftTest_testString_args(); + $args->thing = Fixtures::$testArgs['testString1']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testString1']; + + #$this->assertEquals( $expected, $actual ); + } + + public function testString2_Write() + { + $args = new \ThriftTest\ThriftTest_testString_args(); + $args->thing = Fixtures::$testArgs['testString2']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testString2']; + + $this->assertEquals( $expected, $actual ); + } + + public function testDouble_Write() + { + $args = new \ThriftTest\ThriftTest_testDouble_args(); + $args->thing = Fixtures::$testArgs['testDouble']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testDouble']; + + $this->assertEquals( $expected, $actual ); + } + + public function testByte_Write() + { + $args = new \ThriftTest\ThriftTest_testByte_args(); + $args->thing = Fixtures::$testArgs['testByte']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testByte']; + + $this->assertEquals( $expected, $actual ); + } + + public function testI32_Write() + { + $args = new \ThriftTest\ThriftTest_testI32_args(); + $args->thing = Fixtures::$testArgs['testI32']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testI32']; + + $this->assertEquals( $expected, $actual ); + } + + public function testI64_Write() + { + $args = new \ThriftTest\ThriftTest_testI64_args(); + $args->thing = Fixtures::$testArgs['testI64']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testI64']; + + $this->assertEquals( $expected, $actual ); + } + + public function testStruct_Write() + { + $args = new \ThriftTest\ThriftTest_testStruct_args(); + $args->thing = Fixtures::$testArgs['testStruct']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testStruct']; + + $this->assertEquals( $expected, $actual ); + } + + public function testNest_Write() + { + $args = new \ThriftTest\ThriftTest_testNest_args(); + $args->thing = Fixtures::$testArgs['testNest']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testNest']; + + $this->assertEquals( $expected, $actual ); + } + + public function testMap_Write() + { + $args = new \ThriftTest\ThriftTest_testMap_args(); + $args->thing = Fixtures::$testArgs['testMap']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testMap']; + + $this->assertEquals( $expected, $actual ); + } + + public function testStringMap_Write() + { + $args = new \ThriftTest\ThriftTest_testStringMap_args(); + $args->thing = Fixtures::$testArgs['testStringMap']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testStringMap']; + + /* + * The $actual returns unescaped string. + * It is required to to decode then encode it again + * to get the expected escaped unicode. + */ + $this->assertEquals( $expected, json_encode(json_decode($actual)) ); + } + + public function testSet_Write() + { + $args = new \ThriftTest\ThriftTest_testSet_args(); + $args->thing = Fixtures::$testArgs['testSet']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testSet']; + + $this->assertEquals( $expected, $actual ); + } + + public function testList_Write() + { + $args = new \ThriftTest\ThriftTest_testList_args(); + $args->thing = Fixtures::$testArgs['testList']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testList']; + + $this->assertEquals( $expected, $actual ); + } + + public function testEnum_Write() + { + $args = new \ThriftTest\ThriftTest_testEnum_args(); + $args->thing = Fixtures::$testArgs['testEnum']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testEnum']; + + $this->assertEquals( $expected, $actual ); + } + + public function testTypedef_Write() + { + $args = new \ThriftTest\ThriftTest_testTypedef_args(); + $args->thing = Fixtures::$testArgs['testTypedef']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testTypedef']; + + $this->assertEquals( $expected, $actual ); + } + + /*** + * READ TESTS + */ + + public function testVoid_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testVoid'] + ); + $args = new \ThriftTest\ThriftTest_testVoid_args(); + $args->read( $this->protocol ); + } + + public function testString1_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testString1'] + ); + $args = new \ThriftTest\ThriftTest_testString_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testString1']; + + $this->assertEquals( $expected, $actual ); + } + + public function testString2_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testString2'] + ); + $args = new \ThriftTest\ThriftTest_testString_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testString2']; + + $this->assertEquals( $expected, $actual ); + } + + public function testString3_Write() + { + $args = new \ThriftTest\ThriftTest_testString_args(); + $args->thing = Fixtures::$testArgs['testString3']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testString3']; + + $this->assertEquals( $expected, $actual ); + } + + public function testString4_Write() + { + $args = new \ThriftTest\ThriftTest_testString_args(); + $args->thing = Fixtures::$testArgs['testUnicodeStringWithNonBMP']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testUnicodeStringWithNonBMP']; + + $this->assertEquals( $expected, $actual ); + } + + public function testDouble_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testDouble'] + ); + $args = new \ThriftTest\ThriftTest_testDouble_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testDouble']; + + $this->assertEquals( $expected, $actual ); + } + + public function testByte_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testByte'] + ); + $args = new \ThriftTest\ThriftTest_testByte_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testByte']; + + $this->assertEquals( $expected, $actual ); + } + + public function testI32_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testI32'] + ); + $args = new \ThriftTest\ThriftTest_testI32_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testI32']; + + $this->assertEquals( $expected, $actual ); + } + + public function testI64_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testI64'] + ); + $args = new \ThriftTest\ThriftTest_testI64_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testI64']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testStruct_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testStruct'] + ); + $args = new \ThriftTest\ThriftTest_testStruct_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testStruct']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testNest_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testNest'] + ); + $args = new \ThriftTest\ThriftTest_testNest_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testNest']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testMap_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testMap'] + ); + $args = new \ThriftTest\ThriftTest_testMap_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testMap']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testStringMap_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testStringMap'] + ); + $args = new \ThriftTest\ThriftTest_testStringMap_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testStringMap']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testSet_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testSet'] + ); + $args = new \ThriftTest\ThriftTest_testSet_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testSet']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testList_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testList'] + ); + $args = new \ThriftTest\ThriftTest_testList_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testList']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testEnum_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testEnum'] + ); + $args = new \ThriftTest\ThriftTest_testEnum_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testEnum']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testTypedef_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testTypedef'] + ); + $args = new \ThriftTest\ThriftTest_testTypedef_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testTypedef']; + + $this->assertEquals( $expected, $actual ); + } + + public function testMapMap_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testMapMap'] + ); + $result = new \ThriftTest\ThriftTest_testMapMap_result(); + $result->read( $this->protocol ); + + $actual = $result->success; + $expected = Fixtures::$testArgs['testMapMapExpectedResult']; + + $this->assertEquals( $expected, $actual ); + } + + public function testInsanity_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testInsanity'] + ); + $result = new \ThriftTest\ThriftTest_testInsanity_result(); + $result->read( $this->protocol ); + + $actual = $result->success; + $expected = Fixtures::$testArgs['testInsanityExpectedResult']; + + $this->assertEquals( $expected, $actual ); + } + +} + +class TestTJSONProtocol_Fixtures +{ + public static $testArgsJSON = array(); + + public static function populateTestArgsJSON() + { + self::$testArgsJSON['testVoid'] = '{}'; + + self::$testArgsJSON['testString1'] = '{"1":{"str":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e"}}'; + + self::$testArgsJSON['testString2'] = '{"1":{"str":"quote: \\\\\" backslash: forwardslash-escaped: \\\\\/ backspace: \\\\b formfeed: \f newline: \n return: \r tab: now-all-of-them-together: \"\\\\\\\\\/\\\\b\n\r\t now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><"}}'; + + self::$testArgsJSON['testString3'] = '{"1":{"str":"string that ends in double-backslash \\\\\\\\"}}'; + + self::$testArgsJSON['testUnicodeStringWithNonBMP'] = '{"1":{"str":"สวัสดี\/𝒯"}}'; + + self::$testArgsJSON['testDouble'] = '{"1":{"dbl":3.1415926535898}}'; + + self::$testArgsJSON['testByte'] = '{"1":{"i8":1}}'; + + self::$testArgsJSON['testI32'] = '{"1":{"i32":1073741824}}'; + + if (PHP_INT_SIZE == 8) { + self::$testArgsJSON['testI64'] = '{"1":{"i64":'.pow( 2, 60 ).'}}'; + self::$testArgsJSON['testStruct'] = '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":'.pow( 2, 60 ).'}}}}'; + self::$testArgsJSON['testNest'] = '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":'.pow( 2, 60 ).'}}},"3":{"i32":32768}}}}'; + } else { + self::$testArgsJSON['testI64'] = '{"1":{"i64":1152921504606847000}}'; + self::$testArgsJSON['testStruct'] = '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}}}'; + self::$testArgsJSON['testNest'] = '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}},"3":{"i32":32768}}}}'; + } + + self::$testArgsJSON['testMap'] = '{"1":{"map":["i32","i32",3,{"7":77,"8":88,"9":99}]}}'; + + self::$testArgsJSON['testStringMap'] = '{"1":{"map":["str","str",6,{"a":"123","a b":"with spaces ","same":"same","0":"numeric key","longValue":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e","Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e":"long key"}]}}'; + + self::$testArgsJSON['testSet'] = '{"1":{"set":["i32",3,1,5,6]}}'; + + self::$testArgsJSON['testList'] = '{"1":{"lst":["i32",3,1,2,3]}}'; + + self::$testArgsJSON['testEnum'] = '{"1":{"i32":1}}'; + + self::$testArgsJSON['testTypedef'] = '{"1":{"i64":69}}'; + + self::$testArgsJSON['testMapMap'] = '{"0":{"map":["i32","map",2,{"4":["i32","i32",4,{"1":1,"2":2,"3":3,"4":4}],"-4":["i32","i32",4,{"-4":-4,"-3":-3,"-2":-2,"-1":-1}]}]}}'; + + self::$testArgsJSON['testInsanity'] = '{"0":{"map":["i64","map",2,{"1":["i32","rec",2,{"2":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}},"3":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}}}],"2":["i32","rec",1,{"6":{}}]}]}}'; + + } +} diff --git a/lib/php/test/Test/Thrift/Protocol/TestTSimpleJSONProtocol.php b/lib/php/test/Test/Thrift/Protocol/TestTSimpleJSONProtocol.php new file mode 100755 index 0000000..973f55c --- /dev/null +++ b/lib/php/test/Test/Thrift/Protocol/TestTSimpleJSONProtocol.php @@ -0,0 +1,300 @@ +registerNamespace('Thrift', __DIR__ . '/../../../../lib'); +$loader->registerNamespace('Test', __DIR__ . '/../../..'); +$loader->registerDefinition('ThriftTest', __DIR__ . '/../../../packages'); +$loader->register(); + +/*** + * This test suite depends on running the compiler against the + * standard ThriftTest.thrift file: + * + * lib/php/test$ ../../../compiler/cpp/thrift --gen php -r \ + * --out ./packages ../../../test/ThriftTest.thrift + */ + +class TestTSimpleJSONProtocol extends \PHPUnit_Framework_TestCase +{ + private $transport; + private $protocol; + + public static function setUpBeforeClass() + { + Fixtures::populateTestArgs(); + TestTSimpleJSONProtocol_Fixtures::populateTestArgsSimpleJSON(); + } + + public function setUp() + { + $this->transport = new TMemoryBuffer(); + $this->protocol = new TSimpleJSONProtocol($this->transport); + $this->transport->open(); + } + + /*** + * WRITE TESTS + */ + + public function testVoid_Write() + { + $args = new \ThriftTest\ThriftTest_testVoid_args(); + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testVoid']; + + $this->assertEquals( $expected, $actual ); + } + + public function testString1_Write() + { + $args = new \ThriftTest\ThriftTest_testString_args(); + $args->thing = Fixtures::$testArgs['testString1']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testString1']; + + #$this->assertEquals( $expected, $actual ); + } + + public function testString2_Write() + { + $args = new \ThriftTest\ThriftTest_testString_args(); + $args->thing = Fixtures::$testArgs['testString2']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testString2']; + + $this->assertEquals( $expected, $actual ); + } + + public function testDouble_Write() + { + $args = new \ThriftTest\ThriftTest_testDouble_args(); + $args->thing = Fixtures::$testArgs['testDouble']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testDouble']; + + $this->assertEquals( $expected, $actual ); + } + + public function testByte_Write() + { + $args = new \ThriftTest\ThriftTest_testByte_args(); + $args->thing = Fixtures::$testArgs['testByte']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testByte']; + + $this->assertEquals( $expected, $actual ); + } + + public function testI32_Write() + { + $args = new \ThriftTest\ThriftTest_testI32_args(); + $args->thing = Fixtures::$testArgs['testI32']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testI32']; + + $this->assertEquals( $expected, $actual ); + } + + public function testI64_Write() + { + $args = new \ThriftTest\ThriftTest_testI64_args(); + $args->thing = Fixtures::$testArgs['testI64']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testI64']; + + $this->assertEquals( $expected, $actual ); + } + + public function testStruct_Write() + { + $args = new \ThriftTest\ThriftTest_testStruct_args(); + $args->thing = Fixtures::$testArgs['testStruct']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testStruct']; + + $this->assertEquals( $expected, $actual ); + } + + public function testNest_Write() + { + $args = new \ThriftTest\ThriftTest_testNest_args(); + $args->thing = Fixtures::$testArgs['testNest']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testNest']; + + $this->assertEquals( $expected, $actual ); + } + + public function testMap_Write() + { + $args = new \ThriftTest\ThriftTest_testMap_args(); + $args->thing = Fixtures::$testArgs['testMap']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testMap']; + + $this->assertEquals( $expected, $actual ); + } + + public function testStringMap_Write() + { + $args = new \ThriftTest\ThriftTest_testStringMap_args(); + $args->thing = Fixtures::$testArgs['testStringMap']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testStringMap']; + + $this->assertEquals( $expected, $actual ); + } + + public function testSet_Write() + { + $args = new \ThriftTest\ThriftTest_testSet_args(); + $args->thing = Fixtures::$testArgs['testSet']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testSet']; + + $this->assertEquals( $expected, $actual ); + } + + public function testList_Write() + { + $args = new \ThriftTest\ThriftTest_testList_args(); + $args->thing = Fixtures::$testArgs['testList']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testList']; + + $this->assertEquals( $expected, $actual ); + } + + public function testEnum_Write() + { + $args = new \ThriftTest\ThriftTest_testEnum_args(); + $args->thing = Fixtures::$testArgs['testEnum']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testEnum']; + + $this->assertEquals( $expected, $actual ); + } + + public function testTypedef_Write() + { + $args = new \ThriftTest\ThriftTest_testTypedef_args(); + $args->thing = Fixtures::$testArgs['testTypedef']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTSimpleJSONProtocol_Fixtures::$testArgsJSON['testTypedef']; + + $this->assertEquals( $expected, $actual ); + } +} + +class TestTSimpleJSONProtocol_Fixtures +{ + public static $testArgsJSON = array(); + + public static function populateTestArgsSimpleJSON() + { + self::$testArgsJSON['testVoid'] = '{}'; + + self::$testArgsJSON['testString1'] = '{"1":{"str":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e"}}'; + + self::$testArgsJSON['testString2'] = '{"thing":"quote: \\\\\" backslash: forwardslash-escaped: \\\\\/ backspace: \\\\b formfeed: \f newline: \n return: \r tab: now-all-of-them-together: \"\\\\\\\\\/\\\\b\n\r\t now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><"}'; + + self::$testArgsJSON['testDouble'] = '{"thing":3.1415926535898}'; + + self::$testArgsJSON['testByte'] = '{"thing":1}'; + + self::$testArgsJSON['testI32'] = '{"thing":1073741824}'; + + if (PHP_INT_SIZE == 8) { + self::$testArgsJSON['testI64'] = '{"thing":'.pow( 2, 60 ).'}'; + self::$testArgsJSON['testStruct'] = '{"thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":'.pow( 2, 60 ).'}}'; + self::$testArgsJSON['testNest'] = '{"thing":{"byte_thing":1,"struct_thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":'.pow( 2, 60 ).'},"i32_thing":32768}}'; + } else { + self::$testArgsJSON['testI64'] = '{"thing":1152921504606847000}'; + + self::$testArgsJSON['testStruct'] = '{"thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":1152921504606847000}}'; + self::$testArgsJSON['testNest'] = '{"thing":{"byte_thing":1,"struct_thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":1152921504606847000},"i32_thing":32768}}'; + } + + self::$testArgsJSON['testMap'] = '{"thing":{"7":77,"8":88,"9":99}}'; + + self::$testArgsJSON['testStringMap'] = '{"thing":{"a":"123","a b":"with spaces ","same":"same","0":"numeric key","longValue":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e","Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e":"long key"}}'; + + self::$testArgsJSON['testSet'] = '{"thing":[1,5,6]}'; + + self::$testArgsJSON['testList'] = '{"thing":[1,2,3]}'; + + self::$testArgsJSON['testEnum'] = '{"thing":1}'; + + self::$testArgsJSON['testTypedef'] = '{"thing":69}'; + } +} diff --git a/lib/php/test/Test/Thrift/TestValidators.php b/lib/php/test/Test/Thrift/TestValidators.php new file mode 100644 index 0000000..36cf000 --- /dev/null +++ b/lib/php/test/Test/Thrift/TestValidators.php @@ -0,0 +1,156 @@ +registerNamespace('Thrift', __DIR__ . '/../../../lib'); +$loader->registerDefinition('ThriftTest', __DIR__ . '/../../packages/' . $GEN_DIR); +$loader->registerDefinition('TestValidators', __DIR__ . '/../../packages/' . $GEN_DIR); +$loader->register(); + +// Would be nice to have PHPUnit here, but for now just hack it. + +set_exception_handler(function ($e) { + my_assert(false, "Unexpected exception caught: " . $e->getMessage()); +}); + +set_error_handler(function ($errno, $errmsg) { + my_assert(false, "Unexpected PHP error: " . $errmsg); +}); + +// Empty structs should not have validators +assert_has_no_read_validator('ThriftTest\EmptyStruct'); +assert_has_no_write_validator('ThriftTest\EmptyStruct'); + +// Bonk has only opt_in_req_out fields +{ + assert_has_no_read_validator('ThriftTest\Bonk'); + assert_has_a_write_validator('ThriftTest\Bonk'); + { + // Check that we can read an empty object + $bonk = new \ThriftTest\Bonk(); + $transport = new TMemoryBuffer("\000"); + $protocol = new TBinaryProtocol($transport); + $bonk->read($protocol); + } + { + // ...but not write an empty object + $bonk = new \ThriftTest\Bonk(); + $transport = new TMemoryBuffer(); + $protocol = new TBinaryProtocol($transport); + assert_protocol_exception_thrown(function () use ($bonk, $protocol) { $bonk->write($protocol); }, + 'Bonk was able to write an empty object'); + } +} + +// StructA has a single required field +{ + assert_has_a_read_validator('ThriftTest\StructA'); + assert_has_a_write_validator('ThriftTest\StructA'); + { + // Check that we are not able to write StructA with a missing required field + $structa = new \ThriftTest\StructA(); + $transport = new TMemoryBuffer(); + $protocol = new TBinaryProtocol($transport); + assert_protocol_exception_thrown(function () use ($structa, $protocol) { $structa->write($protocol); }, + 'StructA was able to write an empty object'); + } + { + // Check that we are able to read and write a message with a good StructA + $transport = new TMemoryBuffer(base64_decode('CwABAAAAA2FiYwA=')); + $protocol = new TBinaryProtocol($transport); + $structa = new \ThriftTest\StructA(); + $structa->read($protocol); + $structa->write($protocol); + } +} + +// Unions should not get write validators +assert_has_no_write_validator('TestValidators\UnionOfStrings'); + +// Service _result classes should not get any validators +assert_has_no_read_validator('TestValidators\TestService_test_result'); +assert_has_no_write_validator('TestValidators\TestService_test_result'); + +function assert_has_a_read_validator($class) +{ + my_assert(has_read_validator_method($class), + $class . ' class should have a read validator'); +} + +function assert_has_no_read_validator($class) +{ + my_assert(!has_read_validator_method($class), + $class . ' class should not have a read validator'); +} + +function assert_has_a_write_validator($class) +{ + my_assert(has_write_validator_method($class), + $class . ' class should have a write validator'); +} + +function assert_has_no_write_validator($class) +{ + my_assert(!has_write_validator_method($class), + $class . ' class should not have a write validator'); +} + +function assert_protocol_exception_thrown($callable, $message) +{ + try { + call_user_func($callable); + my_assert(false, $message); + } catch (TProtocolException $e) { + } +} + +function has_write_validator_method($class) +{ + $rc = new \ReflectionClass($class); + + return $rc->hasMethod('_validateForWrite'); +} + +function has_read_validator_method($class) +{ + $rc = new \ReflectionClass($class); + + return $rc->hasMethod('_validateForRead'); +} + +function my_assert($something, $message) +{ + if (!$something) { + fwrite(STDERR, basename(__FILE__) . " FAILED: $message\n"); + exit(1); + } +} diff --git a/lib/php/test/TestValidators.thrift b/lib/php/test/TestValidators.thrift new file mode 100644 index 0000000..9c38d92 --- /dev/null +++ b/lib/php/test/TestValidators.thrift @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +namespace php TestValidators + +include "../../../test/ThriftTest.thrift" + +union UnionOfStrings { + 1: string aa; + 2: string bb; +} + +service TestService { + void test() throws(1: ThriftTest.Xception xception); +} diff --git a/lib/php/thrift_protocol.ini b/lib/php/thrift_protocol.ini new file mode 100644 index 0000000..a260d83 --- /dev/null +++ b/lib/php/thrift_protocol.ini @@ -0,0 +1 @@ +extension=thrift_protocol.so diff --git a/lib/py/CMakeLists.txt b/lib/py/CMakeLists.txt new file mode 100644 index 0000000..7bb91fe --- /dev/null +++ b/lib/py/CMakeLists.txt @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +include_directories(${PYTHON_INCLUDE_DIRS}) + +add_custom_target(python_build ALL + COMMAND ${PYTHON_EXECUTABLE} setup.py build + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Building Python library" +) + +if(BUILD_TESTING) + add_test(PythonTestSSLSocket ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/test_sslsocket.py) + add_test(PythonThriftJson ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/thrift_json.py) +endif() diff --git a/lib/py/MANIFEST.in b/lib/py/MANIFEST.in new file mode 100644 index 0000000..af54e29 --- /dev/null +++ b/lib/py/MANIFEST.in @@ -0,0 +1 @@ +include src/ext/* diff --git a/lib/py/Makefile.am b/lib/py/Makefile.am new file mode 100644 index 0000000..5861858 --- /dev/null +++ b/lib/py/Makefile.am @@ -0,0 +1,59 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +AUTOMAKE_OPTIONS = serial-tests +DESTDIR ?= / + +if WITH_PY3 +py3-build: + $(PYTHON3) setup.py build +py3-test: py3-build + $(PYTHON3) test/thrift_json.py + $(PYTHON3) test/test_sslsocket.py +else +py3-build: +py3-test: +endif + +all-local: py3-build + $(PYTHON) setup.py build + +# We're ignoring prefix here because site-packages seems to be +# the equivalent of /usr/local/lib in Python land. +# Old version (can't put inline because it's not portable). +#$(PYTHON) setup.py install --prefix=$(prefix) --root=$(DESTDIR) $(PYTHON_SETUPUTIL_ARGS) +install-exec-hook: + $(PYTHON) setup.py install --root=$(DESTDIR) --prefix=$(PY_PREFIX) $(PYTHON_SETUPUTIL_ARGS) + +clean-local: + $(RM) -r build + +check-local: all py3-test + $(PYTHON) test/thrift_json.py + $(PYTHON) test/test_sslsocket.py + +EXTRA_DIST = \ + CMakeLists.txt \ + MANIFEST.in \ + coding_standards.md \ + compat \ + setup.py \ + setup.cfg \ + src \ + test \ + README.md diff --git a/lib/py/Makefile.in b/lib/py/Makefile.in new file mode 100644 index 0000000..40b7738 --- /dev/null +++ b/lib/py/Makefile.in @@ -0,0 +1,663 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/py +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +AUTOMAKE_OPTIONS = serial-tests +EXTRA_DIST = \ + CMakeLists.txt \ + MANIFEST.in \ + coding_standards.md \ + compat \ + setup.py \ + setup.cfg \ + src \ + test \ + README.md + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/py/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/py/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: check-am install-am install-exec-am install-strip + +.PHONY: all all-am all-local check check-am check-local clean \ + clean-generic clean-libtool clean-local cscopelist-am ctags-am \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-exec-hook install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + +DESTDIR ?= / + +@WITH_PY3_TRUE@py3-build: +@WITH_PY3_TRUE@ $(PYTHON3) setup.py build +@WITH_PY3_TRUE@py3-test: py3-build +@WITH_PY3_TRUE@ $(PYTHON3) test/thrift_json.py +@WITH_PY3_TRUE@ $(PYTHON3) test/test_sslsocket.py +@WITH_PY3_FALSE@py3-build: +@WITH_PY3_FALSE@py3-test: + +all-local: py3-build + $(PYTHON) setup.py build + +# We're ignoring prefix here because site-packages seems to be +# the equivalent of /usr/local/lib in Python land. +# Old version (can't put inline because it's not portable). +#$(PYTHON) setup.py install --prefix=$(prefix) --root=$(DESTDIR) $(PYTHON_SETUPUTIL_ARGS) +install-exec-hook: + $(PYTHON) setup.py install --root=$(DESTDIR) --prefix=$(PY_PREFIX) $(PYTHON_SETUPUTIL_ARGS) + +clean-local: + $(RM) -r build + +check-local: all py3-test + $(PYTHON) test/thrift_json.py + $(PYTHON) test/test_sslsocket.py + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/py/README.md b/lib/py/README.md new file mode 100644 index 0000000..29b8c73 --- /dev/null +++ b/lib/py/README.md @@ -0,0 +1,35 @@ +Thrift Python Software Library + +License +======= + +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + +Using Thrift with Python +======================== + +Thrift is provided as a set of Python packages. The top level package is +thrift, and there are subpackages for the protocol, transport, and server +code. Each package contains modules using standard Thrift naming conventions +(i.e. TProtocol, TTransport) and implementations in corresponding modules +(i.e. TSocket). There is also a subpackage reflection, which contains +the generated code for the reflection structures. + +The Python libraries can be installed manually using the provided setup.py +file, or automatically using the install hook provided via autoconf/automake. +To use the latter, become superuser and do make install. diff --git a/lib/py/coding_standards.md b/lib/py/coding_standards.md new file mode 100644 index 0000000..4c560b5 --- /dev/null +++ b/lib/py/coding_standards.md @@ -0,0 +1,7 @@ +## Python Coding Standards + +Please follow: + * [Thrift General Coding Standards](/doc/coding_standards.md) + * Code Style for Python Code [PEP8](http://legacy.python.org/dev/peps/pep-0008/) + +When in doubt - check with or online with . diff --git a/lib/py/compat/win32/stdint.h b/lib/py/compat/win32/stdint.h new file mode 100644 index 0000000..d02608a --- /dev/null +++ b/lib/py/compat/win32/stdint.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/lib/py/setup.cfg b/lib/py/setup.cfg new file mode 100644 index 0000000..c9ed0ae --- /dev/null +++ b/lib/py/setup.cfg @@ -0,0 +1,6 @@ +[install] +optimize = 1 +[metadata] +description-file = README.md +[flake8] +max-line-length = 100 diff --git a/lib/py/setup.py b/lib/py/setup.py new file mode 100644 index 0000000..e3435c7 --- /dev/null +++ b/lib/py/setup.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import sys +try: + from setuptools import setup, Extension +except Exception: + from distutils.core import setup, Extension + +from distutils.command.build_ext import build_ext +from distutils.errors import CCompilerError, DistutilsExecError, DistutilsPlatformError + +# Fix to build sdist under vagrant +import os +if 'vagrant' in str(os.environ): + del os.link + +include_dirs = ['src'] +if sys.platform == 'win32': + include_dirs.append('compat/win32') + ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError, IOError) +else: + ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError) + + +class BuildFailed(Exception): + pass + + +class ve_build_ext(build_ext): + def run(self): + try: + build_ext.run(self) + except DistutilsPlatformError: + raise BuildFailed() + + def build_extension(self, ext): + try: + build_ext.build_extension(self, ext) + except ext_errors: + raise BuildFailed() + + +def run_setup(with_binary): + if with_binary: + extensions = dict( + ext_modules=[ + Extension('thrift.protocol.fastbinary', + sources=[ + 'src/ext/module.cpp', + 'src/ext/types.cpp', + 'src/ext/binary.cpp', + 'src/ext/compact.cpp', + ], + include_dirs=include_dirs, + ) + ], + cmdclass=dict(build_ext=ve_build_ext) + ) + else: + extensions = dict() + + ssl_deps = [] + if sys.version_info[0] == 2: + ssl_deps.append('ipaddress') + if sys.hexversion < 0x03050000: + ssl_deps.append('backports.ssl_match_hostname>=3.5') + tornado_deps = ['tornado>=4.0'] + twisted_deps = ['twisted'] + + setup(name='thrift', + version='0.11.0', + description='Python bindings for the Apache Thrift RPC system', + author='Thrift Developers', + author_email='dev@thrift.apache.org', + url='http://thrift.apache.org', + license='Apache License 2.0', + install_requires=['six>=1.7.2'], + extras_require={ + 'ssl': ssl_deps, + 'tornado': tornado_deps, + 'twisted': twisted_deps, + 'all': ssl_deps + tornado_deps + twisted_deps, + }, + packages=[ + 'thrift', + 'thrift.protocol', + 'thrift.transport', + 'thrift.server', + ], + package_dir={'thrift': 'src'}, + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 3', + 'Topic :: Software Development :: Libraries', + 'Topic :: System :: Networking' + ], + zip_safe=False, + **extensions + ) + + +try: + with_binary = True + run_setup(with_binary) +except BuildFailed: + print() + print('*' * 80) + print("An error occurred while trying to compile with the C extension enabled") + print("Attempting to build without the extension now") + print('*' * 80) + print() + + run_setup(False) diff --git a/lib/py/src/TMultiplexedProcessor.py b/lib/py/src/TMultiplexedProcessor.py new file mode 100644 index 0000000..605aa1f --- /dev/null +++ b/lib/py/src/TMultiplexedProcessor.py @@ -0,0 +1,55 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from thrift.Thrift import TProcessor, TMessageType, TException +from thrift.protocol import TProtocolDecorator, TMultiplexedProtocol + + +class TMultiplexedProcessor(TProcessor): + def __init__(self): + self.services = {} + + def registerProcessor(self, serviceName, processor): + self.services[serviceName] = processor + + def process(self, iprot, oprot): + (name, type, seqid) = iprot.readMessageBegin() + if type != TMessageType.CALL and type != TMessageType.ONEWAY: + raise TException("TMultiplex protocol only supports CALL & ONEWAY") + + index = name.find(TMultiplexedProtocol.SEPARATOR) + if index < 0: + raise TException("Service name not found in message name: " + name + ". Did you forget to use TMultiplexProtocol in your client?") + + serviceName = name[0:index] + call = name[index + len(TMultiplexedProtocol.SEPARATOR):] + if serviceName not in self.services: + raise TException("Service name not found: " + serviceName + ". Did you forget to call registerProcessor()?") + + standardMessage = (call, type, seqid) + return self.services[serviceName].process(StoredMessageProtocol(iprot, standardMessage), oprot) + + +class StoredMessageProtocol(TProtocolDecorator.TProtocolDecorator): + def __init__(self, protocol, messageBegin): + TProtocolDecorator.TProtocolDecorator.__init__(self, protocol) + self.messageBegin = messageBegin + + def readMessageBegin(self): + return self.messageBegin diff --git a/lib/py/src/TRecursive.py b/lib/py/src/TRecursive.py new file mode 100644 index 0000000..abf202c --- /dev/null +++ b/lib/py/src/TRecursive.py @@ -0,0 +1,83 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from thrift.Thrift import TType + +TYPE_IDX = 1 +SPEC_ARGS_IDX = 3 +SPEC_ARGS_CLASS_REF_IDX = 0 +SPEC_ARGS_THRIFT_SPEC_IDX = 1 + + +def fix_spec(all_structs): + """Wire up recursive references for all TStruct definitions inside of each thrift_spec.""" + for struc in all_structs: + spec = struc.thrift_spec + for thrift_spec in spec: + if thrift_spec is None: + continue + elif thrift_spec[TYPE_IDX] == TType.STRUCT: + other = thrift_spec[SPEC_ARGS_IDX][SPEC_ARGS_CLASS_REF_IDX].thrift_spec + thrift_spec[SPEC_ARGS_IDX][SPEC_ARGS_THRIFT_SPEC_IDX] = other + elif thrift_spec[TYPE_IDX] in (TType.LIST, TType.SET): + _fix_list_or_set(thrift_spec[SPEC_ARGS_IDX]) + elif thrift_spec[TYPE_IDX] == TType.MAP: + _fix_map(thrift_spec[SPEC_ARGS_IDX]) + + +def _fix_list_or_set(element_type): + # For a list or set, the thrift_spec entry looks like, + # (1, TType.LIST, 'lister', (TType.STRUCT, [RecList, None], False), None, ), # 1 + # so ``element_type`` will be, + # (TType.STRUCT, [RecList, None], False) + if element_type[0] == TType.STRUCT: + element_type[1][1] = element_type[1][0].thrift_spec + elif element_type[0] in (TType.LIST, TType.SET): + _fix_list_or_set(element_type[1]) + elif element_type[0] == TType.MAP: + _fix_map(element_type[1]) + + +def _fix_map(element_type): + # For a map of key -> value type, ``element_type`` will be, + # (TType.I16, None, TType.STRUCT, [RecMapBasic, None], False), None, ) + # which is just a normal struct definition. + # + # For a map of key -> list / set, ``element_type`` will be, + # (TType.I16, None, TType.LIST, (TType.STRUCT, [RecMapList, None], False), False) + # and we need to process the 3rd element as a list. + # + # For a map of key -> map, ``element_type`` will be, + # (TType.I16, None, TType.MAP, (TType.I16, None, TType.STRUCT, + # [RecMapMap, None], False), False) + # and need to process 3rd element as a map. + + # Is the map key a struct? + if element_type[0] == TType.STRUCT: + element_type[1][1] = element_type[1][0].thrift_spec + elif element_type[0] in (TType.LIST, TType.SET): + _fix_list_or_set(element_type[1]) + elif element_type[0] == TType.MAP: + _fix_map(element_type[1]) + + # Is the map value a struct? + if element_type[2] == TType.STRUCT: + element_type[3][1] = element_type[3][0].thrift_spec + elif element_type[2] in (TType.LIST, TType.SET): + _fix_list_or_set(element_type[3]) + elif element_type[2] == TType.MAP: + _fix_map(element_type[3]) diff --git a/lib/py/src/TSCons.py b/lib/py/src/TSCons.py new file mode 100644 index 0000000..bc67d70 --- /dev/null +++ b/lib/py/src/TSCons.py @@ -0,0 +1,36 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from os import path +from SCons.Builder import Builder +from six.moves import map + + +def scons_env(env, add=''): + opath = path.dirname(path.abspath('$TARGET')) + lstr = 'thrift --gen cpp -o ' + opath + ' ' + add + ' $SOURCE' + cppbuild = Builder(action=lstr) + env.Append(BUILDERS={'ThriftCpp': cppbuild}) + + +def gen_cpp(env, dir, file): + scons_env(env) + suffixes = ['_types.h', '_types.cpp'] + targets = map(lambda s: 'gen-cpp/' + file + s, suffixes) + return env.ThriftCpp(targets, dir + file + '.thrift') diff --git a/lib/py/src/TSerialization.py b/lib/py/src/TSerialization.py new file mode 100644 index 0000000..fbbe768 --- /dev/null +++ b/lib/py/src/TSerialization.py @@ -0,0 +1,38 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from .protocol import TBinaryProtocol +from .transport import TTransport + + +def serialize(thrift_object, + protocol_factory=TBinaryProtocol.TBinaryProtocolFactory()): + transport = TTransport.TMemoryBuffer() + protocol = protocol_factory.getProtocol(transport) + thrift_object.write(protocol) + return transport.getvalue() + + +def deserialize(base, + buf, + protocol_factory=TBinaryProtocol.TBinaryProtocolFactory()): + transport = TTransport.TMemoryBuffer(buf) + protocol = protocol_factory.getProtocol(transport) + base.read(protocol) + return base diff --git a/lib/py/src/TTornado.py b/lib/py/src/TTornado.py new file mode 100644 index 0000000..5eff11d --- /dev/null +++ b/lib/py/src/TTornado.py @@ -0,0 +1,188 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from __future__ import absolute_import +import logging +import socket +import struct + +from .transport.TTransport import TTransportException, TTransportBase, TMemoryBuffer + +from io import BytesIO +from collections import deque +from contextlib import contextmanager +from tornado import gen, iostream, ioloop, tcpserver, concurrent + +__all__ = ['TTornadoServer', 'TTornadoStreamTransport'] + +logger = logging.getLogger(__name__) + + +class _Lock(object): + def __init__(self): + self._waiters = deque() + + def acquired(self): + return len(self._waiters) > 0 + + @gen.coroutine + def acquire(self): + blocker = self._waiters[-1] if self.acquired() else None + future = concurrent.Future() + self._waiters.append(future) + if blocker: + yield blocker + + raise gen.Return(self._lock_context()) + + def release(self): + assert self.acquired(), 'Lock not aquired' + future = self._waiters.popleft() + future.set_result(None) + + @contextmanager + def _lock_context(self): + try: + yield + finally: + self.release() + + +class TTornadoStreamTransport(TTransportBase): + """a framed, buffered transport over a Tornado stream""" + def __init__(self, host, port, stream=None, io_loop=None): + self.host = host + self.port = port + self.io_loop = io_loop or ioloop.IOLoop.current() + self.__wbuf = BytesIO() + self._read_lock = _Lock() + + # servers provide a ready-to-go stream + self.stream = stream + + def with_timeout(self, timeout, future): + return gen.with_timeout(timeout, future, self.io_loop) + + @gen.coroutine + def open(self, timeout=None): + logger.debug('socket connecting') + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + self.stream = iostream.IOStream(sock) + + try: + connect = self.stream.connect((self.host, self.port)) + if timeout is not None: + yield self.with_timeout(timeout, connect) + else: + yield connect + except (socket.error, IOError, ioloop.TimeoutError) as e: + message = 'could not connect to {}:{} ({})'.format(self.host, self.port, e) + raise TTransportException( + type=TTransportException.NOT_OPEN, + message=message) + + raise gen.Return(self) + + def set_close_callback(self, callback): + """ + Should be called only after open() returns + """ + self.stream.set_close_callback(callback) + + def close(self): + # don't raise if we intend to close + self.stream.set_close_callback(None) + self.stream.close() + + def read(self, _): + # The generated code for Tornado shouldn't do individual reads -- only + # frames at a time + assert False, "you're doing it wrong" + + @contextmanager + def io_exception_context(self): + try: + yield + except (socket.error, IOError) as e: + raise TTransportException( + type=TTransportException.END_OF_FILE, + message=str(e)) + except iostream.StreamBufferFullError as e: + raise TTransportException( + type=TTransportException.UNKNOWN, + message=str(e)) + + @gen.coroutine + def readFrame(self): + # IOStream processes reads one at a time + with (yield self._read_lock.acquire()): + with self.io_exception_context(): + frame_header = yield self.stream.read_bytes(4) + if len(frame_header) == 0: + raise iostream.StreamClosedError('Read zero bytes from stream') + frame_length, = struct.unpack('!i', frame_header) + frame = yield self.stream.read_bytes(frame_length) + raise gen.Return(frame) + + def write(self, buf): + self.__wbuf.write(buf) + + def flush(self): + frame = self.__wbuf.getvalue() + # reset wbuf before write/flush to preserve state on underlying failure + frame_length = struct.pack('!i', len(frame)) + self.__wbuf = BytesIO() + with self.io_exception_context(): + return self.stream.write(frame_length + frame) + + +class TTornadoServer(tcpserver.TCPServer): + def __init__(self, processor, iprot_factory, oprot_factory=None, + *args, **kwargs): + super(TTornadoServer, self).__init__(*args, **kwargs) + + self._processor = processor + self._iprot_factory = iprot_factory + self._oprot_factory = (oprot_factory if oprot_factory is not None + else iprot_factory) + + @gen.coroutine + def handle_stream(self, stream, address): + host, port = address[:2] + trans = TTornadoStreamTransport(host=host, port=port, stream=stream, + io_loop=self.io_loop) + oprot = self._oprot_factory.getProtocol(trans) + + try: + while not trans.stream.closed(): + try: + frame = yield trans.readFrame() + except TTransportException as e: + if e.type == TTransportException.END_OF_FILE: + break + else: + raise + tr = TMemoryBuffer(frame) + iprot = self._iprot_factory.getProtocol(tr) + yield self._processor.process(iprot, oprot) + except Exception: + logger.exception('thrift exception in handle_stream') + trans.close() + + logger.info('client disconnected %s:%d', host, port) diff --git a/lib/py/src/Thrift.py b/lib/py/src/Thrift.py new file mode 100644 index 0000000..00941d8 --- /dev/null +++ b/lib/py/src/Thrift.py @@ -0,0 +1,192 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import sys + + +class TType(object): + STOP = 0 + VOID = 1 + BOOL = 2 + BYTE = 3 + I08 = 3 + DOUBLE = 4 + I16 = 6 + I32 = 8 + I64 = 10 + STRING = 11 + UTF7 = 11 + STRUCT = 12 + MAP = 13 + SET = 14 + LIST = 15 + UTF8 = 16 + UTF16 = 17 + + _VALUES_TO_NAMES = ( + 'STOP', + 'VOID', + 'BOOL', + 'BYTE', + 'DOUBLE', + None, + 'I16', + None, + 'I32', + None, + 'I64', + 'STRING', + 'STRUCT', + 'MAP', + 'SET', + 'LIST', + 'UTF8', + 'UTF16', + ) + + +class TMessageType(object): + CALL = 1 + REPLY = 2 + EXCEPTION = 3 + ONEWAY = 4 + + +class TProcessor(object): + """Base class for processor, which works on two streams.""" + + def process(self, iprot, oprot): + pass + + +class TException(Exception): + """Base class for all thrift exceptions.""" + + # BaseException.message is deprecated in Python v[2.6,3.0) + if (2, 6, 0) <= sys.version_info < (3, 0): + def _get_message(self): + return self._message + + def _set_message(self, message): + self._message = message + message = property(_get_message, _set_message) + + def __init__(self, message=None): + Exception.__init__(self, message) + self.message = message + + +class TApplicationException(TException): + """Application level thrift exceptions.""" + + UNKNOWN = 0 + UNKNOWN_METHOD = 1 + INVALID_MESSAGE_TYPE = 2 + WRONG_METHOD_NAME = 3 + BAD_SEQUENCE_ID = 4 + MISSING_RESULT = 5 + INTERNAL_ERROR = 6 + PROTOCOL_ERROR = 7 + INVALID_TRANSFORM = 8 + INVALID_PROTOCOL = 9 + UNSUPPORTED_CLIENT_TYPE = 10 + + def __init__(self, type=UNKNOWN, message=None): + TException.__init__(self, message) + self.type = type + + def __str__(self): + if self.message: + return self.message + elif self.type == self.UNKNOWN_METHOD: + return 'Unknown method' + elif self.type == self.INVALID_MESSAGE_TYPE: + return 'Invalid message type' + elif self.type == self.WRONG_METHOD_NAME: + return 'Wrong method name' + elif self.type == self.BAD_SEQUENCE_ID: + return 'Bad sequence ID' + elif self.type == self.MISSING_RESULT: + return 'Missing result' + elif self.type == self.INTERNAL_ERROR: + return 'Internal error' + elif self.type == self.PROTOCOL_ERROR: + return 'Protocol error' + elif self.type == self.INVALID_TRANSFORM: + return 'Invalid transform' + elif self.type == self.INVALID_PROTOCOL: + return 'Invalid protocol' + elif self.type == self.UNSUPPORTED_CLIENT_TYPE: + return 'Unsupported client type' + else: + return 'Default (unknown) TApplicationException' + + def read(self, iprot): + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.STRING: + self.message = iprot.readString() + else: + iprot.skip(ftype) + elif fid == 2: + if ftype == TType.I32: + self.type = iprot.readI32() + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + oprot.writeStructBegin('TApplicationException') + if self.message is not None: + oprot.writeFieldBegin('message', TType.STRING, 1) + oprot.writeString(self.message) + oprot.writeFieldEnd() + if self.type is not None: + oprot.writeFieldBegin('type', TType.I32, 2) + oprot.writeI32(self.type) + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + +class TFrozenDict(dict): + """A dictionary that is "frozen" like a frozenset""" + + def __init__(self, *args, **kwargs): + super(TFrozenDict, self).__init__(*args, **kwargs) + # Sort the items so they will be in a consistent order. + # XOR in the hash of the class so we don't collide with + # the hash of a list of tuples. + self.__hashval = hash(TFrozenDict) ^ hash(tuple(sorted(self.items()))) + + def __setitem__(self, *args): + raise TypeError("Can't modify frozen TFreezableDict") + + def __delitem__(self, *args): + raise TypeError("Can't modify frozen TFreezableDict") + + def __hash__(self): + return self.__hashval diff --git a/lib/py/src/__init__.py b/lib/py/src/__init__.py new file mode 100644 index 0000000..48d659c --- /dev/null +++ b/lib/py/src/__init__.py @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +__all__ = ['Thrift', 'TSCons'] diff --git a/lib/py/src/compat.py b/lib/py/src/compat.py new file mode 100644 index 0000000..41bcf35 --- /dev/null +++ b/lib/py/src/compat.py @@ -0,0 +1,40 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import sys + +if sys.version_info[0] == 2: + + from cStringIO import StringIO as BufferIO + + def binary_to_str(bin_val): + return bin_val + + def str_to_binary(str_val): + return str_val + +else: + + from io import BytesIO as BufferIO # noqa + + def binary_to_str(bin_val): + return bin_val.decode('utf8') + + def str_to_binary(str_val): + return bytes(str_val, 'utf8') diff --git a/lib/py/src/ext/binary.cpp b/lib/py/src/ext/binary.cpp new file mode 100644 index 0000000..85d8d92 --- /dev/null +++ b/lib/py/src/ext/binary.cpp @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "ext/binary.h" +namespace apache { +namespace thrift { +namespace py { + +bool BinaryProtocol::readFieldBegin(TType& type, int16_t& tag) { + uint8_t b = 0; + if (!readByte(b)) { + return false; + } + type = static_cast(b); + if (type == T_STOP) { + return true; + } + return readI16(tag); +} +} +} +} diff --git a/lib/py/src/ext/binary.h b/lib/py/src/ext/binary.h new file mode 100644 index 0000000..960b0d0 --- /dev/null +++ b/lib/py/src/ext/binary.h @@ -0,0 +1,217 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef THRIFT_PY_BINARY_H +#define THRIFT_PY_BINARY_H + +#include +#include "ext/protocol.h" +#include "ext/endian.h" +#include + +namespace apache { +namespace thrift { +namespace py { + +class BinaryProtocol : public ProtocolBase { +public: + virtual ~BinaryProtocol() {} + + void writeI8(int8_t val) { writeBuffer(reinterpret_cast(&val), sizeof(int8_t)); } + + void writeI16(int16_t val) { + int16_t net = static_cast(htons(val)); + writeBuffer(reinterpret_cast(&net), sizeof(int16_t)); + } + + void writeI32(int32_t val) { + int32_t net = static_cast(htonl(val)); + writeBuffer(reinterpret_cast(&net), sizeof(int32_t)); + } + + void writeI64(int64_t val) { + int64_t net = static_cast(htonll(val)); + writeBuffer(reinterpret_cast(&net), sizeof(int64_t)); + } + + void writeDouble(double dub) { + // Unfortunately, bitwise_cast doesn't work in C. Bad C! + union { + double f; + int64_t t; + } transfer; + transfer.f = dub; + writeI64(transfer.t); + } + + void writeBool(int v) { writeByte(static_cast(v)); } + + void writeString(PyObject* value, int32_t len) { + writeI32(len); + writeBuffer(PyBytes_AS_STRING(value), len); + } + + bool writeListBegin(PyObject* value, const SetListTypeArgs& parsedargs, int32_t len) { + writeByte(parsedargs.element_type); + writeI32(len); + return true; + } + + bool writeMapBegin(PyObject* value, const MapTypeArgs& parsedargs, int32_t len) { + writeByte(parsedargs.ktag); + writeByte(parsedargs.vtag); + writeI32(len); + return true; + } + + bool writeStructBegin() { return true; } + bool writeStructEnd() { return true; } + bool writeField(PyObject* value, const StructItemSpec& parsedspec) { + writeByte(static_cast(parsedspec.type)); + writeI16(parsedspec.tag); + return encodeValue(value, parsedspec.type, parsedspec.typeargs); + } + + void writeFieldStop() { writeByte(static_cast(T_STOP)); } + + bool readBool(bool& val) { + char* buf; + if (!readBytes(&buf, 1)) { + return false; + } + val = buf[0] == 1; + return true; + } + + bool readI8(int8_t& val) { + char* buf; + if (!readBytes(&buf, 1)) { + return false; + } + val = buf[0]; + return true; + } + + bool readI16(int16_t& val) { + char* buf; + if (!readBytes(&buf, sizeof(int16_t))) { + return false; + } + memcpy(&val, buf, sizeof(int16_t)); + val = ntohs(val); + return true; + } + + bool readI32(int32_t& val) { + char* buf; + if (!readBytes(&buf, sizeof(int32_t))) { + return false; + } + memcpy(&val, buf, sizeof(int32_t)); + val = ntohl(val); + return true; + } + + bool readI64(int64_t& val) { + char* buf; + if (!readBytes(&buf, sizeof(int64_t))) { + return false; + } + memcpy(&val, buf, sizeof(int64_t)); + val = ntohll(val); + return true; + } + + bool readDouble(double& val) { + union { + int64_t f; + double t; + } transfer; + + if (!readI64(transfer.f)) { + return false; + } + val = transfer.t; + return true; + } + + int32_t readString(char** buf) { + int32_t len = 0; + if (!readI32(len) || !checkLengthLimit(len, stringLimit()) || !readBytes(buf, len)) { + return -1; + } + return len; + } + + int32_t readListBegin(TType& etype) { + int32_t len; + uint8_t b = 0; + if (!readByte(b) || !readI32(len) || !checkLengthLimit(len, containerLimit())) { + return -1; + } + etype = static_cast(b); + return len; + } + + int32_t readMapBegin(TType& ktype, TType& vtype) { + int32_t len; + uint8_t k, v; + if (!readByte(k) || !readByte(v) || !readI32(len) || !checkLengthLimit(len, containerLimit())) { + return -1; + } + ktype = static_cast(k); + vtype = static_cast(v); + return len; + } + + bool readStructBegin() { return true; } + bool readStructEnd() { return true; } + + bool readFieldBegin(TType& type, int16_t& tag); + +#define SKIPBYTES(n) \ + do { \ + if (!readBytes(&dummy_buf_, (n))) { \ + return false; \ + } \ + return true; \ + } while (0) + + bool skipBool() { SKIPBYTES(1); } + bool skipByte() { SKIPBYTES(1); } + bool skipI16() { SKIPBYTES(2); } + bool skipI32() { SKIPBYTES(4); } + bool skipI64() { SKIPBYTES(8); } + bool skipDouble() { SKIPBYTES(8); } + bool skipString() { + int32_t len; + if (!readI32(len)) { + return false; + } + SKIPBYTES(len); + } +#undef SKIPBYTES + +private: + char* dummy_buf_; +}; +} +} +} +#endif // THRIFT_PY_BINARY_H diff --git a/lib/py/src/ext/compact.cpp b/lib/py/src/ext/compact.cpp new file mode 100644 index 0000000..15a99a0 --- /dev/null +++ b/lib/py/src/ext/compact.cpp @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "ext/compact.h" + +namespace apache { +namespace thrift { +namespace py { + +const uint8_t CompactProtocol::TTypeToCType[] = { + CT_STOP, // T_STOP + 0, // unused + CT_BOOLEAN_TRUE, // T_BOOL + CT_BYTE, // T_BYTE + CT_DOUBLE, // T_DOUBLE + 0, // unused + CT_I16, // T_I16 + 0, // unused + CT_I32, // T_I32 + 0, // unused + CT_I64, // T_I64 + CT_BINARY, // T_STRING + CT_STRUCT, // T_STRUCT + CT_MAP, // T_MAP + CT_SET, // T_SET + CT_LIST, // T_LIST +}; + +bool CompactProtocol::readFieldBegin(TType& type, int16_t& tag) { + uint8_t b; + if (!readByte(b)) { + return false; + } + uint8_t ctype = b & 0xf; + type = getTType(ctype); + if (type == -1) { + return false; + } else if (type == T_STOP) { + tag = 0; + return true; + } + uint8_t diff = (b & 0xf0) >> 4; + if (diff) { + tag = readTags_.top() + diff; + } else if (!readI16(tag)) { + readTags_.top() = -1; + return false; + } + if (ctype == CT_BOOLEAN_FALSE || ctype == CT_BOOLEAN_TRUE) { + readBool_.exists = true; + readBool_.value = ctype == CT_BOOLEAN_TRUE; + } + readTags_.top() = tag; + return true; +} + +TType CompactProtocol::getTType(uint8_t type) { + switch (type) { + case T_STOP: + return T_STOP; + case CT_BOOLEAN_FALSE: + case CT_BOOLEAN_TRUE: + return T_BOOL; + case CT_BYTE: + return T_BYTE; + case CT_I16: + return T_I16; + case CT_I32: + return T_I32; + case CT_I64: + return T_I64; + case CT_DOUBLE: + return T_DOUBLE; + case CT_BINARY: + return T_STRING; + case CT_LIST: + return T_LIST; + case CT_SET: + return T_SET; + case CT_MAP: + return T_MAP; + case CT_STRUCT: + return T_STRUCT; + default: + PyErr_Format(PyExc_TypeError, "don't know what type: %d", type); + return static_cast(-1); + } +} +} +} +} diff --git a/lib/py/src/ext/compact.h b/lib/py/src/ext/compact.h new file mode 100644 index 0000000..a78d7a7 --- /dev/null +++ b/lib/py/src/ext/compact.h @@ -0,0 +1,368 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef THRIFT_PY_COMPACT_H +#define THRIFT_PY_COMPACT_H + +#include +#include "ext/protocol.h" +#include "ext/endian.h" +#include +#include + +namespace apache { +namespace thrift { +namespace py { + +class CompactProtocol : public ProtocolBase { +public: + CompactProtocol() { readBool_.exists = false; } + + virtual ~CompactProtocol() {} + + void writeI8(int8_t val) { writeBuffer(reinterpret_cast(&val), 1); } + + void writeI16(int16_t val) { writeVarint(toZigZag(val)); } + + int writeI32(int32_t val) { return writeVarint(toZigZag(val)); } + + void writeI64(int64_t val) { writeVarint64(toZigZag64(val)); } + + void writeDouble(double dub) { + union { + double f; + int64_t t; + } transfer; + transfer.f = htolell(dub); + writeBuffer(reinterpret_cast(&transfer.t), sizeof(int64_t)); + } + + void writeBool(int v) { writeByte(static_cast(v ? CT_BOOLEAN_TRUE : CT_BOOLEAN_FALSE)); } + + void writeString(PyObject* value, int32_t len) { + writeVarint(len); + writeBuffer(PyBytes_AS_STRING(value), len); + } + + bool writeListBegin(PyObject* value, const SetListTypeArgs& args, int32_t len) { + int ctype = toCompactType(args.element_type); + if (len <= 14) { + writeByte(static_cast(len << 4 | ctype)); + } else { + writeByte(0xf0 | ctype); + writeVarint(len); + } + return true; + } + + bool writeMapBegin(PyObject* value, const MapTypeArgs& args, int32_t len) { + if (len == 0) { + writeByte(0); + return true; + } + int ctype = toCompactType(args.ktag) << 4 | toCompactType(args.vtag); + writeVarint(len); + writeByte(ctype); + return true; + } + + bool writeStructBegin() { + writeTags_.push(0); + return true; + } + bool writeStructEnd() { + writeTags_.pop(); + return true; + } + + bool writeField(PyObject* value, const StructItemSpec& spec) { + if (spec.type == T_BOOL) { + doWriteFieldBegin(spec, PyObject_IsTrue(value) ? CT_BOOLEAN_TRUE : CT_BOOLEAN_FALSE); + return true; + } else { + doWriteFieldBegin(spec, toCompactType(spec.type)); + return encodeValue(value, spec.type, spec.typeargs); + } + } + + void writeFieldStop() { writeByte(0); } + + bool readBool(bool& val) { + if (readBool_.exists) { + readBool_.exists = false; + val = readBool_.value; + return true; + } + char* buf; + if (!readBytes(&buf, 1)) { + return false; + } + val = buf[0] == CT_BOOLEAN_TRUE; + return true; + } + bool readI8(int8_t& val) { + char* buf; + if (!readBytes(&buf, 1)) { + return false; + } + val = buf[0]; + return true; + } + + bool readI16(int16_t& val) { + uint16_t uval; + if (readVarint(uval)) { + val = fromZigZag(uval); + return true; + } + return false; + } + + bool readI32(int32_t& val) { + uint32_t uval; + if (readVarint(uval)) { + val = fromZigZag(uval); + return true; + } + return false; + } + + bool readI64(int64_t& val) { + uint64_t uval; + if (readVarint(uval)) { + val = fromZigZag(uval); + return true; + } + return false; + } + + bool readDouble(double& val) { + union { + int64_t f; + double t; + } transfer; + + char* buf; + if (!readBytes(&buf, 8)) { + return false; + } + memcpy(&transfer.f, buf, sizeof(int64_t)); + transfer.f = letohll(transfer.f); + val = transfer.t; + return true; + } + + int32_t readString(char** buf) { + uint32_t len; + if (!readVarint(len) || !checkLengthLimit(len, stringLimit())) { + return -1; + } + if (len == 0) { + return 0; + } + if (!readBytes(buf, len)) { + return -1; + } + return len; + } + + int32_t readListBegin(TType& etype) { + uint8_t b; + if (!readByte(b)) { + return -1; + } + etype = getTType(b & 0xf); + if (etype == -1) { + return -1; + } + uint32_t len = (b >> 4) & 0xf; + if (len == 15 && !readVarint(len)) { + return -1; + } + if (!checkLengthLimit(len, containerLimit())) { + return -1; + } + return len; + } + + int32_t readMapBegin(TType& ktype, TType& vtype) { + uint32_t len; + if (!readVarint(len) || !checkLengthLimit(len, containerLimit())) { + return -1; + } + if (len != 0) { + uint8_t kvType; + if (!readByte(kvType)) { + return -1; + } + ktype = getTType(kvType >> 4); + vtype = getTType(kvType & 0xf); + if (ktype == -1 || vtype == -1) { + return -1; + } + } + return len; + } + + bool readStructBegin() { + readTags_.push(0); + return true; + } + bool readStructEnd() { + readTags_.pop(); + return true; + } + bool readFieldBegin(TType& type, int16_t& tag); + + bool skipBool() { + bool val; + return readBool(val); + } +#define SKIPBYTES(n) \ + do { \ + if (!readBytes(&dummy_buf_, (n))) { \ + return false; \ + } \ + return true; \ + } while (0) + bool skipByte() { SKIPBYTES(1); } + bool skipDouble() { SKIPBYTES(8); } + bool skipI16() { + int16_t val; + return readI16(val); + } + bool skipI32() { + int32_t val; + return readI32(val); + } + bool skipI64() { + int64_t val; + return readI64(val); + } + bool skipString() { + uint32_t len; + if (!readVarint(len)) { + return false; + } + SKIPBYTES(len); + } +#undef SKIPBYTES + +private: + enum Types { + CT_STOP = 0x00, + CT_BOOLEAN_TRUE = 0x01, + CT_BOOLEAN_FALSE = 0x02, + CT_BYTE = 0x03, + CT_I16 = 0x04, + CT_I32 = 0x05, + CT_I64 = 0x06, + CT_DOUBLE = 0x07, + CT_BINARY = 0x08, + CT_LIST = 0x09, + CT_SET = 0x0A, + CT_MAP = 0x0B, + CT_STRUCT = 0x0C + }; + + static const uint8_t TTypeToCType[]; + + TType getTType(uint8_t type); + + int toCompactType(TType type) { + int i = static_cast(type); + return i < 16 ? TTypeToCType[i] : -1; + } + + uint32_t toZigZag(int32_t val) { return (val >> 31) ^ (val << 1); } + + uint64_t toZigZag64(int64_t val) { return (val >> 63) ^ (val << 1); } + + int writeVarint(uint32_t val) { + int cnt = 1; + while (val & ~0x7fU) { + writeByte(static_cast((val & 0x7fU) | 0x80U)); + val >>= 7; + ++cnt; + } + writeByte(static_cast(val)); + return cnt; + } + + int writeVarint64(uint64_t val) { + int cnt = 1; + while (val & ~0x7fULL) { + writeByte(static_cast((val & 0x7fULL) | 0x80ULL)); + val >>= 7; + ++cnt; + } + writeByte(static_cast(val)); + return cnt; + } + + template + bool readVarint(T& result) { + uint8_t b; + T val = 0; + int shift = 0; + for (int i = 0; i < Max; ++i) { + if (!readByte(b)) { + return false; + } + if (b & 0x80) { + val |= static_cast(b & 0x7f) << shift; + } else { + val |= static_cast(b) << shift; + result = val; + return true; + } + shift += 7; + } + PyErr_Format(PyExc_OverflowError, "varint exceeded %d bytes", Max); + return false; + } + + template + S fromZigZag(U val) { + return (val >> 1) ^ static_cast(-static_cast(val & 1)); + } + + void doWriteFieldBegin(const StructItemSpec& spec, int ctype) { + int diff = spec.tag - writeTags_.top(); + if (diff > 0 && diff <= 15) { + writeByte(static_cast(diff << 4 | ctype)); + } else { + writeByte(static_cast(ctype)); + writeI16(spec.tag); + } + writeTags_.top() = spec.tag; + } + + std::stack writeTags_; + std::stack readTags_; + struct { + bool exists; + bool value; + } readBool_; + char* dummy_buf_; +}; +} +} +} +#endif // THRIFT_PY_COMPACT_H diff --git a/lib/py/src/ext/endian.h b/lib/py/src/ext/endian.h new file mode 100644 index 0000000..91372a7 --- /dev/null +++ b/lib/py/src/ext/endian.h @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef THRIFT_PY_ENDIAN_H +#define THRIFT_PY_ENDIAN_H + +#include + +#ifndef _WIN32 +#include +#else +#include +#pragma comment(lib, "ws2_32.lib") +#define BIG_ENDIAN (4321) +#define LITTLE_ENDIAN (1234) +#define BYTE_ORDER LITTLE_ENDIAN +#define inline __inline +#endif + +/* Fix endianness issues on Solaris */ +#if defined(__SVR4) && defined(__sun) +#if defined(__i386) && !defined(__i386__) +#define __i386__ +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN (4321) +#endif +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN (1234) +#endif + +/* I386 is LE, even on Solaris */ +#if !defined(BYTE_ORDER) && defined(__i386__) +#define BYTE_ORDER LITTLE_ENDIAN +#endif +#endif + +#ifndef __BYTE_ORDER +#if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) +#define __BYTE_ORDER BYTE_ORDER +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#define __BIG_ENDIAN BIG_ENDIAN +#else +#error "Cannot determine endianness" +#endif +#endif + +// Same comment as the enum. Sorry. +#if __BYTE_ORDER == __BIG_ENDIAN +#define ntohll(n) (n) +#define htonll(n) (n) +#if defined(__GNUC__) && defined(__GLIBC__) +#include +#define letohll(n) bswap_64(n) +#define htolell(n) bswap_64(n) +#else /* GNUC & GLIBC */ +#define letohll(n) ((((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32)) +#define htolell(n) ((((unsigned long long)htonl(n)) << 32) + htonl(n >> 32)) +#endif +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#if defined(__GNUC__) && defined(__GLIBC__) +#include +#define ntohll(n) bswap_64(n) +#define htonll(n) bswap_64(n) +#else /* GNUC & GLIBC */ +#define ntohll(n) ((((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32)) +#define htonll(n) ((((unsigned long long)htonl(n)) << 32) + htonl(n >> 32)) +#endif /* GNUC & GLIBC */ +#define letohll(n) (n) +#define htolell(n) (n) +#else /* __BYTE_ORDER */ +#error "Can't define htonll or ntohll!" +#endif + +#endif // THRIFT_PY_ENDIAN_H diff --git a/lib/py/src/ext/module.cpp b/lib/py/src/ext/module.cpp new file mode 100644 index 0000000..7158b8f --- /dev/null +++ b/lib/py/src/ext/module.cpp @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include "types.h" +#include "binary.h" +#include "compact.h" +#include +#include + +// TODO(dreiss): defval appears to be unused. Look into removing it. +// TODO(dreiss): Make parse_spec_args recursive, and cache the output +// permanently in the object. (Malloc and orphan.) +// TODO(dreiss): Why do we need cStringIO for reading, why not just char*? +// Can cStringIO let us work with a BufferedTransport? +// TODO(dreiss): Don't ignore the rv from cwrite (maybe). + +// Doing a benchmark shows that interning actually makes a difference, amazingly. + +/** Pointer to interned string to speed up attribute lookup. */ +PyObject* INTERN_STRING(TFrozenDict); +PyObject* INTERN_STRING(cstringio_buf); +PyObject* INTERN_STRING(cstringio_refill); +static PyObject* INTERN_STRING(string_length_limit); +static PyObject* INTERN_STRING(container_length_limit); +static PyObject* INTERN_STRING(trans); + +namespace apache { +namespace thrift { +namespace py { + +template +static PyObject* encode_impl(PyObject* args) { + if (!args) + return NULL; + + PyObject* enc_obj = NULL; + PyObject* type_args = NULL; + if (!PyArg_ParseTuple(args, "OO", &enc_obj, &type_args)) { + return NULL; + } + if (!enc_obj || !type_args) { + return NULL; + } + + T protocol; + if (!protocol.prepareEncodeBuffer() || !protocol.encodeValue(enc_obj, T_STRUCT, type_args)) { + return NULL; + } + + return protocol.getEncodedValue(); +} + +static inline long as_long_then_delete(PyObject* value, long default_value) { + ScopedPyObject scope(value); + long v = PyInt_AsLong(value); + if (INT_CONV_ERROR_OCCURRED(v)) { + PyErr_Clear(); + return default_value; + } + return v; +} + +template +static PyObject* decode_impl(PyObject* args) { + PyObject* output_obj = NULL; + PyObject* oprot = NULL; + PyObject* typeargs = NULL; + if (!PyArg_ParseTuple(args, "OOO", &output_obj, &oprot, &typeargs)) { + return NULL; + } + + T protocol; + int32_t default_limit = (std::numeric_limits::max)(); + protocol.setStringLengthLimit( + as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(string_length_limit)), + default_limit)); + protocol.setContainerLengthLimit( + as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(container_length_limit)), + default_limit)); + ScopedPyObject transport(PyObject_GetAttr(oprot, INTERN_STRING(trans))); + if (!transport) { + return NULL; + } + + StructTypeArgs parsedargs; + if (!parse_struct_args(&parsedargs, typeargs)) { + return NULL; + } + + if (!protocol.prepareDecodeBufferFromTransport(transport.get())) { + return NULL; + } + + return protocol.readStruct(output_obj, parsedargs.klass, parsedargs.spec); +} +} +} +} + +using namespace apache::thrift::py; + +/* -- PYTHON MODULE SETUP STUFF --- */ + +extern "C" { + +static PyObject* encode_binary(PyObject*, PyObject* args) { + return encode_impl(args); +} + +static PyObject* decode_binary(PyObject*, PyObject* args) { + return decode_impl(args); +} + +static PyObject* encode_compact(PyObject*, PyObject* args) { + return encode_impl(args); +} + +static PyObject* decode_compact(PyObject*, PyObject* args) { + return decode_impl(args); +} + +static PyMethodDef ThriftFastBinaryMethods[] = { + {"encode_binary", encode_binary, METH_VARARGS, ""}, + {"decode_binary", decode_binary, METH_VARARGS, ""}, + {"encode_compact", encode_compact, METH_VARARGS, ""}, + {"decode_compact", decode_compact, METH_VARARGS, ""}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +#if PY_MAJOR_VERSION >= 3 + +static struct PyModuleDef ThriftFastBinaryDef = {PyModuleDef_HEAD_INIT, + "thrift.protocol.fastbinary", + NULL, + 0, + ThriftFastBinaryMethods, + NULL, + NULL, + NULL, + NULL}; + +#define INITERROR return NULL; + +PyObject* PyInit_fastbinary() { + +#else + +#define INITERROR return; + +void initfastbinary() { + + PycString_IMPORT; + if (PycStringIO == NULL) + INITERROR + +#endif + +#define INIT_INTERN_STRING(value) \ + do { \ + INTERN_STRING(value) = PyString_InternFromString(#value); \ + if (!INTERN_STRING(value)) \ + INITERROR \ + } while (0) + + INIT_INTERN_STRING(TFrozenDict); + INIT_INTERN_STRING(cstringio_buf); + INIT_INTERN_STRING(cstringio_refill); + INIT_INTERN_STRING(string_length_limit); + INIT_INTERN_STRING(container_length_limit); + INIT_INTERN_STRING(trans); +#undef INIT_INTERN_STRING + + PyObject* module = +#if PY_MAJOR_VERSION >= 3 + PyModule_Create(&ThriftFastBinaryDef); +#else + Py_InitModule("thrift.protocol.fastbinary", ThriftFastBinaryMethods); +#endif + if (module == NULL) + INITERROR; + +#if PY_MAJOR_VERSION >= 3 + return module; +#endif +} +} diff --git a/lib/py/src/ext/protocol.h b/lib/py/src/ext/protocol.h new file mode 100644 index 0000000..126dbc3 --- /dev/null +++ b/lib/py/src/ext/protocol.h @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef THRIFT_PY_PROTOCOL_H +#define THRIFT_PY_PROTOCOL_H + +#include "ext/types.h" +#include +#include + +namespace apache { +namespace thrift { +namespace py { + +template +class ProtocolBase { + +public: + ProtocolBase() + : stringLimit_(std::numeric_limits::max()), + containerLimit_(std::numeric_limits::max()), + output_(NULL) {} + inline virtual ~ProtocolBase(); + + bool prepareDecodeBufferFromTransport(PyObject* trans); + + PyObject* readStruct(PyObject* output, PyObject* klass, PyObject* spec_seq); + + bool prepareEncodeBuffer(); + + bool encodeValue(PyObject* value, TType type, PyObject* typeargs); + + PyObject* getEncodedValue(); + + long stringLimit() const { return stringLimit_; } + void setStringLengthLimit(long limit) { stringLimit_ = limit; } + + long containerLimit() const { return containerLimit_; } + void setContainerLengthLimit(long limit) { containerLimit_ = limit; } + +protected: + bool readBytes(char** output, int len); + + bool readByte(uint8_t& val) { + char* buf; + if (!readBytes(&buf, 1)) { + return false; + } + val = static_cast(buf[0]); + return true; + } + + bool writeBuffer(char* data, size_t len); + + void writeByte(uint8_t val) { writeBuffer(reinterpret_cast(&val), 1); } + + PyObject* decodeValue(TType type, PyObject* typeargs); + + bool skip(TType type); + + inline bool checkType(TType got, TType expected); + inline bool checkLengthLimit(int32_t len, long limit); + + inline bool isUtf8(PyObject* typeargs); + +private: + Impl* impl() { return static_cast(this); } + + long stringLimit_; + long containerLimit_; + EncodeBuffer* output_; + DecodeBuffer input_; +}; +} +} +} + +#include "ext/protocol.tcc" + +#endif // THRIFT_PY_PROTOCOL_H diff --git a/lib/py/src/ext/protocol.tcc b/lib/py/src/ext/protocol.tcc new file mode 100644 index 0000000..c025d0c --- /dev/null +++ b/lib/py/src/ext/protocol.tcc @@ -0,0 +1,913 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef THRIFT_PY_PROTOCOL_TCC +#define THRIFT_PY_PROTOCOL_TCC + +#include + +#define CHECK_RANGE(v, min, max) (((v) <= (max)) && ((v) >= (min))) +#define INIT_OUTBUF_SIZE 128 + +#if PY_MAJOR_VERSION < 3 +#include +#else +#include +#endif + +namespace apache { +namespace thrift { +namespace py { + +#if PY_MAJOR_VERSION < 3 + +namespace detail { + +inline bool input_check(PyObject* input) { + return PycStringIO_InputCheck(input); +} + +inline EncodeBuffer* new_encode_buffer(size_t size) { + if (!PycStringIO) { + PycString_IMPORT; + } + if (!PycStringIO) { + return NULL; + } + return PycStringIO->NewOutput(size); +} + +inline int read_buffer(PyObject* buf, char** output, int len) { + if (!PycStringIO) { + PycString_IMPORT; + } + if (!PycStringIO) { + PyErr_SetString(PyExc_ImportError, "failed to import native cStringIO"); + return -1; + } + return PycStringIO->cread(buf, output, len); +} +} + +template +inline ProtocolBase::~ProtocolBase() { + if (output_) { + Py_CLEAR(output_); + } +} + +template +inline bool ProtocolBase::isUtf8(PyObject* typeargs) { + return PyString_Check(typeargs) && !strncmp(PyString_AS_STRING(typeargs), "UTF8", 4); +} + +template +PyObject* ProtocolBase::getEncodedValue() { + if (!PycStringIO) { + PycString_IMPORT; + } + if (!PycStringIO) { + return NULL; + } + return PycStringIO->cgetvalue(output_); +} + +template +inline bool ProtocolBase::writeBuffer(char* data, size_t size) { + if (!PycStringIO) { + PycString_IMPORT; + } + if (!PycStringIO) { + PyErr_SetString(PyExc_ImportError, "failed to import native cStringIO"); + return false; + } + int len = PycStringIO->cwrite(output_, data, size); + if (len < 0) { + PyErr_SetString(PyExc_IOError, "failed to write to cStringIO object"); + return false; + } + if (static_cast(len) != size) { + PyErr_Format(PyExc_EOFError, "write length mismatch: expected %lu got %d", size, len); + return false; + } + return true; +} + +#else + +namespace detail { + +inline bool input_check(PyObject* input) { + // TODO: Check for BytesIO type + return true; +} + +inline EncodeBuffer* new_encode_buffer(size_t size) { + EncodeBuffer* buffer = new EncodeBuffer; + buffer->buf.reserve(size); + buffer->pos = 0; + return buffer; +} + +struct bytesio { + PyObject_HEAD +#if PY_MINOR_VERSION < 5 + char* buf; +#else + PyObject* buf; +#endif + Py_ssize_t pos; + Py_ssize_t string_size; +}; + +inline int read_buffer(PyObject* buf, char** output, int len) { + bytesio* buf2 = reinterpret_cast(buf); +#if PY_MINOR_VERSION < 5 + *output = buf2->buf + buf2->pos; +#else + *output = PyBytes_AS_STRING(buf2->buf) + buf2->pos; +#endif + Py_ssize_t pos0 = buf2->pos; + buf2->pos = std::min(buf2->pos + static_cast(len), buf2->string_size); + return static_cast(buf2->pos - pos0); +} +} + +template +inline ProtocolBase::~ProtocolBase() { + if (output_) { + delete output_; + } +} + +template +inline bool ProtocolBase::isUtf8(PyObject* typeargs) { + // while condition for py2 is "arg == 'UTF8'", it should be "arg != 'BINARY'" for py3. + // HACK: check the length and don't bother reading the value + return !PyUnicode_Check(typeargs) || PyUnicode_GET_LENGTH(typeargs) != 6; +} + +template +PyObject* ProtocolBase::getEncodedValue() { + return PyBytes_FromStringAndSize(output_->buf.data(), output_->buf.size()); +} + +template +inline bool ProtocolBase::writeBuffer(char* data, size_t size) { + size_t need = size + output_->pos; + if (output_->buf.capacity() < need) { + try { + output_->buf.reserve(need); + } catch (std::bad_alloc& ex) { + PyErr_SetString(PyExc_MemoryError, "Failed to allocate write buffer"); + return false; + } + } + std::copy(data, data + size, std::back_inserter(output_->buf)); + return true; +} + +#endif + +namespace detail { + +#define DECLARE_OP_SCOPE(name, op) \ + template \ + struct name##Scope { \ + Impl* impl; \ + bool valid; \ + name##Scope(Impl* thiz) : impl(thiz), valid(impl->op##Begin()) {} \ + ~name##Scope() { \ + if (valid) \ + impl->op##End(); \ + } \ + operator bool() { return valid; } \ + }; \ + template class T> \ + name##Scope op##Scope(T* thiz) { \ + return name##Scope(static_cast(thiz)); \ + } +DECLARE_OP_SCOPE(WriteStruct, writeStruct) +DECLARE_OP_SCOPE(ReadStruct, readStruct) +#undef DECLARE_OP_SCOPE + +inline bool check_ssize_t_32(Py_ssize_t len) { + // error from getting the int + if (INT_CONV_ERROR_OCCURRED(len)) { + return false; + } + if (!CHECK_RANGE(len, 0, std::numeric_limits::max())) { + PyErr_SetString(PyExc_OverflowError, "size out of range: exceeded INT32_MAX"); + return false; + } + return true; +} +} + +template +bool parse_pyint(PyObject* o, T* ret, int32_t min, int32_t max) { + long val = PyInt_AsLong(o); + + if (INT_CONV_ERROR_OCCURRED(val)) { + return false; + } + if (!CHECK_RANGE(val, min, max)) { + PyErr_SetString(PyExc_OverflowError, "int out of range"); + return false; + } + + *ret = static_cast(val); + return true; +} + +template +inline bool ProtocolBase::checkType(TType got, TType expected) { + if (expected != got) { + PyErr_SetString(PyExc_TypeError, "got wrong ttype while reading field"); + return false; + } + return true; +} + +template +bool ProtocolBase::checkLengthLimit(int32_t len, long limit) { + if (len < 0) { + PyErr_Format(PyExc_OverflowError, "negative length: %ld", limit); + return false; + } + if (len > limit) { + PyErr_Format(PyExc_OverflowError, "size exceeded specified limit: %ld", limit); + return false; + } + return true; +} + +template +bool ProtocolBase::readBytes(char** output, int len) { + if (len < 0) { + PyErr_Format(PyExc_ValueError, "attempted to read negative length: %d", len); + return false; + } + // TODO(dreiss): Don't fear the malloc. Think about taking a copy of + // the partial read instead of forcing the transport + // to prepend it to its buffer. + + int rlen = detail::read_buffer(input_.stringiobuf.get(), output, len); + + if (rlen == len) { + return true; + } else if (rlen == -1) { + return false; + } else { + // using building functions as this is a rare codepath + ScopedPyObject newiobuf(PyObject_CallFunction(input_.refill_callable.get(), refill_signature, + *output, rlen, len, NULL)); + if (!newiobuf) { + return false; + } + + // must do this *AFTER* the call so that we don't deref the io buffer + input_.stringiobuf.reset(newiobuf.release()); + + rlen = detail::read_buffer(input_.stringiobuf.get(), output, len); + + if (rlen == len) { + return true; + } else if (rlen == -1) { + return false; + } else { + // TODO(dreiss): This could be a valid code path for big binary blobs. + PyErr_SetString(PyExc_TypeError, "refill claimed to have refilled the buffer, but didn't!!"); + return false; + } + } +} + +template +bool ProtocolBase::prepareDecodeBufferFromTransport(PyObject* trans) { + if (input_.stringiobuf) { + PyErr_SetString(PyExc_ValueError, "decode buffer is already initialized"); + return false; + } + + ScopedPyObject stringiobuf(PyObject_GetAttr(trans, INTERN_STRING(cstringio_buf))); + if (!stringiobuf) { + return false; + } + if (!detail::input_check(stringiobuf.get())) { + PyErr_SetString(PyExc_TypeError, "expecting stringio input_"); + return false; + } + + ScopedPyObject refill_callable(PyObject_GetAttr(trans, INTERN_STRING(cstringio_refill))); + if (!refill_callable) { + return false; + } + if (!PyCallable_Check(refill_callable.get())) { + PyErr_SetString(PyExc_TypeError, "expecting callable"); + return false; + } + + input_.stringiobuf.swap(stringiobuf); + input_.refill_callable.swap(refill_callable); + return true; +} + +template +bool ProtocolBase::prepareEncodeBuffer() { + output_ = detail::new_encode_buffer(INIT_OUTBUF_SIZE); + return output_ != NULL; +} + +template +bool ProtocolBase::encodeValue(PyObject* value, TType type, PyObject* typeargs) { + /* + * Refcounting Strategy: + * + * We assume that elements of the thrift_spec tuple are not going to be + * mutated, so we don't ref count those at all. Other than that, we try to + * keep a reference to all the user-created objects while we work with them. + * encodeValue assumes that a reference is already held. The *caller* is + * responsible for handling references + */ + + switch (type) { + + case T_BOOL: { + int v = PyObject_IsTrue(value); + if (v == -1) { + return false; + } + impl()->writeBool(v); + return true; + } + case T_I08: { + int8_t val; + + if (!parse_pyint(value, &val, std::numeric_limits::min(), + std::numeric_limits::max())) { + return false; + } + + impl()->writeI8(val); + return true; + } + case T_I16: { + int16_t val; + + if (!parse_pyint(value, &val, std::numeric_limits::min(), + std::numeric_limits::max())) { + return false; + } + + impl()->writeI16(val); + return true; + } + case T_I32: { + int32_t val; + + if (!parse_pyint(value, &val, std::numeric_limits::min(), + std::numeric_limits::max())) { + return false; + } + + impl()->writeI32(val); + return true; + } + case T_I64: { + int64_t nval = PyLong_AsLongLong(value); + + if (INT_CONV_ERROR_OCCURRED(nval)) { + return false; + } + + if (!CHECK_RANGE(nval, std::numeric_limits::min(), + std::numeric_limits::max())) { + PyErr_SetString(PyExc_OverflowError, "int out of range"); + return false; + } + + impl()->writeI64(nval); + return true; + } + + case T_DOUBLE: { + double nval = PyFloat_AsDouble(value); + if (nval == -1.0 && PyErr_Occurred()) { + return false; + } + + impl()->writeDouble(nval); + return true; + } + + case T_STRING: { + ScopedPyObject nval; + + if (PyUnicode_Check(value)) { + nval.reset(PyUnicode_AsUTF8String(value)); + if (!nval) { + return false; + } + } else { + Py_INCREF(value); + nval.reset(value); + } + + Py_ssize_t len = PyBytes_Size(nval.get()); + if (!detail::check_ssize_t_32(len)) { + return false; + } + + impl()->writeString(nval.get(), static_cast(len)); + return true; + } + + case T_LIST: + case T_SET: { + SetListTypeArgs parsedargs; + if (!parse_set_list_args(&parsedargs, typeargs)) { + return false; + } + + Py_ssize_t len = PyObject_Length(value); + if (!detail::check_ssize_t_32(len)) { + return false; + } + + if (!impl()->writeListBegin(value, parsedargs, static_cast(len)) || PyErr_Occurred()) { + return false; + } + ScopedPyObject iterator(PyObject_GetIter(value)); + if (!iterator) { + return false; + } + + while (PyObject* rawItem = PyIter_Next(iterator.get())) { + ScopedPyObject item(rawItem); + if (!encodeValue(item.get(), parsedargs.element_type, parsedargs.typeargs)) { + return false; + } + } + + return true; + } + + case T_MAP: { + Py_ssize_t len = PyDict_Size(value); + if (!detail::check_ssize_t_32(len)) { + return false; + } + + MapTypeArgs parsedargs; + if (!parse_map_args(&parsedargs, typeargs)) { + return false; + } + + if (!impl()->writeMapBegin(value, parsedargs, static_cast(len)) || PyErr_Occurred()) { + return false; + } + Py_ssize_t pos = 0; + PyObject* k = NULL; + PyObject* v = NULL; + // TODO(bmaurer): should support any mapping, not just dicts + while (PyDict_Next(value, &pos, &k, &v)) { + if (!encodeValue(k, parsedargs.ktag, parsedargs.ktypeargs) + || !encodeValue(v, parsedargs.vtag, parsedargs.vtypeargs)) { + return false; + } + } + return true; + } + + case T_STRUCT: { + StructTypeArgs parsedargs; + if (!parse_struct_args(&parsedargs, typeargs)) { + return false; + } + + Py_ssize_t nspec = PyTuple_Size(parsedargs.spec); + if (nspec == -1) { + PyErr_SetString(PyExc_TypeError, "spec is not a tuple"); + return false; + } + + detail::WriteStructScope scope = detail::writeStructScope(this); + if (!scope) { + return false; + } + for (Py_ssize_t i = 0; i < nspec; i++) { + PyObject* spec_tuple = PyTuple_GET_ITEM(parsedargs.spec, i); + if (spec_tuple == Py_None) { + continue; + } + + StructItemSpec parsedspec; + if (!parse_struct_item_spec(&parsedspec, spec_tuple)) { + return false; + } + + ScopedPyObject instval(PyObject_GetAttr(value, parsedspec.attrname)); + + if (!instval) { + return false; + } + + if (instval.get() == Py_None) { + continue; + } + + bool res = impl()->writeField(instval.get(), parsedspec); + if (!res) { + return false; + } + } + impl()->writeFieldStop(); + return true; + } + + case T_STOP: + case T_VOID: + case T_UTF16: + case T_UTF8: + case T_U64: + default: + PyErr_Format(PyExc_TypeError, "Unexpected TType for encodeValue: %d", type); + return false; + } + + return true; +} + +template +bool ProtocolBase::skip(TType type) { + switch (type) { + case T_BOOL: + return impl()->skipBool(); + case T_I08: + return impl()->skipByte(); + case T_I16: + return impl()->skipI16(); + case T_I32: + return impl()->skipI32(); + case T_I64: + return impl()->skipI64(); + case T_DOUBLE: + return impl()->skipDouble(); + + case T_STRING: { + return impl()->skipString(); + } + + case T_LIST: + case T_SET: { + TType etype = T_STOP; + int32_t len = impl()->readListBegin(etype); + if (len < 0) { + return false; + } + for (int32_t i = 0; i < len; i++) { + if (!skip(etype)) { + return false; + } + } + return true; + } + + case T_MAP: { + TType ktype = T_STOP; + TType vtype = T_STOP; + int32_t len = impl()->readMapBegin(ktype, vtype); + if (len < 0) { + return false; + } + for (int32_t i = 0; i < len; i++) { + if (!skip(ktype) || !skip(vtype)) { + return false; + } + } + return true; + } + + case T_STRUCT: { + detail::ReadStructScope scope = detail::readStructScope(this); + if (!scope) { + return false; + } + while (true) { + TType type = T_STOP; + int16_t tag; + if (!impl()->readFieldBegin(type, tag)) { + return false; + } + if (type == T_STOP) { + return true; + } + if (!skip(type)) { + return false; + } + } + return true; + } + + case T_STOP: + case T_VOID: + case T_UTF16: + case T_UTF8: + case T_U64: + default: + PyErr_Format(PyExc_TypeError, "Unexpected TType for skip: %d", type); + return false; + } + + return true; +} + +// Returns a new reference. +template +PyObject* ProtocolBase::decodeValue(TType type, PyObject* typeargs) { + switch (type) { + + case T_BOOL: { + bool v = 0; + if (!impl()->readBool(v)) { + return NULL; + } + if (v) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } + case T_I08: { + int8_t v = 0; + if (!impl()->readI8(v)) { + return NULL; + } + return PyInt_FromLong(v); + } + case T_I16: { + int16_t v = 0; + if (!impl()->readI16(v)) { + return NULL; + } + return PyInt_FromLong(v); + } + case T_I32: { + int32_t v = 0; + if (!impl()->readI32(v)) { + return NULL; + } + return PyInt_FromLong(v); + } + + case T_I64: { + int64_t v = 0; + if (!impl()->readI64(v)) { + return NULL; + } + // TODO(dreiss): Find out if we can take this fastpath always when + // sizeof(long) == sizeof(long long). + if (CHECK_RANGE(v, LONG_MIN, LONG_MAX)) { + return PyInt_FromLong((long)v); + } + return PyLong_FromLongLong(v); + } + + case T_DOUBLE: { + double v = 0.0; + if (!impl()->readDouble(v)) { + return NULL; + } + return PyFloat_FromDouble(v); + } + + case T_STRING: { + char* buf = NULL; + int len = impl()->readString(&buf); + if (len < 0) { + return NULL; + } + if (isUtf8(typeargs)) { + return PyUnicode_DecodeUTF8(buf, len, 0); + } else { + return PyBytes_FromStringAndSize(buf, len); + } + } + + case T_LIST: + case T_SET: { + SetListTypeArgs parsedargs; + if (!parse_set_list_args(&parsedargs, typeargs)) { + return NULL; + } + + TType etype = T_STOP; + int32_t len = impl()->readListBegin(etype); + if (len < 0) { + return NULL; + } + if (len > 0 && !checkType(etype, parsedargs.element_type)) { + return NULL; + } + + bool use_tuple = type == T_LIST && parsedargs.immutable; + ScopedPyObject ret(use_tuple ? PyTuple_New(len) : PyList_New(len)); + if (!ret) { + return NULL; + } + + for (int i = 0; i < len; i++) { + PyObject* item = decodeValue(etype, parsedargs.typeargs); + if (!item) { + return NULL; + } + if (use_tuple) { + PyTuple_SET_ITEM(ret.get(), i, item); + } else { + PyList_SET_ITEM(ret.get(), i, item); + } + } + + // TODO(dreiss): Consider biting the bullet and making two separate cases + // for list and set, avoiding this post facto conversion. + if (type == T_SET) { + PyObject* setret; + setret = parsedargs.immutable ? PyFrozenSet_New(ret.get()) : PySet_New(ret.get()); + return setret; + } + return ret.release(); + } + + case T_MAP: { + MapTypeArgs parsedargs; + if (!parse_map_args(&parsedargs, typeargs)) { + return NULL; + } + + TType ktype = T_STOP; + TType vtype = T_STOP; + uint32_t len = impl()->readMapBegin(ktype, vtype); + if (len > 0 && (!checkType(ktype, parsedargs.ktag) || !checkType(vtype, parsedargs.vtag))) { + return NULL; + } + + ScopedPyObject ret(PyDict_New()); + if (!ret) { + return NULL; + } + + for (uint32_t i = 0; i < len; i++) { + ScopedPyObject k(decodeValue(ktype, parsedargs.ktypeargs)); + if (!k) { + return NULL; + } + ScopedPyObject v(decodeValue(vtype, parsedargs.vtypeargs)); + if (!v) { + return NULL; + } + if (PyDict_SetItem(ret.get(), k.get(), v.get()) == -1) { + return NULL; + } + } + + if (parsedargs.immutable) { + if (!ThriftModule) { + ThriftModule = PyImport_ImportModule("thrift.Thrift"); + } + if (!ThriftModule) { + return NULL; + } + + ScopedPyObject cls(PyObject_GetAttr(ThriftModule, INTERN_STRING(TFrozenDict))); + if (!cls) { + return NULL; + } + + ScopedPyObject arg(PyTuple_New(1)); + PyTuple_SET_ITEM(arg.get(), 0, ret.release()); + ret.reset(PyObject_CallObject(cls.get(), arg.get())); + } + + return ret.release(); + } + + case T_STRUCT: { + StructTypeArgs parsedargs; + if (!parse_struct_args(&parsedargs, typeargs)) { + return NULL; + } + return readStruct(Py_None, parsedargs.klass, parsedargs.spec); + } + + case T_STOP: + case T_VOID: + case T_UTF16: + case T_UTF8: + case T_U64: + default: + PyErr_Format(PyExc_TypeError, "Unexpected TType for decodeValue: %d", type); + return NULL; + } +} + +template +PyObject* ProtocolBase::readStruct(PyObject* output, PyObject* klass, PyObject* spec_seq) { + int spec_seq_len = PyTuple_Size(spec_seq); + bool immutable = output == Py_None; + ScopedPyObject kwargs; + if (spec_seq_len == -1) { + return NULL; + } + + if (immutable) { + kwargs.reset(PyDict_New()); + if (!kwargs) { + PyErr_SetString(PyExc_TypeError, "failed to prepare kwargument storage"); + return NULL; + } + } + + detail::ReadStructScope scope = detail::readStructScope(this); + if (!scope) { + return NULL; + } + while (true) { + TType type = T_STOP; + int16_t tag; + if (!impl()->readFieldBegin(type, tag)) { + return NULL; + } + if (type == T_STOP) { + break; + } + if (tag < 0 || tag >= spec_seq_len) { + if (!skip(type)) { + PyErr_SetString(PyExc_TypeError, "Error while skipping unknown field"); + return NULL; + } + continue; + } + + PyObject* item_spec = PyTuple_GET_ITEM(spec_seq, tag); + if (item_spec == Py_None) { + if (!skip(type)) { + PyErr_SetString(PyExc_TypeError, "Error while skipping unknown field"); + return NULL; + } + continue; + } + StructItemSpec parsedspec; + if (!parse_struct_item_spec(&parsedspec, item_spec)) { + return NULL; + } + if (parsedspec.type != type) { + if (!skip(type)) { + PyErr_Format(PyExc_TypeError, "struct field had wrong type: expected %d but got %d", + parsedspec.type, type); + return NULL; + } + continue; + } + + ScopedPyObject fieldval(decodeValue(parsedspec.type, parsedspec.typeargs)); + if (!fieldval) { + return NULL; + } + + if ((immutable && PyDict_SetItem(kwargs.get(), parsedspec.attrname, fieldval.get()) == -1) + || (!immutable && PyObject_SetAttr(output, parsedspec.attrname, fieldval.get()) == -1)) { + return NULL; + } + } + if (immutable) { + ScopedPyObject args(PyTuple_New(0)); + if (!args) { + PyErr_SetString(PyExc_TypeError, "failed to prepare argument storage"); + return NULL; + } + return PyObject_Call(klass, args.get(), kwargs.get()); + } + Py_INCREF(output); + return output; +} +} +} +} +#endif // THRIFT_PY_PROTOCOL_H diff --git a/lib/py/src/ext/types.cpp b/lib/py/src/ext/types.cpp new file mode 100644 index 0000000..68443fb --- /dev/null +++ b/lib/py/src/ext/types.cpp @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "ext/types.h" +#include "ext/protocol.h" + +namespace apache { +namespace thrift { +namespace py { + +PyObject* ThriftModule = NULL; + +#if PY_MAJOR_VERSION < 3 +char refill_signature[] = {'s', '#', 'i'}; +#else +const char* refill_signature = "y#i"; +#endif + +bool parse_struct_item_spec(StructItemSpec* dest, PyObject* spec_tuple) { + // i'd like to use ParseArgs here, but it seems to be a bottleneck. + if (PyTuple_Size(spec_tuple) != 5) { + PyErr_Format(PyExc_TypeError, "expecting 5 arguments for spec tuple but got %d", + static_cast(PyTuple_Size(spec_tuple))); + return false; + } + + dest->tag = static_cast(PyInt_AsLong(PyTuple_GET_ITEM(spec_tuple, 0))); + if (INT_CONV_ERROR_OCCURRED(dest->tag)) { + return false; + } + + dest->type = static_cast(PyInt_AsLong(PyTuple_GET_ITEM(spec_tuple, 1))); + if (INT_CONV_ERROR_OCCURRED(dest->type)) { + return false; + } + + dest->attrname = PyTuple_GET_ITEM(spec_tuple, 2); + dest->typeargs = PyTuple_GET_ITEM(spec_tuple, 3); + dest->defval = PyTuple_GET_ITEM(spec_tuple, 4); + return true; +} + +bool parse_set_list_args(SetListTypeArgs* dest, PyObject* typeargs) { + if (PyTuple_Size(typeargs) != 3) { + PyErr_SetString(PyExc_TypeError, "expecting tuple of size 3 for list/set type args"); + return false; + } + + dest->element_type = static_cast(PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 0))); + if (INT_CONV_ERROR_OCCURRED(dest->element_type)) { + return false; + } + + dest->typeargs = PyTuple_GET_ITEM(typeargs, 1); + + dest->immutable = Py_True == PyTuple_GET_ITEM(typeargs, 2); + + return true; +} + +bool parse_map_args(MapTypeArgs* dest, PyObject* typeargs) { + if (PyTuple_Size(typeargs) != 5) { + PyErr_SetString(PyExc_TypeError, "expecting 5 arguments for typeargs to map"); + return false; + } + + dest->ktag = static_cast(PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 0))); + if (INT_CONV_ERROR_OCCURRED(dest->ktag)) { + return false; + } + + dest->vtag = static_cast(PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 2))); + if (INT_CONV_ERROR_OCCURRED(dest->vtag)) { + return false; + } + + dest->ktypeargs = PyTuple_GET_ITEM(typeargs, 1); + dest->vtypeargs = PyTuple_GET_ITEM(typeargs, 3); + dest->immutable = Py_True == PyTuple_GET_ITEM(typeargs, 4); + + return true; +} + +bool parse_struct_args(StructTypeArgs* dest, PyObject* typeargs) { + if (PyList_Size(typeargs) != 2) { + PyErr_SetString(PyExc_TypeError, "expecting list of size 2 for struct args"); + return false; + } + + dest->klass = PyList_GET_ITEM(typeargs, 0); + dest->spec = PyList_GET_ITEM(typeargs, 1); + + return true; +} +} +} +} diff --git a/lib/py/src/ext/types.h b/lib/py/src/ext/types.h new file mode 100644 index 0000000..5cd8dda --- /dev/null +++ b/lib/py/src/ext/types.h @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef THRIFT_PY_TYPES_H +#define THRIFT_PY_TYPES_H + +#include + +#ifdef _MSC_VER +#define __STDC_FORMAT_MACROS +#define __STDC_LIMIT_MACROS +#endif +#include + +#if PY_MAJOR_VERSION >= 3 + +#include + +// TODO: better macros +#define PyInt_AsLong(v) PyLong_AsLong(v) +#define PyInt_FromLong(v) PyLong_FromLong(v) + +#define PyString_InternFromString(v) PyUnicode_InternFromString(v) + +#endif + +#define INTERN_STRING(value) _intern_##value + +#define INT_CONV_ERROR_OCCURRED(v) (((v) == -1) && PyErr_Occurred()) + +extern "C" { +extern PyObject* INTERN_STRING(TFrozenDict); +extern PyObject* INTERN_STRING(cstringio_buf); +extern PyObject* INTERN_STRING(cstringio_refill); +} + +namespace apache { +namespace thrift { +namespace py { + +extern PyObject* ThriftModule; + +// Stolen out of TProtocol.h. +// It would be a huge pain to have both get this from one place. +enum TType { + T_INVALID = -1, + T_STOP = 0, + T_VOID = 1, + T_BOOL = 2, + T_BYTE = 3, + T_I08 = 3, + T_I16 = 6, + T_I32 = 8, + T_U64 = 9, + T_I64 = 10, + T_DOUBLE = 4, + T_STRING = 11, + T_UTF7 = 11, + T_STRUCT = 12, + T_MAP = 13, + T_SET = 14, + T_LIST = 15, + T_UTF8 = 16, + T_UTF16 = 17 +}; + +// replace with unique_ptr when we're OK with C++11 +class ScopedPyObject { +public: + ScopedPyObject() : obj_(NULL) {} + explicit ScopedPyObject(PyObject* py_object) : obj_(py_object) {} + ~ScopedPyObject() { + if (obj_) + Py_DECREF(obj_); + } + PyObject* get() throw() { return obj_; } + operator bool() { return obj_; } + void reset(PyObject* py_object) throw() { + if (obj_) + Py_DECREF(obj_); + obj_ = py_object; + } + PyObject* release() throw() { + PyObject* tmp = obj_; + obj_ = NULL; + return tmp; + } + void swap(ScopedPyObject& other) throw() { + ScopedPyObject tmp(other.release()); + other.reset(release()); + reset(tmp.release()); + } + +private: + ScopedPyObject(const ScopedPyObject&) {} + ScopedPyObject& operator=(const ScopedPyObject&) { return *this; } + + PyObject* obj_; +}; + +/** + * A cache of the two key attributes of a CReadableTransport, + * so we don't have to keep calling PyObject_GetAttr. + */ +struct DecodeBuffer { + ScopedPyObject stringiobuf; + ScopedPyObject refill_callable; +}; + +#if PY_MAJOR_VERSION < 3 +extern char refill_signature[3]; +typedef PyObject EncodeBuffer; +#else +extern const char* refill_signature; +struct EncodeBuffer { + std::vector buf; + size_t pos; +}; +#endif + +/** + * A cache of the spec_args for a set or list, + * so we don't have to keep calling PyTuple_GET_ITEM. + */ +struct SetListTypeArgs { + TType element_type; + PyObject* typeargs; + bool immutable; +}; + +/** + * A cache of the spec_args for a map, + * so we don't have to keep calling PyTuple_GET_ITEM. + */ +struct MapTypeArgs { + TType ktag; + TType vtag; + PyObject* ktypeargs; + PyObject* vtypeargs; + bool immutable; +}; + +/** + * A cache of the spec_args for a struct, + * so we don't have to keep calling PyTuple_GET_ITEM. + */ +struct StructTypeArgs { + PyObject* klass; + PyObject* spec; + bool immutable; +}; + +/** + * A cache of the item spec from a struct specification, + * so we don't have to keep calling PyTuple_GET_ITEM. + */ +struct StructItemSpec { + int tag; + TType type; + PyObject* attrname; + PyObject* typeargs; + PyObject* defval; +}; + +bool parse_set_list_args(SetListTypeArgs* dest, PyObject* typeargs); + +bool parse_map_args(MapTypeArgs* dest, PyObject* typeargs); + +bool parse_struct_args(StructTypeArgs* dest, PyObject* typeargs); + +bool parse_struct_item_spec(StructItemSpec* dest, PyObject* spec_tuple); +} +} +} + +#endif // THRIFT_PY_TYPES_H diff --git a/lib/py/src/protocol/TBase.py b/lib/py/src/protocol/TBase.py new file mode 100644 index 0000000..9ae1b11 --- /dev/null +++ b/lib/py/src/protocol/TBase.py @@ -0,0 +1,82 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from thrift.transport import TTransport + + +class TBase(object): + __slots__ = () + + def __repr__(self): + L = ['%s=%r' % (key, getattr(self, key)) for key in self.__slots__] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return False + for attr in self.__slots__: + my_val = getattr(self, attr) + other_val = getattr(other, attr) + if my_val != other_val: + return False + return True + + def __ne__(self, other): + return not (self == other) + + def read(self, iprot): + if (iprot._fast_decode is not None and + isinstance(iprot.trans, TTransport.CReadableTransport) and + self.thrift_spec is not None): + iprot._fast_decode(self, iprot, [self.__class__, self.thrift_spec]) + else: + iprot.readStruct(self, self.thrift_spec) + + def write(self, oprot): + if (oprot._fast_encode is not None and self.thrift_spec is not None): + oprot.trans.write( + oprot._fast_encode(self, [self.__class__, self.thrift_spec])) + else: + oprot.writeStruct(self, self.thrift_spec) + + +class TExceptionBase(TBase, Exception): + pass + + +class TFrozenBase(TBase): + def __setitem__(self, *args): + raise TypeError("Can't modify frozen struct") + + def __delitem__(self, *args): + raise TypeError("Can't modify frozen struct") + + def __hash__(self, *args): + return hash(self.__class__) ^ hash(self.__slots__) + + @classmethod + def read(cls, iprot): + if (iprot._fast_decode is not None and + isinstance(iprot.trans, TTransport.CReadableTransport) and + cls.thrift_spec is not None): + self = cls() + return iprot._fast_decode(None, iprot, + [self.__class__, self.thrift_spec]) + else: + return iprot.readStruct(cls, cls.thrift_spec, True) diff --git a/lib/py/src/protocol/TBinaryProtocol.py b/lib/py/src/protocol/TBinaryProtocol.py new file mode 100644 index 0000000..f6be772 --- /dev/null +++ b/lib/py/src/protocol/TBinaryProtocol.py @@ -0,0 +1,301 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from .TProtocol import TType, TProtocolBase, TProtocolException +from struct import pack, unpack + + +class TBinaryProtocol(TProtocolBase): + """Binary implementation of the Thrift protocol driver.""" + + # NastyHaxx. Python 2.4+ on 32-bit machines forces hex constants to be + # positive, converting this into a long. If we hardcode the int value + # instead it'll stay in 32 bit-land. + + # VERSION_MASK = 0xffff0000 + VERSION_MASK = -65536 + + # VERSION_1 = 0x80010000 + VERSION_1 = -2147418112 + + TYPE_MASK = 0x000000ff + + def __init__(self, trans, strictRead=False, strictWrite=True, **kwargs): + TProtocolBase.__init__(self, trans) + self.strictRead = strictRead + self.strictWrite = strictWrite + self.string_length_limit = kwargs.get('string_length_limit', None) + self.container_length_limit = kwargs.get('container_length_limit', None) + + def _check_string_length(self, length): + self._check_length(self.string_length_limit, length) + + def _check_container_length(self, length): + self._check_length(self.container_length_limit, length) + + def writeMessageBegin(self, name, type, seqid): + if self.strictWrite: + self.writeI32(TBinaryProtocol.VERSION_1 | type) + self.writeString(name) + self.writeI32(seqid) + else: + self.writeString(name) + self.writeByte(type) + self.writeI32(seqid) + + def writeMessageEnd(self): + pass + + def writeStructBegin(self, name): + pass + + def writeStructEnd(self): + pass + + def writeFieldBegin(self, name, type, id): + self.writeByte(type) + self.writeI16(id) + + def writeFieldEnd(self): + pass + + def writeFieldStop(self): + self.writeByte(TType.STOP) + + def writeMapBegin(self, ktype, vtype, size): + self.writeByte(ktype) + self.writeByte(vtype) + self.writeI32(size) + + def writeMapEnd(self): + pass + + def writeListBegin(self, etype, size): + self.writeByte(etype) + self.writeI32(size) + + def writeListEnd(self): + pass + + def writeSetBegin(self, etype, size): + self.writeByte(etype) + self.writeI32(size) + + def writeSetEnd(self): + pass + + def writeBool(self, bool): + if bool: + self.writeByte(1) + else: + self.writeByte(0) + + def writeByte(self, byte): + buff = pack("!b", byte) + self.trans.write(buff) + + def writeI16(self, i16): + buff = pack("!h", i16) + self.trans.write(buff) + + def writeI32(self, i32): + buff = pack("!i", i32) + self.trans.write(buff) + + def writeI64(self, i64): + buff = pack("!q", i64) + self.trans.write(buff) + + def writeDouble(self, dub): + buff = pack("!d", dub) + self.trans.write(buff) + + def writeBinary(self, str): + self.writeI32(len(str)) + self.trans.write(str) + + def readMessageBegin(self): + sz = self.readI32() + if sz < 0: + version = sz & TBinaryProtocol.VERSION_MASK + if version != TBinaryProtocol.VERSION_1: + raise TProtocolException( + type=TProtocolException.BAD_VERSION, + message='Bad version in readMessageBegin: %d' % (sz)) + type = sz & TBinaryProtocol.TYPE_MASK + name = self.readString() + seqid = self.readI32() + else: + if self.strictRead: + raise TProtocolException(type=TProtocolException.BAD_VERSION, + message='No protocol version header') + name = self.trans.readAll(sz) + type = self.readByte() + seqid = self.readI32() + return (name, type, seqid) + + def readMessageEnd(self): + pass + + def readStructBegin(self): + pass + + def readStructEnd(self): + pass + + def readFieldBegin(self): + type = self.readByte() + if type == TType.STOP: + return (None, type, 0) + id = self.readI16() + return (None, type, id) + + def readFieldEnd(self): + pass + + def readMapBegin(self): + ktype = self.readByte() + vtype = self.readByte() + size = self.readI32() + self._check_container_length(size) + return (ktype, vtype, size) + + def readMapEnd(self): + pass + + def readListBegin(self): + etype = self.readByte() + size = self.readI32() + self._check_container_length(size) + return (etype, size) + + def readListEnd(self): + pass + + def readSetBegin(self): + etype = self.readByte() + size = self.readI32() + self._check_container_length(size) + return (etype, size) + + def readSetEnd(self): + pass + + def readBool(self): + byte = self.readByte() + if byte == 0: + return False + return True + + def readByte(self): + buff = self.trans.readAll(1) + val, = unpack('!b', buff) + return val + + def readI16(self): + buff = self.trans.readAll(2) + val, = unpack('!h', buff) + return val + + def readI32(self): + buff = self.trans.readAll(4) + val, = unpack('!i', buff) + return val + + def readI64(self): + buff = self.trans.readAll(8) + val, = unpack('!q', buff) + return val + + def readDouble(self): + buff = self.trans.readAll(8) + val, = unpack('!d', buff) + return val + + def readBinary(self): + size = self.readI32() + self._check_string_length(size) + s = self.trans.readAll(size) + return s + + +class TBinaryProtocolFactory(object): + def __init__(self, strictRead=False, strictWrite=True, **kwargs): + self.strictRead = strictRead + self.strictWrite = strictWrite + self.string_length_limit = kwargs.get('string_length_limit', None) + self.container_length_limit = kwargs.get('container_length_limit', None) + + def getProtocol(self, trans): + prot = TBinaryProtocol(trans, self.strictRead, self.strictWrite, + string_length_limit=self.string_length_limit, + container_length_limit=self.container_length_limit) + return prot + + +class TBinaryProtocolAccelerated(TBinaryProtocol): + """C-Accelerated version of TBinaryProtocol. + + This class does not override any of TBinaryProtocol's methods, + but the generated code recognizes it directly and will call into + our C module to do the encoding, bypassing this object entirely. + We inherit from TBinaryProtocol so that the normal TBinaryProtocol + encoding can happen if the fastbinary module doesn't work for some + reason. (TODO(dreiss): Make this happen sanely in more cases.) + To disable this behavior, pass fallback=False constructor argument. + + In order to take advantage of the C module, just use + TBinaryProtocolAccelerated instead of TBinaryProtocol. + + NOTE: This code was contributed by an external developer. + The internal Thrift team has reviewed and tested it, + but we cannot guarantee that it is production-ready. + Please feel free to report bugs and/or success stories + to the public mailing list. + """ + pass + + def __init__(self, *args, **kwargs): + fallback = kwargs.pop('fallback', True) + super(TBinaryProtocolAccelerated, self).__init__(*args, **kwargs) + try: + from thrift.protocol import fastbinary + except ImportError: + if not fallback: + raise + else: + self._fast_decode = fastbinary.decode_binary + self._fast_encode = fastbinary.encode_binary + + +class TBinaryProtocolAcceleratedFactory(object): + def __init__(self, + string_length_limit=None, + container_length_limit=None, + fallback=True): + self.string_length_limit = string_length_limit + self.container_length_limit = container_length_limit + self._fallback = fallback + + def getProtocol(self, trans): + return TBinaryProtocolAccelerated( + trans, + string_length_limit=self.string_length_limit, + container_length_limit=self.container_length_limit, + fallback=self._fallback) diff --git a/lib/py/src/protocol/TCompactProtocol.py b/lib/py/src/protocol/TCompactProtocol.py new file mode 100644 index 0000000..e485cff --- /dev/null +++ b/lib/py/src/protocol/TCompactProtocol.py @@ -0,0 +1,475 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from .TProtocol import TType, TProtocolBase, TProtocolException, checkIntegerLimits +from struct import pack, unpack + +from ..compat import binary_to_str, str_to_binary + +__all__ = ['TCompactProtocol', 'TCompactProtocolFactory'] + +CLEAR = 0 +FIELD_WRITE = 1 +VALUE_WRITE = 2 +CONTAINER_WRITE = 3 +BOOL_WRITE = 4 +FIELD_READ = 5 +CONTAINER_READ = 6 +VALUE_READ = 7 +BOOL_READ = 8 + + +def make_helper(v_from, container): + def helper(func): + def nested(self, *args, **kwargs): + assert self.state in (v_from, container), (self.state, v_from, container) + return func(self, *args, **kwargs) + return nested + return helper + + +writer = make_helper(VALUE_WRITE, CONTAINER_WRITE) +reader = make_helper(VALUE_READ, CONTAINER_READ) + + +def makeZigZag(n, bits): + checkIntegerLimits(n, bits) + return (n << 1) ^ (n >> (bits - 1)) + + +def fromZigZag(n): + return (n >> 1) ^ -(n & 1) + + +def writeVarint(trans, n): + out = bytearray() + while True: + if n & ~0x7f == 0: + out.append(n) + break + else: + out.append((n & 0xff) | 0x80) + n = n >> 7 + trans.write(bytes(out)) + + +def readVarint(trans): + result = 0 + shift = 0 + while True: + x = trans.readAll(1) + byte = ord(x) + result |= (byte & 0x7f) << shift + if byte >> 7 == 0: + return result + shift += 7 + + +class CompactType(object): + STOP = 0x00 + TRUE = 0x01 + FALSE = 0x02 + BYTE = 0x03 + I16 = 0x04 + I32 = 0x05 + I64 = 0x06 + DOUBLE = 0x07 + BINARY = 0x08 + LIST = 0x09 + SET = 0x0A + MAP = 0x0B + STRUCT = 0x0C + + +CTYPES = { + TType.STOP: CompactType.STOP, + TType.BOOL: CompactType.TRUE, # used for collection + TType.BYTE: CompactType.BYTE, + TType.I16: CompactType.I16, + TType.I32: CompactType.I32, + TType.I64: CompactType.I64, + TType.DOUBLE: CompactType.DOUBLE, + TType.STRING: CompactType.BINARY, + TType.STRUCT: CompactType.STRUCT, + TType.LIST: CompactType.LIST, + TType.SET: CompactType.SET, + TType.MAP: CompactType.MAP, +} + +TTYPES = {} +for k, v in CTYPES.items(): + TTYPES[v] = k +TTYPES[CompactType.FALSE] = TType.BOOL +del k +del v + + +class TCompactProtocol(TProtocolBase): + """Compact implementation of the Thrift protocol driver.""" + + PROTOCOL_ID = 0x82 + VERSION = 1 + VERSION_MASK = 0x1f + TYPE_MASK = 0xe0 + TYPE_BITS = 0x07 + TYPE_SHIFT_AMOUNT = 5 + + def __init__(self, trans, + string_length_limit=None, + container_length_limit=None): + TProtocolBase.__init__(self, trans) + self.state = CLEAR + self.__last_fid = 0 + self.__bool_fid = None + self.__bool_value = None + self.__structs = [] + self.__containers = [] + self.string_length_limit = string_length_limit + self.container_length_limit = container_length_limit + + def _check_string_length(self, length): + self._check_length(self.string_length_limit, length) + + def _check_container_length(self, length): + self._check_length(self.container_length_limit, length) + + def __writeVarint(self, n): + writeVarint(self.trans, n) + + def writeMessageBegin(self, name, type, seqid): + assert self.state == CLEAR + self.__writeUByte(self.PROTOCOL_ID) + self.__writeUByte(self.VERSION | (type << self.TYPE_SHIFT_AMOUNT)) + self.__writeVarint(seqid) + self.__writeBinary(str_to_binary(name)) + self.state = VALUE_WRITE + + def writeMessageEnd(self): + assert self.state == VALUE_WRITE + self.state = CLEAR + + def writeStructBegin(self, name): + assert self.state in (CLEAR, CONTAINER_WRITE, VALUE_WRITE), self.state + self.__structs.append((self.state, self.__last_fid)) + self.state = FIELD_WRITE + self.__last_fid = 0 + + def writeStructEnd(self): + assert self.state == FIELD_WRITE + self.state, self.__last_fid = self.__structs.pop() + + def writeFieldStop(self): + self.__writeByte(0) + + def __writeFieldHeader(self, type, fid): + delta = fid - self.__last_fid + if 0 < delta <= 15: + self.__writeUByte(delta << 4 | type) + else: + self.__writeByte(type) + self.__writeI16(fid) + self.__last_fid = fid + + def writeFieldBegin(self, name, type, fid): + assert self.state == FIELD_WRITE, self.state + if type == TType.BOOL: + self.state = BOOL_WRITE + self.__bool_fid = fid + else: + self.state = VALUE_WRITE + self.__writeFieldHeader(CTYPES[type], fid) + + def writeFieldEnd(self): + assert self.state in (VALUE_WRITE, BOOL_WRITE), self.state + self.state = FIELD_WRITE + + def __writeUByte(self, byte): + self.trans.write(pack('!B', byte)) + + def __writeByte(self, byte): + self.trans.write(pack('!b', byte)) + + def __writeI16(self, i16): + self.__writeVarint(makeZigZag(i16, 16)) + + def __writeSize(self, i32): + self.__writeVarint(i32) + + def writeCollectionBegin(self, etype, size): + assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state + if size <= 14: + self.__writeUByte(size << 4 | CTYPES[etype]) + else: + self.__writeUByte(0xf0 | CTYPES[etype]) + self.__writeSize(size) + self.__containers.append(self.state) + self.state = CONTAINER_WRITE + writeSetBegin = writeCollectionBegin + writeListBegin = writeCollectionBegin + + def writeMapBegin(self, ktype, vtype, size): + assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state + if size == 0: + self.__writeByte(0) + else: + self.__writeSize(size) + self.__writeUByte(CTYPES[ktype] << 4 | CTYPES[vtype]) + self.__containers.append(self.state) + self.state = CONTAINER_WRITE + + def writeCollectionEnd(self): + assert self.state == CONTAINER_WRITE, self.state + self.state = self.__containers.pop() + writeMapEnd = writeCollectionEnd + writeSetEnd = writeCollectionEnd + writeListEnd = writeCollectionEnd + + def writeBool(self, bool): + if self.state == BOOL_WRITE: + if bool: + ctype = CompactType.TRUE + else: + ctype = CompactType.FALSE + self.__writeFieldHeader(ctype, self.__bool_fid) + elif self.state == CONTAINER_WRITE: + if bool: + self.__writeByte(CompactType.TRUE) + else: + self.__writeByte(CompactType.FALSE) + else: + raise AssertionError("Invalid state in compact protocol") + + writeByte = writer(__writeByte) + writeI16 = writer(__writeI16) + + @writer + def writeI32(self, i32): + self.__writeVarint(makeZigZag(i32, 32)) + + @writer + def writeI64(self, i64): + self.__writeVarint(makeZigZag(i64, 64)) + + @writer + def writeDouble(self, dub): + self.trans.write(pack('> 4 + if delta == 0: + fid = self.__readI16() + else: + fid = self.__last_fid + delta + self.__last_fid = fid + type = type & 0x0f + if type == CompactType.TRUE: + self.state = BOOL_READ + self.__bool_value = True + elif type == CompactType.FALSE: + self.state = BOOL_READ + self.__bool_value = False + else: + self.state = VALUE_READ + return (None, self.__getTType(type), fid) + + def readFieldEnd(self): + assert self.state in (VALUE_READ, BOOL_READ), self.state + self.state = FIELD_READ + + def __readUByte(self): + result, = unpack('!B', self.trans.readAll(1)) + return result + + def __readByte(self): + result, = unpack('!b', self.trans.readAll(1)) + return result + + def __readVarint(self): + return readVarint(self.trans) + + def __readZigZag(self): + return fromZigZag(self.__readVarint()) + + def __readSize(self): + result = self.__readVarint() + if result < 0: + raise TProtocolException("Length < 0") + return result + + def readMessageBegin(self): + assert self.state == CLEAR + proto_id = self.__readUByte() + if proto_id != self.PROTOCOL_ID: + raise TProtocolException(TProtocolException.BAD_VERSION, + 'Bad protocol id in the message: %d' % proto_id) + ver_type = self.__readUByte() + type = (ver_type >> self.TYPE_SHIFT_AMOUNT) & self.TYPE_BITS + version = ver_type & self.VERSION_MASK + if version != self.VERSION: + raise TProtocolException(TProtocolException.BAD_VERSION, + 'Bad version: %d (expect %d)' % (version, self.VERSION)) + seqid = self.__readVarint() + name = binary_to_str(self.__readBinary()) + return (name, type, seqid) + + def readMessageEnd(self): + assert self.state == CLEAR + assert len(self.__structs) == 0 + + def readStructBegin(self): + assert self.state in (CLEAR, CONTAINER_READ, VALUE_READ), self.state + self.__structs.append((self.state, self.__last_fid)) + self.state = FIELD_READ + self.__last_fid = 0 + + def readStructEnd(self): + assert self.state == FIELD_READ + self.state, self.__last_fid = self.__structs.pop() + + def readCollectionBegin(self): + assert self.state in (VALUE_READ, CONTAINER_READ), self.state + size_type = self.__readUByte() + size = size_type >> 4 + type = self.__getTType(size_type) + if size == 15: + size = self.__readSize() + self._check_container_length(size) + self.__containers.append(self.state) + self.state = CONTAINER_READ + return type, size + readSetBegin = readCollectionBegin + readListBegin = readCollectionBegin + + def readMapBegin(self): + assert self.state in (VALUE_READ, CONTAINER_READ), self.state + size = self.__readSize() + self._check_container_length(size) + types = 0 + if size > 0: + types = self.__readUByte() + vtype = self.__getTType(types) + ktype = self.__getTType(types >> 4) + self.__containers.append(self.state) + self.state = CONTAINER_READ + return (ktype, vtype, size) + + def readCollectionEnd(self): + assert self.state == CONTAINER_READ, self.state + self.state = self.__containers.pop() + readSetEnd = readCollectionEnd + readListEnd = readCollectionEnd + readMapEnd = readCollectionEnd + + def readBool(self): + if self.state == BOOL_READ: + return self.__bool_value == CompactType.TRUE + elif self.state == CONTAINER_READ: + return self.__readByte() == CompactType.TRUE + else: + raise AssertionError("Invalid state in compact protocol: %d" % + self.state) + + readByte = reader(__readByte) + __readI16 = __readZigZag + readI16 = reader(__readZigZag) + readI32 = reader(__readZigZag) + readI64 = reader(__readZigZag) + + @reader + def readDouble(self): + buff = self.trans.readAll(8) + val, = unpack('= 0xd800 and codeunit <= 0xdbff + + def _isLowSurrogate(self, codeunit): + return codeunit >= 0xdc00 and codeunit <= 0xdfff + + def _toChar(self, high, low=None): + if not low: + if sys.version_info[0] == 2: + return ("\\u%04x" % high).decode('unicode-escape') \ + .encode('utf-8') + else: + return chr(high) + else: + codepoint = (1 << 16) + ((high & 0x3ff) << 10) + codepoint += low & 0x3ff + if sys.version_info[0] == 2: + s = "\\U%08x" % codepoint + return s.decode('unicode-escape').encode('utf-8') + else: + return chr(codepoint) + + def readJSONString(self, skipContext): + highSurrogate = None + string = [] + if skipContext is False: + self.context.read() + self.readJSONSyntaxChar(QUOTE) + while True: + character = self.reader.read() + if character == QUOTE: + break + if ord(character) == ESCSEQ0: + character = self.reader.read() + if ord(character) == ESCSEQ1: + character = self.trans.read(4).decode('ascii') + codeunit = int(character, 16) + if self._isHighSurrogate(codeunit): + if highSurrogate: + raise TProtocolException( + TProtocolException.INVALID_DATA, + "Expected low surrogate char") + highSurrogate = codeunit + continue + elif self._isLowSurrogate(codeunit): + if not highSurrogate: + raise TProtocolException( + TProtocolException.INVALID_DATA, + "Expected high surrogate char") + character = self._toChar(highSurrogate, codeunit) + highSurrogate = None + else: + character = self._toChar(codeunit) + else: + if character not in ESCAPE_CHARS: + raise TProtocolException( + TProtocolException.INVALID_DATA, + "Expected control char") + character = ESCAPE_CHARS[character] + elif character in ESCAPE_CHAR_VALS: + raise TProtocolException(TProtocolException.INVALID_DATA, + "Unescaped control char") + elif sys.version_info[0] > 2: + utf8_bytes = bytearray([ord(character)]) + while ord(self.reader.peek()) >= 0x80: + utf8_bytes.append(ord(self.reader.read())) + character = utf8_bytes.decode('utf8') + string.append(character) + + if highSurrogate: + raise TProtocolException(TProtocolException.INVALID_DATA, + "Expected low surrogate char") + return ''.join(string) + + def isJSONNumeric(self, character): + return (True if NUMERIC_CHAR.find(character) != - 1 else False) + + def readJSONQuotes(self): + if (self.context.escapeNum()): + self.readJSONSyntaxChar(QUOTE) + + def readJSONNumericChars(self): + numeric = [] + while True: + character = self.reader.peek() + if self.isJSONNumeric(character) is False: + break + numeric.append(self.reader.read()) + return b''.join(numeric).decode('ascii') + + def readJSONInteger(self): + self.context.read() + self.readJSONQuotes() + numeric = self.readJSONNumericChars() + self.readJSONQuotes() + try: + return int(numeric) + except ValueError: + raise TProtocolException(TProtocolException.INVALID_DATA, + "Bad data encounted in numeric data") + + def readJSONDouble(self): + self.context.read() + if self.reader.peek() == QUOTE: + string = self.readJSONString(True) + try: + double = float(string) + if (self.context.escapeNum is False and + not math.isinf(double) and + not math.isnan(double)): + raise TProtocolException( + TProtocolException.INVALID_DATA, + "Numeric data unexpectedly quoted") + return double + except ValueError: + raise TProtocolException(TProtocolException.INVALID_DATA, + "Bad data encounted in numeric data") + else: + if self.context.escapeNum() is True: + self.readJSONSyntaxChar(QUOTE) + try: + return float(self.readJSONNumericChars()) + except ValueError: + raise TProtocolException(TProtocolException.INVALID_DATA, + "Bad data encounted in numeric data") + + def readJSONBase64(self): + string = self.readJSONString(False) + size = len(string) + m = size % 4 + # Force padding since b64encode method does not allow it + if m != 0: + for i in range(4 - m): + string += '=' + return base64.b64decode(string) + + def readJSONObjectStart(self): + self.context.read() + self.readJSONSyntaxChar(LBRACE) + self.pushContext(JSONPairContext(self)) + + def readJSONObjectEnd(self): + self.readJSONSyntaxChar(RBRACE) + self.popContext() + + def readJSONArrayStart(self): + self.context.read() + self.readJSONSyntaxChar(LBRACKET) + self.pushContext(JSONListContext(self)) + + def readJSONArrayEnd(self): + self.readJSONSyntaxChar(RBRACKET) + self.popContext() + + +class TJSONProtocol(TJSONProtocolBase): + + def readMessageBegin(self): + self.resetReadContext() + self.readJSONArrayStart() + if self.readJSONInteger() != VERSION: + raise TProtocolException(TProtocolException.BAD_VERSION, + "Message contained bad version.") + name = self.readJSONString(False) + typen = self.readJSONInteger() + seqid = self.readJSONInteger() + return (name, typen, seqid) + + def readMessageEnd(self): + self.readJSONArrayEnd() + + def readStructBegin(self): + self.readJSONObjectStart() + + def readStructEnd(self): + self.readJSONObjectEnd() + + def readFieldBegin(self): + character = self.reader.peek() + ttype = 0 + id = 0 + if character == RBRACE: + ttype = TType.STOP + else: + id = self.readJSONInteger() + self.readJSONObjectStart() + ttype = JTYPES[self.readJSONString(False)] + return (None, ttype, id) + + def readFieldEnd(self): + self.readJSONObjectEnd() + + def readMapBegin(self): + self.readJSONArrayStart() + keyType = JTYPES[self.readJSONString(False)] + valueType = JTYPES[self.readJSONString(False)] + size = self.readJSONInteger() + self.readJSONObjectStart() + return (keyType, valueType, size) + + def readMapEnd(self): + self.readJSONObjectEnd() + self.readJSONArrayEnd() + + def readCollectionBegin(self): + self.readJSONArrayStart() + elemType = JTYPES[self.readJSONString(False)] + size = self.readJSONInteger() + return (elemType, size) + readListBegin = readCollectionBegin + readSetBegin = readCollectionBegin + + def readCollectionEnd(self): + self.readJSONArrayEnd() + readSetEnd = readCollectionEnd + readListEnd = readCollectionEnd + + def readBool(self): + return (False if self.readJSONInteger() == 0 else True) + + def readNumber(self): + return self.readJSONInteger() + readByte = readNumber + readI16 = readNumber + readI32 = readNumber + readI64 = readNumber + + def readDouble(self): + return self.readJSONDouble() + + def readString(self): + return self.readJSONString(False) + + def readBinary(self): + return self.readJSONBase64() + + def writeMessageBegin(self, name, request_type, seqid): + self.resetWriteContext() + self.writeJSONArrayStart() + self.writeJSONNumber(VERSION) + self.writeJSONString(name) + self.writeJSONNumber(request_type) + self.writeJSONNumber(seqid) + + def writeMessageEnd(self): + self.writeJSONArrayEnd() + + def writeStructBegin(self, name): + self.writeJSONObjectStart() + + def writeStructEnd(self): + self.writeJSONObjectEnd() + + def writeFieldBegin(self, name, ttype, id): + self.writeJSONNumber(id) + self.writeJSONObjectStart() + self.writeJSONString(CTYPES[ttype]) + + def writeFieldEnd(self): + self.writeJSONObjectEnd() + + def writeFieldStop(self): + pass + + def writeMapBegin(self, ktype, vtype, size): + self.writeJSONArrayStart() + self.writeJSONString(CTYPES[ktype]) + self.writeJSONString(CTYPES[vtype]) + self.writeJSONNumber(size) + self.writeJSONObjectStart() + + def writeMapEnd(self): + self.writeJSONObjectEnd() + self.writeJSONArrayEnd() + + def writeListBegin(self, etype, size): + self.writeJSONArrayStart() + self.writeJSONString(CTYPES[etype]) + self.writeJSONNumber(size) + + def writeListEnd(self): + self.writeJSONArrayEnd() + + def writeSetBegin(self, etype, size): + self.writeJSONArrayStart() + self.writeJSONString(CTYPES[etype]) + self.writeJSONNumber(size) + + def writeSetEnd(self): + self.writeJSONArrayEnd() + + def writeBool(self, boolean): + self.writeJSONNumber(1 if boolean is True else 0) + + def writeByte(self, byte): + checkIntegerLimits(byte, 8) + self.writeJSONNumber(byte) + + def writeI16(self, i16): + checkIntegerLimits(i16, 16) + self.writeJSONNumber(i16) + + def writeI32(self, i32): + checkIntegerLimits(i32, 32) + self.writeJSONNumber(i32) + + def writeI64(self, i64): + checkIntegerLimits(i64, 64) + self.writeJSONNumber(i64) + + def writeDouble(self, dbl): + # 17 significant digits should be just enough for any double precision + # value. + self.writeJSONNumber(dbl, '{0:.17g}') + + def writeString(self, string): + self.writeJSONString(string) + + def writeBinary(self, binary): + self.writeJSONBase64(binary) + + +class TJSONProtocolFactory(object): + def getProtocol(self, trans): + return TJSONProtocol(trans) + + @property + def string_length_limit(senf): + return None + + @property + def container_length_limit(senf): + return None + + +class TSimpleJSONProtocol(TJSONProtocolBase): + """Simple, readable, write-only JSON protocol. + + Useful for interacting with scripting languages. + """ + + def readMessageBegin(self): + raise NotImplementedError() + + def readMessageEnd(self): + raise NotImplementedError() + + def readStructBegin(self): + raise NotImplementedError() + + def readStructEnd(self): + raise NotImplementedError() + + def writeMessageBegin(self, name, request_type, seqid): + self.resetWriteContext() + + def writeMessageEnd(self): + pass + + def writeStructBegin(self, name): + self.writeJSONObjectStart() + + def writeStructEnd(self): + self.writeJSONObjectEnd() + + def writeFieldBegin(self, name, ttype, fid): + self.writeJSONString(name) + + def writeFieldEnd(self): + pass + + def writeMapBegin(self, ktype, vtype, size): + self.writeJSONObjectStart() + + def writeMapEnd(self): + self.writeJSONObjectEnd() + + def _writeCollectionBegin(self, etype, size): + self.writeJSONArrayStart() + + def _writeCollectionEnd(self): + self.writeJSONArrayEnd() + writeListBegin = _writeCollectionBegin + writeListEnd = _writeCollectionEnd + writeSetBegin = _writeCollectionBegin + writeSetEnd = _writeCollectionEnd + + def writeByte(self, byte): + checkIntegerLimits(byte, 8) + self.writeJSONNumber(byte) + + def writeI16(self, i16): + checkIntegerLimits(i16, 16) + self.writeJSONNumber(i16) + + def writeI32(self, i32): + checkIntegerLimits(i32, 32) + self.writeJSONNumber(i32) + + def writeI64(self, i64): + checkIntegerLimits(i64, 64) + self.writeJSONNumber(i64) + + def writeBool(self, boolean): + self.writeJSONNumber(1 if boolean is True else 0) + + def writeDouble(self, dbl): + self.writeJSONNumber(dbl) + + def writeString(self, string): + self.writeJSONString(string) + + def writeBinary(self, binary): + self.writeJSONBase64(binary) + + +class TSimpleJSONProtocolFactory(object): + + def getProtocol(self, trans): + return TSimpleJSONProtocol(trans) diff --git a/lib/py/src/protocol/TMultiplexedProtocol.py b/lib/py/src/protocol/TMultiplexedProtocol.py new file mode 100644 index 0000000..309f896 --- /dev/null +++ b/lib/py/src/protocol/TMultiplexedProtocol.py @@ -0,0 +1,40 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from thrift.Thrift import TMessageType +from thrift.protocol import TProtocolDecorator + +SEPARATOR = ":" + + +class TMultiplexedProtocol(TProtocolDecorator.TProtocolDecorator): + def __init__(self, protocol, serviceName): + TProtocolDecorator.TProtocolDecorator.__init__(self, protocol) + self.serviceName = serviceName + + def writeMessageBegin(self, name, type, seqid): + if (type == TMessageType.CALL or + type == TMessageType.ONEWAY): + self.protocol.writeMessageBegin( + self.serviceName + SEPARATOR + name, + type, + seqid + ) + else: + self.protocol.writeMessageBegin(name, type, seqid) diff --git a/lib/py/src/protocol/TProtocol.py b/lib/py/src/protocol/TProtocol.py new file mode 100644 index 0000000..fd20cb7 --- /dev/null +++ b/lib/py/src/protocol/TProtocol.py @@ -0,0 +1,419 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from thrift.Thrift import TException, TType, TFrozenDict +from thrift.transport.TTransport import TTransportException +from ..compat import binary_to_str, str_to_binary + +import six +import sys +from itertools import islice +from six.moves import zip + + +class TProtocolException(TException): + """Custom Protocol Exception class""" + + UNKNOWN = 0 + INVALID_DATA = 1 + NEGATIVE_SIZE = 2 + SIZE_LIMIT = 3 + BAD_VERSION = 4 + NOT_IMPLEMENTED = 5 + DEPTH_LIMIT = 6 + + def __init__(self, type=UNKNOWN, message=None): + TException.__init__(self, message) + self.type = type + + +class TProtocolBase(object): + """Base class for Thrift protocol driver.""" + + def __init__(self, trans): + self.trans = trans + self._fast_decode = None + self._fast_encode = None + + @staticmethod + def _check_length(limit, length): + if length < 0: + raise TTransportException(TTransportException.NEGATIVE_SIZE, + 'Negative length: %d' % length) + if limit is not None and length > limit: + raise TTransportException(TTransportException.SIZE_LIMIT, + 'Length exceeded max allowed: %d' % limit) + + def writeMessageBegin(self, name, ttype, seqid): + pass + + def writeMessageEnd(self): + pass + + def writeStructBegin(self, name): + pass + + def writeStructEnd(self): + pass + + def writeFieldBegin(self, name, ttype, fid): + pass + + def writeFieldEnd(self): + pass + + def writeFieldStop(self): + pass + + def writeMapBegin(self, ktype, vtype, size): + pass + + def writeMapEnd(self): + pass + + def writeListBegin(self, etype, size): + pass + + def writeListEnd(self): + pass + + def writeSetBegin(self, etype, size): + pass + + def writeSetEnd(self): + pass + + def writeBool(self, bool_val): + pass + + def writeByte(self, byte): + pass + + def writeI16(self, i16): + pass + + def writeI32(self, i32): + pass + + def writeI64(self, i64): + pass + + def writeDouble(self, dub): + pass + + def writeString(self, str_val): + self.writeBinary(str_to_binary(str_val)) + + def writeBinary(self, str_val): + pass + + def writeUtf8(self, str_val): + self.writeString(str_val.encode('utf8')) + + def readMessageBegin(self): + pass + + def readMessageEnd(self): + pass + + def readStructBegin(self): + pass + + def readStructEnd(self): + pass + + def readFieldBegin(self): + pass + + def readFieldEnd(self): + pass + + def readMapBegin(self): + pass + + def readMapEnd(self): + pass + + def readListBegin(self): + pass + + def readListEnd(self): + pass + + def readSetBegin(self): + pass + + def readSetEnd(self): + pass + + def readBool(self): + pass + + def readByte(self): + pass + + def readI16(self): + pass + + def readI32(self): + pass + + def readI64(self): + pass + + def readDouble(self): + pass + + def readString(self): + return binary_to_str(self.readBinary()) + + def readBinary(self): + pass + + def readUtf8(self): + return self.readString().decode('utf8') + + def skip(self, ttype): + if ttype == TType.STOP: + return + elif ttype == TType.BOOL: + self.readBool() + elif ttype == TType.BYTE: + self.readByte() + elif ttype == TType.I16: + self.readI16() + elif ttype == TType.I32: + self.readI32() + elif ttype == TType.I64: + self.readI64() + elif ttype == TType.DOUBLE: + self.readDouble() + elif ttype == TType.STRING: + self.readString() + elif ttype == TType.STRUCT: + name = self.readStructBegin() + while True: + (name, ttype, id) = self.readFieldBegin() + if ttype == TType.STOP: + break + self.skip(ttype) + self.readFieldEnd() + self.readStructEnd() + elif ttype == TType.MAP: + (ktype, vtype, size) = self.readMapBegin() + for i in range(size): + self.skip(ktype) + self.skip(vtype) + self.readMapEnd() + elif ttype == TType.SET: + (etype, size) = self.readSetBegin() + for i in range(size): + self.skip(etype) + self.readSetEnd() + elif ttype == TType.LIST: + (etype, size) = self.readListBegin() + for i in range(size): + self.skip(etype) + self.readListEnd() + + # tuple of: ( 'reader method' name, is_container bool, 'writer_method' name ) + _TTYPE_HANDLERS = ( + (None, None, False), # 0 TType.STOP + (None, None, False), # 1 TType.VOID # TODO: handle void? + ('readBool', 'writeBool', False), # 2 TType.BOOL + ('readByte', 'writeByte', False), # 3 TType.BYTE and I08 + ('readDouble', 'writeDouble', False), # 4 TType.DOUBLE + (None, None, False), # 5 undefined + ('readI16', 'writeI16', False), # 6 TType.I16 + (None, None, False), # 7 undefined + ('readI32', 'writeI32', False), # 8 TType.I32 + (None, None, False), # 9 undefined + ('readI64', 'writeI64', False), # 10 TType.I64 + ('readString', 'writeString', False), # 11 TType.STRING and UTF7 + ('readContainerStruct', 'writeContainerStruct', True), # 12 *.STRUCT + ('readContainerMap', 'writeContainerMap', True), # 13 TType.MAP + ('readContainerSet', 'writeContainerSet', True), # 14 TType.SET + ('readContainerList', 'writeContainerList', True), # 15 TType.LIST + (None, None, False), # 16 TType.UTF8 # TODO: handle utf8 types? + (None, None, False) # 17 TType.UTF16 # TODO: handle utf16 types? + ) + + def _ttype_handlers(self, ttype, spec): + if spec == 'BINARY': + if ttype != TType.STRING: + raise TProtocolException(type=TProtocolException.INVALID_DATA, + message='Invalid binary field type %d' % ttype) + return ('readBinary', 'writeBinary', False) + if sys.version_info[0] == 2 and spec == 'UTF8': + if ttype != TType.STRING: + raise TProtocolException(type=TProtocolException.INVALID_DATA, + message='Invalid string field type %d' % ttype) + return ('readUtf8', 'writeUtf8', False) + return self._TTYPE_HANDLERS[ttype] if ttype < len(self._TTYPE_HANDLERS) else (None, None, False) + + def _read_by_ttype(self, ttype, spec, espec): + reader_name, _, is_container = self._ttype_handlers(ttype, espec) + if reader_name is None: + raise TProtocolException(type=TProtocolException.INVALID_DATA, + message='Invalid type %d' % (ttype)) + reader_func = getattr(self, reader_name) + read = (lambda: reader_func(espec)) if is_container else reader_func + while True: + yield read() + + def readFieldByTType(self, ttype, spec): + return next(self._read_by_ttype(ttype, spec, spec)) + + def readContainerList(self, spec): + ttype, tspec, is_immutable = spec + (list_type, list_len) = self.readListBegin() + # TODO: compare types we just decoded with thrift_spec + elems = islice(self._read_by_ttype(ttype, spec, tspec), list_len) + results = (tuple if is_immutable else list)(elems) + self.readListEnd() + return results + + def readContainerSet(self, spec): + ttype, tspec, is_immutable = spec + (set_type, set_len) = self.readSetBegin() + # TODO: compare types we just decoded with thrift_spec + elems = islice(self._read_by_ttype(ttype, spec, tspec), set_len) + results = (frozenset if is_immutable else set)(elems) + self.readSetEnd() + return results + + def readContainerStruct(self, spec): + (obj_class, obj_spec) = spec + obj = obj_class() + obj.read(self) + return obj + + def readContainerMap(self, spec): + ktype, kspec, vtype, vspec, is_immutable = spec + (map_ktype, map_vtype, map_len) = self.readMapBegin() + # TODO: compare types we just decoded with thrift_spec and + # abort/skip if types disagree + keys = self._read_by_ttype(ktype, spec, kspec) + vals = self._read_by_ttype(vtype, spec, vspec) + keyvals = islice(zip(keys, vals), map_len) + results = (TFrozenDict if is_immutable else dict)(keyvals) + self.readMapEnd() + return results + + def readStruct(self, obj, thrift_spec, is_immutable=False): + if is_immutable: + fields = {} + self.readStructBegin() + while True: + (fname, ftype, fid) = self.readFieldBegin() + if ftype == TType.STOP: + break + try: + field = thrift_spec[fid] + except IndexError: + self.skip(ftype) + else: + if field is not None and ftype == field[1]: + fname = field[2] + fspec = field[3] + val = self.readFieldByTType(ftype, fspec) + if is_immutable: + fields[fname] = val + else: + setattr(obj, fname, val) + else: + self.skip(ftype) + self.readFieldEnd() + self.readStructEnd() + if is_immutable: + return obj(**fields) + + def writeContainerStruct(self, val, spec): + val.write(self) + + def writeContainerList(self, val, spec): + ttype, tspec, _ = spec + self.writeListBegin(ttype, len(val)) + for _ in self._write_by_ttype(ttype, val, spec, tspec): + pass + self.writeListEnd() + + def writeContainerSet(self, val, spec): + ttype, tspec, _ = spec + self.writeSetBegin(ttype, len(val)) + for _ in self._write_by_ttype(ttype, val, spec, tspec): + pass + self.writeSetEnd() + + def writeContainerMap(self, val, spec): + ktype, kspec, vtype, vspec, _ = spec + self.writeMapBegin(ktype, vtype, len(val)) + for _ in zip(self._write_by_ttype(ktype, six.iterkeys(val), spec, kspec), + self._write_by_ttype(vtype, six.itervalues(val), spec, vspec)): + pass + self.writeMapEnd() + + def writeStruct(self, obj, thrift_spec): + self.writeStructBegin(obj.__class__.__name__) + for field in thrift_spec: + if field is None: + continue + fname = field[2] + val = getattr(obj, fname) + if val is None: + # skip writing out unset fields + continue + fid = field[0] + ftype = field[1] + fspec = field[3] + self.writeFieldBegin(fname, ftype, fid) + self.writeFieldByTType(ftype, val, fspec) + self.writeFieldEnd() + self.writeFieldStop() + self.writeStructEnd() + + def _write_by_ttype(self, ttype, vals, spec, espec): + _, writer_name, is_container = self._ttype_handlers(ttype, espec) + writer_func = getattr(self, writer_name) + write = (lambda v: writer_func(v, espec)) if is_container else writer_func + for v in vals: + yield write(v) + + def writeFieldByTType(self, ttype, val, spec): + next(self._write_by_ttype(ttype, [val], spec, spec)) + + +def checkIntegerLimits(i, bits): + if bits == 8 and (i < -128 or i > 127): + raise TProtocolException(TProtocolException.INVALID_DATA, + "i8 requires -128 <= number <= 127") + elif bits == 16 and (i < -32768 or i > 32767): + raise TProtocolException(TProtocolException.INVALID_DATA, + "i16 requires -32768 <= number <= 32767") + elif bits == 32 and (i < -2147483648 or i > 2147483647): + raise TProtocolException(TProtocolException.INVALID_DATA, + "i32 requires -2147483648 <= number <= 2147483647") + elif bits == 64 and (i < -9223372036854775808 or i > 9223372036854775807): + raise TProtocolException(TProtocolException.INVALID_DATA, + "i64 requires -9223372036854775808 <= number <= 9223372036854775807") + + +class TProtocolFactory(object): + def getProtocol(self, trans): + pass diff --git a/lib/py/src/protocol/TProtocolDecorator.py b/lib/py/src/protocol/TProtocolDecorator.py new file mode 100644 index 0000000..8b270a4 --- /dev/null +++ b/lib/py/src/protocol/TProtocolDecorator.py @@ -0,0 +1,50 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import types + +from thrift.protocol.TProtocol import TProtocolBase + + +class TProtocolDecorator(): + def __init__(self, protocol): + TProtocolBase(protocol) + self.protocol = protocol + + def __getattr__(self, name): + if hasattr(self.protocol, name): + member = getattr(self.protocol, name) + if type(member) in [ + types.MethodType, + types.FunctionType, + types.LambdaType, + types.BuiltinFunctionType, + types.BuiltinMethodType, + ]: + return lambda *args, **kwargs: self._wrap(member, args, kwargs) + else: + return member + raise AttributeError(name) + + def _wrap(self, func, args, kwargs): + if isinstance(func, types.MethodType): + result = func(*args, **kwargs) + else: + result = func(self.protocol, *args, **kwargs) + return result diff --git a/lib/py/src/protocol/__init__.py b/lib/py/src/protocol/__init__.py new file mode 100644 index 0000000..7148f66 --- /dev/null +++ b/lib/py/src/protocol/__init__.py @@ -0,0 +1,21 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +__all__ = ['fastbinary', 'TBase', 'TBinaryProtocol', 'TCompactProtocol', + 'TJSONProtocol', 'TProtocol'] diff --git a/lib/py/src/server/THttpServer.py b/lib/py/src/server/THttpServer.py new file mode 100644 index 0000000..1b501a7 --- /dev/null +++ b/lib/py/src/server/THttpServer.py @@ -0,0 +1,87 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from six.moves import BaseHTTPServer + +from thrift.server import TServer +from thrift.transport import TTransport + + +class ResponseException(Exception): + """Allows handlers to override the HTTP response + + Normally, THttpServer always sends a 200 response. If a handler wants + to override this behavior (e.g., to simulate a misconfigured or + overloaded web server during testing), it can raise a ResponseException. + The function passed to the constructor will be called with the + RequestHandler as its only argument. + """ + def __init__(self, handler): + self.handler = handler + + +class THttpServer(TServer.TServer): + """A simple HTTP-based Thrift server + + This class is not very performant, but it is useful (for example) for + acting as a mock version of an Apache-based PHP Thrift endpoint. + """ + def __init__(self, + processor, + server_address, + inputProtocolFactory, + outputProtocolFactory=None, + server_class=BaseHTTPServer.HTTPServer): + """Set up protocol factories and HTTP server. + + See BaseHTTPServer for server_address. + See TServer for protocol factories. + """ + if outputProtocolFactory is None: + outputProtocolFactory = inputProtocolFactory + + TServer.TServer.__init__(self, processor, None, None, None, + inputProtocolFactory, outputProtocolFactory) + + thttpserver = self + + class RequestHander(BaseHTTPServer.BaseHTTPRequestHandler): + def do_POST(self): + # Don't care about the request path. + itrans = TTransport.TFileObjectTransport(self.rfile) + otrans = TTransport.TFileObjectTransport(self.wfile) + itrans = TTransport.TBufferedTransport( + itrans, int(self.headers['Content-Length'])) + otrans = TTransport.TMemoryBuffer() + iprot = thttpserver.inputProtocolFactory.getProtocol(itrans) + oprot = thttpserver.outputProtocolFactory.getProtocol(otrans) + try: + thttpserver.processor.process(iprot, oprot) + except ResponseException as exn: + exn.handler(self) + else: + self.send_response(200) + self.send_header("content-type", "application/x-thrift") + self.end_headers() + self.wfile.write(otrans.getvalue()) + + self.httpd = server_class(server_address, RequestHander) + + def serve(self): + self.httpd.serve_forever() diff --git a/lib/py/src/server/TNonblockingServer.py b/lib/py/src/server/TNonblockingServer.py new file mode 100644 index 0000000..26c0f7e --- /dev/null +++ b/lib/py/src/server/TNonblockingServer.py @@ -0,0 +1,370 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +"""Implementation of non-blocking server. + +The main idea of the server is to receive and send requests +only from the main thread. + +The thread poool should be sized for concurrent tasks, not +maximum connections +""" + +import logging +import select +import socket +import struct +import threading + +from collections import deque +from six.moves import queue + +from thrift.transport import TTransport +from thrift.protocol.TBinaryProtocol import TBinaryProtocolFactory + +__all__ = ['TNonblockingServer'] + +logger = logging.getLogger(__name__) + + +class Worker(threading.Thread): + """Worker is a small helper to process incoming connection.""" + + def __init__(self, queue): + threading.Thread.__init__(self) + self.queue = queue + + def run(self): + """Process queries from task queue, stop if processor is None.""" + while True: + try: + processor, iprot, oprot, otrans, callback = self.queue.get() + if processor is None: + break + processor.process(iprot, oprot) + callback(True, otrans.getvalue()) + except Exception: + logger.exception("Exception while processing request", exc_info=True) + callback(False, b'') + + +WAIT_LEN = 0 +WAIT_MESSAGE = 1 +WAIT_PROCESS = 2 +SEND_ANSWER = 3 +CLOSED = 4 + + +def locked(func): + """Decorator which locks self.lock.""" + def nested(self, *args, **kwargs): + self.lock.acquire() + try: + return func(self, *args, **kwargs) + finally: + self.lock.release() + return nested + + +def socket_exception(func): + """Decorator close object on socket.error.""" + def read(self, *args, **kwargs): + try: + return func(self, *args, **kwargs) + except socket.error: + logger.debug('ignoring socket exception', exc_info=True) + self.close() + return read + + +class Message(object): + def __init__(self, offset, len_, header): + self.offset = offset + self.len = len_ + self.buffer = None + self.is_header = header + + @property + def end(self): + return self.offset + self.len + + +class Connection(object): + """Basic class is represented connection. + + It can be in state: + WAIT_LEN --- connection is reading request len. + WAIT_MESSAGE --- connection is reading request. + WAIT_PROCESS --- connection has just read whole request and + waits for call ready routine. + SEND_ANSWER --- connection is sending answer string (including length + of answer). + CLOSED --- socket was closed and connection should be deleted. + """ + def __init__(self, new_socket, wake_up): + self.socket = new_socket + self.socket.setblocking(False) + self.status = WAIT_LEN + self.len = 0 + self.received = deque() + self._reading = Message(0, 4, True) + self._rbuf = b'' + self._wbuf = b'' + self.lock = threading.Lock() + self.wake_up = wake_up + self.remaining = False + + @socket_exception + def read(self): + """Reads data from stream and switch state.""" + assert self.status in (WAIT_LEN, WAIT_MESSAGE) + assert not self.received + buf_size = 8192 + first = True + done = False + while not done: + read = self.socket.recv(buf_size) + rlen = len(read) + done = rlen < buf_size + self._rbuf += read + if first and rlen == 0: + if self.status != WAIT_LEN or self._rbuf: + logger.error('could not read frame from socket') + else: + logger.debug('read zero length. client might have disconnected') + self.close() + while len(self._rbuf) >= self._reading.end: + if self._reading.is_header: + mlen, = struct.unpack('!i', self._rbuf[:4]) + self._reading = Message(self._reading.end, mlen, False) + self.status = WAIT_MESSAGE + else: + self._reading.buffer = self._rbuf + self.received.append(self._reading) + self._rbuf = self._rbuf[self._reading.end:] + self._reading = Message(0, 4, True) + first = False + if self.received: + self.status = WAIT_PROCESS + break + self.remaining = not done + + @socket_exception + def write(self): + """Writes data from socket and switch state.""" + assert self.status == SEND_ANSWER + sent = self.socket.send(self._wbuf) + if sent == len(self._wbuf): + self.status = WAIT_LEN + self._wbuf = b'' + self.len = 0 + else: + self._wbuf = self.message[sent:] + + @locked + def ready(self, all_ok, message): + """Callback function for switching state and waking up main thread. + + This function is the only function witch can be called asynchronous. + + The ready can switch Connection to three states: + WAIT_LEN if request was oneway. + SEND_ANSWER if request was processed in normal way. + CLOSED if request throws unexpected exception. + + The one wakes up main thread. + """ + assert self.status == WAIT_PROCESS + if not all_ok: + self.close() + self.wake_up() + return + self.len = 0 + if len(message) == 0: + # it was a oneway request, do not write answer + self._wbuf = b'' + self.status = WAIT_LEN + else: + self._wbuf = struct.pack('!i', len(message)) + message + self.status = SEND_ANSWER + self.wake_up() + + @locked + def is_writeable(self): + """Return True if connection should be added to write list of select""" + return self.status == SEND_ANSWER + + # it's not necessary, but... + @locked + def is_readable(self): + """Return True if connection should be added to read list of select""" + return self.status in (WAIT_LEN, WAIT_MESSAGE) + + @locked + def is_closed(self): + """Returns True if connection is closed.""" + return self.status == CLOSED + + def fileno(self): + """Returns the file descriptor of the associated socket.""" + return self.socket.fileno() + + def close(self): + """Closes connection""" + self.status = CLOSED + self.socket.close() + + +class TNonblockingServer(object): + """Non-blocking server.""" + + def __init__(self, + processor, + lsocket, + inputProtocolFactory=None, + outputProtocolFactory=None, + threads=10): + self.processor = processor + self.socket = lsocket + self.in_protocol = inputProtocolFactory or TBinaryProtocolFactory() + self.out_protocol = outputProtocolFactory or self.in_protocol + self.threads = int(threads) + self.clients = {} + self.tasks = queue.Queue() + self._read, self._write = socket.socketpair() + self.prepared = False + self._stop = False + + def setNumThreads(self, num): + """Set the number of worker threads that should be created.""" + # implement ThreadPool interface + assert not self.prepared, "Can't change number of threads after start" + self.threads = num + + def prepare(self): + """Prepares server for serve requests.""" + if self.prepared: + return + self.socket.listen() + for _ in range(self.threads): + thread = Worker(self.tasks) + thread.setDaemon(True) + thread.start() + self.prepared = True + + def wake_up(self): + """Wake up main thread. + + The server usually waits in select call in we should terminate one. + The simplest way is using socketpair. + + Select always wait to read from the first socket of socketpair. + + In this case, we can just write anything to the second socket from + socketpair. + """ + self._write.send(b'1') + + def stop(self): + """Stop the server. + + This method causes the serve() method to return. stop() may be invoked + from within your handler, or from another thread. + + After stop() is called, serve() will return but the server will still + be listening on the socket. serve() may then be called again to resume + processing requests. Alternatively, close() may be called after + serve() returns to close the server socket and shutdown all worker + threads. + """ + self._stop = True + self.wake_up() + + def _select(self): + """Does select on open connections.""" + readable = [self.socket.handle.fileno(), self._read.fileno()] + writable = [] + remaining = [] + for i, connection in list(self.clients.items()): + if connection.is_readable(): + readable.append(connection.fileno()) + if connection.remaining or connection.received: + remaining.append(connection.fileno()) + if connection.is_writeable(): + writable.append(connection.fileno()) + if connection.is_closed(): + del self.clients[i] + if remaining: + return remaining, [], [], False + else: + return select.select(readable, writable, readable) + (True,) + + def handle(self): + """Handle requests. + + WARNING! You must call prepare() BEFORE calling handle() + """ + assert self.prepared, "You have to call prepare before handle" + rset, wset, xset, selected = self._select() + for readable in rset: + if readable == self._read.fileno(): + # don't care i just need to clean readable flag + self._read.recv(1024) + elif readable == self.socket.handle.fileno(): + try: + client = self.socket.accept() + if client: + self.clients[client.handle.fileno()] = Connection(client.handle, + self.wake_up) + except socket.error: + logger.debug('error while accepting', exc_info=True) + else: + connection = self.clients[readable] + if selected: + connection.read() + if connection.received: + connection.status = WAIT_PROCESS + msg = connection.received.popleft() + itransport = TTransport.TMemoryBuffer(msg.buffer, msg.offset) + otransport = TTransport.TMemoryBuffer() + iprot = self.in_protocol.getProtocol(itransport) + oprot = self.out_protocol.getProtocol(otransport) + self.tasks.put([self.processor, iprot, oprot, + otransport, connection.ready]) + for writeable in wset: + self.clients[writeable].write() + for oob in xset: + self.clients[oob].close() + del self.clients[oob] + + def close(self): + """Closes the server.""" + for _ in range(self.threads): + self.tasks.put([None, None, None, None, None]) + self.socket.close() + self.prepared = False + + def serve(self): + """Serve requests. + + Serve requests forever, or until stop() is called. + """ + self._stop = False + self.prepare() + while not self._stop: + self.handle() diff --git a/lib/py/src/server/TProcessPoolServer.py b/lib/py/src/server/TProcessPoolServer.py new file mode 100644 index 0000000..fe6dc81 --- /dev/null +++ b/lib/py/src/server/TProcessPoolServer.py @@ -0,0 +1,123 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +import logging + +from multiprocessing import Process, Value, Condition + +from .TServer import TServer +from thrift.transport.TTransport import TTransportException + +logger = logging.getLogger(__name__) + + +class TProcessPoolServer(TServer): + """Server with a fixed size pool of worker subprocesses to service requests + + Note that if you need shared state between the handlers - it's up to you! + Written by Dvir Volk, doat.com + """ + def __init__(self, *args): + TServer.__init__(self, *args) + self.numWorkers = 10 + self.workers = [] + self.isRunning = Value('b', False) + self.stopCondition = Condition() + self.postForkCallback = None + + def setPostForkCallback(self, callback): + if not callable(callback): + raise TypeError("This is not a callback!") + self.postForkCallback = callback + + def setNumWorkers(self, num): + """Set the number of worker threads that should be created""" + self.numWorkers = num + + def workerProcess(self): + """Loop getting clients from the shared queue and process them""" + if self.postForkCallback: + self.postForkCallback() + + while self.isRunning.value: + try: + client = self.serverTransport.accept() + if not client: + continue + self.serveClient(client) + except (KeyboardInterrupt, SystemExit): + return 0 + except Exception as x: + logger.exception(x) + + def serveClient(self, client): + """Process input/output from a client for as long as possible""" + itrans = self.inputTransportFactory.getTransport(client) + otrans = self.outputTransportFactory.getTransport(client) + iprot = self.inputProtocolFactory.getProtocol(itrans) + oprot = self.outputProtocolFactory.getProtocol(otrans) + + try: + while True: + self.processor.process(iprot, oprot) + except TTransportException: + pass + except Exception as x: + logger.exception(x) + + itrans.close() + otrans.close() + + def serve(self): + """Start workers and put into queue""" + # this is a shared state that can tell the workers to exit when False + self.isRunning.value = True + + # first bind and listen to the port + self.serverTransport.listen() + + # fork the children + for i in range(self.numWorkers): + try: + w = Process(target=self.workerProcess) + w.daemon = True + w.start() + self.workers.append(w) + except Exception as x: + logger.exception(x) + + # wait until the condition is set by stop() + while True: + self.stopCondition.acquire() + try: + self.stopCondition.wait() + break + except (SystemExit, KeyboardInterrupt): + break + except Exception as x: + logger.exception(x) + + self.isRunning.value = False + + def stop(self): + self.isRunning.value = False + self.stopCondition.acquire() + self.stopCondition.notify() + self.stopCondition.release() diff --git a/lib/py/src/server/TServer.py b/lib/py/src/server/TServer.py new file mode 100644 index 0000000..d5d9c98 --- /dev/null +++ b/lib/py/src/server/TServer.py @@ -0,0 +1,276 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from six.moves import queue +import logging +import os +import threading + +from thrift.protocol import TBinaryProtocol +from thrift.transport import TTransport + +logger = logging.getLogger(__name__) + + +class TServer(object): + """Base interface for a server, which must have a serve() method. + + Three constructors for all servers: + 1) (processor, serverTransport) + 2) (processor, serverTransport, transportFactory, protocolFactory) + 3) (processor, serverTransport, + inputTransportFactory, outputTransportFactory, + inputProtocolFactory, outputProtocolFactory) + """ + def __init__(self, *args): + if (len(args) == 2): + self.__initArgs__(args[0], args[1], + TTransport.TTransportFactoryBase(), + TTransport.TTransportFactoryBase(), + TBinaryProtocol.TBinaryProtocolFactory(), + TBinaryProtocol.TBinaryProtocolFactory()) + elif (len(args) == 4): + self.__initArgs__(args[0], args[1], args[2], args[2], args[3], args[3]) + elif (len(args) == 6): + self.__initArgs__(args[0], args[1], args[2], args[3], args[4], args[5]) + + def __initArgs__(self, processor, serverTransport, + inputTransportFactory, outputTransportFactory, + inputProtocolFactory, outputProtocolFactory): + self.processor = processor + self.serverTransport = serverTransport + self.inputTransportFactory = inputTransportFactory + self.outputTransportFactory = outputTransportFactory + self.inputProtocolFactory = inputProtocolFactory + self.outputProtocolFactory = outputProtocolFactory + + def serve(self): + pass + + +class TSimpleServer(TServer): + """Simple single-threaded server that just pumps around one transport.""" + + def __init__(self, *args): + TServer.__init__(self, *args) + + def serve(self): + self.serverTransport.listen() + while True: + client = self.serverTransport.accept() + if not client: + continue + itrans = self.inputTransportFactory.getTransport(client) + otrans = self.outputTransportFactory.getTransport(client) + iprot = self.inputProtocolFactory.getProtocol(itrans) + oprot = self.outputProtocolFactory.getProtocol(otrans) + try: + while True: + self.processor.process(iprot, oprot) + except TTransport.TTransportException: + pass + except Exception as x: + logger.exception(x) + + itrans.close() + otrans.close() + + +class TThreadedServer(TServer): + """Threaded server that spawns a new thread per each connection.""" + + def __init__(self, *args, **kwargs): + TServer.__init__(self, *args) + self.daemon = kwargs.get("daemon", False) + + def serve(self): + self.serverTransport.listen() + while True: + try: + client = self.serverTransport.accept() + if not client: + continue + t = threading.Thread(target=self.handle, args=(client,)) + t.setDaemon(self.daemon) + t.start() + except KeyboardInterrupt: + raise + except Exception as x: + logger.exception(x) + + def handle(self, client): + itrans = self.inputTransportFactory.getTransport(client) + otrans = self.outputTransportFactory.getTransport(client) + iprot = self.inputProtocolFactory.getProtocol(itrans) + oprot = self.outputProtocolFactory.getProtocol(otrans) + try: + while True: + self.processor.process(iprot, oprot) + except TTransport.TTransportException: + pass + except Exception as x: + logger.exception(x) + + itrans.close() + otrans.close() + + +class TThreadPoolServer(TServer): + """Server with a fixed size pool of threads which service requests.""" + + def __init__(self, *args, **kwargs): + TServer.__init__(self, *args) + self.clients = queue.Queue() + self.threads = 10 + self.daemon = kwargs.get("daemon", False) + + def setNumThreads(self, num): + """Set the number of worker threads that should be created""" + self.threads = num + + def serveThread(self): + """Loop around getting clients from the shared queue and process them.""" + while True: + try: + client = self.clients.get() + self.serveClient(client) + except Exception as x: + logger.exception(x) + + def serveClient(self, client): + """Process input/output from a client for as long as possible""" + itrans = self.inputTransportFactory.getTransport(client) + otrans = self.outputTransportFactory.getTransport(client) + iprot = self.inputProtocolFactory.getProtocol(itrans) + oprot = self.outputProtocolFactory.getProtocol(otrans) + try: + while True: + self.processor.process(iprot, oprot) + except TTransport.TTransportException: + pass + except Exception as x: + logger.exception(x) + + itrans.close() + otrans.close() + + def serve(self): + """Start a fixed number of worker threads and put client into a queue""" + for i in range(self.threads): + try: + t = threading.Thread(target=self.serveThread) + t.setDaemon(self.daemon) + t.start() + except Exception as x: + logger.exception(x) + + # Pump the socket for clients + self.serverTransport.listen() + while True: + try: + client = self.serverTransport.accept() + if not client: + continue + self.clients.put(client) + except Exception as x: + logger.exception(x) + + +class TForkingServer(TServer): + """A Thrift server that forks a new process for each request + + This is more scalable than the threaded server as it does not cause + GIL contention. + + Note that this has different semantics from the threading server. + Specifically, updates to shared variables will no longer be shared. + It will also not work on windows. + + This code is heavily inspired by SocketServer.ForkingMixIn in the + Python stdlib. + """ + def __init__(self, *args): + TServer.__init__(self, *args) + self.children = [] + + def serve(self): + def try_close(file): + try: + file.close() + except IOError as e: + logger.warning(e, exc_info=True) + + self.serverTransport.listen() + while True: + client = self.serverTransport.accept() + if not client: + continue + try: + pid = os.fork() + + if pid: # parent + # add before collect, otherwise you race w/ waitpid + self.children.append(pid) + self.collect_children() + + # Parent must close socket or the connection may not get + # closed promptly + itrans = self.inputTransportFactory.getTransport(client) + otrans = self.outputTransportFactory.getTransport(client) + try_close(itrans) + try_close(otrans) + else: + itrans = self.inputTransportFactory.getTransport(client) + otrans = self.outputTransportFactory.getTransport(client) + + iprot = self.inputProtocolFactory.getProtocol(itrans) + oprot = self.outputProtocolFactory.getProtocol(otrans) + + ecode = 0 + try: + try: + while True: + self.processor.process(iprot, oprot) + except TTransport.TTransportException: + pass + except Exception as e: + logger.exception(e) + ecode = 1 + finally: + try_close(itrans) + try_close(otrans) + + os._exit(ecode) + + except TTransport.TTransportException: + pass + except Exception as x: + logger.exception(x) + + def collect_children(self): + while self.children: + try: + pid, status = os.waitpid(0, os.WNOHANG) + except os.error: + pid = None + + if pid: + self.children.remove(pid) + else: + break diff --git a/lib/py/src/server/__init__.py b/lib/py/src/server/__init__.py new file mode 100644 index 0000000..1bf6e25 --- /dev/null +++ b/lib/py/src/server/__init__.py @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +__all__ = ['TServer', 'TNonblockingServer'] diff --git a/lib/py/src/transport/THttpClient.py b/lib/py/src/transport/THttpClient.py new file mode 100644 index 0000000..fb33421 --- /dev/null +++ b/lib/py/src/transport/THttpClient.py @@ -0,0 +1,194 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from io import BytesIO +import os +import socket +import sys +import warnings +import base64 + +from six.moves import urllib +from six.moves import http_client + +from .TTransport import TTransportBase +import six + + +class THttpClient(TTransportBase): + """Http implementation of TTransport base.""" + + def __init__(self, uri_or_host, port=None, path=None): + """THttpClient supports two different types constructor parameters. + + THttpClient(host, port, path) - deprecated + THttpClient(uri) + + Only the second supports https. + """ + if port is not None: + warnings.warn( + "Please use the THttpClient('http://host:port/path') syntax", + DeprecationWarning, + stacklevel=2) + self.host = uri_or_host + self.port = port + assert path + self.path = path + self.scheme = 'http' + else: + parsed = urllib.parse.urlparse(uri_or_host) + self.scheme = parsed.scheme + assert self.scheme in ('http', 'https') + if self.scheme == 'http': + self.port = parsed.port or http_client.HTTP_PORT + elif self.scheme == 'https': + self.port = parsed.port or http_client.HTTPS_PORT + self.host = parsed.hostname + self.path = parsed.path + if parsed.query: + self.path += '?%s' % parsed.query + try: + proxy = urllib.request.getproxies()[self.scheme] + except KeyError: + proxy = None + else: + if urllib.request.proxy_bypass(self.host): + proxy = None + if proxy: + parsed = urllib.parse.urlparse(proxy) + self.realhost = self.host + self.realport = self.port + self.host = parsed.hostname + self.port = parsed.port + self.proxy_auth = self.basic_proxy_auth_header(parsed) + else: + self.realhost = self.realport = self.proxy_auth = None + self.__wbuf = BytesIO() + self.__http = None + self.__http_response = None + self.__timeout = None + self.__custom_headers = None + + @staticmethod + def basic_proxy_auth_header(proxy): + if proxy is None or not proxy.username: + return None + ap = "%s:%s" % (urllib.parse.unquote(proxy.username), + urllib.parse.unquote(proxy.password)) + cr = base64.b64encode(ap).strip() + return "Basic " + cr + + def using_proxy(self): + return self.realhost is not None + + def open(self): + if self.scheme == 'http': + self.__http = http_client.HTTPConnection(self.host, self.port) + elif self.scheme == 'https': + self.__http = http_client.HTTPSConnection(self.host, self.port) + if self.using_proxy(): + self.__http.set_tunnel(self.realhost, self.realport, + {"Proxy-Authorization": self.proxy_auth}) + + def close(self): + self.__http.close() + self.__http = None + self.__http_response = None + + def isOpen(self): + return self.__http is not None + + def setTimeout(self, ms): + if not hasattr(socket, 'getdefaulttimeout'): + raise NotImplementedError + + if ms is None: + self.__timeout = None + else: + self.__timeout = ms / 1000.0 + + def setCustomHeaders(self, headers): + self.__custom_headers = headers + + def read(self, sz): + return self.__http_response.read(sz) + + def write(self, buf): + self.__wbuf.write(buf) + + def __withTimeout(f): + def _f(*args, **kwargs): + orig_timeout = socket.getdefaulttimeout() + socket.setdefaulttimeout(args[0].__timeout) + try: + result = f(*args, **kwargs) + finally: + socket.setdefaulttimeout(orig_timeout) + return result + return _f + + def flush(self): + if self.isOpen(): + self.close() + self.open() + + # Pull data out of buffer + data = self.__wbuf.getvalue() + self.__wbuf = BytesIO() + + # HTTP request + if self.using_proxy() and self.scheme == "http": + # need full URL of real host for HTTP proxy here (HTTPS uses CONNECT tunnel) + self.__http.putrequest('POST', "http://%s:%s%s" % + (self.realhost, self.realport, self.path)) + else: + self.__http.putrequest('POST', self.path) + + # Write headers + self.__http.putheader('Content-Type', 'application/x-thrift') + self.__http.putheader('Content-Length', str(len(data))) + if self.using_proxy() and self.scheme == "http" and self.proxy_auth is not None: + self.__http.putheader("Proxy-Authorization", self.proxy_auth) + + if not self.__custom_headers or 'User-Agent' not in self.__custom_headers: + user_agent = 'Python/THttpClient' + script = os.path.basename(sys.argv[0]) + if script: + user_agent = '%s (%s)' % (user_agent, urllib.parse.quote(script)) + self.__http.putheader('User-Agent', user_agent) + + if self.__custom_headers: + for key, val in six.iteritems(self.__custom_headers): + self.__http.putheader(key, val) + + self.__http.endheaders() + + # Write payload + self.__http.send(data) + + # Get reply to flush the request + self.__http_response = self.__http.getresponse() + self.code = self.__http_response.status + self.message = self.__http_response.reason + self.headers = self.__http_response.msg + + # Decorate if we know how to timeout + if hasattr(socket, 'getdefaulttimeout'): + flush = __withTimeout(flush) diff --git a/lib/py/src/transport/TSSLSocket.py b/lib/py/src/transport/TSSLSocket.py new file mode 100644 index 0000000..f85778a --- /dev/null +++ b/lib/py/src/transport/TSSLSocket.py @@ -0,0 +1,396 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import logging +import os +import socket +import ssl +import sys +import warnings + +from .sslcompat import _match_hostname, _match_has_ipaddress +from thrift.transport import TSocket +from thrift.transport.TTransport import TTransportException + +logger = logging.getLogger(__name__) +warnings.filterwarnings( + 'default', category=DeprecationWarning, module=__name__) + + +class TSSLBase(object): + # SSLContext is not available for Python < 2.7.9 + _has_ssl_context = sys.hexversion >= 0x020709F0 + + # ciphers argument is not available for Python < 2.7.0 + _has_ciphers = sys.hexversion >= 0x020700F0 + + # For python >= 2.7.9, use latest TLS that both client and server + # supports. + # SSL 2.0 and 3.0 are disabled via ssl.OP_NO_SSLv2 and ssl.OP_NO_SSLv3. + # For python < 2.7.9, use TLS 1.0 since TLSv1_X nor OP_NO_SSLvX is + # unavailable. + _default_protocol = ssl.PROTOCOL_SSLv23 if _has_ssl_context else \ + ssl.PROTOCOL_TLSv1 + + def _init_context(self, ssl_version): + if self._has_ssl_context: + self._context = ssl.SSLContext(ssl_version) + if self._context.protocol == ssl.PROTOCOL_SSLv23: + self._context.options |= ssl.OP_NO_SSLv2 + self._context.options |= ssl.OP_NO_SSLv3 + else: + self._context = None + self._ssl_version = ssl_version + + @property + def _should_verify(self): + if self._has_ssl_context: + return self._context.verify_mode != ssl.CERT_NONE + else: + return self.cert_reqs != ssl.CERT_NONE + + @property + def ssl_version(self): + if self._has_ssl_context: + return self.ssl_context.protocol + else: + return self._ssl_version + + @property + def ssl_context(self): + return self._context + + SSL_VERSION = _default_protocol + """ + Default SSL version. + For backword compatibility, it can be modified. + Use __init__ keywoard argument "ssl_version" instead. + """ + + def _deprecated_arg(self, args, kwargs, pos, key): + if len(args) <= pos: + return + real_pos = pos + 3 + warnings.warn( + '%dth positional argument is deprecated.' + 'please use keyward argument insteand.' + % real_pos, DeprecationWarning, stacklevel=3) + + if key in kwargs: + raise TypeError( + 'Duplicate argument: %dth argument and %s keyward argument.' + % (real_pos, key)) + kwargs[key] = args[pos] + + def _unix_socket_arg(self, host, port, args, kwargs): + key = 'unix_socket' + if host is None and port is None and len(args) == 1 and key not in kwargs: + kwargs[key] = args[0] + return True + return False + + def __getattr__(self, key): + if key == 'SSL_VERSION': + warnings.warn( + 'SSL_VERSION is deprecated.' + 'please use ssl_version attribute instead.', + DeprecationWarning, stacklevel=2) + return self.ssl_version + + def __init__(self, server_side, host, ssl_opts): + self._server_side = server_side + if TSSLBase.SSL_VERSION != self._default_protocol: + warnings.warn( + 'SSL_VERSION is deprecated.' + 'please use ssl_version keyward argument instead.', + DeprecationWarning, stacklevel=2) + self._context = ssl_opts.pop('ssl_context', None) + self._server_hostname = None + if not self._server_side: + self._server_hostname = ssl_opts.pop('server_hostname', host) + if self._context: + self._custom_context = True + if ssl_opts: + raise ValueError( + 'Incompatible arguments: ssl_context and %s' + % ' '.join(ssl_opts.keys())) + if not self._has_ssl_context: + raise ValueError( + 'ssl_context is not available for this version of Python') + else: + self._custom_context = False + ssl_version = ssl_opts.pop('ssl_version', TSSLBase.SSL_VERSION) + self._init_context(ssl_version) + self.cert_reqs = ssl_opts.pop('cert_reqs', ssl.CERT_REQUIRED) + self.ca_certs = ssl_opts.pop('ca_certs', None) + self.keyfile = ssl_opts.pop('keyfile', None) + self.certfile = ssl_opts.pop('certfile', None) + self.ciphers = ssl_opts.pop('ciphers', None) + + if ssl_opts: + raise ValueError( + 'Unknown keyword arguments: ', ' '.join(ssl_opts.keys())) + + if self._should_verify: + if not self.ca_certs: + raise ValueError( + 'ca_certs is needed when cert_reqs is not ssl.CERT_NONE') + if not os.access(self.ca_certs, os.R_OK): + raise IOError('Certificate Authority ca_certs file "%s" ' + 'is not readable, cannot validate SSL ' + 'certificates.' % (self.ca_certs)) + + @property + def certfile(self): + return self._certfile + + @certfile.setter + def certfile(self, certfile): + if self._server_side and not certfile: + raise ValueError('certfile is needed for server-side') + if certfile and not os.access(certfile, os.R_OK): + raise IOError('No such certfile found: %s' % (certfile)) + self._certfile = certfile + + def _wrap_socket(self, sock): + if self._has_ssl_context: + if not self._custom_context: + self.ssl_context.verify_mode = self.cert_reqs + if self.certfile: + self.ssl_context.load_cert_chain(self.certfile, + self.keyfile) + if self.ciphers: + self.ssl_context.set_ciphers(self.ciphers) + if self.ca_certs: + self.ssl_context.load_verify_locations(self.ca_certs) + return self.ssl_context.wrap_socket( + sock, server_side=self._server_side, + server_hostname=self._server_hostname) + else: + ssl_opts = { + 'ssl_version': self._ssl_version, + 'server_side': self._server_side, + 'ca_certs': self.ca_certs, + 'keyfile': self.keyfile, + 'certfile': self.certfile, + 'cert_reqs': self.cert_reqs, + } + if self.ciphers: + if self._has_ciphers: + ssl_opts['ciphers'] = self.ciphers + else: + logger.warning( + 'ciphers is specified but ignored due to old Python version') + return ssl.wrap_socket(sock, **ssl_opts) + + +class TSSLSocket(TSocket.TSocket, TSSLBase): + """ + SSL implementation of TSocket + + This class creates outbound sockets wrapped using the + python standard ssl module for encrypted connections. + """ + + # New signature + # def __init__(self, host='localhost', port=9090, unix_socket=None, + # **ssl_args): + # Deprecated signature + # def __init__(self, host='localhost', port=9090, validate=True, + # ca_certs=None, keyfile=None, certfile=None, + # unix_socket=None, ciphers=None): + def __init__(self, host='localhost', port=9090, *args, **kwargs): + """Positional arguments: ``host``, ``port``, ``unix_socket`` + + Keyword arguments: ``keyfile``, ``certfile``, ``cert_reqs``, + ``ssl_version``, ``ca_certs``, + ``ciphers`` (Python 2.7.0 or later), + ``server_hostname`` (Python 2.7.9 or later) + Passed to ssl.wrap_socket. See ssl.wrap_socket documentation. + + Alternative keyword arguments: (Python 2.7.9 or later) + ``ssl_context``: ssl.SSLContext to be used for SSLContext.wrap_socket + ``server_hostname``: Passed to SSLContext.wrap_socket + + Common keyword argument: + ``validate_callback`` (cert, hostname) -> None: + Called after SSL handshake. Can raise when hostname does not + match the cert. + """ + self.is_valid = False + self.peercert = None + + if args: + if len(args) > 6: + raise TypeError('Too many positional argument') + if not self._unix_socket_arg(host, port, args, kwargs): + self._deprecated_arg(args, kwargs, 0, 'validate') + self._deprecated_arg(args, kwargs, 1, 'ca_certs') + self._deprecated_arg(args, kwargs, 2, 'keyfile') + self._deprecated_arg(args, kwargs, 3, 'certfile') + self._deprecated_arg(args, kwargs, 4, 'unix_socket') + self._deprecated_arg(args, kwargs, 5, 'ciphers') + + validate = kwargs.pop('validate', None) + if validate is not None: + cert_reqs_name = 'CERT_REQUIRED' if validate else 'CERT_NONE' + warnings.warn( + 'validate is deprecated. please use cert_reqs=ssl.%s instead' + % cert_reqs_name, + DeprecationWarning, stacklevel=2) + if 'cert_reqs' in kwargs: + raise TypeError('Cannot specify both validate and cert_reqs') + kwargs['cert_reqs'] = ssl.CERT_REQUIRED if validate else ssl.CERT_NONE + + unix_socket = kwargs.pop('unix_socket', None) + self._validate_callback = kwargs.pop('validate_callback', _match_hostname) + TSSLBase.__init__(self, False, host, kwargs) + TSocket.TSocket.__init__(self, host, port, unix_socket) + + @property + def validate(self): + warnings.warn('validate is deprecated. please use cert_reqs instead', + DeprecationWarning, stacklevel=2) + return self.cert_reqs != ssl.CERT_NONE + + @validate.setter + def validate(self, value): + warnings.warn('validate is deprecated. please use cert_reqs instead', + DeprecationWarning, stacklevel=2) + self.cert_reqs = ssl.CERT_REQUIRED if value else ssl.CERT_NONE + + def _do_open(self, family, socktype): + plain_sock = socket.socket(family, socktype) + try: + return self._wrap_socket(plain_sock) + except Exception: + plain_sock.close() + msg = 'failed to initialize SSL' + logger.exception(msg) + raise TTransportException(TTransportException.NOT_OPEN, msg) + + def open(self): + super(TSSLSocket, self).open() + if self._should_verify: + self.peercert = self.handle.getpeercert() + try: + self._validate_callback(self.peercert, self._server_hostname) + self.is_valid = True + except TTransportException: + raise + except Exception as ex: + raise TTransportException(TTransportException.UNKNOWN, str(ex)) + + +class TSSLServerSocket(TSocket.TServerSocket, TSSLBase): + """SSL implementation of TServerSocket + + This uses the ssl module's wrap_socket() method to provide SSL + negotiated encryption. + """ + + # New signature + # def __init__(self, host='localhost', port=9090, unix_socket=None, **ssl_args): + # Deprecated signature + # def __init__(self, host=None, port=9090, certfile='cert.pem', unix_socket=None, ciphers=None): + def __init__(self, host=None, port=9090, *args, **kwargs): + """Positional arguments: ``host``, ``port``, ``unix_socket`` + + Keyword arguments: ``keyfile``, ``certfile``, ``cert_reqs``, ``ssl_version``, + ``ca_certs``, ``ciphers`` (Python 2.7.0 or later) + See ssl.wrap_socket documentation. + + Alternative keyword arguments: (Python 2.7.9 or later) + ``ssl_context``: ssl.SSLContext to be used for SSLContext.wrap_socket + ``server_hostname``: Passed to SSLContext.wrap_socket + + Common keyword argument: + ``validate_callback`` (cert, hostname) -> None: + Called after SSL handshake. Can raise when hostname does not + match the cert. + """ + if args: + if len(args) > 3: + raise TypeError('Too many positional argument') + if not self._unix_socket_arg(host, port, args, kwargs): + self._deprecated_arg(args, kwargs, 0, 'certfile') + self._deprecated_arg(args, kwargs, 1, 'unix_socket') + self._deprecated_arg(args, kwargs, 2, 'ciphers') + + if 'ssl_context' not in kwargs: + # Preserve existing behaviors for default values + if 'cert_reqs' not in kwargs: + kwargs['cert_reqs'] = ssl.CERT_NONE + if'certfile' not in kwargs: + kwargs['certfile'] = 'cert.pem' + + unix_socket = kwargs.pop('unix_socket', None) + self._validate_callback = \ + kwargs.pop('validate_callback', _match_hostname) + TSSLBase.__init__(self, True, None, kwargs) + TSocket.TServerSocket.__init__(self, host, port, unix_socket) + if self._should_verify and not _match_has_ipaddress: + raise ValueError('Need ipaddress and backports.ssl_match_hostname ' + 'module to verify client certificate') + + def setCertfile(self, certfile): + """Set or change the server certificate file used to wrap new + connections. + + @param certfile: The filename of the server certificate, + i.e. '/etc/certs/server.pem' + @type certfile: str + + Raises an IOError exception if the certfile is not present or unreadable. + """ + warnings.warn( + 'setCertfile is deprecated. please use certfile property instead.', + DeprecationWarning, stacklevel=2) + self.certfile = certfile + + def accept(self): + plain_client, addr = self.handle.accept() + try: + client = self._wrap_socket(plain_client) + except (ssl.SSLError, OSError): + logger.exception('Error while accepting from %s', addr) + # failed handshake/ssl wrap, close socket to client + plain_client.close() + # raise + # We can't raise the exception, because it kills most TServer derived + # serve() methods. + # Instead, return None, and let the TServer instance deal with it in + # other exception handling. (but TSimpleServer dies anyway) + return None + + if self._should_verify: + client.peercert = client.getpeercert() + try: + self._validate_callback(client.peercert, addr[0]) + client.is_valid = True + except Exception: + logger.warn('Failed to validate client certificate address: %s', + addr[0], exc_info=True) + client.close() + plain_client.close() + return None + + result = TSocket.TSocket() + result.handle = client + return result diff --git a/lib/py/src/transport/TSocket.py b/lib/py/src/transport/TSocket.py new file mode 100644 index 0000000..c91de9d --- /dev/null +++ b/lib/py/src/transport/TSocket.py @@ -0,0 +1,192 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import errno +import logging +import os +import socket +import sys + +from .TTransport import TTransportBase, TTransportException, TServerTransportBase + +logger = logging.getLogger(__name__) + + +class TSocketBase(TTransportBase): + def _resolveAddr(self): + if self._unix_socket is not None: + return [(socket.AF_UNIX, socket.SOCK_STREAM, None, None, + self._unix_socket)] + else: + return socket.getaddrinfo(self.host, + self.port, + self._socket_family, + socket.SOCK_STREAM, + 0, + socket.AI_PASSIVE | socket.AI_ADDRCONFIG) + + def close(self): + if self.handle: + self.handle.close() + self.handle = None + + +class TSocket(TSocketBase): + """Socket implementation of TTransport base.""" + + def __init__(self, host='localhost', port=9090, unix_socket=None, socket_family=socket.AF_UNSPEC): + """Initialize a TSocket + + @param host(str) The host to connect to. + @param port(int) The (TCP) port to connect to. + @param unix_socket(str) The filename of a unix socket to connect to. + (host and port will be ignored.) + @param socket_family(int) The socket family to use with this socket. + """ + self.host = host + self.port = port + self.handle = None + self._unix_socket = unix_socket + self._timeout = None + self._socket_family = socket_family + + def setHandle(self, h): + self.handle = h + + def isOpen(self): + return self.handle is not None + + def setTimeout(self, ms): + if ms is None: + self._timeout = None + else: + self._timeout = ms / 1000.0 + + if self.handle is not None: + self.handle.settimeout(self._timeout) + + def _do_open(self, family, socktype): + return socket.socket(family, socktype) + + @property + def _address(self): + return self._unix_socket if self._unix_socket else '%s:%d' % (self.host, self.port) + + def open(self): + if self.handle: + raise TTransportException(TTransportException.ALREADY_OPEN) + try: + addrs = self._resolveAddr() + except socket.gaierror: + msg = 'failed to resolve sockaddr for ' + str(self._address) + logger.exception(msg) + raise TTransportException(TTransportException.NOT_OPEN, msg) + for family, socktype, _, _, sockaddr in addrs: + handle = self._do_open(family, socktype) + handle.settimeout(self._timeout) + try: + handle.connect(sockaddr) + self.handle = handle + return + except socket.error: + handle.close() + logger.info('Could not connect to %s', sockaddr, exc_info=True) + msg = 'Could not connect to any of %s' % list(map(lambda a: a[4], + addrs)) + logger.error(msg) + raise TTransportException(TTransportException.NOT_OPEN, msg) + + def read(self, sz): + try: + buff = self.handle.recv(sz) + except socket.error as e: + if (e.args[0] == errno.ECONNRESET and + (sys.platform == 'darwin' or sys.platform.startswith('freebsd'))): + # freebsd and Mach don't follow POSIX semantic of recv + # and fail with ECONNRESET if peer performed shutdown. + # See corresponding comment and code in TSocket::read() + # in lib/cpp/src/transport/TSocket.cpp. + self.close() + # Trigger the check to raise the END_OF_FILE exception below. + buff = '' + else: + raise + if len(buff) == 0: + raise TTransportException(type=TTransportException.END_OF_FILE, + message='TSocket read 0 bytes') + return buff + + def write(self, buff): + if not self.handle: + raise TTransportException(type=TTransportException.NOT_OPEN, + message='Transport not open') + sent = 0 + have = len(buff) + while sent < have: + plus = self.handle.send(buff) + if plus == 0: + raise TTransportException(type=TTransportException.END_OF_FILE, + message='TSocket sent 0 bytes') + sent += plus + buff = buff[plus:] + + def flush(self): + pass + + +class TServerSocket(TSocketBase, TServerTransportBase): + """Socket implementation of TServerTransport base.""" + + def __init__(self, host=None, port=9090, unix_socket=None, socket_family=socket.AF_UNSPEC): + self.host = host + self.port = port + self._unix_socket = unix_socket + self._socket_family = socket_family + self.handle = None + + def listen(self): + res0 = self._resolveAddr() + socket_family = self._socket_family == socket.AF_UNSPEC and socket.AF_INET6 or self._socket_family + for res in res0: + if res[0] is socket_family or res is res0[-1]: + break + + # We need remove the old unix socket if the file exists and + # nobody is listening on it. + if self._unix_socket: + tmp = socket.socket(res[0], res[1]) + try: + tmp.connect(res[4]) + except socket.error as err: + eno, message = err.args + if eno == errno.ECONNREFUSED: + os.unlink(res[4]) + + self.handle = socket.socket(res[0], res[1]) + self.handle.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + if hasattr(self.handle, 'settimeout'): + self.handle.settimeout(None) + self.handle.bind(res[4]) + self.handle.listen(128) + + def accept(self): + client, addr = self.handle.accept() + result = TSocket() + result.setHandle(client) + return result diff --git a/lib/py/src/transport/TTransport.py b/lib/py/src/transport/TTransport.py new file mode 100644 index 0000000..c8855ca --- /dev/null +++ b/lib/py/src/transport/TTransport.py @@ -0,0 +1,454 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from struct import pack, unpack +from thrift.Thrift import TException +from ..compat import BufferIO + + +class TTransportException(TException): + """Custom Transport Exception class""" + + UNKNOWN = 0 + NOT_OPEN = 1 + ALREADY_OPEN = 2 + TIMED_OUT = 3 + END_OF_FILE = 4 + NEGATIVE_SIZE = 5 + SIZE_LIMIT = 6 + + def __init__(self, type=UNKNOWN, message=None): + TException.__init__(self, message) + self.type = type + + +class TTransportBase(object): + """Base class for Thrift transport layer.""" + + def isOpen(self): + pass + + def open(self): + pass + + def close(self): + pass + + def read(self, sz): + pass + + def readAll(self, sz): + buff = b'' + have = 0 + while (have < sz): + chunk = self.read(sz - have) + chunkLen = len(chunk) + have += chunkLen + buff += chunk + + if chunkLen == 0: + raise EOFError() + + return buff + + def write(self, buf): + pass + + def flush(self): + pass + + +# This class should be thought of as an interface. +class CReadableTransport(object): + """base class for transports that are readable from C""" + + # TODO(dreiss): Think about changing this interface to allow us to use + # a (Python, not c) StringIO instead, because it allows + # you to write after reading. + + # NOTE: This is a classic class, so properties will NOT work + # correctly for setting. + @property + def cstringio_buf(self): + """A cStringIO buffer that contains the current chunk we are reading.""" + pass + + def cstringio_refill(self, partialread, reqlen): + """Refills cstringio_buf. + + Returns the currently used buffer (which can but need not be the same as + the old cstringio_buf). partialread is what the C code has read from the + buffer, and should be inserted into the buffer before any more reads. The + return value must be a new, not borrowed reference. Something along the + lines of self._buf should be fine. + + If reqlen bytes can't be read, throw EOFError. + """ + pass + + +class TServerTransportBase(object): + """Base class for Thrift server transports.""" + + def listen(self): + pass + + def accept(self): + pass + + def close(self): + pass + + +class TTransportFactoryBase(object): + """Base class for a Transport Factory""" + + def getTransport(self, trans): + return trans + + +class TBufferedTransportFactory(object): + """Factory transport that builds buffered transports""" + + def getTransport(self, trans): + buffered = TBufferedTransport(trans) + return buffered + + +class TBufferedTransport(TTransportBase, CReadableTransport): + """Class that wraps another transport and buffers its I/O. + + The implementation uses a (configurable) fixed-size read buffer + but buffers all writes until a flush is performed. + """ + DEFAULT_BUFFER = 4096 + + def __init__(self, trans, rbuf_size=DEFAULT_BUFFER): + self.__trans = trans + self.__wbuf = BufferIO() + # Pass string argument to initialize read buffer as cStringIO.InputType + self.__rbuf = BufferIO(b'') + self.__rbuf_size = rbuf_size + + def isOpen(self): + return self.__trans.isOpen() + + def open(self): + return self.__trans.open() + + def close(self): + return self.__trans.close() + + def read(self, sz): + ret = self.__rbuf.read(sz) + if len(ret) != 0: + return ret + self.__rbuf = BufferIO(self.__trans.read(max(sz, self.__rbuf_size))) + return self.__rbuf.read(sz) + + def write(self, buf): + try: + self.__wbuf.write(buf) + except Exception as e: + # on exception reset wbuf so it doesn't contain a partial function call + self.__wbuf = BufferIO() + raise e + + def flush(self): + out = self.__wbuf.getvalue() + # reset wbuf before write/flush to preserve state on underlying failure + self.__wbuf = BufferIO() + self.__trans.write(out) + self.__trans.flush() + + # Implement the CReadableTransport interface. + @property + def cstringio_buf(self): + return self.__rbuf + + def cstringio_refill(self, partialread, reqlen): + retstring = partialread + if reqlen < self.__rbuf_size: + # try to make a read of as much as we can. + retstring += self.__trans.read(self.__rbuf_size) + + # but make sure we do read reqlen bytes. + if len(retstring) < reqlen: + retstring += self.__trans.readAll(reqlen - len(retstring)) + + self.__rbuf = BufferIO(retstring) + return self.__rbuf + + +class TMemoryBuffer(TTransportBase, CReadableTransport): + """Wraps a cBytesIO object as a TTransport. + + NOTE: Unlike the C++ version of this class, you cannot write to it + then immediately read from it. If you want to read from a + TMemoryBuffer, you must either pass a string to the constructor. + TODO(dreiss): Make this work like the C++ version. + """ + + def __init__(self, value=None, offset=0): + """value -- a value to read from for stringio + + If value is set, this will be a transport for reading, + otherwise, it is for writing""" + if value is not None: + self._buffer = BufferIO(value) + else: + self._buffer = BufferIO() + if offset: + self._buffer.seek(offset) + + def isOpen(self): + return not self._buffer.closed + + def open(self): + pass + + def close(self): + self._buffer.close() + + def read(self, sz): + return self._buffer.read(sz) + + def write(self, buf): + self._buffer.write(buf) + + def flush(self): + pass + + def getvalue(self): + return self._buffer.getvalue() + + # Implement the CReadableTransport interface. + @property + def cstringio_buf(self): + return self._buffer + + def cstringio_refill(self, partialread, reqlen): + # only one shot at reading... + raise EOFError() + + +class TFramedTransportFactory(object): + """Factory transport that builds framed transports""" + + def getTransport(self, trans): + framed = TFramedTransport(trans) + return framed + + +class TFramedTransport(TTransportBase, CReadableTransport): + """Class that wraps another transport and frames its I/O when writing.""" + + def __init__(self, trans,): + self.__trans = trans + self.__rbuf = BufferIO(b'') + self.__wbuf = BufferIO() + + def isOpen(self): + return self.__trans.isOpen() + + def open(self): + return self.__trans.open() + + def close(self): + return self.__trans.close() + + def read(self, sz): + ret = self.__rbuf.read(sz) + if len(ret) != 0: + return ret + + self.readFrame() + return self.__rbuf.read(sz) + + def readFrame(self): + buff = self.__trans.readAll(4) + sz, = unpack('!i', buff) + self.__rbuf = BufferIO(self.__trans.readAll(sz)) + + def write(self, buf): + self.__wbuf.write(buf) + + def flush(self): + wout = self.__wbuf.getvalue() + wsz = len(wout) + # reset wbuf before write/flush to preserve state on underlying failure + self.__wbuf = BufferIO() + # N.B.: Doing this string concatenation is WAY cheaper than making + # two separate calls to the underlying socket object. Socket writes in + # Python turn out to be REALLY expensive, but it seems to do a pretty + # good job of managing string buffer operations without excessive copies + buf = pack("!i", wsz) + wout + self.__trans.write(buf) + self.__trans.flush() + + # Implement the CReadableTransport interface. + @property + def cstringio_buf(self): + return self.__rbuf + + def cstringio_refill(self, prefix, reqlen): + # self.__rbuf will already be empty here because fastbinary doesn't + # ask for a refill until the previous buffer is empty. Therefore, + # we can start reading new frames immediately. + while len(prefix) < reqlen: + self.readFrame() + prefix += self.__rbuf.getvalue() + self.__rbuf = BufferIO(prefix) + return self.__rbuf + + +class TFileObjectTransport(TTransportBase): + """Wraps a file-like object to make it work as a Thrift transport.""" + + def __init__(self, fileobj): + self.fileobj = fileobj + + def isOpen(self): + return True + + def close(self): + self.fileobj.close() + + def read(self, sz): + return self.fileobj.read(sz) + + def write(self, buf): + self.fileobj.write(buf) + + def flush(self): + self.fileobj.flush() + + +class TSaslClientTransport(TTransportBase, CReadableTransport): + """ + SASL transport + """ + + START = 1 + OK = 2 + BAD = 3 + ERROR = 4 + COMPLETE = 5 + + def __init__(self, transport, host, service, mechanism='GSSAPI', + **sasl_kwargs): + """ + transport: an underlying transport to use, typically just a TSocket + host: the name of the server, from a SASL perspective + service: the name of the server's service, from a SASL perspective + mechanism: the name of the preferred mechanism to use + + All other kwargs will be passed to the puresasl.client.SASLClient + constructor. + """ + + from puresasl.client import SASLClient + + self.transport = transport + self.sasl = SASLClient(host, service, mechanism, **sasl_kwargs) + + self.__wbuf = BufferIO() + self.__rbuf = BufferIO(b'') + + def open(self): + if not self.transport.isOpen(): + self.transport.open() + + self.send_sasl_msg(self.START, self.sasl.mechanism) + self.send_sasl_msg(self.OK, self.sasl.process()) + + while True: + status, challenge = self.recv_sasl_msg() + if status == self.OK: + self.send_sasl_msg(self.OK, self.sasl.process(challenge)) + elif status == self.COMPLETE: + if not self.sasl.complete: + raise TTransportException( + TTransportException.NOT_OPEN, + "The server erroneously indicated " + "that SASL negotiation was complete") + else: + break + else: + raise TTransportException( + TTransportException.NOT_OPEN, + "Bad SASL negotiation status: %d (%s)" + % (status, challenge)) + + def send_sasl_msg(self, status, body): + header = pack(">BI", status, len(body)) + self.transport.write(header + body) + self.transport.flush() + + def recv_sasl_msg(self): + header = self.transport.readAll(5) + status, length = unpack(">BI", header) + if length > 0: + payload = self.transport.readAll(length) + else: + payload = "" + return status, payload + + def write(self, data): + self.__wbuf.write(data) + + def flush(self): + data = self.__wbuf.getvalue() + encoded = self.sasl.wrap(data) + self.transport.write(''.join((pack("!i", len(encoded)), encoded))) + self.transport.flush() + self.__wbuf = BufferIO() + + def read(self, sz): + ret = self.__rbuf.read(sz) + if len(ret) != 0: + return ret + + self._read_frame() + return self.__rbuf.read(sz) + + def _read_frame(self): + header = self.transport.readAll(4) + length, = unpack('!i', header) + encoded = self.transport.readAll(length) + self.__rbuf = BufferIO(self.sasl.unwrap(encoded)) + + def close(self): + self.sasl.dispose() + self.transport.close() + + # based on TFramedTransport + @property + def cstringio_buf(self): + return self.__rbuf + + def cstringio_refill(self, prefix, reqlen): + # self.__rbuf will already be empty here because fastbinary doesn't + # ask for a refill until the previous buffer is empty. Therefore, + # we can start reading new frames immediately. + while len(prefix) < reqlen: + self._read_frame() + prefix += self.__rbuf.getvalue() + self.__rbuf = BufferIO(prefix) + return self.__rbuf diff --git a/lib/py/src/transport/TTwisted.py b/lib/py/src/transport/TTwisted.py new file mode 100644 index 0000000..a27f0ad --- /dev/null +++ b/lib/py/src/transport/TTwisted.py @@ -0,0 +1,329 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from io import BytesIO +import struct + +from zope.interface import implementer, Interface, Attribute +from twisted.internet.protocol import ServerFactory, ClientFactory, \ + connectionDone +from twisted.internet import defer +from twisted.internet.threads import deferToThread +from twisted.protocols import basic +from twisted.web import server, resource, http + +from thrift.transport import TTransport + + +class TMessageSenderTransport(TTransport.TTransportBase): + + def __init__(self): + self.__wbuf = BytesIO() + + def write(self, buf): + self.__wbuf.write(buf) + + def flush(self): + msg = self.__wbuf.getvalue() + self.__wbuf = BytesIO() + return self.sendMessage(msg) + + def sendMessage(self, message): + raise NotImplementedError + + +class TCallbackTransport(TMessageSenderTransport): + + def __init__(self, func): + TMessageSenderTransport.__init__(self) + self.func = func + + def sendMessage(self, message): + return self.func(message) + + +class ThriftClientProtocol(basic.Int32StringReceiver): + + MAX_LENGTH = 2 ** 31 - 1 + + def __init__(self, client_class, iprot_factory, oprot_factory=None): + self._client_class = client_class + self._iprot_factory = iprot_factory + if oprot_factory is None: + self._oprot_factory = iprot_factory + else: + self._oprot_factory = oprot_factory + + self.recv_map = {} + self.started = defer.Deferred() + + def dispatch(self, msg): + self.sendString(msg) + + def connectionMade(self): + tmo = TCallbackTransport(self.dispatch) + self.client = self._client_class(tmo, self._oprot_factory) + self.started.callback(self.client) + + def connectionLost(self, reason=connectionDone): + # the called errbacks can add items to our client's _reqs, + # so we need to use a tmp, and iterate until no more requests + # are added during errbacks + if self.client: + tex = TTransport.TTransportException( + type=TTransport.TTransportException.END_OF_FILE, + message='Connection closed (%s)' % reason) + while self.client._reqs: + _, v = self.client._reqs.popitem() + v.errback(tex) + del self.client._reqs + self.client = None + + def stringReceived(self, frame): + tr = TTransport.TMemoryBuffer(frame) + iprot = self._iprot_factory.getProtocol(tr) + (fname, mtype, rseqid) = iprot.readMessageBegin() + + try: + method = self.recv_map[fname] + except KeyError: + method = getattr(self.client, 'recv_' + fname) + self.recv_map[fname] = method + + method(iprot, mtype, rseqid) + + +class ThriftSASLClientProtocol(ThriftClientProtocol): + + START = 1 + OK = 2 + BAD = 3 + ERROR = 4 + COMPLETE = 5 + + MAX_LENGTH = 2 ** 31 - 1 + + def __init__(self, client_class, iprot_factory, oprot_factory=None, + host=None, service=None, mechanism='GSSAPI', **sasl_kwargs): + """ + host: the name of the server, from a SASL perspective + service: the name of the server's service, from a SASL perspective + mechanism: the name of the preferred mechanism to use + + All other kwargs will be passed to the puresasl.client.SASLClient + constructor. + """ + + from puresasl.client import SASLClient + self.SASLCLient = SASLClient + + ThriftClientProtocol.__init__(self, client_class, iprot_factory, oprot_factory) + + self._sasl_negotiation_deferred = None + self._sasl_negotiation_status = None + self.client = None + + if host is not None: + self.createSASLClient(host, service, mechanism, **sasl_kwargs) + + def createSASLClient(self, host, service, mechanism, **kwargs): + self.sasl = self.SASLClient(host, service, mechanism, **kwargs) + + def dispatch(self, msg): + encoded = self.sasl.wrap(msg) + len_and_encoded = ''.join((struct.pack('!i', len(encoded)), encoded)) + ThriftClientProtocol.dispatch(self, len_and_encoded) + + @defer.inlineCallbacks + def connectionMade(self): + self._sendSASLMessage(self.START, self.sasl.mechanism) + initial_message = yield deferToThread(self.sasl.process) + self._sendSASLMessage(self.OK, initial_message) + + while True: + status, challenge = yield self._receiveSASLMessage() + if status == self.OK: + response = yield deferToThread(self.sasl.process, challenge) + self._sendSASLMessage(self.OK, response) + elif status == self.COMPLETE: + if not self.sasl.complete: + msg = "The server erroneously indicated that SASL " \ + "negotiation was complete" + raise TTransport.TTransportException(msg, message=msg) + else: + break + else: + msg = "Bad SASL negotiation status: %d (%s)" % (status, challenge) + raise TTransport.TTransportException(msg, message=msg) + + self._sasl_negotiation_deferred = None + ThriftClientProtocol.connectionMade(self) + + def _sendSASLMessage(self, status, body): + if body is None: + body = "" + header = struct.pack(">BI", status, len(body)) + self.transport.write(header + body) + + def _receiveSASLMessage(self): + self._sasl_negotiation_deferred = defer.Deferred() + self._sasl_negotiation_status = None + return self._sasl_negotiation_deferred + + def connectionLost(self, reason=connectionDone): + if self.client: + ThriftClientProtocol.connectionLost(self, reason) + + def dataReceived(self, data): + if self._sasl_negotiation_deferred: + # we got a sasl challenge in the format (status, length, challenge) + # save the status, let IntNStringReceiver piece the challenge data together + self._sasl_negotiation_status, = struct.unpack("B", data[0]) + ThriftClientProtocol.dataReceived(self, data[1:]) + else: + # normal frame, let IntNStringReceiver piece it together + ThriftClientProtocol.dataReceived(self, data) + + def stringReceived(self, frame): + if self._sasl_negotiation_deferred: + # the frame is just a SASL challenge + response = (self._sasl_negotiation_status, frame) + self._sasl_negotiation_deferred.callback(response) + else: + # there's a second 4 byte length prefix inside the frame + decoded_frame = self.sasl.unwrap(frame[4:]) + ThriftClientProtocol.stringReceived(self, decoded_frame) + + +class ThriftServerProtocol(basic.Int32StringReceiver): + + MAX_LENGTH = 2 ** 31 - 1 + + def dispatch(self, msg): + self.sendString(msg) + + def processError(self, error): + self.transport.loseConnection() + + def processOk(self, _, tmo): + msg = tmo.getvalue() + + if len(msg) > 0: + self.dispatch(msg) + + def stringReceived(self, frame): + tmi = TTransport.TMemoryBuffer(frame) + tmo = TTransport.TMemoryBuffer() + + iprot = self.factory.iprot_factory.getProtocol(tmi) + oprot = self.factory.oprot_factory.getProtocol(tmo) + + d = self.factory.processor.process(iprot, oprot) + d.addCallbacks(self.processOk, self.processError, + callbackArgs=(tmo,)) + + +class IThriftServerFactory(Interface): + + processor = Attribute("Thrift processor") + + iprot_factory = Attribute("Input protocol factory") + + oprot_factory = Attribute("Output protocol factory") + + +class IThriftClientFactory(Interface): + + client_class = Attribute("Thrift client class") + + iprot_factory = Attribute("Input protocol factory") + + oprot_factory = Attribute("Output protocol factory") + + +@implementer(IThriftServerFactory) +class ThriftServerFactory(ServerFactory): + + protocol = ThriftServerProtocol + + def __init__(self, processor, iprot_factory, oprot_factory=None): + self.processor = processor + self.iprot_factory = iprot_factory + if oprot_factory is None: + self.oprot_factory = iprot_factory + else: + self.oprot_factory = oprot_factory + + +@implementer(IThriftClientFactory) +class ThriftClientFactory(ClientFactory): + + protocol = ThriftClientProtocol + + def __init__(self, client_class, iprot_factory, oprot_factory=None): + self.client_class = client_class + self.iprot_factory = iprot_factory + if oprot_factory is None: + self.oprot_factory = iprot_factory + else: + self.oprot_factory = oprot_factory + + def buildProtocol(self, addr): + p = self.protocol(self.client_class, self.iprot_factory, + self.oprot_factory) + p.factory = self + return p + + +class ThriftResource(resource.Resource): + + allowedMethods = ('POST',) + + def __init__(self, processor, inputProtocolFactory, + outputProtocolFactory=None): + resource.Resource.__init__(self) + self.inputProtocolFactory = inputProtocolFactory + if outputProtocolFactory is None: + self.outputProtocolFactory = inputProtocolFactory + else: + self.outputProtocolFactory = outputProtocolFactory + self.processor = processor + + def getChild(self, path, request): + return self + + def _cbProcess(self, _, request, tmo): + msg = tmo.getvalue() + request.setResponseCode(http.OK) + request.setHeader("content-type", "application/x-thrift") + request.write(msg) + request.finish() + + def render_POST(self, request): + request.content.seek(0, 0) + data = request.content.read() + tmi = TTransport.TMemoryBuffer(data) + tmo = TTransport.TMemoryBuffer() + + iprot = self.inputProtocolFactory.getProtocol(tmi) + oprot = self.outputProtocolFactory.getProtocol(tmo) + + d = self.processor.process(iprot, oprot) + d.addCallback(self._cbProcess, request, tmo) + return server.NOT_DONE_YET diff --git a/lib/py/src/transport/TZlibTransport.py b/lib/py/src/transport/TZlibTransport.py new file mode 100644 index 0000000..e848579 --- /dev/null +++ b/lib/py/src/transport/TZlibTransport.py @@ -0,0 +1,248 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +"""TZlibTransport provides a compressed transport and transport factory +class, using the python standard library zlib module to implement +data compression. +""" + +from __future__ import division +import zlib +from .TTransport import TTransportBase, CReadableTransport +from ..compat import BufferIO + + +class TZlibTransportFactory(object): + """Factory transport that builds zlib compressed transports. + + This factory caches the last single client/transport that it was passed + and returns the same TZlibTransport object that was created. + + This caching means the TServer class will get the _same_ transport + object for both input and output transports from this factory. + (For non-threaded scenarios only, since the cache only holds one object) + + The purpose of this caching is to allocate only one TZlibTransport where + only one is really needed (since it must have separate read/write buffers), + and makes the statistics from getCompSavings() and getCompRatio() + easier to understand. + """ + # class scoped cache of last transport given and zlibtransport returned + _last_trans = None + _last_z = None + + def getTransport(self, trans, compresslevel=9): + """Wrap a transport, trans, with the TZlibTransport + compressed transport class, returning a new + transport to the caller. + + @param compresslevel: The zlib compression level, ranging + from 0 (no compression) to 9 (best compression). Defaults to 9. + @type compresslevel: int + + This method returns a TZlibTransport which wraps the + passed C{trans} TTransport derived instance. + """ + if trans == self._last_trans: + return self._last_z + ztrans = TZlibTransport(trans, compresslevel) + self._last_trans = trans + self._last_z = ztrans + return ztrans + + +class TZlibTransport(TTransportBase, CReadableTransport): + """Class that wraps a transport with zlib, compressing writes + and decompresses reads, using the python standard + library zlib module. + """ + # Read buffer size for the python fastbinary C extension, + # the TBinaryProtocolAccelerated class. + DEFAULT_BUFFSIZE = 4096 + + def __init__(self, trans, compresslevel=9): + """Create a new TZlibTransport, wrapping C{trans}, another + TTransport derived object. + + @param trans: A thrift transport object, i.e. a TSocket() object. + @type trans: TTransport + @param compresslevel: The zlib compression level, ranging + from 0 (no compression) to 9 (best compression). Default is 9. + @type compresslevel: int + """ + self.__trans = trans + self.compresslevel = compresslevel + self.__rbuf = BufferIO() + self.__wbuf = BufferIO() + self._init_zlib() + self._init_stats() + + def _reinit_buffers(self): + """Internal method to initialize/reset the internal StringIO objects + for read and write buffers. + """ + self.__rbuf = BufferIO() + self.__wbuf = BufferIO() + + def _init_stats(self): + """Internal method to reset the internal statistics counters + for compression ratios and bandwidth savings. + """ + self.bytes_in = 0 + self.bytes_out = 0 + self.bytes_in_comp = 0 + self.bytes_out_comp = 0 + + def _init_zlib(self): + """Internal method for setting up the zlib compression and + decompression objects. + """ + self._zcomp_read = zlib.decompressobj() + self._zcomp_write = zlib.compressobj(self.compresslevel) + + def getCompRatio(self): + """Get the current measured compression ratios (in,out) from + this transport. + + Returns a tuple of: + (inbound_compression_ratio, outbound_compression_ratio) + + The compression ratios are computed as: + compressed / uncompressed + + E.g., data that compresses by 10x will have a ratio of: 0.10 + and data that compresses to half of ts original size will + have a ratio of 0.5 + + None is returned if no bytes have yet been processed in + a particular direction. + """ + r_percent, w_percent = (None, None) + if self.bytes_in > 0: + r_percent = self.bytes_in_comp / self.bytes_in + if self.bytes_out > 0: + w_percent = self.bytes_out_comp / self.bytes_out + return (r_percent, w_percent) + + def getCompSavings(self): + """Get the current count of saved bytes due to data + compression. + + Returns a tuple of: + (inbound_saved_bytes, outbound_saved_bytes) + + Note: if compression is actually expanding your + data (only likely with very tiny thrift objects), then + the values returned will be negative. + """ + r_saved = self.bytes_in - self.bytes_in_comp + w_saved = self.bytes_out - self.bytes_out_comp + return (r_saved, w_saved) + + def isOpen(self): + """Return the underlying transport's open status""" + return self.__trans.isOpen() + + def open(self): + """Open the underlying transport""" + self._init_stats() + return self.__trans.open() + + def listen(self): + """Invoke the underlying transport's listen() method""" + self.__trans.listen() + + def accept(self): + """Accept connections on the underlying transport""" + return self.__trans.accept() + + def close(self): + """Close the underlying transport,""" + self._reinit_buffers() + self._init_zlib() + return self.__trans.close() + + def read(self, sz): + """Read up to sz bytes from the decompressed bytes buffer, and + read from the underlying transport if the decompression + buffer is empty. + """ + ret = self.__rbuf.read(sz) + if len(ret) > 0: + return ret + # keep reading from transport until something comes back + while True: + if self.readComp(sz): + break + ret = self.__rbuf.read(sz) + return ret + + def readComp(self, sz): + """Read compressed data from the underlying transport, then + decompress it and append it to the internal StringIO read buffer + """ + zbuf = self.__trans.read(sz) + zbuf = self._zcomp_read.unconsumed_tail + zbuf + buf = self._zcomp_read.decompress(zbuf) + self.bytes_in += len(zbuf) + self.bytes_in_comp += len(buf) + old = self.__rbuf.read() + self.__rbuf = BufferIO(old + buf) + if len(old) + len(buf) == 0: + return False + return True + + def write(self, buf): + """Write some bytes, putting them into the internal write + buffer for eventual compression. + """ + self.__wbuf.write(buf) + + def flush(self): + """Flush any queued up data in the write buffer and ensure the + compression buffer is flushed out to the underlying transport + """ + wout = self.__wbuf.getvalue() + if len(wout) > 0: + zbuf = self._zcomp_write.compress(wout) + self.bytes_out += len(wout) + self.bytes_out_comp += len(zbuf) + else: + zbuf = '' + ztail = self._zcomp_write.flush(zlib.Z_SYNC_FLUSH) + self.bytes_out_comp += len(ztail) + if (len(zbuf) + len(ztail)) > 0: + self.__wbuf = BufferIO() + self.__trans.write(zbuf + ztail) + self.__trans.flush() + + @property + def cstringio_buf(self): + """Implement the CReadableTransport interface""" + return self.__rbuf + + def cstringio_refill(self, partialread, reqlen): + """Implement the CReadableTransport interface for refill""" + retstring = partialread + if reqlen < self.DEFAULT_BUFFSIZE: + retstring += self.read(self.DEFAULT_BUFFSIZE) + while len(retstring) < reqlen: + retstring += self.read(reqlen - len(retstring)) + self.__rbuf = BufferIO(retstring) + return self.__rbuf diff --git a/lib/py/src/transport/__init__.py b/lib/py/src/transport/__init__.py new file mode 100644 index 0000000..c9596d9 --- /dev/null +++ b/lib/py/src/transport/__init__.py @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +__all__ = ['TTransport', 'TSocket', 'THttpClient', 'TZlibTransport'] diff --git a/lib/py/src/transport/sslcompat.py b/lib/py/src/transport/sslcompat.py new file mode 100644 index 0000000..ab00cb2 --- /dev/null +++ b/lib/py/src/transport/sslcompat.py @@ -0,0 +1,100 @@ +# +# licensed to the apache software foundation (asf) under one +# or more contributor license agreements. see the notice file +# distributed with this work for additional information +# regarding copyright ownership. the asf licenses this file +# to you under the apache license, version 2.0 (the +# "license"); you may not use this file except in compliance +# with the license. you may obtain a copy of the license at +# +# http://www.apache.org/licenses/license-2.0 +# +# unless required by applicable law or agreed to in writing, +# software distributed under the license is distributed on an +# "as is" basis, without warranties or conditions of any +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import logging +import sys + +from thrift.transport.TTransport import TTransportException + +logger = logging.getLogger(__name__) + + +def legacy_validate_callback(cert, hostname): + """legacy method to validate the peer's SSL certificate, and to check + the commonName of the certificate to ensure it matches the hostname we + used to make this connection. Does not support subjectAltName records + in certificates. + + raises TTransportException if the certificate fails validation. + """ + if 'subject' not in cert: + raise TTransportException( + TTransportException.NOT_OPEN, + 'No SSL certificate found from %s' % hostname) + fields = cert['subject'] + for field in fields: + # ensure structure we get back is what we expect + if not isinstance(field, tuple): + continue + cert_pair = field[0] + if len(cert_pair) < 2: + continue + cert_key, cert_value = cert_pair[0:2] + if cert_key != 'commonName': + continue + certhost = cert_value + # this check should be performed by some sort of Access Manager + if certhost == hostname: + # success, cert commonName matches desired hostname + return + else: + raise TTransportException( + TTransportException.UNKNOWN, + 'Hostname we connected to "%s" doesn\'t match certificate ' + 'provided commonName "%s"' % (hostname, certhost)) + raise TTransportException( + TTransportException.UNKNOWN, + 'Could not validate SSL certificate from host "%s". Cert=%s' + % (hostname, cert)) + + +def _optional_dependencies(): + try: + import ipaddress # noqa + logger.debug('ipaddress module is available') + ipaddr = True + except ImportError: + logger.warn('ipaddress module is unavailable') + ipaddr = False + + if sys.hexversion < 0x030500F0: + try: + from backports.ssl_match_hostname import match_hostname, __version__ as ver + ver = list(map(int, ver.split('.'))) + logger.debug('backports.ssl_match_hostname module is available') + match = match_hostname + if ver[0] * 10 + ver[1] >= 35: + return ipaddr, match + else: + logger.warn('backports.ssl_match_hostname module is too old') + ipaddr = False + except ImportError: + logger.warn('backports.ssl_match_hostname is unavailable') + ipaddr = False + try: + from ssl import match_hostname + logger.debug('ssl.match_hostname is available') + match = match_hostname + except ImportError: + logger.warn('using legacy validation callback') + match = legacy_validate_callback + return ipaddr, match + + +_match_has_ipaddress, _match_hostname = _optional_dependencies() diff --git a/lib/py/test/_import_local_thrift.py b/lib/py/test/_import_local_thrift.py new file mode 100644 index 0000000..d223122 --- /dev/null +++ b/lib/py/test/_import_local_thrift.py @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import glob +import os +import sys + +SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__)) +ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(SCRIPT_DIR))) + +for libpath in glob.glob(os.path.join(ROOT_DIR, 'lib', 'py', 'build', 'lib.*')): + if libpath.endswith('-%d.%d' % (sys.version_info[0], sys.version_info[1])): + sys.path.insert(0, libpath) + break diff --git a/lib/py/test/test_sslsocket.py b/lib/py/test/test_sslsocket.py new file mode 100644 index 0000000..3c4be9c --- /dev/null +++ b/lib/py/test/test_sslsocket.py @@ -0,0 +1,343 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import inspect +import logging +import os +import platform +import ssl +import sys +import tempfile +import threading +import unittest +import warnings +from contextlib import contextmanager + +import _import_local_thrift # noqa + +SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__)) +ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(SCRIPT_DIR))) +SERVER_PEM = os.path.join(ROOT_DIR, 'test', 'keys', 'server.pem') +SERVER_CERT = os.path.join(ROOT_DIR, 'test', 'keys', 'server.crt') +SERVER_KEY = os.path.join(ROOT_DIR, 'test', 'keys', 'server.key') +CLIENT_CERT_NO_IP = os.path.join(ROOT_DIR, 'test', 'keys', 'client.crt') +CLIENT_KEY_NO_IP = os.path.join(ROOT_DIR, 'test', 'keys', 'client.key') +CLIENT_CERT = os.path.join(ROOT_DIR, 'test', 'keys', 'client_v3.crt') +CLIENT_KEY = os.path.join(ROOT_DIR, 'test', 'keys', 'client_v3.key') +CLIENT_CA = os.path.join(ROOT_DIR, 'test', 'keys', 'CA.pem') + +TEST_CIPHERS = 'DES-CBC3-SHA' + + +class ServerAcceptor(threading.Thread): + def __init__(self, server, expect_failure=False): + super(ServerAcceptor, self).__init__() + self.daemon = True + self._server = server + self._listening = threading.Event() + self._port = None + self._port_bound = threading.Event() + self._client = None + self._client_accepted = threading.Event() + self._expect_failure = expect_failure + frame = inspect.stack(3)[2] + self.name = frame[3] + del frame + + def run(self): + self._server.listen() + self._listening.set() + + try: + address = self._server.handle.getsockname() + if len(address) > 1: + # AF_INET addresses are 2-tuples (host, port) and AF_INET6 are + # 4-tuples (host, port, ...), but in each case port is in the second slot. + self._port = address[1] + finally: + self._port_bound.set() + + try: + self._client = self._server.accept() + except Exception: + logging.exception('error on server side (%s):' % self.name) + if not self._expect_failure: + raise + finally: + self._client_accepted.set() + + def await_listening(self): + self._listening.wait() + + @property + def port(self): + self._port_bound.wait() + return self._port + + @property + def client(self): + self._client_accepted.wait() + return self._client + + +# Python 2.6 compat +class AssertRaises(object): + def __init__(self, expected): + self._expected = expected + + def __enter__(self): + pass + + def __exit__(self, exc_type, exc_value, traceback): + if not exc_type or not issubclass(exc_type, self._expected): + raise Exception('fail') + return True + + +class TSSLSocketTest(unittest.TestCase): + def _server_socket(self, **kwargs): + return TSSLServerSocket(port=0, **kwargs) + + @contextmanager + def _connectable_client(self, server, expect_failure=False, path=None, **client_kwargs): + acc = ServerAcceptor(server, expect_failure) + try: + acc.start() + acc.await_listening() + + host, port = ('localhost', acc.port) if path is None else (None, None) + client = TSSLSocket(host, port, unix_socket=path, **client_kwargs) + yield acc, client + finally: + if acc.client: + acc.client.close() + server.close() + + def _assert_connection_failure(self, server, path=None, **client_args): + logging.disable(logging.CRITICAL) + try: + with self._connectable_client(server, True, path=path, **client_args) as (acc, client): + # We need to wait for a connection failure, but not too long. 20ms is a tunable + # compromise between test speed and stability + client.setTimeout(20) + with self._assert_raises(TTransportException): + client.open() + self.assertTrue(acc.client is None) + finally: + logging.disable(logging.NOTSET) + + def _assert_raises(self, exc): + if sys.hexversion >= 0x020700F0: + return self.assertRaises(exc) + else: + return AssertRaises(exc) + + def _assert_connection_success(self, server, path=None, **client_args): + with self._connectable_client(server, path=path, **client_args) as (acc, client): + client.open() + try: + self.assertTrue(acc.client is not None) + finally: + client.close() + + # deprecated feature + def test_deprecation(self): + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__) + TSSLSocket('localhost', 0, validate=True, ca_certs=SERVER_CERT) + self.assertEqual(len(w), 1) + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__) + # Deprecated signature + # def __init__(self, host='localhost', port=9090, validate=True, ca_certs=None, keyfile=None, certfile=None, unix_socket=None, ciphers=None): + TSSLSocket('localhost', 0, True, SERVER_CERT, CLIENT_KEY, CLIENT_CERT, None, TEST_CIPHERS) + self.assertEqual(len(w), 7) + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__) + # Deprecated signature + # def __init__(self, host=None, port=9090, certfile='cert.pem', unix_socket=None, ciphers=None): + TSSLServerSocket(None, 0, SERVER_PEM, None, TEST_CIPHERS) + self.assertEqual(len(w), 3) + + # deprecated feature + def test_set_cert_reqs_by_validate(self): + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__) + c1 = TSSLSocket('localhost', 0, validate=True, ca_certs=SERVER_CERT) + self.assertEqual(c1.cert_reqs, ssl.CERT_REQUIRED) + + c1 = TSSLSocket('localhost', 0, validate=False) + self.assertEqual(c1.cert_reqs, ssl.CERT_NONE) + + self.assertEqual(len(w), 2) + + # deprecated feature + def test_set_validate_by_cert_reqs(self): + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__) + c1 = TSSLSocket('localhost', 0, cert_reqs=ssl.CERT_NONE) + self.assertFalse(c1.validate) + + c2 = TSSLSocket('localhost', 0, cert_reqs=ssl.CERT_REQUIRED, ca_certs=SERVER_CERT) + self.assertTrue(c2.validate) + + c3 = TSSLSocket('localhost', 0, cert_reqs=ssl.CERT_OPTIONAL, ca_certs=SERVER_CERT) + self.assertTrue(c3.validate) + + self.assertEqual(len(w), 3) + + def test_unix_domain_socket(self): + if platform.system() == 'Windows': + print('skipping test_unix_domain_socket') + return + fd, path = tempfile.mkstemp() + os.close(fd) + try: + server = self._server_socket(unix_socket=path, keyfile=SERVER_KEY, certfile=SERVER_CERT) + self._assert_connection_success(server, path=path, cert_reqs=ssl.CERT_NONE) + finally: + os.unlink(path) + + def test_server_cert(self): + server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT) + self._assert_connection_success(server, cert_reqs=ssl.CERT_REQUIRED, ca_certs=SERVER_CERT) + + server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT) + # server cert not in ca_certs + self._assert_connection_failure(server, cert_reqs=ssl.CERT_REQUIRED, ca_certs=CLIENT_CERT) + + server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT) + self._assert_connection_success(server, cert_reqs=ssl.CERT_NONE) + + def test_set_server_cert(self): + server = self._server_socket(keyfile=SERVER_KEY, certfile=CLIENT_CERT) + with self._assert_raises(Exception): + server.certfile = 'foo' + with self._assert_raises(Exception): + server.certfile = None + server.certfile = SERVER_CERT + self._assert_connection_success(server, cert_reqs=ssl.CERT_REQUIRED, ca_certs=SERVER_CERT) + + def test_client_cert(self): + if not _match_has_ipaddress: + print('skipping test_client_cert') + return + server = self._server_socket( + cert_reqs=ssl.CERT_REQUIRED, keyfile=SERVER_KEY, + certfile=SERVER_CERT, ca_certs=CLIENT_CERT) + self._assert_connection_failure(server, cert_reqs=ssl.CERT_NONE, certfile=SERVER_CERT, keyfile=SERVER_KEY) + + server = self._server_socket( + cert_reqs=ssl.CERT_REQUIRED, keyfile=SERVER_KEY, + certfile=SERVER_CERT, ca_certs=CLIENT_CA) + self._assert_connection_failure(server, cert_reqs=ssl.CERT_NONE, certfile=CLIENT_CERT_NO_IP, keyfile=CLIENT_KEY_NO_IP) + + server = self._server_socket( + cert_reqs=ssl.CERT_REQUIRED, keyfile=SERVER_KEY, + certfile=SERVER_CERT, ca_certs=CLIENT_CA) + self._assert_connection_success(server, cert_reqs=ssl.CERT_NONE, certfile=CLIENT_CERT, keyfile=CLIENT_KEY) + + server = self._server_socket( + cert_reqs=ssl.CERT_OPTIONAL, keyfile=SERVER_KEY, + certfile=SERVER_CERT, ca_certs=CLIENT_CA) + self._assert_connection_success(server, cert_reqs=ssl.CERT_NONE, certfile=CLIENT_CERT, keyfile=CLIENT_KEY) + + def test_ciphers(self): + server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ciphers=TEST_CIPHERS) + self._assert_connection_success(server, ca_certs=SERVER_CERT, ciphers=TEST_CIPHERS) + + if not TSSLSocket._has_ciphers: + # unittest.skip is not available for Python 2.6 + print('skipping test_ciphers') + return + server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT) + self._assert_connection_failure(server, ca_certs=SERVER_CERT, ciphers='NULL') + + server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ciphers=TEST_CIPHERS) + self._assert_connection_failure(server, ca_certs=SERVER_CERT, ciphers='NULL') + + def test_ssl2_and_ssl3_disabled(self): + if not hasattr(ssl, 'PROTOCOL_SSLv3'): + print('PROTOCOL_SSLv3 is not available') + else: + server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT) + self._assert_connection_failure(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv3) + + server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv3) + self._assert_connection_failure(server, ca_certs=SERVER_CERT) + + if not hasattr(ssl, 'PROTOCOL_SSLv2'): + print('PROTOCOL_SSLv2 is not available') + else: + server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT) + self._assert_connection_failure(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv2) + + server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv2) + self._assert_connection_failure(server, ca_certs=SERVER_CERT) + + def test_newer_tls(self): + if not TSSLSocket._has_ssl_context: + # unittest.skip is not available for Python 2.6 + print('skipping test_newer_tls') + return + if not hasattr(ssl, 'PROTOCOL_TLSv1_2'): + print('PROTOCOL_TLSv1_2 is not available') + else: + server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_2) + self._assert_connection_success(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_2) + + if not hasattr(ssl, 'PROTOCOL_TLSv1_1'): + print('PROTOCOL_TLSv1_1 is not available') + else: + server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_1) + self._assert_connection_success(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_1) + + if not hasattr(ssl, 'PROTOCOL_TLSv1_1') or not hasattr(ssl, 'PROTOCOL_TLSv1_2'): + print('PROTOCOL_TLSv1_1 and/or PROTOCOL_TLSv1_2 is not available') + else: + server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_2) + self._assert_connection_failure(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_1) + + def test_ssl_context(self): + if not TSSLSocket._has_ssl_context: + # unittest.skip is not available for Python 2.6 + print('skipping test_ssl_context') + return + server_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + server_context.load_cert_chain(SERVER_CERT, SERVER_KEY) + server_context.load_verify_locations(CLIENT_CA) + server_context.verify_mode = ssl.CERT_REQUIRED + server = self._server_socket(ssl_context=server_context) + + client_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) + client_context.load_cert_chain(CLIENT_CERT, CLIENT_KEY) + client_context.load_verify_locations(SERVER_CERT) + client_context.verify_mode = ssl.CERT_REQUIRED + + self._assert_connection_success(server, ssl_context=client_context) + + +if __name__ == '__main__': + logging.basicConfig(level=logging.WARN) + from thrift.transport.TSSLSocket import TSSLSocket, TSSLServerSocket, _match_has_ipaddress + from thrift.transport.TTransport import TTransportException + + unittest.main() diff --git a/lib/py/test/thrift_json.py b/lib/py/test/thrift_json.py new file mode 100644 index 0000000..40e7a47 --- /dev/null +++ b/lib/py/test/thrift_json.py @@ -0,0 +1,51 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import sys +import unittest + +import _import_local_thrift # noqa +from thrift.protocol.TJSONProtocol import TJSONProtocol +from thrift.transport import TTransport + +# +# In order to run the test under Windows. We need to create symbolic link +# name 'thrift' to '../src' folder by using: +# +# mklink /D thrift ..\src +# + + +class TestJSONString(unittest.TestCase): + + def test_escaped_unicode_string(self): + unicode_json = b'"hello \\u0e01\\u0e02\\u0e03\\ud835\\udcab\\udb40\\udc70 unicode"' + unicode_text = u'hello \u0e01\u0e02\u0e03\U0001D4AB\U000E0070 unicode' + + buf = TTransport.TMemoryBuffer(unicode_json) + transport = TTransport.TBufferedTransportFactory().getTransport(buf) + protocol = TJSONProtocol(transport) + + if sys.version_info[0] == 2: + unicode_text = unicode_text.encode('utf8') + self.assertEqual(protocol.readString(), unicode_text) + + +if __name__ == '__main__': + unittest.main() diff --git a/lib/rb/Gemfile b/lib/rb/Gemfile new file mode 100644 index 0000000..1c86af9 --- /dev/null +++ b/lib/rb/Gemfile @@ -0,0 +1,4 @@ +source "http://rubygems.org" + +gemspec + diff --git a/lib/rb/Makefile.am b/lib/rb/Makefile.am new file mode 100755 index 0000000..137edb4 --- /dev/null +++ b/lib/rb/Makefile.am @@ -0,0 +1,51 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +DESTDIR ?= / + +if HAVE_BUNDLER + +all-local: + $(BUNDLER) install + $(BUNDLER) exec rake build_ext + +install-exec-hook: + $(BUNDLER) exec rake install + +clean-local: + $(BUNDLER) install + $(BUNDLER) exec rake clean + +check-local: all + $(BUNDLER) install + $(BUNDLER) exec rake + +endif + +EXTRA_DIST = \ + coding_standards.md \ + Rakefile \ + Gemfile \ + thrift.gemspec \ + lib \ + ext \ + benchmark \ + script \ + spec \ + README.md diff --git a/lib/rb/Makefile.in b/lib/rb/Makefile.in new file mode 100644 index 0000000..0fd7134 --- /dev/null +++ b/lib/rb/Makefile.in @@ -0,0 +1,658 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/rb +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + coding_standards.md \ + Rakefile \ + Gemfile \ + thrift.gemspec \ + lib \ + ext \ + benchmark \ + script \ + spec \ + README.md + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/rb/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/rb/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +@HAVE_BUNDLER_FALSE@check-local: +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +@HAVE_BUNDLER_FALSE@all-local: +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +@HAVE_BUNDLER_FALSE@clean-local: +@HAVE_BUNDLER_FALSE@install-exec-hook: +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: check-am install-am install-exec-am install-strip + +.PHONY: all all-am all-local check check-am check-local clean \ + clean-generic clean-libtool clean-local cscopelist-am ctags-am \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-exec-hook install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +DESTDIR ?= / + +@HAVE_BUNDLER_TRUE@all-local: +@HAVE_BUNDLER_TRUE@ $(BUNDLER) install +@HAVE_BUNDLER_TRUE@ $(BUNDLER) exec rake build_ext + +@HAVE_BUNDLER_TRUE@install-exec-hook: +@HAVE_BUNDLER_TRUE@ $(BUNDLER) exec rake install + +@HAVE_BUNDLER_TRUE@clean-local: +@HAVE_BUNDLER_TRUE@ $(BUNDLER) install +@HAVE_BUNDLER_TRUE@ $(BUNDLER) exec rake clean + +@HAVE_BUNDLER_TRUE@check-local: all +@HAVE_BUNDLER_TRUE@ $(BUNDLER) install +@HAVE_BUNDLER_TRUE@ $(BUNDLER) exec rake + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/rb/README.md b/lib/rb/README.md new file mode 100644 index 0000000..b6e9a07 --- /dev/null +++ b/lib/rb/README.md @@ -0,0 +1,43 @@ +Thrift Ruby Software Library + http://thrift.apache.org + +== LICENSE: + +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + +== DESCRIPTION: + +Thrift is a strongly-typed language-agnostic RPC system. +This library is the ruby implementation for both clients and servers. + +== INSTALL: + + $ gem install thrift + +== CAVEATS: + +This library provides the client and server implementations of thrift. +It does not provide the compiler for the .thrift files. To compile +.thrift files into language-specific implementations, please download the full +thrift software package. + +== USAGE: + +This section should get written by someone with the time and inclination. +In the meantime, look at existing code, such as the benchmark or the tutorial +in the full thrift distribution. diff --git a/lib/rb/Rakefile b/lib/rb/Rakefile new file mode 100644 index 0000000..cdecaa6 --- /dev/null +++ b/lib/rb/Rakefile @@ -0,0 +1,119 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'rubygems' +require 'rake' +require 'rake/clean' +require 'rspec/core/rake_task' + +THRIFT = '../../compiler/cpp/thrift' + +task :default => [:gem] +task :spec => [:'gen-rb', :build_ext, :realspec] + +RSpec::Core::RakeTask.new(:realspec) do |t| + t.rspec_opts = ['--color', '--format d'] +end + +RSpec::Core::RakeTask.new(:'spec:rcov') do |t| + t.rspec_opts = ['--color', '--format d'] + t.rcov = true + t.rcov_opts = ['--exclude', '^spec,/gems/'] +end + +desc 'Compile the .thrift files for the specs' +task :'gen-rb' => [:'gen-rb:spec', :'gen-rb:namespaced_spec', :'gen-rb:flat_spec', :'gen-rb:benchmark', :'gen-rb:debug_proto'] +namespace :'gen-rb' do + task :'spec' do + dir = File.dirname(__FILE__) + '/spec' + sh THRIFT, '--gen', 'rb', '-o', dir, "#{dir}/ThriftSpec.thrift" + end + + task :'namespaced_spec' do + dir = File.dirname(__FILE__) + '/spec' + sh THRIFT, '--gen', 'rb:namespaced', '--recurse', '-o', dir, "#{dir}/ThriftNamespacedSpec.thrift" + sh THRIFT, '--gen', 'rb:namespaced', '--recurse', '-o', dir, "#{dir}/BaseService.thrift" + sh THRIFT, '--gen', 'rb:namespaced', '--recurse', '-o', dir, "#{dir}/ExtendedService.thrift" + end + + task :'flat_spec' do + dir = File.dirname(__FILE__) + '/spec' + mkdir_p("#{dir}/gen-rb/flat") + sh THRIFT, '--gen', 'rb', '--recurse', '-out', "#{dir}/gen-rb/flat", "#{dir}/ThriftNamespacedSpec.thrift" + end + + task :'benchmark' do + dir = File.dirname(__FILE__) + '/benchmark' + sh THRIFT, '--gen', 'rb', '-o', dir, "#{dir}/Benchmark.thrift" + end + + task :'debug_proto' do + sh "mkdir", "-p", "test/debug_proto" + sh THRIFT, '--gen', 'rb', "-o", "test/debug_proto", "../../test/DebugProtoTest.thrift" + end +end + +desc "Build the native library" +task :build_ext => :'gen-rb' do + Dir::chdir(File::dirname('ext/extconf.rb')) do + unless sh "ruby #{File::basename('ext/extconf.rb')}" + $stderr.puts "Failed to run extconf" + break + end + unless sh "make" + $stderr.puts "make failed" + break + end + end +end + +desc 'Run the compiler tests (requires full thrift checkout)' +task :test do + # ensure this is a full thrift checkout and not a tarball of the ruby libs + cmd = 'head -1 ../../README.md 2>/dev/null | grep Thrift >/dev/null 2>/dev/null' + system(cmd) or fail "rake test requires a full thrift checkout" + sh 'make', '-C', File.dirname(__FILE__) + "/../../test/rb", "check" +end + +desc 'Run benchmarking of NonblockingServer' +task :benchmark do + ruby 'benchmark/benchmark.rb' +end + +desc 'Builds the thrift gem' +task :gem => [:spec, :build_ext] do + unless sh 'gem', 'build', 'thrift.gemspec' + $stderr.puts "Failed to build thrift gem" + break + end +end + +desc 'Install the thrift gem' +task :install => [:gem] do + unless sh 'gem', 'install', Dir.glob('thrift-*.gem').last + $stderr.puts "Failed to install thrift gem" + break + end +end + +CLEAN.include [ + '.bundle', 'benchmark/gen-rb', 'coverage', 'ext/*.{o,bundle,so,dll}', 'ext/mkmf.log', + 'ext/Makefile', 'ext/conftest.dSYM', 'Gemfile.lock', 'mkmf.log', 'pkg', 'spec/gen-rb', + 'test', 'thrift-*.gem' +] diff --git a/lib/rb/benchmark/Benchmark.thrift b/lib/rb/benchmark/Benchmark.thrift new file mode 100644 index 0000000..eb5ae38 --- /dev/null +++ b/lib/rb/benchmark/Benchmark.thrift @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +namespace rb ThriftBenchmark + +service BenchmarkService { + i32 fibonacci(1:byte n) +} diff --git a/lib/rb/benchmark/benchmark.rb b/lib/rb/benchmark/benchmark.rb new file mode 100644 index 0000000..3dc67dd --- /dev/null +++ b/lib/rb/benchmark/benchmark.rb @@ -0,0 +1,271 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'rubygems' +$:.unshift File.dirname(__FILE__) + '/../lib' +require 'thrift' +require 'stringio' + +HOST = '127.0.0.1' +PORT = 42587 + +############### +## Server +############### + +class Server + attr_accessor :serverclass + attr_accessor :interpreter + attr_accessor :host + attr_accessor :port + + def initialize(opts) + @serverclass = opts.fetch(:class, Thrift::NonblockingServer) + @interpreter = opts.fetch(:interpreter, "ruby") + @host = opts.fetch(:host, ::HOST) + @port = opts.fetch(:port, ::PORT) + end + + def start + return if @serverclass == Object + args = (File.basename(@interpreter) == "jruby" ? "-J-server" : "") + @pipe = IO.popen("#{@interpreter} #{args} #{File.dirname(__FILE__)}/server.rb #{@host} #{@port} #{@serverclass.name}", "r+") + Marshal.load(@pipe) # wait until the server has started + sleep 0.4 # give the server time to actually start spawning sockets + end + + def shutdown + return unless @pipe + Marshal.dump(:shutdown, @pipe) + begin + @pipe.read(10) # block until the server shuts down + rescue EOFError + end + @pipe.close + @pipe = nil + end +end + +class BenchmarkManager + def initialize(opts, server) + @socket = opts.fetch(:socket) do + @host = opts.fetch(:host, 'localhost') + @port = opts.fetch(:port) + nil + end + @num_processes = opts.fetch(:num_processes, 40) + @clients_per_process = opts.fetch(:clients_per_process, 10) + @calls_per_client = opts.fetch(:calls_per_client, 50) + @interpreter = opts.fetch(:interpreter, "ruby") + @server = server + @log_exceptions = opts.fetch(:log_exceptions, false) + end + + def run + @pool = [] + @benchmark_start = Time.now + puts "Spawning benchmark processes..." + @num_processes.times do + spawn + sleep 0.02 # space out spawns + end + collect_output + @benchmark_end = Time.now # we know the procs are done here + translate_output + analyze_output + report_output + end + + def spawn + pipe = IO.popen("#{@interpreter} #{File.dirname(__FILE__)}/client.rb #{"-log-exceptions" if @log_exceptions} #{@host} #{@port} #{@clients_per_process} #{@calls_per_client}") + @pool << pipe + end + + def socket_class + if @socket + Thrift::UNIXSocket + else + Thrift::Socket + end + end + + def collect_output + puts "Collecting output..." + # read from @pool until all sockets are closed + @buffers = Hash.new { |h,k| h[k] = '' } + until @pool.empty? + rd, = select(@pool) + next if rd.nil? + rd.each do |fd| + begin + @buffers[fd] << fd.readpartial(4096) + rescue EOFError + @pool.delete fd + end + end + end + end + + def translate_output + puts "Translating output..." + @output = [] + @buffers.each do |fd, buffer| + strio = StringIO.new(buffer) + logs = [] + begin + loop do + logs << Marshal.load(strio) + end + rescue EOFError + @output << logs + end + end + end + + def analyze_output + puts "Analyzing output..." + call_times = [] + client_times = [] + connection_failures = [] + connection_errors = [] + shortest_call = 0 + shortest_client = 0 + longest_call = 0 + longest_client = 0 + @output.each do |logs| + cur_call, cur_client = nil + logs.each do |tok, time| + case tok + when :start + cur_client = time + when :call_start + cur_call = time + when :call_end + delta = time - cur_call + call_times << delta + longest_call = delta unless longest_call > delta + shortest_call = delta if shortest_call == 0 or delta < shortest_call + cur_call = nil + when :end + delta = time - cur_client + client_times << delta + longest_client = delta unless longest_client > delta + shortest_client = delta if shortest_client == 0 or delta < shortest_client + cur_client = nil + when :connection_failure + connection_failures << time + when :connection_error + connection_errors << time + end + end + end + @report = {} + @report[:total_calls] = call_times.inject(0.0) { |a,t| a += t } + @report[:avg_calls] = @report[:total_calls] / call_times.size + @report[:total_clients] = client_times.inject(0.0) { |a,t| a += t } + @report[:avg_clients] = @report[:total_clients] / client_times.size + @report[:connection_failures] = connection_failures.size + @report[:connection_errors] = connection_errors.size + @report[:shortest_call] = shortest_call + @report[:shortest_client] = shortest_client + @report[:longest_call] = longest_call + @report[:longest_client] = longest_client + @report[:total_benchmark_time] = @benchmark_end - @benchmark_start + @report[:fastthread] = $".include?('fastthread.bundle') + end + + def report_output + fmt = "%.4f seconds" + puts + tabulate "%d", + [["Server class", "%s"], @server.serverclass == Object ? "" : @server.serverclass], + [["Server interpreter", "%s"], @server.interpreter], + [["Client interpreter", "%s"], @interpreter], + [["Socket class", "%s"], socket_class], + ["Number of processes", @num_processes], + ["Clients per process", @clients_per_process], + ["Calls per client", @calls_per_client], + [["Using fastthread", "%s"], @report[:fastthread] ? "yes" : "no"] + puts + failures = (@report[:connection_failures] > 0) + tabulate fmt, + [["Connection failures", "%d", [:red, :bold]], @report[:connection_failures]], + [["Connection errors", "%d", [:red, :bold]], @report[:connection_errors]], + ["Average time per call", @report[:avg_calls]], + ["Average time per client (%d calls)" % @calls_per_client, @report[:avg_clients]], + ["Total time for all calls", @report[:total_calls]], + ["Real time for benchmarking", @report[:total_benchmark_time]], + ["Shortest call time", @report[:shortest_call]], + ["Longest call time", @report[:longest_call]], + ["Shortest client time (%d calls)" % @calls_per_client, @report[:shortest_client]], + ["Longest client time (%d calls)" % @calls_per_client, @report[:longest_client]] + end + + ANSI = { + :reset => 0, + :bold => 1, + :black => 30, + :red => 31, + :green => 32, + :yellow => 33, + :blue => 34, + :magenta => 35, + :cyan => 36, + :white => 37 + } + + def tabulate(fmt, *labels_and_values) + labels = labels_and_values.map { |l| Array === l ? l.first : l } + label_width = labels.inject(0) { |w,l| l.size > w ? l.size : w } + labels_and_values.each do |(l,v)| + f = fmt + l, f, c = l if Array === l + fmtstr = "%-#{label_width+1}s #{f}" + if STDOUT.tty? and c and v.to_i > 0 + fmtstr = "\e[#{[*c].map { |x| ANSI[x] } * ";"}m" + fmtstr + "\e[#{ANSI[:reset]}m" + end + puts fmtstr % [l+":", v] + end + end +end + +def resolve_const(const) + const and const.split('::').inject(Object) { |k,c| k.const_get(c) } +end + +puts "Starting server..." +args = {} +args[:interpreter] = ENV['THRIFT_SERVER_INTERPRETER'] || ENV['THRIFT_INTERPRETER'] || "ruby" +args[:class] = resolve_const(ENV['THRIFT_SERVER']) || Thrift::NonblockingServer +args[:host] = ENV['THRIFT_HOST'] || HOST +args[:port] = (ENV['THRIFT_PORT'] || PORT).to_i +server = Server.new(args) +server.start + +args = {} +args[:host] = ENV['THRIFT_HOST'] || HOST +args[:port] = (ENV['THRIFT_PORT'] || PORT).to_i +args[:num_processes] = (ENV['THRIFT_NUM_PROCESSES'] || 40).to_i +args[:clients_per_process] = (ENV['THRIFT_NUM_CLIENTS'] || 5).to_i +args[:calls_per_client] = (ENV['THRIFT_NUM_CALLS'] || 50).to_i +args[:interpreter] = ENV['THRIFT_CLIENT_INTERPRETER'] || ENV['THRIFT_INTERPRETER'] || "ruby" +args[:log_exceptions] = !!ENV['THRIFT_LOG_EXCEPTIONS'] +BenchmarkManager.new(args, server).run + +server.shutdown diff --git a/lib/rb/benchmark/client.rb b/lib/rb/benchmark/client.rb new file mode 100644 index 0000000..703dc8f --- /dev/null +++ b/lib/rb/benchmark/client.rb @@ -0,0 +1,74 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +$:.unshift File.dirname(__FILE__) + '/../lib' +require 'thrift' +$:.unshift File.dirname(__FILE__) + "/gen-rb" +require 'benchmark_service' + +class Client + def initialize(host, port, clients_per_process, calls_per_client, log_exceptions) + @host = host + @port = port + @clients_per_process = clients_per_process + @calls_per_client = calls_per_client + @log_exceptions = log_exceptions + end + + def run + @clients_per_process.times do + socket = Thrift::Socket.new(@host, @port) + transport = Thrift::FramedTransport.new(socket) + protocol = Thrift::BinaryProtocol.new(transport) + client = ThriftBenchmark::BenchmarkService::Client.new(protocol) + begin + start = Time.now + transport.open + Marshal.dump [:start, start], STDOUT + rescue => e + Marshal.dump [:connection_failure, Time.now], STDOUT + print_exception e if @log_exceptions + else + begin + @calls_per_client.times do + Marshal.dump [:call_start, Time.now], STDOUT + client.fibonacci(15) + Marshal.dump [:call_end, Time.now], STDOUT + end + transport.close + Marshal.dump [:end, Time.now], STDOUT + rescue Thrift::TransportException => e + Marshal.dump [:connection_error, Time.now], STDOUT + print_exception e if @log_exceptions + end + end + end + end + + def print_exception(e) + STDERR.puts "ERROR: #{e.message}" + STDERR.puts "\t#{e.backtrace * "\n\t"}" + end +end + +log_exceptions = true if ARGV[0] == '-log-exceptions' and ARGV.shift + +host, port, clients_per_process, calls_per_client = ARGV + +Client.new(host, port.to_i, clients_per_process.to_i, calls_per_client.to_i, log_exceptions).run diff --git a/lib/rb/benchmark/server.rb b/lib/rb/benchmark/server.rb new file mode 100644 index 0000000..74e13f4 --- /dev/null +++ b/lib/rb/benchmark/server.rb @@ -0,0 +1,82 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +$:.unshift File.dirname(__FILE__) + '/../lib' +require 'thrift' +$:.unshift File.dirname(__FILE__) + "/gen-rb" +require 'benchmark_service' + +module Server + include Thrift + + class BenchmarkHandler + # 1-based index into the fibonacci sequence + def fibonacci(n) + seq = [1, 1] + 3.upto(n) do + seq << seq[-1] + seq[-2] + end + seq[n-1] # n is 1-based + end + end + + def self.start_server(host, port, serverClass) + handler = BenchmarkHandler.new + processor = ThriftBenchmark::BenchmarkService::Processor.new(handler) + transport = ServerSocket.new(host, port) + transport_factory = FramedTransportFactory.new + args = [processor, transport, transport_factory, nil, 20] + if serverClass == NonblockingServer + logger = Logger.new(STDERR) + logger.level = Logger::WARN + args << logger + end + server = serverClass.new(*args) + @server_thread = Thread.new do + server.serve + end + @server = server + end + + def self.shutdown + return if @server.nil? + if @server.respond_to? :shutdown + @server.shutdown + else + @server_thread.kill + end + end +end + +def resolve_const(const) + const and const.split('::').inject(Object) { |k,c| k.const_get(c) } +end + +host, port, serverklass = ARGV + +Server.start_server(host, port.to_i, resolve_const(serverklass)) + +# let our host know that the interpreter has started +# ideally we'd wait until the server was serving, but we don't have a hook for that +Marshal.dump(:started, STDOUT) +STDOUT.flush + +Marshal.load(STDIN) # wait until we're instructed to shut down + +Server.shutdown diff --git a/lib/rb/benchmark/thin_server.rb b/lib/rb/benchmark/thin_server.rb new file mode 100644 index 0000000..4de2eef --- /dev/null +++ b/lib/rb/benchmark/thin_server.rb @@ -0,0 +1,44 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +$:.unshift File.dirname(__FILE__) + '/../lib' +require 'thrift' +$:.unshift File.dirname(__FILE__) + "/gen-rb" +require 'benchmark_service' +HOST = 'localhost' +PORT = 42587 + +class BenchmarkHandler + # 1-based index into the fibonacci sequence + def fibonacci(n) + seq = [1, 1] + 3.upto(n) do + seq << seq[-1] + seq[-2] + end + seq[n-1] # n is 1-based + end +end + +handler = BenchmarkHandler.new +processor = ThriftBenchmark::BenchmarkService::Processor.new(handler) +transport = Thrift::ServerSocket.new(HOST, PORT) +transport_factory = Thrift::FramedTransportFactory.new +logger = Logger.new(STDERR) +logger.level = Logger::WARN +Thrift::NonblockingServer.new(processor, transport, transport_factory, nil, 20, logger).serve diff --git a/lib/rb/coding_standards.md b/lib/rb/coding_standards.md new file mode 100644 index 0000000..fa0390b --- /dev/null +++ b/lib/rb/coding_standards.md @@ -0,0 +1 @@ +Please follow [General Coding Standards](/doc/coding_standards.md) diff --git a/lib/rb/ext/binary_protocol_accelerated.c b/lib/rb/ext/binary_protocol_accelerated.c new file mode 100644 index 0000000..65cbe5f --- /dev/null +++ b/lib/rb/ext/binary_protocol_accelerated.c @@ -0,0 +1,460 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +VALUE rb_thrift_binary_proto_native_qmark(VALUE self) { + return Qtrue; +} + + + +static int VERSION_1; +static int VERSION_MASK; +static int TYPE_MASK; +static int BAD_VERSION; +static ID rbuf_ivar_id; + +static void write_byte_direct(VALUE trans, int8_t b) { + WRITE(trans, (char*)&b, 1); +} + +static void write_i16_direct(VALUE trans, int16_t value) { + char data[2]; + + data[1] = value; + data[0] = (value >> 8); + + WRITE(trans, data, 2); +} + +static void write_i32_direct(VALUE trans, int32_t value) { + char data[4]; + + data[3] = value; + data[2] = (value >> 8); + data[1] = (value >> 16); + data[0] = (value >> 24); + + WRITE(trans, data, 4); +} + + +static void write_i64_direct(VALUE trans, int64_t value) { + char data[8]; + + data[7] = value; + data[6] = (value >> 8); + data[5] = (value >> 16); + data[4] = (value >> 24); + data[3] = (value >> 32); + data[2] = (value >> 40); + data[1] = (value >> 48); + data[0] = (value >> 56); + + WRITE(trans, data, 8); +} + +static void write_string_direct(VALUE trans, VALUE str) { + if (TYPE(str) != T_STRING) { + rb_raise(rb_eStandardError, "Value should be a string"); + } + str = convert_to_utf8_byte_buffer(str); + write_i32_direct(trans, RSTRING_LEN(str)); + rb_funcall(trans, write_method_id, 1, str); +} + +//-------------------------------- +// interface writing methods +//-------------------------------- + +VALUE rb_thrift_binary_proto_write_message_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_struct_begin(VALUE self, VALUE name) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_struct_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_field_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_map_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_list_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_set_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_message_begin(VALUE self, VALUE name, VALUE type, VALUE seqid) { + VALUE trans = GET_TRANSPORT(self); + VALUE strict_write = GET_STRICT_WRITE(self); + + if (strict_write == Qtrue) { + write_i32_direct(trans, VERSION_1 | FIX2INT(type)); + write_string_direct(trans, name); + write_i32_direct(trans, FIX2INT(seqid)); + } else { + write_string_direct(trans, name); + write_byte_direct(trans, FIX2INT(type)); + write_i32_direct(trans, FIX2INT(seqid)); + } + + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_field_begin(VALUE self, VALUE name, VALUE type, VALUE id) { + VALUE trans = GET_TRANSPORT(self); + write_byte_direct(trans, FIX2INT(type)); + write_i16_direct(trans, FIX2INT(id)); + + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_field_stop(VALUE self) { + write_byte_direct(GET_TRANSPORT(self), TTYPE_STOP); + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_map_begin(VALUE self, VALUE ktype, VALUE vtype, VALUE size) { + VALUE trans = GET_TRANSPORT(self); + write_byte_direct(trans, FIX2INT(ktype)); + write_byte_direct(trans, FIX2INT(vtype)); + write_i32_direct(trans, FIX2INT(size)); + + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_list_begin(VALUE self, VALUE etype, VALUE size) { + VALUE trans = GET_TRANSPORT(self); + write_byte_direct(trans, FIX2INT(etype)); + write_i32_direct(trans, FIX2INT(size)); + + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_set_begin(VALUE self, VALUE etype, VALUE size) { + rb_thrift_binary_proto_write_list_begin(self, etype, size); + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_bool(VALUE self, VALUE b) { + write_byte_direct(GET_TRANSPORT(self), RTEST(b) ? 1 : 0); + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_byte(VALUE self, VALUE byte) { + CHECK_NIL(byte); + write_byte_direct(GET_TRANSPORT(self), NUM2INT(byte)); + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_i16(VALUE self, VALUE i16) { + CHECK_NIL(i16); + write_i16_direct(GET_TRANSPORT(self), FIX2INT(i16)); + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_i32(VALUE self, VALUE i32) { + CHECK_NIL(i32); + write_i32_direct(GET_TRANSPORT(self), NUM2INT(i32)); + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_i64(VALUE self, VALUE i64) { + CHECK_NIL(i64); + write_i64_direct(GET_TRANSPORT(self), NUM2LL(i64)); + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_double(VALUE self, VALUE dub) { + CHECK_NIL(dub); + // Unfortunately, bitwise_cast doesn't work in C. Bad C! + union { + double f; + int64_t t; + } transfer; + transfer.f = RFLOAT_VALUE(rb_Float(dub)); + write_i64_direct(GET_TRANSPORT(self), transfer.t); + + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_string(VALUE self, VALUE str) { + CHECK_NIL(str); + VALUE trans = GET_TRANSPORT(self); + write_string_direct(trans, str); + return Qnil; +} + +VALUE rb_thrift_binary_proto_write_binary(VALUE self, VALUE buf) { + CHECK_NIL(buf); + VALUE trans = GET_TRANSPORT(self); + buf = force_binary_encoding(buf); + write_i32_direct(trans, RSTRING_LEN(buf)); + rb_funcall(trans, write_method_id, 1, buf); + return Qnil; +} + +//--------------------------------------- +// interface reading methods +//--------------------------------------- + +VALUE rb_thrift_binary_proto_read_string(VALUE self); +VALUE rb_thrift_binary_proto_read_binary(VALUE self); +VALUE rb_thrift_binary_proto_read_byte(VALUE self); +VALUE rb_thrift_binary_proto_read_i32(VALUE self); +VALUE rb_thrift_binary_proto_read_i16(VALUE self); + +static char read_byte_direct(VALUE self) { + VALUE byte = rb_funcall(GET_TRANSPORT(self), read_byte_method_id, 0); + return (char)(FIX2INT(byte)); +} + +static int16_t read_i16_direct(VALUE self) { + VALUE rbuf = rb_ivar_get(self, rbuf_ivar_id); + rb_funcall(GET_TRANSPORT(self), read_into_buffer_method_id, 2, rbuf, INT2FIX(2)); + return (int16_t)(((uint8_t)(RSTRING_PTR(rbuf)[1])) | ((uint16_t)((RSTRING_PTR(rbuf)[0]) << 8))); +} + +static int32_t read_i32_direct(VALUE self) { + VALUE rbuf = rb_ivar_get(self, rbuf_ivar_id); + rb_funcall(GET_TRANSPORT(self), read_into_buffer_method_id, 2, rbuf, INT2FIX(4)); + return ((uint8_t)(RSTRING_PTR(rbuf)[3])) | + (((uint8_t)(RSTRING_PTR(rbuf)[2])) << 8) | + (((uint8_t)(RSTRING_PTR(rbuf)[1])) << 16) | + (((uint8_t)(RSTRING_PTR(rbuf)[0])) << 24); +} + +static int64_t read_i64_direct(VALUE self) { + VALUE rbuf = rb_ivar_get(self, rbuf_ivar_id); + rb_funcall(GET_TRANSPORT(self), read_into_buffer_method_id, 2, rbuf, INT2FIX(8)); + uint64_t hi = ((uint8_t)(RSTRING_PTR(rbuf)[3])) | + (((uint8_t)(RSTRING_PTR(rbuf)[2])) << 8) | + (((uint8_t)(RSTRING_PTR(rbuf)[1])) << 16) | + (((uint8_t)(RSTRING_PTR(rbuf)[0])) << 24); + uint32_t lo = ((uint8_t)(RSTRING_PTR(rbuf)[7])) | + (((uint8_t)(RSTRING_PTR(rbuf)[6])) << 8) | + (((uint8_t)(RSTRING_PTR(rbuf)[5])) << 16) | + (((uint8_t)(RSTRING_PTR(rbuf)[4])) << 24); + return (hi << 32) | lo; +} + +static VALUE get_protocol_exception(VALUE code, VALUE message) { + VALUE args[2]; + args[0] = code; + args[1] = message; + return rb_class_new_instance(2, (VALUE*)&args, protocol_exception_class); +} + +VALUE rb_thrift_binary_proto_read_message_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_read_struct_begin(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_read_struct_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_read_field_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_read_map_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_read_list_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_read_set_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_binary_proto_read_message_begin(VALUE self) { + VALUE strict_read = GET_STRICT_READ(self); + VALUE name, seqid; + int type; + + int version = read_i32_direct(self); + + if (version < 0) { + if ((version & VERSION_MASK) != VERSION_1) { + rb_exc_raise(get_protocol_exception(INT2FIX(BAD_VERSION), rb_str_new2("Missing version identifier"))); + } + type = version & TYPE_MASK; + name = rb_thrift_binary_proto_read_string(self); + seqid = rb_thrift_binary_proto_read_i32(self); + } else { + if (strict_read == Qtrue) { + rb_exc_raise(get_protocol_exception(INT2FIX(BAD_VERSION), rb_str_new2("No version identifier, old protocol client?"))); + } + name = READ(self, version); + type = read_byte_direct(self); + seqid = rb_thrift_binary_proto_read_i32(self); + } + + return rb_ary_new3(3, name, INT2FIX(type), seqid); +} + +VALUE rb_thrift_binary_proto_read_field_begin(VALUE self) { + int type = read_byte_direct(self); + if (type == TTYPE_STOP) { + return rb_ary_new3(3, Qnil, INT2FIX(type), INT2FIX(0)); + } else { + VALUE id = rb_thrift_binary_proto_read_i16(self); + return rb_ary_new3(3, Qnil, INT2FIX(type), id); + } +} + +VALUE rb_thrift_binary_proto_read_map_begin(VALUE self) { + VALUE ktype = rb_thrift_binary_proto_read_byte(self); + VALUE vtype = rb_thrift_binary_proto_read_byte(self); + VALUE size = rb_thrift_binary_proto_read_i32(self); + return rb_ary_new3(3, ktype, vtype, size); +} + +VALUE rb_thrift_binary_proto_read_list_begin(VALUE self) { + VALUE etype = rb_thrift_binary_proto_read_byte(self); + VALUE size = rb_thrift_binary_proto_read_i32(self); + return rb_ary_new3(2, etype, size); +} + +VALUE rb_thrift_binary_proto_read_set_begin(VALUE self) { + return rb_thrift_binary_proto_read_list_begin(self); +} + +VALUE rb_thrift_binary_proto_read_bool(VALUE self) { + char byte = read_byte_direct(self); + return byte != 0 ? Qtrue : Qfalse; +} + +VALUE rb_thrift_binary_proto_read_byte(VALUE self) { + return INT2FIX(read_byte_direct(self)); +} + +VALUE rb_thrift_binary_proto_read_i16(VALUE self) { + return INT2FIX(read_i16_direct(self)); +} + +VALUE rb_thrift_binary_proto_read_i32(VALUE self) { + return INT2NUM(read_i32_direct(self)); +} + +VALUE rb_thrift_binary_proto_read_i64(VALUE self) { + return LL2NUM(read_i64_direct(self)); +} + +VALUE rb_thrift_binary_proto_read_double(VALUE self) { + union { + double f; + int64_t t; + } transfer; + transfer.t = read_i64_direct(self); + return rb_float_new(transfer.f); +} + +VALUE rb_thrift_binary_proto_read_string(VALUE self) { + VALUE buffer = rb_thrift_binary_proto_read_binary(self); + return convert_to_string(buffer); +} + +VALUE rb_thrift_binary_proto_read_binary(VALUE self) { + int size = read_i32_direct(self); + return READ(self, size); +} + +void Init_binary_protocol_accelerated() { + VALUE thrift_binary_protocol_class = rb_const_get(thrift_module, rb_intern("BinaryProtocol")); + + VERSION_1 = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("VERSION_1"))); + VERSION_MASK = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("VERSION_MASK"))); + TYPE_MASK = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("TYPE_MASK"))); + + VALUE bpa_class = rb_define_class_under(thrift_module, "BinaryProtocolAccelerated", thrift_binary_protocol_class); + + rb_define_method(bpa_class, "native?", rb_thrift_binary_proto_native_qmark, 0); + + rb_define_method(bpa_class, "write_message_begin", rb_thrift_binary_proto_write_message_begin, 3); + rb_define_method(bpa_class, "write_field_begin", rb_thrift_binary_proto_write_field_begin, 3); + rb_define_method(bpa_class, "write_field_stop", rb_thrift_binary_proto_write_field_stop, 0); + rb_define_method(bpa_class, "write_map_begin", rb_thrift_binary_proto_write_map_begin, 3); + rb_define_method(bpa_class, "write_list_begin", rb_thrift_binary_proto_write_list_begin, 2); + rb_define_method(bpa_class, "write_set_begin", rb_thrift_binary_proto_write_set_begin, 2); + rb_define_method(bpa_class, "write_byte", rb_thrift_binary_proto_write_byte, 1); + rb_define_method(bpa_class, "write_bool", rb_thrift_binary_proto_write_bool, 1); + rb_define_method(bpa_class, "write_i16", rb_thrift_binary_proto_write_i16, 1); + rb_define_method(bpa_class, "write_i32", rb_thrift_binary_proto_write_i32, 1); + rb_define_method(bpa_class, "write_i64", rb_thrift_binary_proto_write_i64, 1); + rb_define_method(bpa_class, "write_double", rb_thrift_binary_proto_write_double, 1); + rb_define_method(bpa_class, "write_string", rb_thrift_binary_proto_write_string, 1); + rb_define_method(bpa_class, "write_binary", rb_thrift_binary_proto_write_binary, 1); + // unused methods + rb_define_method(bpa_class, "write_message_end", rb_thrift_binary_proto_write_message_end, 0); + rb_define_method(bpa_class, "write_struct_begin", rb_thrift_binary_proto_write_struct_begin, 1); + rb_define_method(bpa_class, "write_struct_end", rb_thrift_binary_proto_write_struct_end, 0); + rb_define_method(bpa_class, "write_field_end", rb_thrift_binary_proto_write_field_end, 0); + rb_define_method(bpa_class, "write_map_end", rb_thrift_binary_proto_write_map_end, 0); + rb_define_method(bpa_class, "write_list_end", rb_thrift_binary_proto_write_list_end, 0); + rb_define_method(bpa_class, "write_set_end", rb_thrift_binary_proto_write_set_end, 0); + + rb_define_method(bpa_class, "read_message_begin", rb_thrift_binary_proto_read_message_begin, 0); + rb_define_method(bpa_class, "read_field_begin", rb_thrift_binary_proto_read_field_begin, 0); + rb_define_method(bpa_class, "read_map_begin", rb_thrift_binary_proto_read_map_begin, 0); + rb_define_method(bpa_class, "read_list_begin", rb_thrift_binary_proto_read_list_begin, 0); + rb_define_method(bpa_class, "read_set_begin", rb_thrift_binary_proto_read_set_begin, 0); + rb_define_method(bpa_class, "read_byte", rb_thrift_binary_proto_read_byte, 0); + rb_define_method(bpa_class, "read_bool", rb_thrift_binary_proto_read_bool, 0); + rb_define_method(bpa_class, "read_i16", rb_thrift_binary_proto_read_i16, 0); + rb_define_method(bpa_class, "read_i32", rb_thrift_binary_proto_read_i32, 0); + rb_define_method(bpa_class, "read_i64", rb_thrift_binary_proto_read_i64, 0); + rb_define_method(bpa_class, "read_double", rb_thrift_binary_proto_read_double, 0); + rb_define_method(bpa_class, "read_string", rb_thrift_binary_proto_read_string, 0); + rb_define_method(bpa_class, "read_binary", rb_thrift_binary_proto_read_binary, 0); + // unused methods + rb_define_method(bpa_class, "read_message_end", rb_thrift_binary_proto_read_message_end, 0); + rb_define_method(bpa_class, "read_struct_begin", rb_thrift_binary_proto_read_struct_begin, 0); + rb_define_method(bpa_class, "read_struct_end", rb_thrift_binary_proto_read_struct_end, 0); + rb_define_method(bpa_class, "read_field_end", rb_thrift_binary_proto_read_field_end, 0); + rb_define_method(bpa_class, "read_map_end", rb_thrift_binary_proto_read_map_end, 0); + rb_define_method(bpa_class, "read_list_end", rb_thrift_binary_proto_read_list_end, 0); + rb_define_method(bpa_class, "read_set_end", rb_thrift_binary_proto_read_set_end, 0); + + rbuf_ivar_id = rb_intern("@rbuf"); +} diff --git a/lib/rb/ext/binary_protocol_accelerated.h b/lib/rb/ext/binary_protocol_accelerated.h new file mode 100644 index 0000000..37baf41 --- /dev/null +++ b/lib/rb/ext/binary_protocol_accelerated.h @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +void Init_binary_protocol_accelerated(); diff --git a/lib/rb/ext/bytes.c b/lib/rb/ext/bytes.c new file mode 100644 index 0000000..8a6fac4 --- /dev/null +++ b/lib/rb/ext/bytes.c @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#ifdef HAVE_RUBY_ENCODING_H +#include +#endif +#include + +VALUE force_binary_encoding(VALUE buffer) { + return rb_funcall(thrift_bytes_module, force_binary_encoding_id, 1, buffer); +} + +VALUE convert_to_utf8_byte_buffer(VALUE string) { + return rb_funcall(thrift_bytes_module, convert_to_utf8_byte_buffer_id, 1, string); +} + +VALUE convert_to_string(VALUE utf8_buffer) { + return rb_funcall(thrift_bytes_module, convert_to_string_id, 1, utf8_buffer); +} diff --git a/lib/rb/ext/bytes.h b/lib/rb/ext/bytes.h new file mode 100644 index 0000000..7108d83 --- /dev/null +++ b/lib/rb/ext/bytes.h @@ -0,0 +1,31 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include + +/* + * A collection of utilities for working with bytes and byte buffers. + * + * These methods are the native analogies to some of the methods in + * Thrift::Bytes (thrift/bytes.rb). + */ + +VALUE force_binary_encoding(VALUE buffer); +VALUE convert_to_utf8_byte_buffer(VALUE string); +VALUE convert_to_string(VALUE utf8_buffer); diff --git a/lib/rb/ext/compact_protocol.c b/lib/rb/ext/compact_protocol.c new file mode 100644 index 0000000..c0f46b9 --- /dev/null +++ b/lib/rb/ext/compact_protocol.c @@ -0,0 +1,637 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define LAST_ID(obj) FIX2INT(rb_ary_pop(rb_ivar_get(obj, last_field_id))) +#define SET_LAST_ID(obj, val) rb_ary_push(rb_ivar_get(obj, last_field_id), val) + +VALUE rb_thrift_compact_proto_native_qmark(VALUE self) { + return Qtrue; +} + +static ID last_field_id; +static ID boolean_field_id; +static ID bool_value_id; +static ID rbuf_ivar_id; + +static int VERSION; +static int VERSION_MASK; +static int TYPE_MASK; +static int TYPE_BITS; +static int TYPE_SHIFT_AMOUNT; +static int PROTOCOL_ID; + +static VALUE thrift_compact_protocol_class; + +static int CTYPE_BOOLEAN_TRUE = 0x01; +static int CTYPE_BOOLEAN_FALSE = 0x02; +static int CTYPE_BYTE = 0x03; +static int CTYPE_I16 = 0x04; +static int CTYPE_I32 = 0x05; +static int CTYPE_I64 = 0x06; +static int CTYPE_DOUBLE = 0x07; +static int CTYPE_BINARY = 0x08; +static int CTYPE_LIST = 0x09; +static int CTYPE_SET = 0x0A; +static int CTYPE_MAP = 0x0B; +static int CTYPE_STRUCT = 0x0C; + +VALUE rb_thrift_compact_proto_write_i16(VALUE self, VALUE i16); + +// TODO: implement this +static int get_compact_type(VALUE type_value) { + int type = FIX2INT(type_value); + if (type == TTYPE_BOOL) { + return CTYPE_BOOLEAN_TRUE; + } else if (type == TTYPE_BYTE) { + return CTYPE_BYTE; + } else if (type == TTYPE_I16) { + return CTYPE_I16; + } else if (type == TTYPE_I32) { + return CTYPE_I32; + } else if (type == TTYPE_I64) { + return CTYPE_I64; + } else if (type == TTYPE_DOUBLE) { + return CTYPE_DOUBLE; + } else if (type == TTYPE_STRING) { + return CTYPE_BINARY; + } else if (type == TTYPE_LIST) { + return CTYPE_LIST; + } else if (type == TTYPE_SET) { + return CTYPE_SET; + } else if (type == TTYPE_MAP) { + return CTYPE_MAP; + } else if (type == TTYPE_STRUCT) { + return CTYPE_STRUCT; + } else { + char str[50]; + sprintf(str, "don't know what type: %d", type); + rb_raise(rb_eStandardError, "%s", str); + return 0; + } +} + +static void write_byte_direct(VALUE transport, int8_t b) { + WRITE(transport, (char*)&b, 1); +} + +static void write_field_begin_internal(VALUE self, VALUE type, VALUE id_value, VALUE type_override) { + int id = FIX2INT(id_value); + int last_id = LAST_ID(self); + VALUE transport = GET_TRANSPORT(self); + + // if there's a type override, use that. + int8_t type_to_write = RTEST(type_override) ? FIX2INT(type_override) : get_compact_type(type); + // check if we can use delta encoding for the field id + int diff = id - last_id; + if (diff > 0 && diff <= 15) { + // write them together + write_byte_direct(transport, diff << 4 | (type_to_write & 0x0f)); + } else { + // write them separate + write_byte_direct(transport, type_to_write & 0x0f); + rb_thrift_compact_proto_write_i16(self, id_value); + } + + SET_LAST_ID(self, id_value); +} + +static int32_t int_to_zig_zag(int32_t n) { + return (n << 1) ^ (n >> 31); +} + +static uint64_t ll_to_zig_zag(int64_t n) { + return (n << 1) ^ (n >> 63); +} + +static void write_varint32(VALUE transport, uint32_t n) { + while (true) { + if ((n & ~0x7F) == 0) { + write_byte_direct(transport, n & 0x7f); + break; + } else { + write_byte_direct(transport, (n & 0x7F) | 0x80); + n = n >> 7; + } + } +} + +static void write_varint64(VALUE transport, uint64_t n) { + while (true) { + if ((n & ~0x7F) == 0) { + write_byte_direct(transport, n & 0x7f); + break; + } else { + write_byte_direct(transport, (n & 0x7F) | 0x80); + n = n >> 7; + } + } +} + +static void write_collection_begin(VALUE transport, VALUE elem_type, VALUE size_value) { + int size = FIX2INT(size_value); + if (size <= 14) { + write_byte_direct(transport, size << 4 | get_compact_type(elem_type)); + } else { + write_byte_direct(transport, 0xf0 | get_compact_type(elem_type)); + write_varint32(transport, size); + } +} + + +//-------------------------------- +// interface writing methods +//-------------------------------- + +VALUE rb_thrift_compact_proto_write_i32(VALUE self, VALUE i32); +VALUE rb_thrift_compact_proto_write_string(VALUE self, VALUE str); +VALUE rb_thrift_compact_proto_write_binary(VALUE self, VALUE buf); + +VALUE rb_thrift_compact_proto_write_message_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_struct_begin(VALUE self, VALUE name) { + rb_ary_push(rb_ivar_get(self, last_field_id), INT2FIX(0)); + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_struct_end(VALUE self) { + rb_ary_pop(rb_ivar_get(self, last_field_id)); + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_field_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_map_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_list_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_set_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_message_begin(VALUE self, VALUE name, VALUE type, VALUE seqid) { + VALUE transport = GET_TRANSPORT(self); + write_byte_direct(transport, PROTOCOL_ID); + write_byte_direct(transport, (VERSION & VERSION_MASK) | ((FIX2INT(type) << TYPE_SHIFT_AMOUNT) & TYPE_MASK)); + write_varint32(transport, FIX2INT(seqid)); + rb_thrift_compact_proto_write_string(self, name); + + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_field_begin(VALUE self, VALUE name, VALUE type, VALUE id) { + if (FIX2INT(type) == TTYPE_BOOL) { + // we want to possibly include the value, so we'll wait. + rb_ivar_set(self, boolean_field_id, rb_ary_new3(2, type, id)); + } else { + write_field_begin_internal(self, type, id, Qnil); + } + + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_field_stop(VALUE self) { + write_byte_direct(GET_TRANSPORT(self), TTYPE_STOP); + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_map_begin(VALUE self, VALUE ktype, VALUE vtype, VALUE size_value) { + int size = FIX2INT(size_value); + VALUE transport = GET_TRANSPORT(self); + if (size == 0) { + write_byte_direct(transport, 0); + } else { + write_varint32(transport, size); + write_byte_direct(transport, get_compact_type(ktype) << 4 | get_compact_type(vtype)); + } + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_list_begin(VALUE self, VALUE etype, VALUE size) { + write_collection_begin(GET_TRANSPORT(self), etype, size); + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_set_begin(VALUE self, VALUE etype, VALUE size) { + write_collection_begin(GET_TRANSPORT(self), etype, size); + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_bool(VALUE self, VALUE b) { + int8_t type = b == Qtrue ? CTYPE_BOOLEAN_TRUE : CTYPE_BOOLEAN_FALSE; + VALUE boolean_field = rb_ivar_get(self, boolean_field_id); + if (NIL_P(boolean_field)) { + // we're not part of a field, so just write the value. + write_byte_direct(GET_TRANSPORT(self), type); + } else { + // we haven't written the field header yet + write_field_begin_internal(self, rb_ary_entry(boolean_field, 0), rb_ary_entry(boolean_field, 1), INT2FIX(type)); + rb_ivar_set(self, boolean_field_id, Qnil); + } + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_byte(VALUE self, VALUE byte) { + CHECK_NIL(byte); + write_byte_direct(GET_TRANSPORT(self), FIX2INT(byte)); + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_i16(VALUE self, VALUE i16) { + rb_thrift_compact_proto_write_i32(self, i16); + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_i32(VALUE self, VALUE i32) { + CHECK_NIL(i32); + write_varint32(GET_TRANSPORT(self), int_to_zig_zag(NUM2INT(i32))); + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_i64(VALUE self, VALUE i64) { + CHECK_NIL(i64); + write_varint64(GET_TRANSPORT(self), ll_to_zig_zag(NUM2LL(i64))); + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_double(VALUE self, VALUE dub) { + CHECK_NIL(dub); + // Unfortunately, bitwise_cast doesn't work in C. Bad C! + union { + double f; + int64_t l; + } transfer; + transfer.f = RFLOAT_VALUE(rb_Float(dub)); + char buf[8]; + buf[0] = transfer.l & 0xff; + buf[1] = (transfer.l >> 8) & 0xff; + buf[2] = (transfer.l >> 16) & 0xff; + buf[3] = (transfer.l >> 24) & 0xff; + buf[4] = (transfer.l >> 32) & 0xff; + buf[5] = (transfer.l >> 40) & 0xff; + buf[6] = (transfer.l >> 48) & 0xff; + buf[7] = (transfer.l >> 56) & 0xff; + WRITE(GET_TRANSPORT(self), buf, 8); + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_string(VALUE self, VALUE str) { + str = convert_to_utf8_byte_buffer(str); + rb_thrift_compact_proto_write_binary(self, str); + return Qnil; +} + +VALUE rb_thrift_compact_proto_write_binary(VALUE self, VALUE buf) { + buf = force_binary_encoding(buf); + VALUE transport = GET_TRANSPORT(self); + write_varint32(transport, RSTRING_LEN(buf)); + WRITE(transport, StringValuePtr(buf), RSTRING_LEN(buf)); + return Qnil; +} + +//--------------------------------------- +// interface reading methods +//--------------------------------------- + +#define is_bool_type(ctype) (((ctype) & 0x0F) == CTYPE_BOOLEAN_TRUE || ((ctype) & 0x0F) == CTYPE_BOOLEAN_FALSE) + +VALUE rb_thrift_compact_proto_read_string(VALUE self); +VALUE rb_thrift_compact_proto_read_binary(VALUE self); +VALUE rb_thrift_compact_proto_read_byte(VALUE self); +VALUE rb_thrift_compact_proto_read_i32(VALUE self); +VALUE rb_thrift_compact_proto_read_i16(VALUE self); + +static int8_t get_ttype(int8_t ctype) { + if (ctype == TTYPE_STOP) { + return TTYPE_STOP; + } else if (ctype == CTYPE_BOOLEAN_TRUE || ctype == CTYPE_BOOLEAN_FALSE) { + return TTYPE_BOOL; + } else if (ctype == CTYPE_BYTE) { + return TTYPE_BYTE; + } else if (ctype == CTYPE_I16) { + return TTYPE_I16; + } else if (ctype == CTYPE_I32) { + return TTYPE_I32; + } else if (ctype == CTYPE_I64) { + return TTYPE_I64; + } else if (ctype == CTYPE_DOUBLE) { + return TTYPE_DOUBLE; + } else if (ctype == CTYPE_BINARY) { + return TTYPE_STRING; + } else if (ctype == CTYPE_LIST) { + return TTYPE_LIST; + } else if (ctype == CTYPE_SET) { + return TTYPE_SET; + } else if (ctype == CTYPE_MAP) { + return TTYPE_MAP; + } else if (ctype == CTYPE_STRUCT) { + return TTYPE_STRUCT; + } else { + char str[50]; + sprintf(str, "don't know what type: %d", ctype); + rb_raise(rb_eStandardError, "%s", str); + return 0; + } +} + +static char read_byte_direct(VALUE self) { + VALUE byte = rb_funcall(GET_TRANSPORT(self), read_byte_method_id, 0); + return (char)(FIX2INT(byte)); +} + +static int64_t zig_zag_to_ll(int64_t n) { + return (((uint64_t)n) >> 1) ^ -(n & 1); +} + +static int32_t zig_zag_to_int(int32_t n) { + return (((uint32_t)n) >> 1) ^ -(n & 1); +} + +static int64_t read_varint64(VALUE self) { + int shift = 0; + int64_t result = 0; + while (true) { + int8_t b = read_byte_direct(self); + result = result | ((uint64_t)(b & 0x7f) << shift); + if ((b & 0x80) != 0x80) { + break; + } + shift += 7; + } + return result; +} + +static int16_t read_i16(VALUE self) { + return zig_zag_to_int((int32_t)read_varint64(self)); +} + +static VALUE get_protocol_exception(VALUE code, VALUE message) { + VALUE args[2]; + args[0] = code; + args[1] = message; + return rb_class_new_instance(2, (VALUE*)&args, protocol_exception_class); +} + +VALUE rb_thrift_compact_proto_read_message_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_compact_proto_read_struct_begin(VALUE self) { + rb_ary_push(rb_ivar_get(self, last_field_id), INT2FIX(0)); + return Qnil; +} + +VALUE rb_thrift_compact_proto_read_struct_end(VALUE self) { + rb_ary_pop(rb_ivar_get(self, last_field_id)); + return Qnil; +} + +VALUE rb_thrift_compact_proto_read_field_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_compact_proto_read_map_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_compact_proto_read_list_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_compact_proto_read_set_end(VALUE self) { + return Qnil; +} + +VALUE rb_thrift_compact_proto_read_message_begin(VALUE self) { + int8_t protocol_id = read_byte_direct(self); + if (protocol_id != PROTOCOL_ID) { + char buf[100]; + int len = sprintf(buf, "Expected protocol id %d but got %d", PROTOCOL_ID, protocol_id); + buf[len] = 0; + rb_exc_raise(get_protocol_exception(INT2FIX(-1), rb_str_new2(buf))); + } + + int8_t version_and_type = read_byte_direct(self); + int8_t version = version_and_type & VERSION_MASK; + if (version != VERSION) { + char buf[100]; + int len = sprintf(buf, "Expected version id %d but got %d", version, VERSION); + buf[len] = 0; + rb_exc_raise(get_protocol_exception(INT2FIX(-1), rb_str_new2(buf))); + } + + int8_t type = (version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS; + int32_t seqid = read_varint64(self); + VALUE messageName = rb_thrift_compact_proto_read_string(self); + return rb_ary_new3(3, messageName, INT2FIX(type), INT2NUM(seqid)); +} + +VALUE rb_thrift_compact_proto_read_field_begin(VALUE self) { + int8_t type = read_byte_direct(self); + // if it's a stop, then we can return immediately, as the struct is over. + if ((type & 0x0f) == TTYPE_STOP) { + return rb_ary_new3(3, Qnil, INT2FIX(0), INT2FIX(0)); + } else { + int field_id = 0; + + // mask off the 4 MSB of the type header. it could contain a field id delta. + uint8_t modifier = ((type & 0xf0) >> 4); + + if (modifier == 0) { + // not a delta. look ahead for the zigzag varint field id. + (void) LAST_ID(self); + field_id = read_i16(self); + } else { + // has a delta. add the delta to the last read field id. + field_id = LAST_ID(self) + modifier; + } + + // if this happens to be a boolean field, the value is encoded in the type + if (is_bool_type(type)) { + // save the boolean value in a special instance variable. + rb_ivar_set(self, bool_value_id, (type & 0x0f) == CTYPE_BOOLEAN_TRUE ? Qtrue : Qfalse); + } + + // push the new field onto the field stack so we can keep the deltas going. + SET_LAST_ID(self, INT2FIX(field_id)); + return rb_ary_new3(3, Qnil, INT2FIX(get_ttype(type & 0x0f)), INT2FIX(field_id)); + } +} + +VALUE rb_thrift_compact_proto_read_map_begin(VALUE self) { + int32_t size = read_varint64(self); + uint8_t key_and_value_type = size == 0 ? 0 : read_byte_direct(self); + return rb_ary_new3(3, INT2FIX(get_ttype(key_and_value_type >> 4)), INT2FIX(get_ttype(key_and_value_type & 0xf)), INT2FIX(size)); +} + +VALUE rb_thrift_compact_proto_read_list_begin(VALUE self) { + uint8_t size_and_type = read_byte_direct(self); + int32_t size = (size_and_type >> 4) & 0x0f; + if (size == 15) { + size = read_varint64(self); + } + uint8_t type = get_ttype(size_and_type & 0x0f); + return rb_ary_new3(2, INT2FIX(type), INT2FIX(size)); +} + +VALUE rb_thrift_compact_proto_read_set_begin(VALUE self) { + return rb_thrift_compact_proto_read_list_begin(self); +} + +VALUE rb_thrift_compact_proto_read_bool(VALUE self) { + VALUE bool_value = rb_ivar_get(self, bool_value_id); + if (NIL_P(bool_value)) { + return read_byte_direct(self) == CTYPE_BOOLEAN_TRUE ? Qtrue : Qfalse; + } else { + rb_ivar_set(self, bool_value_id, Qnil); + return bool_value; + } +} + +VALUE rb_thrift_compact_proto_read_byte(VALUE self) { + return INT2FIX(read_byte_direct(self)); +} + +VALUE rb_thrift_compact_proto_read_i16(VALUE self) { + return INT2FIX(read_i16(self)); +} + +VALUE rb_thrift_compact_proto_read_i32(VALUE self) { + return INT2NUM(zig_zag_to_int(read_varint64(self))); +} + +VALUE rb_thrift_compact_proto_read_i64(VALUE self) { + return LL2NUM(zig_zag_to_ll(read_varint64(self))); +} + +VALUE rb_thrift_compact_proto_read_double(VALUE self) { + union { + double f; + int64_t l; + } transfer; + VALUE rbuf = rb_ivar_get(self, rbuf_ivar_id); + rb_funcall(GET_TRANSPORT(self), read_into_buffer_method_id, 2, rbuf, INT2FIX(8)); + uint32_t lo = ((uint8_t)(RSTRING_PTR(rbuf)[0])) + | (((uint8_t)(RSTRING_PTR(rbuf)[1])) << 8) + | (((uint8_t)(RSTRING_PTR(rbuf)[2])) << 16) + | (((uint8_t)(RSTRING_PTR(rbuf)[3])) << 24); + uint64_t hi = (((uint8_t)(RSTRING_PTR(rbuf)[4]))) + | (((uint8_t)(RSTRING_PTR(rbuf)[5])) << 8) + | (((uint8_t)(RSTRING_PTR(rbuf)[6])) << 16) + | (((uint8_t)(RSTRING_PTR(rbuf)[7])) << 24); + transfer.l = (hi << 32) | lo; + + return rb_float_new(transfer.f); +} + +VALUE rb_thrift_compact_proto_read_string(VALUE self) { + VALUE buffer = rb_thrift_compact_proto_read_binary(self); + return convert_to_string(buffer); +} + +VALUE rb_thrift_compact_proto_read_binary(VALUE self) { + int64_t size = read_varint64(self); + return READ(self, size); +} + +static void Init_constants() { + thrift_compact_protocol_class = rb_const_get(thrift_module, rb_intern("CompactProtocol")); + + VERSION = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("VERSION"))); + VERSION_MASK = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("VERSION_MASK"))); + TYPE_MASK = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("TYPE_MASK"))); + TYPE_BITS = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("TYPE_BITS"))); + TYPE_SHIFT_AMOUNT = FIX2INT(rb_const_get(thrift_compact_protocol_class, rb_intern("TYPE_SHIFT_AMOUNT"))); + PROTOCOL_ID = FIX2INT(rb_const_get(thrift_compact_protocol_class, rb_intern("PROTOCOL_ID"))); + + last_field_id = rb_intern("@last_field"); + boolean_field_id = rb_intern("@boolean_field"); + bool_value_id = rb_intern("@bool_value"); + rbuf_ivar_id = rb_intern("@rbuf"); +} + +static void Init_rb_methods() { + rb_define_method(thrift_compact_protocol_class, "native?", rb_thrift_compact_proto_native_qmark, 0); + + rb_define_method(thrift_compact_protocol_class, "write_message_begin", rb_thrift_compact_proto_write_message_begin, 3); + rb_define_method(thrift_compact_protocol_class, "write_field_begin", rb_thrift_compact_proto_write_field_begin, 3); + rb_define_method(thrift_compact_protocol_class, "write_field_stop", rb_thrift_compact_proto_write_field_stop, 0); + rb_define_method(thrift_compact_protocol_class, "write_map_begin", rb_thrift_compact_proto_write_map_begin, 3); + rb_define_method(thrift_compact_protocol_class, "write_list_begin", rb_thrift_compact_proto_write_list_begin, 2); + rb_define_method(thrift_compact_protocol_class, "write_set_begin", rb_thrift_compact_proto_write_set_begin, 2); + rb_define_method(thrift_compact_protocol_class, "write_byte", rb_thrift_compact_proto_write_byte, 1); + rb_define_method(thrift_compact_protocol_class, "write_bool", rb_thrift_compact_proto_write_bool, 1); + rb_define_method(thrift_compact_protocol_class, "write_i16", rb_thrift_compact_proto_write_i16, 1); + rb_define_method(thrift_compact_protocol_class, "write_i32", rb_thrift_compact_proto_write_i32, 1); + rb_define_method(thrift_compact_protocol_class, "write_i64", rb_thrift_compact_proto_write_i64, 1); + rb_define_method(thrift_compact_protocol_class, "write_double", rb_thrift_compact_proto_write_double, 1); + rb_define_method(thrift_compact_protocol_class, "write_string", rb_thrift_compact_proto_write_string, 1); + rb_define_method(thrift_compact_protocol_class, "write_binary", rb_thrift_compact_proto_write_binary, 1); + + rb_define_method(thrift_compact_protocol_class, "write_message_end", rb_thrift_compact_proto_write_message_end, 0); + rb_define_method(thrift_compact_protocol_class, "write_struct_begin", rb_thrift_compact_proto_write_struct_begin, 1); + rb_define_method(thrift_compact_protocol_class, "write_struct_end", rb_thrift_compact_proto_write_struct_end, 0); + rb_define_method(thrift_compact_protocol_class, "write_field_end", rb_thrift_compact_proto_write_field_end, 0); + rb_define_method(thrift_compact_protocol_class, "write_map_end", rb_thrift_compact_proto_write_map_end, 0); + rb_define_method(thrift_compact_protocol_class, "write_list_end", rb_thrift_compact_proto_write_list_end, 0); + rb_define_method(thrift_compact_protocol_class, "write_set_end", rb_thrift_compact_proto_write_set_end, 0); + + + rb_define_method(thrift_compact_protocol_class, "read_message_begin", rb_thrift_compact_proto_read_message_begin, 0); + rb_define_method(thrift_compact_protocol_class, "read_field_begin", rb_thrift_compact_proto_read_field_begin, 0); + rb_define_method(thrift_compact_protocol_class, "read_map_begin", rb_thrift_compact_proto_read_map_begin, 0); + rb_define_method(thrift_compact_protocol_class, "read_list_begin", rb_thrift_compact_proto_read_list_begin, 0); + rb_define_method(thrift_compact_protocol_class, "read_set_begin", rb_thrift_compact_proto_read_set_begin, 0); + rb_define_method(thrift_compact_protocol_class, "read_byte", rb_thrift_compact_proto_read_byte, 0); + rb_define_method(thrift_compact_protocol_class, "read_bool", rb_thrift_compact_proto_read_bool, 0); + rb_define_method(thrift_compact_protocol_class, "read_i16", rb_thrift_compact_proto_read_i16, 0); + rb_define_method(thrift_compact_protocol_class, "read_i32", rb_thrift_compact_proto_read_i32, 0); + rb_define_method(thrift_compact_protocol_class, "read_i64", rb_thrift_compact_proto_read_i64, 0); + rb_define_method(thrift_compact_protocol_class, "read_double", rb_thrift_compact_proto_read_double, 0); + rb_define_method(thrift_compact_protocol_class, "read_string", rb_thrift_compact_proto_read_string, 0); + rb_define_method(thrift_compact_protocol_class, "read_binary", rb_thrift_compact_proto_read_binary, 0); + + rb_define_method(thrift_compact_protocol_class, "read_message_end", rb_thrift_compact_proto_read_message_end, 0); + rb_define_method(thrift_compact_protocol_class, "read_struct_begin", rb_thrift_compact_proto_read_struct_begin, 0); + rb_define_method(thrift_compact_protocol_class, "read_struct_end", rb_thrift_compact_proto_read_struct_end, 0); + rb_define_method(thrift_compact_protocol_class, "read_field_end", rb_thrift_compact_proto_read_field_end, 0); + rb_define_method(thrift_compact_protocol_class, "read_map_end", rb_thrift_compact_proto_read_map_end, 0); + rb_define_method(thrift_compact_protocol_class, "read_list_end", rb_thrift_compact_proto_read_list_end, 0); + rb_define_method(thrift_compact_protocol_class, "read_set_end", rb_thrift_compact_proto_read_set_end, 0); +} + +void Init_compact_protocol() { + Init_constants(); + Init_rb_methods(); +} diff --git a/lib/rb/ext/compact_protocol.h b/lib/rb/ext/compact_protocol.h new file mode 100644 index 0000000..163915e --- /dev/null +++ b/lib/rb/ext/compact_protocol.h @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +void Init_compact_protocol(); diff --git a/lib/rb/ext/constants.h b/lib/rb/ext/constants.h new file mode 100644 index 0000000..e7aec44 --- /dev/null +++ b/lib/rb/ext/constants.h @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +extern int TTYPE_STOP; +extern int TTYPE_BOOL; +extern int TTYPE_BYTE; +extern int TTYPE_I16; +extern int TTYPE_I32; +extern int TTYPE_I64; +extern int TTYPE_DOUBLE; +extern int TTYPE_STRING; +extern int TTYPE_MAP; +extern int TTYPE_SET; +extern int TTYPE_LIST; +extern int TTYPE_STRUCT; + +extern ID validate_method_id; +extern ID write_struct_begin_method_id; +extern ID write_struct_end_method_id; +extern ID write_field_begin_method_id; +extern ID write_field_end_method_id; +extern ID write_boolean_method_id; +extern ID write_byte_method_id; +extern ID write_i16_method_id; +extern ID write_i32_method_id; +extern ID write_i64_method_id; +extern ID write_double_method_id; +extern ID write_string_method_id; +extern ID write_binary_method_id; +extern ID write_map_begin_method_id; +extern ID write_map_end_method_id; +extern ID write_list_begin_method_id; +extern ID write_list_end_method_id; +extern ID write_set_begin_method_id; +extern ID write_set_end_method_id; +extern ID read_bool_method_id; +extern ID read_byte_method_id; +extern ID read_i16_method_id; +extern ID read_i32_method_id; +extern ID read_i64_method_id; +extern ID read_string_method_id; +extern ID read_binary_method_id; +extern ID read_double_method_id; +extern ID read_map_begin_method_id; +extern ID read_map_end_method_id; +extern ID read_list_begin_method_id; +extern ID read_list_end_method_id; +extern ID read_set_begin_method_id; +extern ID read_set_end_method_id; +extern ID read_struct_begin_method_id; +extern ID read_struct_end_method_id; +extern ID read_field_begin_method_id; +extern ID read_field_end_method_id; +extern ID keys_method_id; +extern ID entries_method_id; +extern ID write_field_stop_method_id; +extern ID skip_method_id; +extern ID write_method_id; +extern ID read_all_method_id; +extern ID read_into_buffer_method_id; +extern ID force_binary_encoding_id; +extern ID convert_to_utf8_byte_buffer_id; +extern ID convert_to_string_id; + +extern ID fields_const_id; +extern ID transport_ivar_id; +extern ID strict_read_ivar_id; +extern ID strict_write_ivar_id; + +extern VALUE type_sym; +extern VALUE name_sym; +extern VALUE key_sym; +extern VALUE value_sym; +extern VALUE element_sym; +extern VALUE class_sym; +extern VALUE binary_sym; + +extern VALUE rb_cSet; +extern VALUE thrift_module; +extern VALUE thrift_types_module; +extern VALUE thrift_bytes_module; +extern VALUE class_thrift_protocol; +extern VALUE protocol_exception_class; diff --git a/lib/rb/ext/extconf.rb b/lib/rb/ext/extconf.rb new file mode 100644 index 0000000..b35f60b --- /dev/null +++ b/lib/rb/ext/extconf.rb @@ -0,0 +1,34 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ + File.open('Makefile', 'w'){|f| f.puts "all:\n\ninstall:\n" } +else + require 'mkmf' + require 'rbconfig' + + $ARCH_FLAGS = RbConfig::CONFIG['CFLAGS'].scan( /(-arch )(\S+)/ ).map{|x,y| x + y + ' ' }.join('') + + + $CFLAGS = "-fsigned-char -g -O2 -Wall -Werror " + $ARCH_FLAGS + + have_func("strlcpy", "string.h") + + create_makefile 'thrift_native' +end diff --git a/lib/rb/ext/macros.h b/lib/rb/ext/macros.h new file mode 100644 index 0000000..265f693 --- /dev/null +++ b/lib/rb/ext/macros.h @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#define GET_TRANSPORT(obj) rb_ivar_get(obj, transport_ivar_id) +#define GET_STRICT_READ(obj) rb_ivar_get(obj, strict_read_ivar_id) +#define GET_STRICT_WRITE(obj) rb_ivar_get(obj, strict_write_ivar_id) +#define WRITE(obj, data, length) rb_funcall(obj, write_method_id, 1, rb_str_new(data, length)) +#define CHECK_NIL(obj) if (NIL_P(obj)) { rb_raise(rb_eStandardError, "nil argument not allowed!");} +#define READ(obj, length) rb_funcall(GET_TRANSPORT(obj), read_all_method_id, 1, INT2FIX(length)) + +#ifndef RFLOAT_VALUE +# define RFLOAT_VALUE(v) RFLOAT(rb_Float(v))->value +#endif + +#ifndef RSTRING_LEN +# define RSTRING_LEN(v) RSTRING(rb_String(v))->len +#endif + +#ifndef RSTRING_PTR +# define RSTRING_PTR(v) RSTRING(rb_String(v))->ptr +#endif + +#ifndef RARRAY_LEN +# define RARRAY_LEN(v) RARRAY(rb_Array(v))->len +#endif diff --git a/lib/rb/ext/memory_buffer.c b/lib/rb/ext/memory_buffer.c new file mode 100644 index 0000000..8b52c4a --- /dev/null +++ b/lib/rb/ext/memory_buffer.c @@ -0,0 +1,134 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include + +ID buf_ivar_id; +ID index_ivar_id; + +ID slice_method_id; + +int GARBAGE_BUFFER_SIZE; + +#define GET_BUF(self) rb_ivar_get(self, buf_ivar_id) + +VALUE rb_thrift_memory_buffer_write(VALUE self, VALUE str); +VALUE rb_thrift_memory_buffer_read(VALUE self, VALUE length_value); +VALUE rb_thrift_memory_buffer_read_byte(VALUE self); +VALUE rb_thrift_memory_buffer_read_into_buffer(VALUE self, VALUE buffer_value, VALUE size_value); + +VALUE rb_thrift_memory_buffer_write(VALUE self, VALUE str) { + VALUE buf = GET_BUF(self); + str = force_binary_encoding(str); + rb_str_buf_cat(buf, StringValuePtr(str), RSTRING_LEN(str)); + return Qnil; +} + +VALUE rb_thrift_memory_buffer_read(VALUE self, VALUE length_value) { + int length = FIX2INT(length_value); + + VALUE index_value = rb_ivar_get(self, index_ivar_id); + int index = FIX2INT(index_value); + + VALUE buf = GET_BUF(self); + VALUE data = rb_funcall(buf, slice_method_id, 2, index_value, length_value); + + index += length; + if (index > RSTRING_LEN(buf)) { + index = RSTRING_LEN(buf); + } + if (index >= GARBAGE_BUFFER_SIZE) { + rb_ivar_set(self, buf_ivar_id, rb_funcall(buf, slice_method_id, 2, INT2FIX(index), INT2FIX(RSTRING_LEN(buf) - 1))); + index = 0; + } + rb_ivar_set(self, index_ivar_id, INT2FIX(index)); + + if (RSTRING_LEN(data) < length) { + rb_raise(rb_eEOFError, "Not enough bytes remain in memory buffer"); + } + + return data; +} + +VALUE rb_thrift_memory_buffer_read_byte(VALUE self) { + VALUE index_value = rb_ivar_get(self, index_ivar_id); + int index = FIX2INT(index_value); + + VALUE buf = GET_BUF(self); + if (index >= RSTRING_LEN(buf)) { + rb_raise(rb_eEOFError, "Not enough bytes remain in memory buffer"); + } + char byte = RSTRING_PTR(buf)[index++]; + + if (index >= GARBAGE_BUFFER_SIZE) { + rb_ivar_set(self, buf_ivar_id, rb_funcall(buf, slice_method_id, 2, INT2FIX(index), INT2FIX(RSTRING_LEN(buf) - 1))); + index = 0; + } + rb_ivar_set(self, index_ivar_id, INT2FIX(index)); + + int result = (int) byte; + return INT2FIX(result); +} + +VALUE rb_thrift_memory_buffer_read_into_buffer(VALUE self, VALUE buffer_value, VALUE size_value) { + int i = 0; + int size = FIX2INT(size_value); + int index; + VALUE buf = GET_BUF(self); + + index = FIX2INT(rb_ivar_get(self, index_ivar_id)); + while (i < size) { + if (index >= RSTRING_LEN(buf)) { + rb_raise(rb_eEOFError, "Not enough bytes remain in memory buffer"); + } + char byte = RSTRING_PTR(buf)[index++]; + + if (i >= RSTRING_LEN(buffer_value)) { + rb_raise(rb_eIndexError, "index %d out of string", i); + } + ((char*)RSTRING_PTR(buffer_value))[i] = byte; + i++; + } + + if (index >= GARBAGE_BUFFER_SIZE) { + rb_ivar_set(self, buf_ivar_id, rb_funcall(buf, slice_method_id, 2, INT2FIX(index), INT2FIX(RSTRING_LEN(buf) - 1))); + index = 0; + } + rb_ivar_set(self, index_ivar_id, INT2FIX(index)); + + return INT2FIX(i); +} + +void Init_memory_buffer() { + VALUE thrift_memory_buffer_class = rb_const_get(thrift_module, rb_intern("MemoryBufferTransport")); + rb_define_method(thrift_memory_buffer_class, "write", rb_thrift_memory_buffer_write, 1); + rb_define_method(thrift_memory_buffer_class, "read", rb_thrift_memory_buffer_read, 1); + rb_define_method(thrift_memory_buffer_class, "read_byte", rb_thrift_memory_buffer_read_byte, 0); + rb_define_method(thrift_memory_buffer_class, "read_into_buffer", rb_thrift_memory_buffer_read_into_buffer, 2); + + buf_ivar_id = rb_intern("@buf"); + index_ivar_id = rb_intern("@index"); + + slice_method_id = rb_intern("slice"); + + GARBAGE_BUFFER_SIZE = FIX2INT(rb_const_get(thrift_memory_buffer_class, rb_intern("GARBAGE_BUFFER_SIZE"))); +} diff --git a/lib/rb/ext/memory_buffer.h b/lib/rb/ext/memory_buffer.h new file mode 100644 index 0000000..b277fa6 --- /dev/null +++ b/lib/rb/ext/memory_buffer.h @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +void Init_memory_buffer(); diff --git a/lib/rb/ext/protocol.c b/lib/rb/ext/protocol.c new file mode 100644 index 0000000..e69de29 diff --git a/lib/rb/ext/protocol.h b/lib/rb/ext/protocol.h new file mode 100644 index 0000000..e69de29 diff --git a/lib/rb/ext/strlcpy.c b/lib/rb/ext/strlcpy.c new file mode 100644 index 0000000..6700ff2 --- /dev/null +++ b/lib/rb/ext/strlcpy.c @@ -0,0 +1,41 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "strlcpy.h" + +#ifndef HAVE_STRLCPY +#define HAVE_STRLCPY +size_t +strlcpy (char *dst, const char *src, size_t dst_sz) +{ + size_t n; + + for (n = 0; n < dst_sz; n++) { + if ((*dst++ = *src++) == '\0') + break; + } + + if (n < dst_sz) + return n; + if (n > 0) + *(dst - 1) = '\0'; + return n + strlen (src); +} +#endif + diff --git a/lib/rb/ext/strlcpy.h b/lib/rb/ext/strlcpy.h new file mode 100644 index 0000000..f6fe0fe --- /dev/null +++ b/lib/rb/ext/strlcpy.h @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#ifndef HAVE_STRLCPY +size_t strlcpy (char *dst, const char *src, size_t dst_sz); +#else +#if !__has_builtin(strlcpy) +extern size_t strlcpy(char *, const char *, size_t); +#endif +#endif + diff --git a/lib/rb/ext/struct.c b/lib/rb/ext/struct.c new file mode 100644 index 0000000..e3aa855 --- /dev/null +++ b/lib/rb/ext/struct.c @@ -0,0 +1,711 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "struct.h" +#include "constants.h" +#include "macros.h" +#include "strlcpy.h" + +VALUE thrift_union_class; + +ID setfield_id; +ID setvalue_id; + +ID to_s_method_id; +ID name_to_id_method_id; +static ID sorted_field_ids_method_id; + +#define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET) +#define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id) + +//------------------------------------------- +// Writing section +//------------------------------------------- + +// default fn pointers for protocol stuff here + +VALUE default_write_bool(VALUE protocol, VALUE value) { + rb_funcall(protocol, write_boolean_method_id, 1, value); + return Qnil; +} + +VALUE default_write_byte(VALUE protocol, VALUE value) { + rb_funcall(protocol, write_byte_method_id, 1, value); + return Qnil; +} + +VALUE default_write_i16(VALUE protocol, VALUE value) { + rb_funcall(protocol, write_i16_method_id, 1, value); + return Qnil; +} + +VALUE default_write_i32(VALUE protocol, VALUE value) { + rb_funcall(protocol, write_i32_method_id, 1, value); + return Qnil; +} + +VALUE default_write_i64(VALUE protocol, VALUE value) { + rb_funcall(protocol, write_i64_method_id, 1, value); + return Qnil; +} + +VALUE default_write_double(VALUE protocol, VALUE value) { + rb_funcall(protocol, write_double_method_id, 1, value); + return Qnil; +} + +VALUE default_write_string(VALUE protocol, VALUE value) { + rb_funcall(protocol, write_string_method_id, 1, value); + return Qnil; +} + +VALUE default_write_binary(VALUE protocol, VALUE value) { + rb_funcall(protocol, write_binary_method_id, 1, value); + return Qnil; +} + +VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) { + rb_funcall(protocol, write_list_begin_method_id, 2, etype, length); + return Qnil; +} + +VALUE default_write_list_end(VALUE protocol) { + rb_funcall(protocol, write_list_end_method_id, 0); + return Qnil; +} + +VALUE default_write_set_begin(VALUE protocol, VALUE etype, VALUE length) { + rb_funcall(protocol, write_set_begin_method_id, 2, etype, length); + return Qnil; +} + +VALUE default_write_set_end(VALUE protocol) { + rb_funcall(protocol, write_set_end_method_id, 0); + return Qnil; +} + +VALUE default_write_map_begin(VALUE protocol, VALUE ktype, VALUE vtype, VALUE length) { + rb_funcall(protocol, write_map_begin_method_id, 3, ktype, vtype, length); + return Qnil; +} + +VALUE default_write_map_end(VALUE protocol) { + rb_funcall(protocol, write_map_end_method_id, 0); + return Qnil; +} + +VALUE default_write_struct_begin(VALUE protocol, VALUE struct_name) { + rb_funcall(protocol, write_struct_begin_method_id, 1, struct_name); + return Qnil; +} + +VALUE default_write_struct_end(VALUE protocol) { + rb_funcall(protocol, write_struct_end_method_id, 0); + return Qnil; +} + +VALUE default_write_field_begin(VALUE protocol, VALUE name, VALUE type, VALUE id) { + rb_funcall(protocol, write_field_begin_method_id, 3, name, type, id); + return Qnil; +} + +VALUE default_write_field_end(VALUE protocol) { + rb_funcall(protocol, write_field_end_method_id, 0); + return Qnil; +} + +VALUE default_write_field_stop(VALUE protocol) { + rb_funcall(protocol, write_field_stop_method_id, 0); + return Qnil; +} + +VALUE default_read_field_begin(VALUE protocol) { + return rb_funcall(protocol, read_field_begin_method_id, 0); +} + +VALUE default_read_field_end(VALUE protocol) { + return rb_funcall(protocol, read_field_end_method_id, 0); +} + +VALUE default_read_map_begin(VALUE protocol) { + return rb_funcall(protocol, read_map_begin_method_id, 0); +} + +VALUE default_read_map_end(VALUE protocol) { + return rb_funcall(protocol, read_map_end_method_id, 0); +} + +VALUE default_read_list_begin(VALUE protocol) { + return rb_funcall(protocol, read_list_begin_method_id, 0); +} + +VALUE default_read_list_end(VALUE protocol) { + return rb_funcall(protocol, read_list_end_method_id, 0); +} + +VALUE default_read_set_begin(VALUE protocol) { + return rb_funcall(protocol, read_set_begin_method_id, 0); +} + +VALUE default_read_set_end(VALUE protocol) { + return rb_funcall(protocol, read_set_end_method_id, 0); +} + +VALUE default_read_byte(VALUE protocol) { + return rb_funcall(protocol, read_byte_method_id, 0); +} + +VALUE default_read_bool(VALUE protocol) { + return rb_funcall(protocol, read_bool_method_id, 0); +} + +VALUE default_read_i16(VALUE protocol) { + return rb_funcall(protocol, read_i16_method_id, 0); +} + +VALUE default_read_i32(VALUE protocol) { + return rb_funcall(protocol, read_i32_method_id, 0); +} + +VALUE default_read_i64(VALUE protocol) { + return rb_funcall(protocol, read_i64_method_id, 0); +} + +VALUE default_read_double(VALUE protocol) { + return rb_funcall(protocol, read_double_method_id, 0); +} + +VALUE default_read_string(VALUE protocol) { + return rb_funcall(protocol, read_string_method_id, 0); +} + +VALUE default_read_binary(VALUE protocol) { + return rb_funcall(protocol, read_binary_method_id, 0); +} + +VALUE default_read_struct_begin(VALUE protocol) { + return rb_funcall(protocol, read_struct_begin_method_id, 0); +} + +VALUE default_read_struct_end(VALUE protocol) { + return rb_funcall(protocol, read_struct_end_method_id, 0); +} + +// end default protocol methods + +static VALUE rb_thrift_union_write (VALUE self, VALUE protocol); +static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol); +static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info); + +VALUE get_field_value(VALUE obj, VALUE field_name) { + char name_buf[RSTRING_LEN(field_name) + 2]; + + name_buf[0] = '@'; + strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name) + 1); + + VALUE value = rb_ivar_get(obj, rb_intern(name_buf)); + + return value; +} + +static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) { + int sz, i; + + if (ttype == TTYPE_MAP) { + VALUE keys; + VALUE key; + VALUE val; + + Check_Type(value, T_HASH); + + VALUE key_info = rb_hash_aref(field_info, key_sym); + VALUE keytype_value = rb_hash_aref(key_info, type_sym); + int keytype = FIX2INT(keytype_value); + + VALUE value_info = rb_hash_aref(field_info, value_sym); + VALUE valuetype_value = rb_hash_aref(value_info, type_sym); + int valuetype = FIX2INT(valuetype_value); + + keys = rb_funcall(value, keys_method_id, 0); + + sz = RARRAY_LEN(keys); + + default_write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz)); + + for (i = 0; i < sz; i++) { + key = rb_ary_entry(keys, i); + val = rb_hash_aref(value, key); + + if (IS_CONTAINER(keytype)) { + write_container(keytype, key_info, key, protocol); + } else { + write_anything(keytype, key, protocol, key_info); + } + + if (IS_CONTAINER(valuetype)) { + write_container(valuetype, value_info, val, protocol); + } else { + write_anything(valuetype, val, protocol, value_info); + } + } + + default_write_map_end(protocol); + } else if (ttype == TTYPE_LIST) { + Check_Type(value, T_ARRAY); + + sz = RARRAY_LEN(value); + + VALUE element_type_info = rb_hash_aref(field_info, element_sym); + VALUE element_type_value = rb_hash_aref(element_type_info, type_sym); + int element_type = FIX2INT(element_type_value); + + default_write_list_begin(protocol, element_type_value, INT2FIX(sz)); + for (i = 0; i < sz; ++i) { + VALUE val = rb_ary_entry(value, i); + if (IS_CONTAINER(element_type)) { + write_container(element_type, element_type_info, val, protocol); + } else { + write_anything(element_type, val, protocol, element_type_info); + } + } + default_write_list_end(protocol); + } else if (ttype == TTYPE_SET) { + VALUE items; + + if (TYPE(value) == T_ARRAY) { + items = value; + } else { + if (rb_cSet == CLASS_OF(value)) { + items = rb_funcall(value, entries_method_id, 0); + } else { + Check_Type(value, T_HASH); + items = rb_funcall(value, keys_method_id, 0); + } + } + + sz = RARRAY_LEN(items); + + VALUE element_type_info = rb_hash_aref(field_info, element_sym); + VALUE element_type_value = rb_hash_aref(element_type_info, type_sym); + int element_type = FIX2INT(element_type_value); + + default_write_set_begin(protocol, element_type_value, INT2FIX(sz)); + + for (i = 0; i < sz; i++) { + VALUE val = rb_ary_entry(items, i); + if (IS_CONTAINER(element_type)) { + write_container(element_type, element_type_info, val, protocol); + } else { + write_anything(element_type, val, protocol, element_type_info); + } + } + + default_write_set_end(protocol); + } else { + rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype); + } +} + +static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) { + if (ttype == TTYPE_BOOL) { + default_write_bool(protocol, value); + } else if (ttype == TTYPE_BYTE) { + default_write_byte(protocol, value); + } else if (ttype == TTYPE_I16) { + default_write_i16(protocol, value); + } else if (ttype == TTYPE_I32) { + default_write_i32(protocol, value); + } else if (ttype == TTYPE_I64) { + default_write_i64(protocol, value); + } else if (ttype == TTYPE_DOUBLE) { + default_write_double(protocol, value); + } else if (ttype == TTYPE_STRING) { + VALUE is_binary = rb_hash_aref(field_info, binary_sym); + if (is_binary != Qtrue) { + default_write_string(protocol, value); + } else { + default_write_binary(protocol, value); + } + } else if (IS_CONTAINER(ttype)) { + write_container(ttype, field_info, value, protocol); + } else if (ttype == TTYPE_STRUCT) { + if (rb_obj_is_kind_of(value, thrift_union_class)) { + rb_thrift_union_write(value, protocol); + } else { + rb_thrift_struct_write(value, protocol); + } + } else { + rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype); + } +} + +static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) { + // call validate + rb_funcall(self, validate_method_id, 0); + + // write struct begin + default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self))); + + // iterate through all the fields here + VALUE struct_fields = STRUCT_FIELDS(self); + VALUE sorted_field_ids = rb_funcall(self, sorted_field_ids_method_id, 0); + + int i = 0; + for (i=0; i < RARRAY_LEN(sorted_field_ids); i++) { + VALUE field_id = rb_ary_entry(sorted_field_ids, i); + + VALUE field_info = rb_hash_aref(struct_fields, field_id); + + VALUE ttype_value = rb_hash_aref(field_info, type_sym); + int ttype = FIX2INT(ttype_value); + VALUE field_name = rb_hash_aref(field_info, name_sym); + + VALUE field_value = get_field_value(self, field_name); + + if (!NIL_P(field_value)) { + default_write_field_begin(protocol, field_name, ttype_value, field_id); + + write_anything(ttype, field_value, protocol, field_info); + + default_write_field_end(protocol); + } + } + + default_write_field_stop(protocol); + + // write struct end + default_write_struct_end(protocol); + + return Qnil; +} + +//------------------------------------------- +// Reading section +//------------------------------------------- + +static VALUE rb_thrift_union_read(VALUE self, VALUE protocol); +static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol); +static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size); +static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size); + +static void set_field_value(VALUE obj, VALUE field_name, VALUE value) { + char name_buf[RSTRING_LEN(field_name) + 2]; + + name_buf[0] = '@'; + strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name)+1); + + rb_ivar_set(obj, rb_intern(name_buf), value); +} + +// Helper method to skip the contents of a map (assumes the map header has been read). +static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size) { + int i; + for (i = 0; i < size; i++) { + rb_funcall(protocol, skip_method_id, 1, key_type_value); + rb_funcall(protocol, skip_method_id, 1, value_type_value); + } +} + +// Helper method to skip the contents of a list or set (assumes the list/set header has been read). +static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size) { + int i; + for (i = 0; i < size; i++) { + rb_funcall(protocol, skip_method_id, 1, element_type_value); + } +} + +static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) { + VALUE result = Qnil; + + if (ttype == TTYPE_BOOL) { + result = default_read_bool(protocol); + } else if (ttype == TTYPE_BYTE) { + result = default_read_byte(protocol); + } else if (ttype == TTYPE_I16) { + result = default_read_i16(protocol); + } else if (ttype == TTYPE_I32) { + result = default_read_i32(protocol); + } else if (ttype == TTYPE_I64) { + result = default_read_i64(protocol); + } else if (ttype == TTYPE_STRING) { + VALUE is_binary = rb_hash_aref(field_info, binary_sym); + if (is_binary != Qtrue) { + result = default_read_string(protocol); + } else { + result = default_read_binary(protocol); + } + } else if (ttype == TTYPE_DOUBLE) { + result = default_read_double(protocol); + } else if (ttype == TTYPE_STRUCT) { + VALUE klass = rb_hash_aref(field_info, class_sym); + result = rb_class_new_instance(0, NULL, klass); + + if (rb_obj_is_kind_of(result, thrift_union_class)) { + rb_thrift_union_read(result, protocol); + } else { + rb_thrift_struct_read(result, protocol); + } + } else if (ttype == TTYPE_MAP) { + int i; + + VALUE map_header = default_read_map_begin(protocol); + int key_ttype = FIX2INT(rb_ary_entry(map_header, 0)); + int value_ttype = FIX2INT(rb_ary_entry(map_header, 1)); + int num_entries = FIX2INT(rb_ary_entry(map_header, 2)); + + // Check the declared key and value types against the expected ones and skip the map contents + // if the types don't match. + VALUE key_info = rb_hash_aref(field_info, key_sym); + VALUE value_info = rb_hash_aref(field_info, value_sym); + + if (!NIL_P(key_info) && !NIL_P(value_info)) { + int specified_key_type = FIX2INT(rb_hash_aref(key_info, type_sym)); + int specified_value_type = FIX2INT(rb_hash_aref(value_info, type_sym)); + if (num_entries == 0 || (specified_key_type == key_ttype && specified_value_type == value_ttype)) { + result = rb_hash_new(); + + for (i = 0; i < num_entries; ++i) { + VALUE key, val; + + key = read_anything(protocol, key_ttype, key_info); + val = read_anything(protocol, value_ttype, value_info); + + rb_hash_aset(result, key, val); + } + } else { + skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries); + } + } else { + skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries); + } + + default_read_map_end(protocol); + } else if (ttype == TTYPE_LIST) { + int i; + + VALUE list_header = default_read_list_begin(protocol); + int element_ttype = FIX2INT(rb_ary_entry(list_header, 0)); + int num_elements = FIX2INT(rb_ary_entry(list_header, 1)); + + // Check the declared element type against the expected one and skip the list contents + // if the types don't match. + VALUE element_info = rb_hash_aref(field_info, element_sym); + if (!NIL_P(element_info)) { + int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym)); + if (specified_element_type == element_ttype) { + result = rb_ary_new2(num_elements); + + for (i = 0; i < num_elements; ++i) { + rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym))); + } + } else { + skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements); + } + } else { + skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements); + } + + default_read_list_end(protocol); + } else if (ttype == TTYPE_SET) { + VALUE items; + int i; + + VALUE set_header = default_read_set_begin(protocol); + int element_ttype = FIX2INT(rb_ary_entry(set_header, 0)); + int num_elements = FIX2INT(rb_ary_entry(set_header, 1)); + + // Check the declared element type against the expected one and skip the set contents + // if the types don't match. + VALUE element_info = rb_hash_aref(field_info, element_sym); + if (!NIL_P(element_info)) { + int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym)); + if (specified_element_type == element_ttype) { + items = rb_ary_new2(num_elements); + + for (i = 0; i < num_elements; ++i) { + rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym))); + } + + result = rb_class_new_instance(1, &items, rb_cSet); + } else { + skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements); + } + } else { + skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements); + } + + default_read_set_end(protocol); + } else { + rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype); + } + + return result; +} + +static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) { + // read struct begin + default_read_struct_begin(protocol); + + VALUE struct_fields = STRUCT_FIELDS(self); + + // read each field + while (true) { + VALUE field_header = default_read_field_begin(protocol); + VALUE field_type_value = rb_ary_entry(field_header, 1); + int field_type = FIX2INT(field_type_value); + + if (field_type == TTYPE_STOP) { + break; + } + + // make sure we got a type we expected + VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2)); + + if (!NIL_P(field_info)) { + int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym)); + if (field_type == specified_type) { + // read the value + VALUE name = rb_hash_aref(field_info, name_sym); + set_field_value(self, name, read_anything(protocol, field_type, field_info)); + } else { + rb_funcall(protocol, skip_method_id, 1, field_type_value); + } + } else { + rb_funcall(protocol, skip_method_id, 1, field_type_value); + } + + // read field end + default_read_field_end(protocol); + } + + // read struct end + default_read_struct_end(protocol); + + // call validate + rb_funcall(self, validate_method_id, 0); + + return Qnil; +} + + +// -------------------------------- +// Union section +// -------------------------------- + +static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) { + // read struct begin + default_read_struct_begin(protocol); + + VALUE struct_fields = STRUCT_FIELDS(self); + + VALUE field_header = default_read_field_begin(protocol); + VALUE field_type_value = rb_ary_entry(field_header, 1); + int field_type = FIX2INT(field_type_value); + + // make sure we got a type we expected + VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2)); + + if (!NIL_P(field_info)) { + int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym)); + if (field_type == specified_type) { + // read the value + VALUE name = rb_hash_aref(field_info, name_sym); + rb_iv_set(self, "@setfield", rb_str_intern(name)); + rb_iv_set(self, "@value", read_anything(protocol, field_type, field_info)); + } else { + rb_funcall(protocol, skip_method_id, 1, field_type_value); + } + } else { + rb_funcall(protocol, skip_method_id, 1, field_type_value); + } + + // read field end + default_read_field_end(protocol); + + field_header = default_read_field_begin(protocol); + field_type_value = rb_ary_entry(field_header, 1); + field_type = FIX2INT(field_type_value); + + if (field_type != TTYPE_STOP) { + rb_raise(rb_eRuntimeError, "too many fields in union!"); + } + + // read struct end + default_read_struct_end(protocol); + + // call validate + rb_funcall(self, validate_method_id, 0); + + return Qnil; +} + +static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) { + // call validate + rb_funcall(self, validate_method_id, 0); + + // write struct begin + default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self))); + + VALUE struct_fields = STRUCT_FIELDS(self); + + VALUE setfield = rb_ivar_get(self, setfield_id); + VALUE setvalue = rb_ivar_get(self, setvalue_id); + VALUE field_id = rb_funcall(self, name_to_id_method_id, 1, rb_funcall(setfield, to_s_method_id, 0)); + + VALUE field_info = rb_hash_aref(struct_fields, field_id); + + if(NIL_P(field_info)) { + rb_raise(rb_eRuntimeError, "set_field is not valid for this union!"); + } + + VALUE ttype_value = rb_hash_aref(field_info, type_sym); + int ttype = FIX2INT(ttype_value); + + default_write_field_begin(protocol, setfield, ttype_value, field_id); + + write_anything(ttype, setvalue, protocol, field_info); + + default_write_field_end(protocol); + + default_write_field_stop(protocol); + + // write struct end + default_write_struct_end(protocol); + + return Qnil; +} + +void Init_struct() { + VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct")); + + rb_define_method(struct_module, "write", rb_thrift_struct_write, 1); + rb_define_method(struct_module, "read", rb_thrift_struct_read, 1); + + thrift_union_class = rb_const_get(thrift_module, rb_intern("Union")); + + rb_define_method(thrift_union_class, "write", rb_thrift_union_write, 1); + rb_define_method(thrift_union_class, "read", rb_thrift_union_read, 1); + + setfield_id = rb_intern("@setfield"); + setvalue_id = rb_intern("@value"); + + to_s_method_id = rb_intern("to_s"); + name_to_id_method_id = rb_intern("name_to_id"); + sorted_field_ids_method_id = rb_intern("sorted_field_ids"); +} diff --git a/lib/rb/ext/struct.h b/lib/rb/ext/struct.h new file mode 100644 index 0000000..4748be5 --- /dev/null +++ b/lib/rb/ext/struct.h @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +#include +#include + +void Init_struct(); +void Init_union(); diff --git a/lib/rb/ext/thrift_native.c b/lib/rb/ext/thrift_native.c new file mode 100644 index 0000000..3430b7c --- /dev/null +++ b/lib/rb/ext/thrift_native.c @@ -0,0 +1,201 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include + +// cached classes/modules +VALUE rb_cSet; +VALUE thrift_module; +VALUE thrift_bytes_module; +VALUE thrift_types_module; + +// TType constants +int TTYPE_STOP; +int TTYPE_BOOL; +int TTYPE_BYTE; +int TTYPE_I16; +int TTYPE_I32; +int TTYPE_I64; +int TTYPE_DOUBLE; +int TTYPE_STRING; +int TTYPE_MAP; +int TTYPE_SET; +int TTYPE_LIST; +int TTYPE_STRUCT; + +// method ids +ID validate_method_id; +ID write_struct_begin_method_id; +ID write_struct_end_method_id; +ID write_field_begin_method_id; +ID write_field_end_method_id; +ID write_boolean_method_id; +ID write_byte_method_id; +ID write_i16_method_id; +ID write_i32_method_id; +ID write_i64_method_id; +ID write_double_method_id; +ID write_string_method_id; +ID write_binary_method_id; +ID write_map_begin_method_id; +ID write_map_end_method_id; +ID write_list_begin_method_id; +ID write_list_end_method_id; +ID write_set_begin_method_id; +ID write_set_end_method_id; +ID read_bool_method_id; +ID read_byte_method_id; +ID read_i16_method_id; +ID read_i32_method_id; +ID read_i64_method_id; +ID read_string_method_id; +ID read_binary_method_id; +ID read_double_method_id; +ID read_map_begin_method_id; +ID read_map_end_method_id; +ID read_list_begin_method_id; +ID read_list_end_method_id; +ID read_set_begin_method_id; +ID read_set_end_method_id; +ID read_struct_begin_method_id; +ID read_struct_end_method_id; +ID read_field_begin_method_id; +ID read_field_end_method_id; +ID keys_method_id; +ID entries_method_id; +ID write_field_stop_method_id; +ID skip_method_id; +ID write_method_id; +ID read_all_method_id; +ID read_into_buffer_method_id; +ID force_binary_encoding_id; +ID convert_to_utf8_byte_buffer_id; +ID convert_to_string_id; + +// constant ids +ID fields_const_id; +ID transport_ivar_id; +ID strict_read_ivar_id; +ID strict_write_ivar_id; + +// cached symbols +VALUE type_sym; +VALUE name_sym; +VALUE key_sym; +VALUE value_sym; +VALUE element_sym; +VALUE class_sym; +VALUE binary_sym; +VALUE protocol_exception_class; + +void Init_thrift_native() { + // cached classes + thrift_module = rb_const_get(rb_cObject, rb_intern("Thrift")); + thrift_bytes_module = rb_const_get(thrift_module, rb_intern("Bytes")); + thrift_types_module = rb_const_get(thrift_module, rb_intern("Types")); + rb_cSet = rb_const_get(rb_cObject, rb_intern("Set")); + protocol_exception_class = rb_const_get(thrift_module, rb_intern("ProtocolException")); + + // Init ttype constants + TTYPE_BOOL = FIX2INT(rb_const_get(thrift_types_module, rb_intern("BOOL"))); + TTYPE_BYTE = FIX2INT(rb_const_get(thrift_types_module, rb_intern("BYTE"))); + TTYPE_I16 = FIX2INT(rb_const_get(thrift_types_module, rb_intern("I16"))); + TTYPE_I32 = FIX2INT(rb_const_get(thrift_types_module, rb_intern("I32"))); + TTYPE_I64 = FIX2INT(rb_const_get(thrift_types_module, rb_intern("I64"))); + TTYPE_DOUBLE = FIX2INT(rb_const_get(thrift_types_module, rb_intern("DOUBLE"))); + TTYPE_STRING = FIX2INT(rb_const_get(thrift_types_module, rb_intern("STRING"))); + TTYPE_MAP = FIX2INT(rb_const_get(thrift_types_module, rb_intern("MAP"))); + TTYPE_SET = FIX2INT(rb_const_get(thrift_types_module, rb_intern("SET"))); + TTYPE_LIST = FIX2INT(rb_const_get(thrift_types_module, rb_intern("LIST"))); + TTYPE_STRUCT = FIX2INT(rb_const_get(thrift_types_module, rb_intern("STRUCT"))); + + // method ids + validate_method_id = rb_intern("validate"); + write_struct_begin_method_id = rb_intern("write_struct_begin"); + write_struct_end_method_id = rb_intern("write_struct_end"); + write_field_begin_method_id = rb_intern("write_field_begin"); + write_field_end_method_id = rb_intern("write_field_end"); + write_boolean_method_id = rb_intern("write_bool"); + write_byte_method_id = rb_intern("write_byte"); + write_i16_method_id = rb_intern("write_i16"); + write_i32_method_id = rb_intern("write_i32"); + write_i64_method_id = rb_intern("write_i64"); + write_double_method_id = rb_intern("write_double"); + write_string_method_id = rb_intern("write_string"); + write_binary_method_id = rb_intern("write_binary"); + write_map_begin_method_id = rb_intern("write_map_begin"); + write_map_end_method_id = rb_intern("write_map_end"); + write_list_begin_method_id = rb_intern("write_list_begin"); + write_list_end_method_id = rb_intern("write_list_end"); + write_set_begin_method_id = rb_intern("write_set_begin"); + write_set_end_method_id = rb_intern("write_set_end"); + read_bool_method_id = rb_intern("read_bool"); + read_byte_method_id = rb_intern("read_byte"); + read_i16_method_id = rb_intern("read_i16"); + read_i32_method_id = rb_intern("read_i32"); + read_i64_method_id = rb_intern("read_i64"); + read_string_method_id = rb_intern("read_string"); + read_binary_method_id = rb_intern("read_binary"); + read_double_method_id = rb_intern("read_double"); + read_map_begin_method_id = rb_intern("read_map_begin"); + read_map_end_method_id = rb_intern("read_map_end"); + read_list_begin_method_id = rb_intern("read_list_begin"); + read_list_end_method_id = rb_intern("read_list_end"); + read_set_begin_method_id = rb_intern("read_set_begin"); + read_set_end_method_id = rb_intern("read_set_end"); + read_struct_begin_method_id = rb_intern("read_struct_begin"); + read_struct_end_method_id = rb_intern("read_struct_end"); + read_field_begin_method_id = rb_intern("read_field_begin"); + read_field_end_method_id = rb_intern("read_field_end"); + keys_method_id = rb_intern("keys"); + entries_method_id = rb_intern("entries"); + write_field_stop_method_id = rb_intern("write_field_stop"); + skip_method_id = rb_intern("skip"); + write_method_id = rb_intern("write"); + read_all_method_id = rb_intern("read_all"); + read_into_buffer_method_id = rb_intern("read_into_buffer"); + force_binary_encoding_id = rb_intern("force_binary_encoding"); + convert_to_utf8_byte_buffer_id = rb_intern("convert_to_utf8_byte_buffer"); + convert_to_string_id = rb_intern("convert_to_string"); + + // constant ids + fields_const_id = rb_intern("FIELDS"); + transport_ivar_id = rb_intern("@trans"); + strict_read_ivar_id = rb_intern("@strict_read"); + strict_write_ivar_id = rb_intern("@strict_write"); + + // cached symbols + type_sym = ID2SYM(rb_intern("type")); + name_sym = ID2SYM(rb_intern("name")); + key_sym = ID2SYM(rb_intern("key")); + value_sym = ID2SYM(rb_intern("value")); + element_sym = ID2SYM(rb_intern("element")); + class_sym = ID2SYM(rb_intern("class")); + binary_sym = ID2SYM(rb_intern("binary")); + + Init_struct(); + Init_binary_protocol_accelerated(); + Init_compact_protocol(); + Init_memory_buffer(); +} diff --git a/lib/rb/lib/thrift.rb b/lib/rb/lib/thrift.rb new file mode 100644 index 0000000..0f58122 --- /dev/null +++ b/lib/rb/lib/thrift.rb @@ -0,0 +1,70 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Contains some contributions under the Thrift Software License. +# Please see doc/old-thrift-license.txt in the Thrift distribution for +# details. + +$:.unshift File.dirname(__FILE__) + +require 'thrift/bytes' +require 'thrift/core_ext' +require 'thrift/exceptions' +require 'thrift/types' +require 'thrift/processor' +require 'thrift/multiplexed_processor' +require 'thrift/client' +require 'thrift/struct' +require 'thrift/union' +require 'thrift/struct_union' + +# serializer +require 'thrift/serializer/serializer' +require 'thrift/serializer/deserializer' + +# protocol +require 'thrift/protocol/base_protocol' +require 'thrift/protocol/binary_protocol' +require 'thrift/protocol/binary_protocol_accelerated' +require 'thrift/protocol/compact_protocol' +require 'thrift/protocol/json_protocol' +require 'thrift/protocol/multiplexed_protocol' + +# transport +require 'thrift/transport/base_transport' +require 'thrift/transport/base_server_transport' +require 'thrift/transport/socket' +require 'thrift/transport/ssl_socket' +require 'thrift/transport/server_socket' +require 'thrift/transport/ssl_server_socket' +require 'thrift/transport/unix_socket' +require 'thrift/transport/unix_server_socket' +require 'thrift/transport/buffered_transport' +require 'thrift/transport/framed_transport' +require 'thrift/transport/http_client_transport' +require 'thrift/transport/io_stream_transport' +require 'thrift/transport/memory_buffer_transport' + +# server +require 'thrift/server/base_server' +require 'thrift/server/nonblocking_server' +require 'thrift/server/simple_server' +require 'thrift/server/threaded_server' +require 'thrift/server/thread_pool_server' + +require 'thrift/thrift_native' diff --git a/lib/rb/lib/thrift/bytes.rb b/lib/rb/lib/thrift/bytes.rb new file mode 100644 index 0000000..efd4f64 --- /dev/null +++ b/lib/rb/lib/thrift/bytes.rb @@ -0,0 +1,131 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + # A collection of utilities for working with bytes and byte buffers. + module Bytes + if RUBY_VERSION >= '1.9' + # Creates and empty byte buffer (String with BINARY encoding) + # + # size - The Integer size of the buffer (default: nil) to create + # + # Returns a String with BINARY encoding, filled with null characters + # if size is greater than zero + def self.empty_byte_buffer(size = nil) + if (size && size > 0) + "\0".force_encoding(Encoding::BINARY) * size + else + ''.force_encoding(Encoding::BINARY) + end + end + + # Forces the encoding of the buffer to BINARY. If the buffer + # passed is frozen, then it will be duplicated. + # + # buffer - The String to force the encoding of. + # + # Returns the String passed with an encoding of BINARY; returned + # String may be a duplicate. + def self.force_binary_encoding(buffer) + buffer = buffer.dup if buffer.frozen? + buffer.force_encoding(Encoding::BINARY) + end + + # Gets the byte value of a given position in a String. + # + # string - The String to retrive the byte value from. + # index - The Integer location of the byte value to retrieve. + # + # Returns an Integer value between 0 and 255. + def self.get_string_byte(string, index) + string.getbyte(index) + end + + # Sets the byte value given to a given index in a String. + # + # string - The String to set the byte value in. + # index - The Integer location to set the byte value at. + # byte - The Integer value (0 to 255) to set in the string. + # + # Returns an Integer value of the byte value to set. + def self.set_string_byte(string, index, byte) + string.setbyte(index, byte) + end + + # Converts the given String to a UTF-8 byte buffer. + # + # string - The String to convert. + # + # Returns a new String with BINARY encoding, containing the UTF-8 + # bytes of the original string. + def self.convert_to_utf8_byte_buffer(string) + if string.encoding != Encoding::UTF_8 + # transcode to UTF-8 + string = string.encode(Encoding::UTF_8) + else + # encoding is already UTF-8, but a duplicate is needed + string = string.dup + end + string.force_encoding(Encoding::BINARY) + end + + # Converts the given UTF-8 byte buffer into a String + # + # utf8_buffer - A String, with BINARY encoding, containing UTF-8 bytes + # + # Returns a new String with UTF-8 encoding, + def self.convert_to_string(utf8_buffer) + # duplicate the buffer, force encoding to UTF-8 + utf8_buffer.dup.force_encoding(Encoding::UTF_8) + end + else + def self.empty_byte_buffer(size = nil) + if (size && size > 0) + "\0" * size + else + '' + end + end + + def self.force_binary_encoding(buffer) + buffer + end + + def self.get_string_byte(string, index) + string[index] + end + + def self.set_string_byte(string, index, byte) + string[index] = byte + end + + def self.convert_to_utf8_byte_buffer(string) + # This assumes $KCODE is 'UTF8'/'U', which would mean the String is already a UTF-8 byte buffer + # TODO consider handling other $KCODE values and transcoding with iconv + string + end + + def self.convert_to_string(utf8_buffer) + # See comment in 'convert_to_utf8_byte_buffer' for relevant assumptions. + utf8_buffer + end + end + end +end diff --git a/lib/rb/lib/thrift/client.rb b/lib/rb/lib/thrift/client.rb new file mode 100644 index 0000000..64ef059 --- /dev/null +++ b/lib/rb/lib/thrift/client.rb @@ -0,0 +1,71 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + module Client + def initialize(iprot, oprot=nil) + @iprot = iprot + @oprot = oprot || iprot + @seqid = 0 + end + + def send_message(name, args_class, args = {}) + @oprot.write_message_begin(name, MessageTypes::CALL, @seqid) + send_message_args(args_class, args) + end + + def send_oneway_message(name, args_class, args = {}) + @oprot.write_message_begin(name, MessageTypes::ONEWAY, @seqid) + send_message_args(args_class, args) + end + + def send_message_args(args_class, args) + data = args_class.new + args.each do |k, v| + data.send("#{k.to_s}=", v) + end + begin + data.write(@oprot) + rescue StandardError => e + @oprot.trans.close + raise e + end + @oprot.write_message_end + @oprot.trans.flush + end + + def receive_message(result_klass) + fname, mtype, rseqid = @iprot.read_message_begin + handle_exception(mtype) + result = result_klass.new + result.read(@iprot) + @iprot.read_message_end + result + end + + def handle_exception(mtype) + if mtype == MessageTypes::EXCEPTION + x = ApplicationException.new + x.read(@iprot) + @iprot.read_message_end + raise x + end + end + end +end diff --git a/lib/rb/lib/thrift/core_ext.rb b/lib/rb/lib/thrift/core_ext.rb new file mode 100644 index 0000000..f763cd5 --- /dev/null +++ b/lib/rb/lib/thrift/core_ext.rb @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +Dir[File.dirname(__FILE__) + "/core_ext/*.rb"].each do |file| + name = File.basename(file, '.rb') + require "thrift/core_ext/#{name}" +end diff --git a/lib/rb/lib/thrift/core_ext/fixnum.rb b/lib/rb/lib/thrift/core_ext/fixnum.rb new file mode 100644 index 0000000..b4fc90d --- /dev/null +++ b/lib/rb/lib/thrift/core_ext/fixnum.rb @@ -0,0 +1,29 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Versions of ruby pre 1.8.7 do not have an .ord method available in the Fixnum +# class. +# +if RUBY_VERSION < "1.8.7" + class Fixnum + def ord + self + end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/exceptions.rb b/lib/rb/lib/thrift/exceptions.rb new file mode 100644 index 0000000..68cb9e0 --- /dev/null +++ b/lib/rb/lib/thrift/exceptions.rb @@ -0,0 +1,87 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + class Exception < StandardError + def initialize(message) + super + @message = message + end + + attr_reader :message + end + + class ApplicationException < Exception + + UNKNOWN = 0 + UNKNOWN_METHOD = 1 + INVALID_MESSAGE_TYPE = 2 + WRONG_METHOD_NAME = 3 + BAD_SEQUENCE_ID = 4 + MISSING_RESULT = 5 + INTERNAL_ERROR = 6 + PROTOCOL_ERROR = 7 + INVALID_TRANSFORM = 8 + INVALID_PROTOCOL = 9 + UNSUPPORTED_CLIENT_TYPE = 10 + + attr_reader :type + + def initialize(type=UNKNOWN, message=nil) + super(message) + @type = type + end + + def read(iprot) + iprot.read_struct_begin + while true + fname, ftype, fid = iprot.read_field_begin + if ftype == Types::STOP + break + end + if fid == 1 and ftype == Types::STRING + @message = iprot.read_string + elsif fid == 2 and ftype == Types::I32 + @type = iprot.read_i32 + else + iprot.skip(ftype) + end + iprot.read_field_end + end + iprot.read_struct_end + end + + def write(oprot) + oprot.write_struct_begin('Thrift::ApplicationException') + unless @message.nil? + oprot.write_field_begin('message', Types::STRING, 1) + oprot.write_string(@message) + oprot.write_field_end + end + unless @type.nil? + oprot.write_field_begin('type', Types::I32, 2) + oprot.write_i32(@type) + oprot.write_field_end + end + oprot.write_field_stop + oprot.write_struct_end + end + + end +end diff --git a/lib/rb/lib/thrift/multiplexed_processor.rb b/lib/rb/lib/thrift/multiplexed_processor.rb new file mode 100644 index 0000000..c734c04 --- /dev/null +++ b/lib/rb/lib/thrift/multiplexed_processor.rb @@ -0,0 +1,76 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +require 'thrift/protocol/protocol_decorator' +require 'thrift/protocol/base_protocol' + +module Thrift + class MultiplexedProcessor + def initialize + @actual_processors = {} + end + + def register_processor(service_name, processor) + @actual_processors[service_name] = processor + end + + def process(iprot, oprot) + name, type, seqid = iprot.read_message_begin + check_type(type) + check_separator(name) + service_name, method = name.split(':') + processor(service_name).process(StoredMessageProtocol.new(iprot, [method, type, seqid]), oprot) + end + + protected + + def processor(service_name) + if @actual_processors.has_key?(service_name) + @actual_processors[service_name] + else + raise Thrift::Exception.new("Service name not found: #{service_name}. Did you forget to call #{self.class.name}#register_processor?") + end + end + + def check_type(type) + unless [MessageTypes::CALL, MessageTypes::ONEWAY].include?(type) + raise Thrift::Exception.new('This should not have happened!?') + end + end + + def check_separator(name) + if name.count(':') < 1 + raise Thrift::Exception.new("Service name not found in message name: #{name}. Did you forget to use a Thrift::Protocol::MultiplexedProtocol in your client?") + end + end + end + + class StoredMessageProtocol < BaseProtocol + + include ProtocolDecorator + + def initialize(protocol, message_begin) + super(protocol) + @message_begin = message_begin + end + + def read_message_begin + @message_begin + end + end +end diff --git a/lib/rb/lib/thrift/processor.rb b/lib/rb/lib/thrift/processor.rb new file mode 100644 index 0000000..ce21e12 --- /dev/null +++ b/lib/rb/lib/thrift/processor.rb @@ -0,0 +1,75 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'logger' + +module Thrift + module Processor + def initialize(handler, logger=nil) + @handler = handler + if logger.nil? + @logger = Logger.new(STDERR) + @logger.level = Logger::WARN + else + @logger = logger + end + end + + def process(iprot, oprot) + name, type, seqid = iprot.read_message_begin + if respond_to?("process_#{name}") + begin + send("process_#{name}", seqid, iprot, oprot) + rescue => e + x = ApplicationException.new(ApplicationException::INTERNAL_ERROR, 'Internal error') + @logger.debug "Internal error : #{e.message}\n#{e.backtrace.join("\n")}" + write_error(x, oprot, name, seqid) + end + true + else + iprot.skip(Types::STRUCT) + iprot.read_message_end + x = ApplicationException.new(ApplicationException::UNKNOWN_METHOD, 'Unknown function '+name) + write_error(x, oprot, name, seqid) + false + end + end + + def read_args(iprot, args_class) + args = args_class.new + args.read(iprot) + iprot.read_message_end + args + end + + def write_result(result, oprot, name, seqid) + oprot.write_message_begin(name, MessageTypes::REPLY, seqid) + result.write(oprot) + oprot.write_message_end + oprot.trans.flush + end + + def write_error(err, oprot, name, seqid) + oprot.write_message_begin(name, MessageTypes::EXCEPTION, seqid) + err.write(oprot) + oprot.write_message_end + oprot.trans.flush + end + end +end diff --git a/lib/rb/lib/thrift/protocol/base_protocol.rb b/lib/rb/lib/thrift/protocol/base_protocol.rb new file mode 100644 index 0000000..88f44d4 --- /dev/null +++ b/lib/rb/lib/thrift/protocol/base_protocol.rb @@ -0,0 +1,379 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# this require is to make generated struct definitions happy +require 'set' + +module Thrift + class ProtocolException < Exception + + UNKNOWN = 0 + INVALID_DATA = 1 + NEGATIVE_SIZE = 2 + SIZE_LIMIT = 3 + BAD_VERSION = 4 + NOT_IMPLEMENTED = 5 + DEPTH_LIMIT = 6 + + attr_reader :type + + def initialize(type=UNKNOWN, message=nil) + super(message) + @type = type + end + end + + class BaseProtocol + + attr_reader :trans + + def initialize(trans) + @trans = trans + end + + def native? + puts "wrong method is being called!" + false + end + + def write_message_begin(name, type, seqid) + raise NotImplementedError + end + + def write_message_end; nil; end + + def write_struct_begin(name) + raise NotImplementedError + end + + def write_struct_end; nil; end + + def write_field_begin(name, type, id) + raise NotImplementedError + end + + def write_field_end; nil; end + + def write_field_stop + raise NotImplementedError + end + + def write_map_begin(ktype, vtype, size) + raise NotImplementedError + end + + def write_map_end; nil; end + + def write_list_begin(etype, size) + raise NotImplementedError + end + + def write_list_end; nil; end + + def write_set_begin(etype, size) + raise NotImplementedError + end + + def write_set_end; nil; end + + def write_bool(bool) + raise NotImplementedError + end + + def write_byte(byte) + raise NotImplementedError + end + + def write_i16(i16) + raise NotImplementedError + end + + def write_i32(i32) + raise NotImplementedError + end + + def write_i64(i64) + raise NotImplementedError + end + + def write_double(dub) + raise NotImplementedError + end + + # Writes a Thrift String. In Ruby 1.9+, the String passed will be transcoded to UTF-8. + # + # str - The String to write. + # + # Raises EncodingError if the transcoding to UTF-8 fails. + # + # Returns nothing. + def write_string(str) + raise NotImplementedError + end + + # Writes a Thrift Binary (Thrift String with no encoding). In Ruby 1.9+, the String passed + # will forced into BINARY encoding. + # + # buf - The String to write. + # + # Returns nothing. + def write_binary(buf) + raise NotImplementedError + end + + def read_message_begin + raise NotImplementedError + end + + def read_message_end; nil; end + + def read_struct_begin + raise NotImplementedError + end + + def read_struct_end; nil; end + + def read_field_begin + raise NotImplementedError + end + + def read_field_end; nil; end + + def read_map_begin + raise NotImplementedError + end + + def read_map_end; nil; end + + def read_list_begin + raise NotImplementedError + end + + def read_list_end; nil; end + + def read_set_begin + raise NotImplementedError + end + + def read_set_end; nil; end + + def read_bool + raise NotImplementedError + end + + def read_byte + raise NotImplementedError + end + + def read_i16 + raise NotImplementedError + end + + def read_i32 + raise NotImplementedError + end + + def read_i64 + raise NotImplementedError + end + + def read_double + raise NotImplementedError + end + + # Reads a Thrift String. In Ruby 1.9+, all Strings will be returned with an Encoding of UTF-8. + # + # Returns a String. + def read_string + raise NotImplementedError + end + + # Reads a Thrift Binary (Thrift String without encoding). In Ruby 1.9+, all Strings will be returned + # with an Encoding of BINARY. + # + # Returns a String. + def read_binary + raise NotImplementedError + end + + # Writes a field based on the field information, field ID and value. + # + # field_info - A Hash containing the definition of the field: + # :name - The name of the field. + # :type - The type of the field, which must be a Thrift::Types constant. + # :binary - A Boolean flag that indicates if Thrift::Types::STRING is a binary string (string without encoding). + # fid - The ID of the field. + # value - The field's value to write; object type varies based on :type. + # + # Returns nothing. + def write_field(*args) + if args.size == 3 + # handles the documented method signature - write_field(field_info, fid, value) + field_info = args[0] + fid = args[1] + value = args[2] + elsif args.size == 4 + # handles the deprecated method signature - write_field(name, type, fid, value) + field_info = {:name => args[0], :type => args[1]} + fid = args[2] + value = args[3] + else + raise ArgumentError, "wrong number of arguments (#{args.size} for 3)" + end + + write_field_begin(field_info[:name], field_info[:type], fid) + write_type(field_info, value) + write_field_end + end + + # Writes a field value based on the field information. + # + # field_info - A Hash containing the definition of the field: + # :type - The Thrift::Types constant that determines how the value is written. + # :binary - A Boolean flag that indicates if Thrift::Types::STRING is a binary string (string without encoding). + # value - The field's value to write; object type varies based on field_info[:type]. + # + # Returns nothing. + def write_type(field_info, value) + # if field_info is a Fixnum, assume it is a Thrift::Types constant + # convert it into a field_info Hash for backwards compatibility + if field_info.is_a? Fixnum + field_info = {:type => field_info} + end + + case field_info[:type] + when Types::BOOL + write_bool(value) + when Types::BYTE + write_byte(value) + when Types::DOUBLE + write_double(value) + when Types::I16 + write_i16(value) + when Types::I32 + write_i32(value) + when Types::I64 + write_i64(value) + when Types::STRING + if field_info[:binary] + write_binary(value) + else + write_string(value) + end + when Types::STRUCT + value.write(self) + else + raise NotImplementedError + end + end + + # Reads a field value based on the field information. + # + # field_info - A Hash containing the pertinent data to write: + # :type - The Thrift::Types constant that determines how the value is written. + # :binary - A flag that indicates if Thrift::Types::STRING is a binary string (string without encoding). + # + # Returns the value read; object type varies based on field_info[:type]. + def read_type(field_info) + # if field_info is a Fixnum, assume it is a Thrift::Types constant + # convert it into a field_info Hash for backwards compatibility + if field_info.is_a? Fixnum + field_info = {:type => field_info} + end + + case field_info[:type] + when Types::BOOL + read_bool + when Types::BYTE + read_byte + when Types::DOUBLE + read_double + when Types::I16 + read_i16 + when Types::I32 + read_i32 + when Types::I64 + read_i64 + when Types::STRING + if field_info[:binary] + read_binary + else + read_string + end + else + raise NotImplementedError + end + end + + def skip(type) + case type + when Types::STOP + nil + when Types::BOOL + read_bool + when Types::BYTE + read_byte + when Types::I16 + read_i16 + when Types::I32 + read_i32 + when Types::I64 + read_i64 + when Types::DOUBLE + read_double + when Types::STRING + read_string + when Types::STRUCT + read_struct_begin + while true + name, type, id = read_field_begin + break if type == Types::STOP + skip(type) + read_field_end + end + read_struct_end + when Types::MAP + ktype, vtype, size = read_map_begin + size.times do + skip(ktype) + skip(vtype) + end + read_map_end + when Types::SET + etype, size = read_set_begin + size.times do + skip(etype) + end + read_set_end + when Types::LIST + etype, size = read_list_begin + size.times do + skip(etype) + end + read_list_end + end + end + end + + class BaseProtocolFactory + def get_protocol(trans) + raise NotImplementedError + end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/protocol/binary_protocol.rb b/lib/rb/lib/thrift/protocol/binary_protocol.rb new file mode 100644 index 0000000..e70b1e3 --- /dev/null +++ b/lib/rb/lib/thrift/protocol/binary_protocol.rb @@ -0,0 +1,237 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + class BinaryProtocol < BaseProtocol + VERSION_MASK = 0xffff0000 + VERSION_1 = 0x80010000 + TYPE_MASK = 0x000000ff + + attr_reader :strict_read, :strict_write + + def initialize(trans, strict_read=true, strict_write=true) + super(trans) + @strict_read = strict_read + @strict_write = strict_write + + # Pre-allocated read buffer for fixed-size read methods. Needs to be at least 8 bytes long for + # read_i64() and read_double(). + @rbuf = Bytes.empty_byte_buffer(8) + end + + def write_message_begin(name, type, seqid) + # this is necessary because we added (needed) bounds checking to + # write_i32, and 0x80010000 is too big for that. + if strict_write + write_i16(VERSION_1 >> 16) + write_i16(type) + write_string(name) + write_i32(seqid) + else + write_string(name) + write_byte(type) + write_i32(seqid) + end + end + + def write_struct_begin(name); nil; end + + def write_field_begin(name, type, id) + write_byte(type) + write_i16(id) + end + + def write_field_stop + write_byte(Thrift::Types::STOP) + end + + def write_map_begin(ktype, vtype, size) + write_byte(ktype) + write_byte(vtype) + write_i32(size) + end + + def write_list_begin(etype, size) + write_byte(etype) + write_i32(size) + end + + def write_set_begin(etype, size) + write_byte(etype) + write_i32(size) + end + + def write_bool(bool) + write_byte(bool ? 1 : 0) + end + + def write_byte(byte) + raise RangeError if byte < -2**31 || byte >= 2**32 + trans.write([byte].pack('c')) + end + + def write_i16(i16) + trans.write([i16].pack('n')) + end + + def write_i32(i32) + raise RangeError if i32 < -2**31 || i32 >= 2**31 + trans.write([i32].pack('N')) + end + + def write_i64(i64) + raise RangeError if i64 < -2**63 || i64 >= 2**64 + hi = i64 >> 32 + lo = i64 & 0xffffffff + trans.write([hi, lo].pack('N2')) + end + + def write_double(dub) + trans.write([dub].pack('G')) + end + + def write_string(str) + buf = Bytes.convert_to_utf8_byte_buffer(str) + write_binary(buf) + end + + def write_binary(buf) + write_i32(buf.bytesize) + trans.write(buf) + end + + def read_message_begin + version = read_i32 + if version < 0 + if (version & VERSION_MASK != VERSION_1) + raise ProtocolException.new(ProtocolException::BAD_VERSION, 'Missing version identifier') + end + type = version & TYPE_MASK + name = read_string + seqid = read_i32 + [name, type, seqid] + else + if strict_read + raise ProtocolException.new(ProtocolException::BAD_VERSION, 'No version identifier, old protocol client?') + end + name = trans.read_all(version) + type = read_byte + seqid = read_i32 + [name, type, seqid] + end + end + + def read_struct_begin; nil; end + + def read_field_begin + type = read_byte + if (type == Types::STOP) + [nil, type, 0] + else + id = read_i16 + [nil, type, id] + end + end + + def read_map_begin + ktype = read_byte + vtype = read_byte + size = read_i32 + [ktype, vtype, size] + end + + def read_list_begin + etype = read_byte + size = read_i32 + [etype, size] + end + + def read_set_begin + etype = read_byte + size = read_i32 + [etype, size] + end + + def read_bool + byte = read_byte + byte != 0 + end + + def read_byte + val = trans.read_byte + if (val > 0x7f) + val = 0 - ((val - 1) ^ 0xff) + end + val + end + + def read_i16 + trans.read_into_buffer(@rbuf, 2) + val, = @rbuf.unpack('n') + if (val > 0x7fff) + val = 0 - ((val - 1) ^ 0xffff) + end + val + end + + def read_i32 + trans.read_into_buffer(@rbuf, 4) + val, = @rbuf.unpack('N') + if (val > 0x7fffffff) + val = 0 - ((val - 1) ^ 0xffffffff) + end + val + end + + def read_i64 + trans.read_into_buffer(@rbuf, 8) + hi, lo = @rbuf.unpack('N2') + if (hi > 0x7fffffff) + hi ^= 0xffffffff + lo ^= 0xffffffff + 0 - (hi << 32) - lo - 1 + else + (hi << 32) + lo + end + end + + def read_double + trans.read_into_buffer(@rbuf, 8) + val = @rbuf.unpack('G').first + val + end + + def read_string + buffer = read_binary + Bytes.convert_to_string(buffer) + end + + def read_binary + size = read_i32 + trans.read_all(size) + end + + end + + class BinaryProtocolFactory < BaseProtocolFactory + def get_protocol(trans) + return Thrift::BinaryProtocol.new(trans) + end + end +end diff --git a/lib/rb/lib/thrift/protocol/binary_protocol_accelerated.rb b/lib/rb/lib/thrift/protocol/binary_protocol_accelerated.rb new file mode 100644 index 0000000..70ea652 --- /dev/null +++ b/lib/rb/lib/thrift/protocol/binary_protocol_accelerated.rb @@ -0,0 +1,39 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +=begin +The only change required for a transport to support BinaryProtocolAccelerated is to implement 2 methods: + * borrow(size), which takes an optional argument and returns atleast _size_ bytes from the transport, + or the default buffer size if no argument is given + * consume!(size), which removes size bytes from the front of the buffer + +See MemoryBuffer and BufferedTransport for examples. +=end + +module Thrift + class BinaryProtocolAcceleratedFactory < BaseProtocolFactory + def get_protocol(trans) + if (defined? BinaryProtocolAccelerated) + BinaryProtocolAccelerated.new(trans) + else + BinaryProtocol.new(trans) + end + end + end +end diff --git a/lib/rb/lib/thrift/protocol/compact_protocol.rb b/lib/rb/lib/thrift/protocol/compact_protocol.rb new file mode 100644 index 0000000..605eea6 --- /dev/null +++ b/lib/rb/lib/thrift/protocol/compact_protocol.rb @@ -0,0 +1,435 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + class CompactProtocol < BaseProtocol + + PROTOCOL_ID = [0x82].pack('c').unpack('c').first + VERSION = 1 + VERSION_MASK = 0x1f + TYPE_MASK = 0xE0 + TYPE_BITS = 0x07 + TYPE_SHIFT_AMOUNT = 5 + + TSTOP = ["", Types::STOP, 0] + + # + # All of the on-wire type codes. + # + class CompactTypes + BOOLEAN_TRUE = 0x01 + BOOLEAN_FALSE = 0x02 + BYTE = 0x03 + I16 = 0x04 + I32 = 0x05 + I64 = 0x06 + DOUBLE = 0x07 + BINARY = 0x08 + LIST = 0x09 + SET = 0x0A + MAP = 0x0B + STRUCT = 0x0C + + def self.is_bool_type?(b) + (b & 0x0f) == BOOLEAN_TRUE || (b & 0x0f) == BOOLEAN_FALSE + end + + COMPACT_TO_TTYPE = { + Types::STOP => Types::STOP, + BOOLEAN_FALSE => Types::BOOL, + BOOLEAN_TRUE => Types::BOOL, + BYTE => Types::BYTE, + I16 => Types::I16, + I32 => Types::I32, + I64 => Types::I64, + DOUBLE => Types::DOUBLE, + BINARY => Types::STRING, + LIST => Types::LIST, + SET => Types::SET, + MAP => Types::MAP, + STRUCT => Types::STRUCT + } + + TTYPE_TO_COMPACT = { + Types::STOP => Types::STOP, + Types::BOOL => BOOLEAN_TRUE, + Types::BYTE => BYTE, + Types::I16 => I16, + Types::I32 => I32, + Types::I64 => I64, + Types::DOUBLE => DOUBLE, + Types::STRING => BINARY, + Types::LIST => LIST, + Types::SET => SET, + Types::MAP => MAP, + Types::STRUCT => STRUCT + } + + def self.get_ttype(compact_type) + val = COMPACT_TO_TTYPE[compact_type & 0x0f] + raise "don't know what type: #{compact_type & 0x0f}" unless val + val + end + + def self.get_compact_type(ttype) + val = TTYPE_TO_COMPACT[ttype] + raise "don't know what type: #{ttype & 0x0f}" unless val + val + end + end + + def initialize(transport) + super(transport) + + @last_field = [0] + @boolean_value = nil + + # Pre-allocated read buffer for read_double(). + @rbuf = Bytes.empty_byte_buffer(8) + end + + def write_message_begin(name, type, seqid) + write_byte(PROTOCOL_ID) + write_byte((VERSION & VERSION_MASK) | ((type << TYPE_SHIFT_AMOUNT) & TYPE_MASK)) + write_varint32(seqid) + write_string(name) + nil + end + + def write_struct_begin(name) + @last_field.push(0) + nil + end + + def write_struct_end + @last_field.pop + nil + end + + def write_field_begin(name, type, id) + if type == Types::BOOL + # we want to possibly include the value, so we'll wait. + @boolean_field = [type, id] + else + write_field_begin_internal(type, id) + end + nil + end + + # + # The workhorse of writeFieldBegin. It has the option of doing a + # 'type override' of the type header. This is used specifically in the + # boolean field case. + # + def write_field_begin_internal(type, id, type_override=nil) + last_id = @last_field.pop + + # if there's a type override, use that. + typeToWrite = type_override || CompactTypes.get_compact_type(type) + + # check if we can use delta encoding for the field id + if id > last_id && id - last_id <= 15 + # write them together + write_byte((id - last_id) << 4 | typeToWrite) + else + # write them separate + write_byte(typeToWrite) + write_i16(id) + end + + @last_field.push(id) + nil + end + + def write_field_stop + write_byte(Types::STOP) + end + + def write_map_begin(ktype, vtype, size) + if (size == 0) + write_byte(0) + else + write_varint32(size) + write_byte(CompactTypes.get_compact_type(ktype) << 4 | CompactTypes.get_compact_type(vtype)) + end + end + + def write_list_begin(etype, size) + write_collection_begin(etype, size) + end + + def write_set_begin(etype, size) + write_collection_begin(etype, size); + end + + def write_bool(bool) + type = bool ? CompactTypes::BOOLEAN_TRUE : CompactTypes::BOOLEAN_FALSE + unless @boolean_field.nil? + # we haven't written the field header yet + write_field_begin_internal(@boolean_field.first, @boolean_field.last, type) + @boolean_field = nil + else + # we're not part of a field, so just write the value. + write_byte(type) + end + end + + def write_byte(byte) + @trans.write([byte].pack('c')) + end + + def write_i16(i16) + write_varint32(int_to_zig_zag(i16)) + end + + def write_i32(i32) + write_varint32(int_to_zig_zag(i32)) + end + + def write_i64(i64) + write_varint64(long_to_zig_zag(i64)) + end + + def write_double(dub) + @trans.write([dub].pack("G").reverse) + end + + def write_string(str) + buf = Bytes.convert_to_utf8_byte_buffer(str) + write_binary(buf) + end + + def write_binary(buf) + write_varint32(buf.bytesize) + @trans.write(buf) + end + + def read_message_begin + protocol_id = read_byte() + if protocol_id != PROTOCOL_ID + raise ProtocolException.new("Expected protocol id #{PROTOCOL_ID} but got #{protocol_id}") + end + + version_and_type = read_byte() + version = version_and_type & VERSION_MASK + if (version != VERSION) + raise ProtocolException.new("Expected version #{VERSION} but got #{version}"); + end + + type = (version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS + seqid = read_varint32() + messageName = read_string() + [messageName, type, seqid] + end + + def read_struct_begin + @last_field.push(0) + "" + end + + def read_struct_end + @last_field.pop() + nil + end + + def read_field_begin + type = read_byte() + + # if it's a stop, then we can return immediately, as the struct is over. + if (type & 0x0f) == Types::STOP + TSTOP + else + field_id = nil + + # mask off the 4 MSB of the type header. it could contain a field id delta. + modifier = (type & 0xf0) >> 4 + if modifier == 0 + # not a delta. look ahead for the zigzag varint field id. + @last_field.pop + field_id = read_i16() + else + # has a delta. add the delta to the last read field id. + field_id = @last_field.pop + modifier + end + + # if this happens to be a boolean field, the value is encoded in the type + if CompactTypes.is_bool_type?(type) + # save the boolean value in a special instance variable. + @bool_value = (type & 0x0f) == CompactTypes::BOOLEAN_TRUE + end + + # push the new field onto the field stack so we can keep the deltas going. + @last_field.push(field_id) + ["", CompactTypes.get_ttype(type & 0x0f), field_id] + end + end + + def read_map_begin + size = read_varint32() + key_and_value_type = size == 0 ? 0 : read_byte() + [CompactTypes.get_ttype(key_and_value_type >> 4), CompactTypes.get_ttype(key_and_value_type & 0xf), size] + end + + def read_list_begin + size_and_type = read_byte() + size = (size_and_type >> 4) & 0x0f + if size == 15 + size = read_varint32() + end + type = CompactTypes.get_ttype(size_and_type) + [type, size] + end + + def read_set_begin + read_list_begin + end + + def read_bool + unless @bool_value.nil? + bv = @bool_value + @bool_value = nil + bv + else + read_byte() == CompactTypes::BOOLEAN_TRUE + end + end + + def read_byte + val = trans.read_byte + if (val > 0x7f) + val = 0 - ((val - 1) ^ 0xff) + end + val + end + + def read_i16 + zig_zag_to_int(read_varint32()) + end + + def read_i32 + zig_zag_to_int(read_varint32()) + end + + def read_i64 + zig_zag_to_long(read_varint64()) + end + + def read_double + trans.read_into_buffer(@rbuf, 8) + val = @rbuf.reverse.unpack('G').first + val + end + + def read_string + buffer = read_binary + Bytes.convert_to_string(buffer) + end + + def read_binary + size = read_varint32() + trans.read_all(size) + end + + private + + # + # Abstract method for writing the start of lists and sets. List and sets on + # the wire differ only by the type indicator. + # + def write_collection_begin(elem_type, size) + if size <= 14 + write_byte(size << 4 | CompactTypes.get_compact_type(elem_type)) + else + write_byte(0xf0 | CompactTypes.get_compact_type(elem_type)) + write_varint32(size) + end + end + + def write_varint32(n) + # int idx = 0; + while true + if (n & ~0x7F) == 0 + # i32buf[idx++] = (byte)n; + write_byte(n) + break + # return; + else + # i32buf[idx++] = (byte)((n & 0x7F) | 0x80); + write_byte((n & 0x7F) | 0x80) + n = n >> 7 + end + end + # trans_.write(i32buf, 0, idx); + end + + SEVEN_BIT_MASK = 0x7F + EVERYTHING_ELSE_MASK = ~SEVEN_BIT_MASK + + def write_varint64(n) + while true + if (n & EVERYTHING_ELSE_MASK) == 0 #TODO need to find a way to make this into a long... + write_byte(n) + break + else + write_byte((n & SEVEN_BIT_MASK) | 0x80) + n >>= 7 + end + end + end + + def read_varint32() + read_varint64() + end + + def read_varint64() + shift = 0 + result = 0 + while true + b = read_byte() + result |= (b & 0x7f) << shift + break if (b & 0x80) != 0x80 + shift += 7 + end + result + end + + def int_to_zig_zag(n) + (n << 1) ^ (n >> 31) + end + + def long_to_zig_zag(l) + # puts "zz encoded #{l} to #{(l << 1) ^ (l >> 63)}" + (l << 1) ^ (l >> 63) + end + + def zig_zag_to_int(n) + (n >> 1) ^ -(n & 1) + end + + def zig_zag_to_long(n) + (n >> 1) ^ -(n & 1) + end + end + + class CompactProtocolFactory < BaseProtocolFactory + def get_protocol(trans) + CompactProtocol.new(trans) + end + end +end diff --git a/lib/rb/lib/thrift/protocol/json_protocol.rb b/lib/rb/lib/thrift/protocol/json_protocol.rb new file mode 100644 index 0000000..514bdbf --- /dev/null +++ b/lib/rb/lib/thrift/protocol/json_protocol.rb @@ -0,0 +1,778 @@ +# encoding: UTF-8 +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'base64' + +module Thrift + class LookaheadReader + def initialize(trans) + @trans = trans + @hasData = false + @data = nil + end + + def read + if @hasData + @hasData = false + else + @data = @trans.read(1) + end + + return @data + end + + def peek + if !@hasData + @data = @trans.read(1) + end + @hasData = true + return @data + end + end + + # + # Class to serve as base JSON context and as base class for other context + # implementations + # + class JSONContext + @@kJSONElemSeparator = ',' + # + # Write context data to the trans. Default is to do nothing. + # + def write(trans) + end + + # + # Read context data from the trans. Default is to do nothing. + # + def read(reader) + end + + # + # Return true if numbers need to be escaped as strings in this context. + # Default behavior is to return false. + # + def escapeNum + return false + end + end + + # Context class for object member key-value pairs + class JSONPairContext < JSONContext + @@kJSONPairSeparator = ':' + + def initialize + @first = true + @colon = true + end + + def write(trans) + if (@first) + @first = false + @colon = true + else + trans.write(@colon ? @@kJSONPairSeparator : @@kJSONElemSeparator) + @colon = !@colon + end + end + + def read(reader) + if (@first) + @first = false + @colon = true + else + ch = (@colon ? @@kJSONPairSeparator : @@kJSONElemSeparator) + @colon = !@colon + JsonProtocol::read_syntax_char(reader, ch) + end + end + + # Numbers must be turned into strings if they are the key part of a pair + def escapeNum + return @colon + end + end + + # Context class for lists + class JSONListContext < JSONContext + + def initialize + @first = true + end + + def write(trans) + if (@first) + @first = false + else + trans.write(@@kJSONElemSeparator) + end + end + + def read(reader) + if (@first) + @first = false + else + JsonProtocol::read_syntax_char(reader, @@kJSONElemSeparator) + end + end + end + + class JsonProtocol < BaseProtocol + + @@kJSONObjectStart = '{' + @@kJSONObjectEnd = '}' + @@kJSONArrayStart = '[' + @@kJSONArrayEnd = ']' + @@kJSONNewline = '\n' + @@kJSONBackslash = '\\' + @@kJSONStringDelimiter = '"' + + @@kThriftVersion1 = 1 + + @@kThriftNan = "NaN" + @@kThriftInfinity = "Infinity" + @@kThriftNegativeInfinity = "-Infinity" + + def initialize(trans) + super(trans) + @context = JSONContext.new + @contexts = Array.new + @reader = LookaheadReader.new(trans) + end + + def get_type_name_for_type_id(id) + case id + when Types::BOOL + "tf" + when Types::BYTE + "i8" + when Types::I16 + "i16" + when Types::I32 + "i32" + when Types::I64 + "i64" + when Types::DOUBLE + "dbl" + when Types::STRING + "str" + when Types::STRUCT + "rec" + when Types::MAP + "map" + when Types::SET + "set" + when Types::LIST + "lst" + else + raise NotImplementedError + end + end + + def get_type_id_for_type_name(name) + if (name == "tf") + result = Types::BOOL + elsif (name == "i8") + result = Types::BYTE + elsif (name == "i16") + result = Types::I16 + elsif (name == "i32") + result = Types::I32 + elsif (name == "i64") + result = Types::I64 + elsif (name == "dbl") + result = Types::DOUBLE + elsif (name == "str") + result = Types::STRING + elsif (name == "rec") + result = Types::STRUCT + elsif (name == "map") + result = Types::MAP + elsif (name == "set") + result = Types::SET + elsif (name == "lst") + result = Types::LIST + else + result = Types::STOP + end + if (result == Types::STOP) + raise NotImplementedError + end + return result + end + + # Static helper functions + + # Read 1 character from the trans and verify that it is the expected character ch. + # Throw a protocol exception if it is not. + def self.read_syntax_char(reader, ch) + ch2 = reader.read + if (ch2 != ch) + raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected \'#{ch}\' got \'#{ch2}\'.") + end + end + + # Return true if the character ch is in [-+0-9.Ee]; false otherwise + def is_json_numeric(ch) + case ch + when '+', '-', '.', '0' .. '9', 'E', "e" + return true + else + return false + end + end + + def push_context(context) + @contexts.push(@context) + @context = context + end + + def pop_context + @context = @contexts.pop + end + + # Write the character ch as a JSON escape sequence ("\u00xx") + def write_json_escape_char(ch) + trans.write('\\u') + ch_value = ch[0] + if (ch_value.kind_of? String) + ch_value = ch.bytes.first + end + trans.write(ch_value.to_s(16).rjust(4,'0')) + end + + # Write the character ch as part of a JSON string, escaping as appropriate. + def write_json_char(ch) + # This table describes the handling for the first 0x30 characters + # 0 : escape using "\u00xx" notation + # 1 : just output index + # : escape using "\" notation + kJSONCharTable = [ + # 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0,'b','t','n', 0,'f','r', 0, 0, # 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 1 + 1, 1,'"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 2 + ] + + ch_value = ch[0] + if (ch_value.kind_of? String) + ch_value = ch.bytes.first + end + if (ch_value >= 0x30) + if (ch == @@kJSONBackslash) # Only special character >= 0x30 is '\' + trans.write(@@kJSONBackslash) + trans.write(@@kJSONBackslash) + else + trans.write(ch) + end + else + outCh = kJSONCharTable[ch_value]; + # Check if regular character, backslash escaped, or JSON escaped + if outCh.kind_of? String + trans.write(@@kJSONBackslash) + trans.write(outCh) + elsif outCh == 1 + trans.write(ch) + else + write_json_escape_char(ch) + end + end + end + + # Write out the contents of the string str as a JSON string, escaping characters as appropriate. + def write_json_string(str) + @context.write(trans) + trans.write(@@kJSONStringDelimiter) + str.split('').each do |ch| + write_json_char(ch) + end + trans.write(@@kJSONStringDelimiter) + end + + # Write out the contents of the string as JSON string, base64-encoding + # the string's contents, and escaping as appropriate + def write_json_base64(str) + @context.write(trans) + trans.write(@@kJSONStringDelimiter) + trans.write(Base64.strict_encode64(str)) + trans.write(@@kJSONStringDelimiter) + end + + # Convert the given integer type to a JSON number, or a string + # if the context requires it (eg: key in a map pair). + def write_json_integer(num) + @context.write(trans) + escapeNum = @context.escapeNum + if (escapeNum) + trans.write(@@kJSONStringDelimiter) + end + trans.write(num.to_s); + if (escapeNum) + trans.write(@@kJSONStringDelimiter) + end + end + + # Convert the given double to a JSON string, which is either the number, + # "NaN" or "Infinity" or "-Infinity". + def write_json_double(num) + @context.write(trans) + # Normalize output of thrift::to_string for NaNs and Infinities + special = false; + if (num.nan?) + special = true; + val = @@kThriftNan; + elsif (num.infinite?) + special = true; + val = @@kThriftInfinity; + if (num < 0.0) + val = @@kThriftNegativeInfinity; + end + else + val = num.to_s + end + + escapeNum = special || @context.escapeNum + if (escapeNum) + trans.write(@@kJSONStringDelimiter) + end + trans.write(val) + if (escapeNum) + trans.write(@@kJSONStringDelimiter) + end + end + + def write_json_object_start + @context.write(trans) + trans.write(@@kJSONObjectStart) + push_context(JSONPairContext.new); + end + + def write_json_object_end + pop_context + trans.write(@@kJSONObjectEnd) + end + + def write_json_array_start + @context.write(trans) + trans.write(@@kJSONArrayStart) + push_context(JSONListContext.new); + end + + def write_json_array_end + pop_context + trans.write(@@kJSONArrayEnd) + end + + def write_message_begin(name, type, seqid) + write_json_array_start + write_json_integer(@@kThriftVersion1) + write_json_string(name) + write_json_integer(type) + write_json_integer(seqid) + end + + def write_message_end + write_json_array_end + end + + def write_struct_begin(name) + write_json_object_start + end + + def write_struct_end + write_json_object_end + end + + def write_field_begin(name, type, id) + write_json_integer(id) + write_json_object_start + write_json_string(get_type_name_for_type_id(type)) + end + + def write_field_end + write_json_object_end + end + + def write_field_stop; nil; end + + def write_map_begin(ktype, vtype, size) + write_json_array_start + write_json_string(get_type_name_for_type_id(ktype)) + write_json_string(get_type_name_for_type_id(vtype)) + write_json_integer(size) + write_json_object_start + end + + def write_map_end + write_json_object_end + write_json_array_end + end + + def write_list_begin(etype, size) + write_json_array_start + write_json_string(get_type_name_for_type_id(etype)) + write_json_integer(size) + end + + def write_list_end + write_json_array_end + end + + def write_set_begin(etype, size) + write_json_array_start + write_json_string(get_type_name_for_type_id(etype)) + write_json_integer(size) + end + + def write_set_end + write_json_array_end + end + + def write_bool(bool) + write_json_integer(bool ? 1 : 0) + end + + def write_byte(byte) + write_json_integer(byte) + end + + def write_i16(i16) + write_json_integer(i16) + end + + def write_i32(i32) + write_json_integer(i32) + end + + def write_i64(i64) + write_json_integer(i64) + end + + def write_double(dub) + write_json_double(dub) + end + + def write_string(str) + write_json_string(str) + end + + def write_binary(str) + write_json_base64(str) + end + + ## + # Reading functions + ## + + # Reads 1 byte and verifies that it matches ch. + def read_json_syntax_char(ch) + JsonProtocol::read_syntax_char(@reader, ch) + end + + # Decodes the four hex parts of a JSON escaped string character and returns + # the character via out. + # + # Note - this only supports Unicode characters in the BMP (U+0000 to U+FFFF); + # characters above the BMP are encoded as two escape sequences (surrogate pairs), + # which is not yet implemented + def read_json_escape_char + str = @reader.read + str += @reader.read + str += @reader.read + str += @reader.read + if RUBY_VERSION >= '1.9' + str.hex.chr(Encoding::UTF_8) + else + str.hex.chr + end + end + + # Decodes a JSON string, including unescaping, and returns the string via str + def read_json_string(skipContext = false) + # This string's characters must match up with the elements in escape_char_vals. + # I don't have '/' on this list even though it appears on www.json.org -- + # it is not in the RFC -> it is. See RFC 4627 + escape_chars = "\"\\/bfnrt" + + # The elements of this array must match up with the sequence of characters in + # escape_chars + escape_char_vals = [ + "\"", "\\", "\/", "\b", "\f", "\n", "\r", "\t", + ] + + if !skipContext + @context.read(@reader) + end + read_json_syntax_char(@@kJSONStringDelimiter) + ch = "" + str = "" + while (true) + ch = @reader.read + if (ch == @@kJSONStringDelimiter) + break + end + if (ch == @@kJSONBackslash) + ch = @reader.read + if (ch == 'u') + ch = read_json_escape_char + else + pos = escape_chars.index(ch); + if (pos.nil?) # not found + raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected control char, got \'#{ch}\'.") + end + ch = escape_char_vals[pos] + end + end + str += ch + end + return str + end + + # Reads a block of base64 characters, decoding it, and returns via str + def read_json_base64 + str = read_json_string + m = str.length % 4 + if m != 0 + # Add missing padding + (4 - m).times do + str += '=' + end + end + Base64.strict_decode64(str) + end + + # Reads a sequence of characters, stopping at the first one that is not + # a valid JSON numeric character. + def read_json_numeric_chars + str = "" + while (true) + ch = @reader.peek + if (!is_json_numeric(ch)) + break; + end + ch = @reader.read + str += ch + end + return str + end + + # Reads a sequence of characters and assembles them into a number, + # returning them via num + def read_json_integer + @context.read(@reader) + if (@context.escapeNum) + read_json_syntax_char(@@kJSONStringDelimiter) + end + str = read_json_numeric_chars + + begin + num = Integer(str); + rescue + raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected numeric value; got \"#{str}\"") + end + + if (@context.escapeNum) + read_json_syntax_char(@@kJSONStringDelimiter) + end + + return num + end + + # Reads a JSON number or string and interprets it as a double. + def read_json_double + @context.read(@reader) + num = 0 + if (@reader.peek == @@kJSONStringDelimiter) + str = read_json_string(true) + # Check for NaN, Infinity and -Infinity + if (str == @@kThriftNan) + num = (+1.0/0.0)/(+1.0/0.0) + elsif (str == @@kThriftInfinity) + num = +1.0/0.0 + elsif (str == @@kThriftNegativeInfinity) + num = -1.0/0.0 + else + if (!@context.escapeNum) + # Raise exception -- we should not be in a string in this case + raise ProtocolException.new(ProtocolException::INVALID_DATA, "Numeric data unexpectedly quoted") + end + begin + num = Float(str) + rescue + raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected numeric value; got \"#{str}\"") + end + end + else + if (@context.escapeNum) + # This will throw - we should have had a quote if escapeNum == true + read_json_syntax_char(@@kJSONStringDelimiter) + end + str = read_json_numeric_chars + begin + num = Float(str) + rescue + raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected numeric value; got \"#{str}\"") + end + end + return num + end + + def read_json_object_start + @context.read(@reader) + read_json_syntax_char(@@kJSONObjectStart) + push_context(JSONPairContext.new) + nil + end + + def read_json_object_end + read_json_syntax_char(@@kJSONObjectEnd) + pop_context + nil + end + + def read_json_array_start + @context.read(@reader) + read_json_syntax_char(@@kJSONArrayStart) + push_context(JSONListContext.new) + nil + end + + def read_json_array_end + read_json_syntax_char(@@kJSONArrayEnd) + pop_context + nil + end + + def read_message_begin + read_json_array_start + version = read_json_integer + if (version != @@kThriftVersion1) + raise ProtocolException.new(ProtocolException::BAD_VERSION, 'Message contained bad version.') + end + name = read_json_string + message_type = read_json_integer + seqid = read_json_integer + [name, message_type, seqid] + end + + def read_message_end + read_json_array_end + nil + end + + def read_struct_begin + read_json_object_start + nil + end + + def read_struct_end + read_json_object_end + nil + end + + def read_field_begin + # Check if we hit the end of the list + ch = @reader.peek + if (ch == @@kJSONObjectEnd) + field_type = Types::STOP + else + field_id = read_json_integer + read_json_object_start + field_type = get_type_id_for_type_name(read_json_string) + end + [nil, field_type, field_id] + end + + def read_field_end + read_json_object_end + end + + def read_map_begin + read_json_array_start + key_type = get_type_id_for_type_name(read_json_string) + val_type = get_type_id_for_type_name(read_json_string) + size = read_json_integer + read_json_object_start + [key_type, val_type, size] + end + + def read_map_end + read_json_object_end + read_json_array_end + end + + def read_list_begin + read_json_array_start + [get_type_id_for_type_name(read_json_string), read_json_integer] + end + + def read_list_end + read_json_array_end + end + + def read_set_begin + read_json_array_start + [get_type_id_for_type_name(read_json_string), read_json_integer] + end + + def read_set_end + read_json_array_end + end + + def read_bool + byte = read_byte + byte != 0 + end + + def read_byte + read_json_integer + end + + def read_i16 + read_json_integer + end + + def read_i32 + read_json_integer + end + + def read_i64 + read_json_integer + end + + def read_double + read_json_double + end + + def read_string + read_json_string + end + + def read_binary + read_json_base64 + end + end + + class JsonProtocolFactory < BaseProtocolFactory + def get_protocol(trans) + return Thrift::JsonProtocol.new(trans) + end + end +end diff --git a/lib/rb/lib/thrift/protocol/multiplexed_protocol.rb b/lib/rb/lib/thrift/protocol/multiplexed_protocol.rb new file mode 100644 index 0000000..13c9d93 --- /dev/null +++ b/lib/rb/lib/thrift/protocol/multiplexed_protocol.rb @@ -0,0 +1,40 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +require 'thrift/protocol/protocol_decorator' + +module Thrift + class MultiplexedProtocol < BaseProtocol + + include ProtocolDecorator + + def initialize(protocol, service_name) + super(protocol) + @service_name = service_name + end + + def write_message_begin(name, type, seqid) + case type + when MessageTypes::CALL, MessageTypes::ONEWAY + @protocol.write_message_begin("#{@service_name}:#{name}", type, seqid) + else + @protocol.write_message_begin(name, type, seqid) + end + end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/protocol/protocol_decorator.rb b/lib/rb/lib/thrift/protocol/protocol_decorator.rb new file mode 100644 index 0000000..b1e3c15 --- /dev/null +++ b/lib/rb/lib/thrift/protocol/protocol_decorator.rb @@ -0,0 +1,194 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module Thrift + module ProtocolDecorator + + def initialize(protocol) + @protocol = protocol + end + + def trans + @protocol.trans + end + + def write_message_begin(name, type, seqid) + @protocol.write_message_begin + end + + def write_message_end + @protocol.write_message_end + end + + def write_struct_begin(name) + @protocol.write_struct_begin(name) + end + + def write_struct_end + @protocol.write_struct_end + end + + def write_field_begin(name, type, id) + @protocol.write_field_begin(name, type, id) + end + + def write_field_end + @protocol.write_field_end + end + + def write_field_stop + @protocol.write_field_stop + end + + def write_map_begin(ktype, vtype, size) + @protocol.write_map_begin(ktype, vtype, size) + end + + def write_map_end + @protocol.write_map_end + end + + def write_list_begin(etype, size) + @protocol.write_list_begin(etype, size) + end + + def write_list_end + @protocol.write_list_end + end + + def write_set_begin(etype, size) + @protocol.write_set_begin(etype, size) + end + + def write_set_end + @protocol.write_set_end + end + + def write_bool(bool) + @protocol.write_bool(bool) + end + + def write_byte(byte) + @protocol.write_byte(byte) + end + + def write_i16(i16) + @protocol.write_i16(i16) + end + + def write_i32(i32) + @protocol.write_i32(i32) + end + + def write_i64(i64) + @protocol.write_i64(i64) + end + + def write_double(dub) + @protocol.write_double(dub) + end + + def write_string(str) + @protocol.write_string(str) + end + + def write_binary(buf) + @protocol.write_binary(buf) + end + + def read_message_begin + @protocol.read_message_begin + end + + def read_message_end + @protocol.read_message_end + end + + def read_struct_begin + @protocol.read_struct_begin + end + + def read_struct_end + @protocol.read_struct_end + end + + def read_field_begin + @protocol.read_field_begin + end + + def read_field_end + @protocol.read_field_end + end + + def read_map_begin + @protocol.read_map_begin + end + + def read_map_end + @protocol.read_map_end + end + + def read_list_begin + @protocol.read_list_begin + end + + def read_list_end + @protocol.read_list_end + end + + def read_set_begin + @protocol.read_set_begin + end + + def read_set_end + @protocol.read_set_end + end + + def read_bool + @protocol.read_bool + end + + def read_byte + @protocol.read_byte + end + + def read_i16 + @protocol.read_i16 + end + + def read_i32 + @protocol.read_i32 + end + + def read_i64 + @protocol.read_i64 + end + + def read_double + @protocol.read_double + end + + def read_string + @protocol.read_string + end + + def read_binary + @protocol.read_binary + end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/serializer/deserializer.rb b/lib/rb/lib/thrift/serializer/deserializer.rb new file mode 100644 index 0000000..d2ee325 --- /dev/null +++ b/lib/rb/lib/thrift/serializer/deserializer.rb @@ -0,0 +1,33 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + class Deserializer + def initialize(protocol_factory = BinaryProtocolFactory.new) + @transport = MemoryBufferTransport.new + @protocol = protocol_factory.get_protocol(@transport) + end + + def deserialize(base, buffer) + @transport.reset_buffer(buffer) + base.read(@protocol) + base + end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/serializer/serializer.rb b/lib/rb/lib/thrift/serializer/serializer.rb new file mode 100644 index 0000000..2231639 --- /dev/null +++ b/lib/rb/lib/thrift/serializer/serializer.rb @@ -0,0 +1,34 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + class Serializer + def initialize(protocol_factory = BinaryProtocolFactory.new) + @transport = MemoryBufferTransport.new + @protocol = protocol_factory.get_protocol(@transport) + end + + def serialize(base) + @transport.reset_buffer + base.write(@protocol) + @transport.read(@transport.available) + end + end +end + diff --git a/lib/rb/lib/thrift/server/base_server.rb b/lib/rb/lib/thrift/server/base_server.rb new file mode 100644 index 0000000..1ee1213 --- /dev/null +++ b/lib/rb/lib/thrift/server/base_server.rb @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + class BaseServer + def initialize(processor, server_transport, transport_factory=nil, protocol_factory=nil) + @processor = processor + @server_transport = server_transport + @transport_factory = transport_factory ? transport_factory : Thrift::BaseTransportFactory.new + @protocol_factory = protocol_factory ? protocol_factory : Thrift::BinaryProtocolFactory.new + end + + def serve; nil; end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/server/mongrel_http_server.rb b/lib/rb/lib/thrift/server/mongrel_http_server.rb new file mode 100644 index 0000000..de354c8 --- /dev/null +++ b/lib/rb/lib/thrift/server/mongrel_http_server.rb @@ -0,0 +1,60 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'mongrel' + +## Sticks a service on a URL, using mongrel to do the HTTP work +# DEPRECATED: Please use Thrift::ThinHTTPServer instead. +module Thrift + class MongrelHTTPServer < BaseServer + class Handler < Mongrel::HttpHandler + def initialize(processor, protocol_factory) + @processor = processor + @protocol_factory = protocol_factory + end + + def process(request, response) + if request.params["REQUEST_METHOD"] == "POST" + response.start(200) do |head, out| + head["Content-Type"] = "application/x-thrift" + transport = IOStreamTransport.new request.body, out + protocol = @protocol_factory.get_protocol transport + @processor.process protocol, protocol + end + else + response.start(404) { } + end + end + end + + def initialize(processor, opts={}) + Kernel.warn "[DEPRECATION WARNING] `Thrift::MongrelHTTPServer` is deprecated. Please use `Thrift::ThinHTTPServer` instead." + port = opts[:port] || 80 + ip = opts[:ip] || "0.0.0.0" + path = opts[:path] || "" + protocol_factory = opts[:protocol_factory] || BinaryProtocolFactory.new + @server = Mongrel::HttpServer.new ip, port + @server.register "/#{path}", Handler.new(processor, protocol_factory) + end + + def serve + @server.run.join + end + end +end diff --git a/lib/rb/lib/thrift/server/nonblocking_server.rb b/lib/rb/lib/thrift/server/nonblocking_server.rb new file mode 100644 index 0000000..740f341 --- /dev/null +++ b/lib/rb/lib/thrift/server/nonblocking_server.rb @@ -0,0 +1,305 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'logger' +require 'thread' + +module Thrift + # this class expects to always use a FramedTransport for reading messages + class NonblockingServer < BaseServer + def initialize(processor, server_transport, transport_factory=nil, protocol_factory=nil, num=20, logger=nil) + super(processor, server_transport, transport_factory, protocol_factory) + @num_threads = num + if logger.nil? + @logger = Logger.new(STDERR) + @logger.level = Logger::WARN + else + @logger = logger + end + @shutdown_semaphore = Mutex.new + @transport_semaphore = Mutex.new + end + + def serve + @logger.info "Starting #{self}" + @server_transport.listen + @io_manager = start_io_manager + + begin + loop do + break if @server_transport.closed? + begin + rd, = select([@server_transport], nil, nil, 0.1) + rescue Errno::EBADF => e + # In Ruby 1.9, calling @server_transport.close in shutdown paths causes the select() to raise an + # Errno::EBADF. If this happens, ignore it and retry the loop. + break + end + next if rd.nil? + socket = @server_transport.accept + @logger.debug "Accepted socket: #{socket.inspect}" + @io_manager.add_connection socket + end + rescue IOError => e + end + # we must be shutting down + @logger.info "#{self} is shutting down, goodbye" + ensure + @transport_semaphore.synchronize do + @server_transport.close + end + @io_manager.ensure_closed unless @io_manager.nil? + end + + def shutdown(timeout = 0, block = true) + @shutdown_semaphore.synchronize do + return if @is_shutdown + @is_shutdown = true + end + # nonblocking is intended for calling from within a Handler + # but we can't change the order of operations here, so lets thread + shutdown_proc = lambda do + @io_manager.shutdown(timeout) + @transport_semaphore.synchronize do + @server_transport.close # this will break the accept loop + end + end + if block + shutdown_proc.call + else + Thread.new &shutdown_proc + end + end + + private + + def start_io_manager + iom = IOManager.new(@processor, @server_transport, @transport_factory, @protocol_factory, @num_threads, @logger) + iom.spawn + iom + end + + class IOManager # :nodoc: + DEFAULT_BUFFER = 2**20 + + def initialize(processor, server_transport, transport_factory, protocol_factory, num, logger) + @processor = processor + @server_transport = server_transport + @transport_factory = transport_factory + @protocol_factory = protocol_factory + @num_threads = num + @logger = logger + @connections = [] + @buffers = Hash.new { |h,k| h[k] = '' } + @signal_queue = Queue.new + @signal_pipes = IO.pipe + @signal_pipes[1].sync = true + @worker_queue = Queue.new + @shutdown_queue = Queue.new + end + + def add_connection(socket) + signal [:connection, socket] + end + + def spawn + @iom_thread = Thread.new do + @logger.debug "Starting #{self}" + run + end + end + + def shutdown(timeout = 0) + @logger.debug "#{self} is shutting down workers" + @worker_queue.clear + @num_threads.times { @worker_queue.push [:shutdown] } + signal [:shutdown, timeout] + @shutdown_queue.pop + @signal_pipes[0].close + @signal_pipes[1].close + @logger.debug "#{self} is shutting down, goodbye" + end + + def ensure_closed + kill_worker_threads if @worker_threads + @iom_thread.kill + end + + private + + def run + spin_worker_threads + + loop do + rd, = select([@signal_pipes[0], *@connections]) + if rd.delete @signal_pipes[0] + break if read_signals == :shutdown + end + rd.each do |fd| + begin + if fd.handle.eof? + remove_connection fd + else + read_connection fd + end + rescue Errno::ECONNRESET + remove_connection fd + end + end + end + join_worker_threads(@shutdown_timeout) + ensure + @shutdown_queue.push :shutdown + end + + def read_connection(fd) + @buffers[fd] << fd.read(DEFAULT_BUFFER) + while(frame = slice_frame!(@buffers[fd])) + @logger.debug "#{self} is processing a frame" + @worker_queue.push [:frame, fd, frame] + end + end + + def spin_worker_threads + @logger.debug "#{self} is spinning up worker threads" + @worker_threads = [] + @num_threads.times do + @worker_threads << spin_thread + end + end + + def spin_thread + Worker.new(@processor, @transport_factory, @protocol_factory, @logger, @worker_queue).spawn + end + + def signal(msg) + @signal_queue << msg + @signal_pipes[1].write " " + end + + def read_signals + # clear the signal pipe + # note that since read_nonblock is broken in jruby, + # we can only read up to a set number of signals at once + sigstr = @signal_pipes[0].readpartial(1024) + # now read the signals + begin + sigstr.length.times do + signal, obj = @signal_queue.pop(true) + case signal + when :connection + @connections << obj + when :shutdown + @shutdown_timeout = obj + return :shutdown + end + end + rescue ThreadError + # out of signals + # note that in a perfect world this would never happen, since we're + # only reading the number of signals pushed on the pipe, but given the lack + # of locks, in theory we could clear the pipe/queue while a new signal is being + # placed on the pipe, at which point our next read_signals would hit this error + end + end + + def remove_connection(fd) + # don't explicitly close it, a thread may still be writing to it + @connections.delete fd + @buffers.delete fd + end + + def join_worker_threads(shutdown_timeout) + start = Time.now + @worker_threads.each do |t| + if shutdown_timeout > 0 + timeout = (start + shutdown_timeout) - Time.now + break if timeout <= 0 + t.join(timeout) + else + t.join + end + end + kill_worker_threads + end + + def kill_worker_threads + @worker_threads.each do |t| + t.kill if t.status + end + @worker_threads.clear + end + + def slice_frame!(buf) + if buf.length >= 4 + size = buf.unpack('N').first + if buf.length >= size + 4 + buf.slice!(0, size + 4) + else + nil + end + else + nil + end + end + + class Worker # :nodoc: + def initialize(processor, transport_factory, protocol_factory, logger, queue) + @processor = processor + @transport_factory = transport_factory + @protocol_factory = protocol_factory + @logger = logger + @queue = queue + end + + def spawn + Thread.new do + @logger.debug "#{self} is spawning" + run + end + end + + private + + def run + loop do + cmd, *args = @queue.pop + case cmd + when :shutdown + @logger.debug "#{self} is shutting down, goodbye" + break + when :frame + fd, frame = args + begin + otrans = @transport_factory.get_transport(fd) + oprot = @protocol_factory.get_protocol(otrans) + membuf = MemoryBufferTransport.new(frame) + itrans = @transport_factory.get_transport(membuf) + iprot = @protocol_factory.get_protocol(itrans) + @processor.process(iprot, oprot) + rescue => e + @logger.error "#{Thread.current.inspect} raised error: #{e.inspect}\n#{e.backtrace.join("\n")}" + end + end + end + end + end + end + end +end diff --git a/lib/rb/lib/thrift/server/simple_server.rb b/lib/rb/lib/thrift/server/simple_server.rb new file mode 100644 index 0000000..21e8659 --- /dev/null +++ b/lib/rb/lib/thrift/server/simple_server.rb @@ -0,0 +1,43 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + class SimpleServer < BaseServer + def serve + begin + @server_transport.listen + loop do + client = @server_transport.accept + trans = @transport_factory.get_transport(client) + prot = @protocol_factory.get_protocol(trans) + begin + loop do + @processor.process(prot, prot) + end + rescue Thrift::TransportException, Thrift::ProtocolException + ensure + trans.close + end + end + ensure + @server_transport.close + end + end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/server/thin_http_server.rb b/lib/rb/lib/thrift/server/thin_http_server.rb new file mode 100644 index 0000000..4a81c6d --- /dev/null +++ b/lib/rb/lib/thrift/server/thin_http_server.rb @@ -0,0 +1,91 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'rack' +require 'thin' + +## +# Wraps the Thin web server to provide a Thrift server over HTTP. +module Thrift + class ThinHTTPServer < BaseServer + + ## + # Accepts a Thrift::Processor + # Options include: + # * :port + # * :ip + # * :path + # * :protocol_factory + def initialize(processor, options={}) + port = options[:port] || 80 + ip = options[:ip] || "0.0.0.0" + path = options[:path] || "/" + protocol_factory = options[:protocol_factory] || BinaryProtocolFactory.new + app = RackApplication.for(path, processor, protocol_factory) + @server = Thin::Server.new(ip, port, app) + end + + ## + # Starts the server + def serve + @server.start + end + + class RackApplication + + THRIFT_HEADER = "application/x-thrift" + + def self.for(path, processor, protocol_factory) + Rack::Builder.new do + use Rack::CommonLogger + use Rack::ShowExceptions + use Rack::Lint + map path do + run lambda { |env| + request = Rack::Request.new(env) + if RackApplication.valid_thrift_request?(request) + RackApplication.successful_request(request, processor, protocol_factory) + else + RackApplication.failed_request + end + } + end + end + end + + def self.successful_request(rack_request, processor, protocol_factory) + response = Rack::Response.new([], 200, {'Content-Type' => THRIFT_HEADER}) + transport = IOStreamTransport.new rack_request.body, response + protocol = protocol_factory.get_protocol transport + processor.process protocol, protocol + response + end + + def self.failed_request + Rack::Response.new(['Not Found'], 404, {'Content-Type' => THRIFT_HEADER}) + end + + def self.valid_thrift_request?(rack_request) + rack_request.post? && rack_request.env["CONTENT_TYPE"] == THRIFT_HEADER + end + + end + + end +end diff --git a/lib/rb/lib/thrift/server/thread_pool_server.rb b/lib/rb/lib/thrift/server/thread_pool_server.rb new file mode 100644 index 0000000..8cec805 --- /dev/null +++ b/lib/rb/lib/thrift/server/thread_pool_server.rb @@ -0,0 +1,75 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'thread' + +module Thrift + class ThreadPoolServer < BaseServer + def initialize(processor, server_transport, transport_factory=nil, protocol_factory=nil, num=20) + super(processor, server_transport, transport_factory, protocol_factory) + @thread_q = SizedQueue.new(num) + @exception_q = Queue.new + @running = false + end + + ## exceptions that happen in worker threads will be relayed here and + ## must be caught. 'retry' can be used to continue. (threads will + ## continue to run while the exception is being handled.) + def rescuable_serve + Thread.new { serve } unless @running + @running = true + raise @exception_q.pop + end + + ## exceptions that happen in worker threads simply cause that thread + ## to die and another to be spawned in its place. + def serve + @server_transport.listen + + begin + loop do + @thread_q.push(:token) + Thread.new do + begin + loop do + client = @server_transport.accept + trans = @transport_factory.get_transport(client) + prot = @protocol_factory.get_protocol(trans) + begin + loop do + @processor.process(prot, prot) + end + rescue Thrift::TransportException, Thrift::ProtocolException => e + ensure + trans.close + end + end + rescue => e + @exception_q.push(e) + ensure + @thread_q.pop # thread died! + end + end + end + ensure + @server_transport.close + end + end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/server/threaded_server.rb b/lib/rb/lib/thrift/server/threaded_server.rb new file mode 100644 index 0000000..a2c917c --- /dev/null +++ b/lib/rb/lib/thrift/server/threaded_server.rb @@ -0,0 +1,47 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'thread' + +module Thrift + class ThreadedServer < BaseServer + def serve + begin + @server_transport.listen + loop do + client = @server_transport.accept + trans = @transport_factory.get_transport(client) + prot = @protocol_factory.get_protocol(trans) + Thread.new(prot, trans) do |p, t| + begin + loop do + @processor.process(p, p) + end + rescue Thrift::TransportException, Thrift::ProtocolException + ensure + t.close + end + end + end + ensure + @server_transport.close + end + end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/struct.rb b/lib/rb/lib/thrift/struct.rb new file mode 100644 index 0000000..df9d656 --- /dev/null +++ b/lib/rb/lib/thrift/struct.rb @@ -0,0 +1,237 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'set' + +module Thrift + module Struct + def initialize(d={}, &block) + # get a copy of the default values to work on, removing defaults in favor of arguments + fields_with_defaults = fields_with_default_values.dup + + # check if the defaults is empty, or if there are no parameters for this + # instantiation, and if so, don't bother overriding defaults. + unless fields_with_defaults.empty? || d.empty? + d.each_key do |name| + fields_with_defaults.delete(name.to_s) + end + end + + # assign all the user-specified arguments + unless d.empty? + d.each do |name, value| + unless name_to_id(name.to_s) + raise Exception, "Unknown key given to #{self.class}.new: #{name}" + end + Thrift.check_type(value, struct_fields[name_to_id(name.to_s)], name) if Thrift.type_checking + instance_variable_set("@#{name}", value) + end + end + + # assign all the default values + unless fields_with_defaults.empty? + fields_with_defaults.each do |name, default_value| + instance_variable_set("@#{name}", (default_value.dup rescue default_value)) + end + end + + yield self if block_given? + end + + def fields_with_default_values + fields_with_default_values = self.class.instance_variable_get(:@fields_with_default_values) + unless fields_with_default_values + fields_with_default_values = {} + struct_fields.each do |fid, field_def| + unless field_def[:default].nil? + fields_with_default_values[field_def[:name]] = field_def[:default] + end + end + self.class.instance_variable_set(:@fields_with_default_values, fields_with_default_values) + end + fields_with_default_values + end + + def inspect(skip_optional_nulls = true) + fields = [] + each_field do |fid, field_info| + name = field_info[:name] + value = instance_variable_get("@#{name}") + unless skip_optional_nulls && field_info[:optional] && value.nil? + fields << "#{name}:#{inspect_field(value, field_info)}" + end + end + "<#{self.class} #{fields.join(", ")}>" + end + + def read(iprot) + iprot.read_struct_begin + loop do + fname, ftype, fid = iprot.read_field_begin + break if (ftype == Types::STOP) + handle_message(iprot, fid, ftype) + iprot.read_field_end + end + iprot.read_struct_end + validate + end + + def write(oprot) + validate + oprot.write_struct_begin(self.class.name) + each_field do |fid, field_info| + name = field_info[:name] + type = field_info[:type] + value = instance_variable_get("@#{name}") + unless value.nil? + if is_container? type + oprot.write_field_begin(name, type, fid) + write_container(oprot, value, field_info) + oprot.write_field_end + else + oprot.write_field(field_info, fid, value) + end + end + end + oprot.write_field_stop + oprot.write_struct_end + end + + def ==(other) + return false if other.nil? + each_field do |fid, field_info| + name = field_info[:name] + return false unless other.respond_to?(name) && self.send(name) == other.send(name) + end + true + end + + def eql?(other) + self.class == other.class && self == other + end + + # This implementation of hash() is inspired by Apache's Java HashCodeBuilder class. + def hash + total = 17 + each_field do |fid, field_info| + name = field_info[:name] + value = self.send(name) + total = (total * 37 + value.hash) & 0xffffffff + end + total + end + + def differences(other) + diffs = [] + unless other.is_a?(self.class) + diffs << "Different class!" + else + each_field do |fid, field_info| + name = field_info[:name] + diffs << "#{name} differs!" unless self.instance_variable_get("@#{name}") == other.instance_variable_get("@#{name}") + end + end + diffs + end + + def self.field_accessor(klass, field_info) + field_name_sym = field_info[:name].to_sym + klass.send :attr_reader, field_name_sym + klass.send :define_method, "#{field_info[:name]}=" do |value| + Thrift.check_type(value, field_info, field_info[:name]) if Thrift.type_checking + instance_variable_set("@#{field_name_sym}", value) + end + end + + def self.generate_accessors(klass) + klass::FIELDS.values.each do |field_info| + field_accessor(klass, field_info) + qmark_isset_method(klass, field_info) + end + end + + def self.qmark_isset_method(klass, field_info) + klass.send :define_method, "#{field_info[:name]}?" do + !self.send(field_info[:name].to_sym).nil? + end + end + + def <=>(other) + if self.class == other.class + each_field do |fid, field_info| + v1 = self.send(field_info[:name]) + v1_set = !v1.nil? + v2 = other.send(field_info[:name]) + v2_set = !v2.nil? + if v1_set && !v2_set + return -1 + elsif !v1_set && v2_set + return 1 + elsif v1_set && v2_set + cmp = v1 <=> v2 + if cmp != 0 + return cmp + end + end + end + 0 + else + self.class <=> other.class + end + end + + protected + + def self.append_features(mod) + if mod.ancestors.include? ::Exception + mod.send :class_variable_set, :'@@__thrift_struct_real_initialize', mod.instance_method(:initialize) + super + # set up our custom initializer so `raise Xception, 'message'` works + mod.send :define_method, :struct_initialize, mod.instance_method(:initialize) + mod.send :define_method, :initialize, mod.instance_method(:exception_initialize) + else + super + end + end + + def exception_initialize(*args, &block) + if args.size == 1 and args.first.is_a? Hash + # looks like it's a regular Struct initialize + method(:struct_initialize).call(args.first) + else + # call the Struct initializer first with no args + # this will set our field default values + method(:struct_initialize).call() + # now give it to the exception + self.class.send(:class_variable_get, :'@@__thrift_struct_real_initialize').bind(self).call(*args, &block) if args.size > 0 + # self.class.instance_method(:initialize).bind(self).call(*args, &block) + end + end + + def handle_message(iprot, fid, ftype) + field = struct_fields[fid] + if field and field[:type] == ftype + value = read_field(iprot, field) + instance_variable_set("@#{field[:name]}", value) + else + iprot.skip(ftype) + end + end + end +end diff --git a/lib/rb/lib/thrift/struct_union.rb b/lib/rb/lib/thrift/struct_union.rb new file mode 100644 index 0000000..e21b39e --- /dev/null +++ b/lib/rb/lib/thrift/struct_union.rb @@ -0,0 +1,192 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +require 'set' + +module Thrift + module Struct_Union + def name_to_id(name) + names_to_ids = self.class.instance_variable_get(:@names_to_ids) + unless names_to_ids + names_to_ids = {} + struct_fields.each do |fid, field_def| + names_to_ids[field_def[:name]] = fid + end + self.class.instance_variable_set(:@names_to_ids, names_to_ids) + end + names_to_ids[name] + end + + def sorted_field_ids + sorted_field_ids = self.class.instance_variable_get(:@sorted_field_ids) + unless sorted_field_ids + sorted_field_ids = struct_fields.keys.sort + self.class.instance_variable_set(:@sorted_field_ids, sorted_field_ids) + end + sorted_field_ids + end + + def each_field + sorted_field_ids.each do |fid| + data = struct_fields[fid] + yield fid, data + end + end + + def read_field(iprot, field = {}) + case field[:type] + when Types::STRUCT + value = field[:class].new + value.read(iprot) + when Types::MAP + key_type, val_type, size = iprot.read_map_begin + # Skip the map contents if the declared key or value types don't match the expected ones. + if (size != 0 && (key_type != field[:key][:type] || val_type != field[:value][:type])) + size.times do + iprot.skip(key_type) + iprot.skip(val_type) + end + value = nil + else + value = {} + size.times do + k = read_field(iprot, field_info(field[:key])) + v = read_field(iprot, field_info(field[:value])) + value[k] = v + end + end + iprot.read_map_end + when Types::LIST + e_type, size = iprot.read_list_begin + # Skip the list contents if the declared element type doesn't match the expected one. + if (e_type != field[:element][:type]) + size.times do + iprot.skip(e_type) + end + value = nil + else + value = Array.new(size) do |n| + read_field(iprot, field_info(field[:element])) + end + end + iprot.read_list_end + when Types::SET + e_type, size = iprot.read_set_begin + # Skip the set contents if the declared element type doesn't match the expected one. + if (e_type != field[:element][:type]) + size.times do + iprot.skip(e_type) + end + else + value = Set.new + size.times do + element = read_field(iprot, field_info(field[:element])) + value << element + end + end + iprot.read_set_end + else + value = iprot.read_type(field) + end + value + end + + def write_data(oprot, value, field) + if is_container? field[:type] + write_container(oprot, value, field) + else + oprot.write_type(field, value) + end + end + + def write_container(oprot, value, field = {}) + case field[:type] + when Types::MAP + oprot.write_map_begin(field[:key][:type], field[:value][:type], value.size) + value.each do |k, v| + write_data(oprot, k, field[:key]) + write_data(oprot, v, field[:value]) + end + oprot.write_map_end + when Types::LIST + oprot.write_list_begin(field[:element][:type], value.size) + value.each do |elem| + write_data(oprot, elem, field[:element]) + end + oprot.write_list_end + when Types::SET + oprot.write_set_begin(field[:element][:type], value.size) + value.each do |v,| # the , is to preserve compatibility with the old Hash-style sets + write_data(oprot, v, field[:element]) + end + oprot.write_set_end + else + raise "Not a container type: #{field[:type]}" + end + end + + CONTAINER_TYPES = [] + CONTAINER_TYPES[Types::LIST] = true + CONTAINER_TYPES[Types::MAP] = true + CONTAINER_TYPES[Types::SET] = true + def is_container?(type) + CONTAINER_TYPES[type] + end + + def field_info(field) + { :type => field[:type], + :class => field[:class], + :key => field[:key], + :value => field[:value], + :element => field[:element] } + end + + def inspect_field(value, field_info) + if enum_class = field_info[:enum_class] + "#{enum_class.const_get(:VALUE_MAP)[value]} (#{value})" + elsif value.is_a? Hash + if field_info[:type] == Types::MAP + map_buf = [] + value.each do |k, v| + map_buf << inspect_field(k, field_info[:key]) + ": " + inspect_field(v, field_info[:value]) + end + "{" + map_buf.join(", ") + "}" + else + # old-style set + inspect_collection(value.keys, field_info) + end + elsif value.is_a? Array + inspect_collection(value, field_info) + elsif value.is_a? Set + inspect_collection(value, field_info) + elsif value.is_a?(String) && field_info[:binary] + value.unpack("H*").first + else + value.inspect + end + end + + def inspect_collection(collection, field_info) + buf = [] + collection.each do |k| + buf << inspect_field(k, field_info[:element]) + end + "[" + buf.join(", ") + "]" + end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/thrift_native.rb b/lib/rb/lib/thrift/thrift_native.rb new file mode 100644 index 0000000..4d8df61 --- /dev/null +++ b/lib/rb/lib/thrift/thrift_native.rb @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +begin + require "thrift_native" +rescue LoadError + puts "Unable to load thrift_native extension. Defaulting to pure Ruby libraries." +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/transport/base_server_transport.rb b/lib/rb/lib/thrift/transport/base_server_transport.rb new file mode 100644 index 0000000..68c5af0 --- /dev/null +++ b/lib/rb/lib/thrift/transport/base_server_transport.rb @@ -0,0 +1,37 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + class BaseServerTransport + def listen + raise NotImplementedError + end + + def accept + raise NotImplementedError + end + + def close; nil; end + + def closed? + raise NotImplementedError + end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/transport/base_transport.rb b/lib/rb/lib/thrift/transport/base_transport.rb new file mode 100644 index 0000000..8790326 --- /dev/null +++ b/lib/rb/lib/thrift/transport/base_transport.rb @@ -0,0 +1,109 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + class TransportException < Exception + UNKNOWN = 0 + NOT_OPEN = 1 + ALREADY_OPEN = 2 + TIMED_OUT = 3 + END_OF_FILE = 4 + + attr_reader :type + + def initialize(type=UNKNOWN, message=nil) + super(message) + @type = type + end + end + + module TransportUtils + # Deprecated: Use Thrift::Bytes instead + def self.get_string_byte(string, index) + Bytes.get_string_byte(string, index) + end + + # Deprecated: Use Thrift::Bytes instead + def self.set_string_byte(string, index, byte) + Bytes.set_string_byte(string, index, byte) + end + end + + class BaseTransport + def open?; end + + def open; end + + def close; end + + # Reads a number of bytes from the transports. In Ruby 1.9+, the String returned will have a BINARY (aka ASCII8BIT) encoding. + # + # sz - The number of bytes to read from the transport. + # + # Returns a String acting as a byte buffer. + def read(sz) + raise NotImplementedError + end + + # Returns an unsigned byte as a Fixnum in the range (0..255). + def read_byte + buf = read_all(1) + return Bytes.get_string_byte(buf, 0) + end + + # Reads size bytes and copies them into buffer[0..size]. + def read_into_buffer(buffer, size) + tmp = read_all(size) + i = 0 + tmp.each_byte do |byte| + Bytes.set_string_byte(buffer, i, byte) + i += 1 + end + i + end + + def read_all(size) + return Bytes.empty_byte_buffer if size <= 0 + buf = read(size) + while (buf.length < size) + chunk = read(size - buf.length) + buf << chunk + end + + buf + end + + # Writes the byte buffer to the transport. In Ruby 1.9+, the buffer will be forced into BINARY encoding. + # + # buf - A String acting as a byte buffer. + # + # Returns nothing. + def write(buf); end + alias_method :<<, :write + + def flush; end + end + + class BaseTransportFactory + def get_transport(trans) + return trans + end + end +end diff --git a/lib/rb/lib/thrift/transport/buffered_transport.rb b/lib/rb/lib/thrift/transport/buffered_transport.rb new file mode 100644 index 0000000..781d3c6 --- /dev/null +++ b/lib/rb/lib/thrift/transport/buffered_transport.rb @@ -0,0 +1,114 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + class BufferedTransport < BaseTransport + DEFAULT_BUFFER = 4096 + + def initialize(transport) + @transport = transport + @wbuf = Bytes.empty_byte_buffer + @rbuf = Bytes.empty_byte_buffer + @index = 0 + end + + def open? + return @transport.open? + end + + def open + @transport.open + end + + def close + flush + @transport.close + end + + def read(sz) + @index += sz + ret = @rbuf.slice(@index - sz, sz) || Bytes.empty_byte_buffer + + if ret.length == 0 + @rbuf = @transport.read([sz, DEFAULT_BUFFER].max) + @index = sz + ret = @rbuf.slice(0, sz) || Bytes.empty_byte_buffer + end + + ret + end + + def read_byte + # If the read buffer is exhausted, try to read up to DEFAULT_BUFFER more bytes into it. + if @index >= @rbuf.size + @rbuf = @transport.read(DEFAULT_BUFFER) + @index = 0 + end + + # The read buffer has some data now, read a single byte. Using get_string_byte() avoids + # allocating a temp string of size 1 unnecessarily. + @index += 1 + return Bytes.get_string_byte(@rbuf, @index - 1) + end + + # Reads a number of bytes from the transport into the buffer passed. + # + # buffer - The String (byte buffer) to write data to; this is assumed to have a BINARY encoding. + # size - The number of bytes to read from the transport and write to the buffer. + # + # Returns the number of bytes read. + def read_into_buffer(buffer, size) + i = 0 + while i < size + # If the read buffer is exhausted, try to read up to DEFAULT_BUFFER more bytes into it. + if @index >= @rbuf.size + @rbuf = @transport.read(DEFAULT_BUFFER) + @index = 0 + end + + # The read buffer has some data now, so copy bytes over to the output buffer. + byte = Bytes.get_string_byte(@rbuf, @index) + Bytes.set_string_byte(buffer, i, byte) + @index += 1 + i += 1 + end + i + end + + def write(buf) + @wbuf << Bytes.force_binary_encoding(buf) + end + + def flush + unless @wbuf.empty? + @transport.write(@wbuf) + @wbuf = Bytes.empty_byte_buffer + end + + @transport.flush + end + end + + class BufferedTransportFactory < BaseTransportFactory + def get_transport(transport) + return BufferedTransport.new(transport) + end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/transport/framed_transport.rb b/lib/rb/lib/thrift/transport/framed_transport.rb new file mode 100644 index 0000000..d806ce0 --- /dev/null +++ b/lib/rb/lib/thrift/transport/framed_transport.rb @@ -0,0 +1,117 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + class FramedTransport < BaseTransport + def initialize(transport, read=true, write=true) + @transport = transport + @rbuf = Bytes.empty_byte_buffer + @wbuf = Bytes.empty_byte_buffer + @read = read + @write = write + @index = 0 + end + + def open? + @transport.open? + end + + def open + @transport.open + end + + def close + @transport.close + end + + def read(sz) + return @transport.read(sz) unless @read + + return Bytes.empty_byte_buffer if sz <= 0 + + read_frame if @index >= @rbuf.length + + @index += sz + @rbuf.slice(@index - sz, sz) || Bytes.empty_byte_buffer + end + + def read_byte + return @transport.read_byte() unless @read + + read_frame if @index >= @rbuf.length + + # The read buffer has some data now, read a single byte. Using get_string_byte() avoids + # allocating a temp string of size 1 unnecessarily. + @index += 1 + return Bytes.get_string_byte(@rbuf, @index - 1) + end + + def read_into_buffer(buffer, size) + i = 0 + while i < size + read_frame if @index >= @rbuf.length + + # The read buffer has some data now, so copy bytes over to the output buffer. + byte = Bytes.get_string_byte(@rbuf, @index) + Bytes.set_string_byte(buffer, i, byte) + @index += 1 + i += 1 + end + i + end + + def write(buf, sz=nil) + return @transport.write(buf) unless @write + + buf = Bytes.force_binary_encoding(buf) + @wbuf << (sz ? buf[0...sz] : buf) + end + + # + # Writes the output buffer to the stream in the format of a 4-byte length + # followed by the actual data. + # + def flush + return @transport.flush unless @write + + out = [@wbuf.length].pack('N') + # Array#pack should return a BINARY encoded String, so it shouldn't be necessary to force encoding + out << @wbuf + @transport.write(out) + @transport.flush + @wbuf = Bytes.empty_byte_buffer + end + + private + + def read_frame + sz = @transport.read_all(4).unpack('N').first + + @index = 0 + @rbuf = @transport.read_all(sz) + end + end + + class FramedTransportFactory < BaseTransportFactory + def get_transport(transport) + return FramedTransport.new(transport) + end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/transport/http_client_transport.rb b/lib/rb/lib/thrift/transport/http_client_transport.rb new file mode 100644 index 0000000..c9c4fec --- /dev/null +++ b/lib/rb/lib/thrift/transport/http_client_transport.rb @@ -0,0 +1,57 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'net/http' +require 'net/https' +require 'openssl' +require 'uri' +require 'stringio' + +module Thrift + class HTTPClientTransport < BaseTransport + + def initialize(url, opts = {}) + @url = URI url + @headers = {'Content-Type' => 'application/x-thrift'} + @outbuf = Bytes.empty_byte_buffer + @ssl_verify_mode = opts.fetch(:ssl_verify_mode, OpenSSL::SSL::VERIFY_PEER) + end + + def open?; true end + def read(sz); @inbuf.read sz end + def write(buf); @outbuf << Bytes.force_binary_encoding(buf) end + + def add_headers(headers) + @headers = @headers.merge(headers) + end + + def flush + http = Net::HTTP.new @url.host, @url.port + http.use_ssl = @url.scheme == 'https' + http.verify_mode = @ssl_verify_mode if @url.scheme == 'https' + resp = http.post(@url.request_uri, @outbuf, @headers) + data = resp.body + data = Bytes.force_binary_encoding(data) + @inbuf = StringIO.new data + ensure + @outbuf = Bytes.empty_byte_buffer + end + end +end diff --git a/lib/rb/lib/thrift/transport/io_stream_transport.rb b/lib/rb/lib/thrift/transport/io_stream_transport.rb new file mode 100644 index 0000000..e3c8379 --- /dev/null +++ b/lib/rb/lib/thrift/transport/io_stream_transport.rb @@ -0,0 +1,39 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Very very simple implementation of wrapping two objects, one with a #read +# method and one with a #write method, into a transport for thrift. +# +# Assumes both objects are open, remain open, don't require flushing, etc. +# +module Thrift + class IOStreamTransport < BaseTransport + def initialize(input, output) + @input = input + @output = output + end + + def open?; not @input.closed? or not @output.closed? end + def read(sz); @input.read(sz) end + def write(buf); @output.write(Bytes.force_binary_encoding(buf)) end + def close; @input.close; @output.close end + def to_io; @input end # we're assuming this is used in a IO.select for reading + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/transport/memory_buffer_transport.rb b/lib/rb/lib/thrift/transport/memory_buffer_transport.rb new file mode 100644 index 0000000..ad5ad85 --- /dev/null +++ b/lib/rb/lib/thrift/transport/memory_buffer_transport.rb @@ -0,0 +1,125 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + class MemoryBufferTransport < BaseTransport + GARBAGE_BUFFER_SIZE = 4*(2**10) # 4kB + + # If you pass a string to this, you should #dup that string + # unless you want it to be modified by #read and #write + #-- + # this behavior is no longer required. If you wish to change it + # go ahead, just make sure the specs pass + def initialize(buffer = nil) + @buf = buffer ? Bytes.force_binary_encoding(buffer) : Bytes.empty_byte_buffer + @index = 0 + end + + def open? + return true + end + + def open + end + + def close + end + + def peek + @index < @buf.size + end + + # this method does not use the passed object directly but copies it + def reset_buffer(new_buf = '') + @buf.replace Bytes.force_binary_encoding(new_buf) + @index = 0 + end + + def available + @buf.length - @index + end + + def read(len) + data = @buf.slice(@index, len) + @index += len + @index = @buf.size if @index > @buf.size + if @index >= GARBAGE_BUFFER_SIZE + @buf = @buf.slice(@index..-1) + @index = 0 + end + if data.size < len + raise EOFError, "Not enough bytes remain in buffer" + end + data + end + + def read_byte + raise EOFError.new("Not enough bytes remain in buffer") if @index >= @buf.size + val = Bytes.get_string_byte(@buf, @index) + @index += 1 + if @index >= GARBAGE_BUFFER_SIZE + @buf = @buf.slice(@index..-1) + @index = 0 + end + val + end + + def read_into_buffer(buffer, size) + i = 0 + while i < size + raise EOFError.new("Not enough bytes remain in buffer") if @index >= @buf.size + + # The read buffer has some data now, so copy bytes over to the output buffer. + byte = Bytes.get_string_byte(@buf, @index) + Bytes.set_string_byte(buffer, i, byte) + @index += 1 + i += 1 + end + if @index >= GARBAGE_BUFFER_SIZE + @buf = @buf.slice(@index..-1) + @index = 0 + end + i + end + + def write(wbuf) + @buf << Bytes.force_binary_encoding(wbuf) + end + + def flush + end + + def inspect_buffer + out = [] + for idx in 0...(@buf.size) + # if idx != 0 + # out << " " + # end + + if idx == @index + out << ">" + end + + out << @buf[idx].ord.to_s(16) + end + out.join(" ") + end + end +end diff --git a/lib/rb/lib/thrift/transport/server_socket.rb b/lib/rb/lib/thrift/transport/server_socket.rb new file mode 100644 index 0000000..7feb9ab --- /dev/null +++ b/lib/rb/lib/thrift/transport/server_socket.rb @@ -0,0 +1,63 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'socket' + +module Thrift + class ServerSocket < BaseServerTransport + # call-seq: initialize(host = nil, port) + def initialize(host_or_port, port = nil) + if port + @host = host_or_port + @port = port + else + @host = nil + @port = host_or_port + end + @handle = nil + end + + attr_reader :handle + + def listen + @handle = TCPServer.new(@host, @port) + end + + def accept + unless @handle.nil? + sock = @handle.accept + trans = Socket.new + trans.handle = sock + trans + end + end + + def close + @handle.close unless @handle.nil? or @handle.closed? + @handle = nil + end + + def closed? + @handle.nil? or @handle.closed? + end + + alias to_io handle + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/transport/socket.rb b/lib/rb/lib/thrift/transport/socket.rb new file mode 100644 index 0000000..517d112 --- /dev/null +++ b/lib/rb/lib/thrift/transport/socket.rb @@ -0,0 +1,141 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'socket' + +module Thrift + class Socket < BaseTransport + def initialize(host='localhost', port=9090, timeout=nil) + @host = host + @port = port + @timeout = timeout + @desc = "#{host}:#{port}" + @handle = nil + end + + attr_accessor :handle, :timeout + + def open + for addrinfo in ::Socket::getaddrinfo(@host, @port, nil, ::Socket::SOCK_STREAM) do + begin + socket = ::Socket.new(addrinfo[4], ::Socket::SOCK_STREAM, 0) + socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1) + sockaddr = ::Socket.sockaddr_in(addrinfo[1], addrinfo[3]) + begin + socket.connect_nonblock(sockaddr) + rescue Errno::EINPROGRESS + unless IO.select(nil, [ socket ], nil, @timeout) + next + end + begin + socket.connect_nonblock(sockaddr) + rescue Errno::EISCONN + end + end + return @handle = socket + rescue StandardError => e + next + end + end + raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: #{e}") + end + + def open? + !@handle.nil? and !@handle.closed? + end + + def write(str) + raise IOError, "closed stream" unless open? + str = Bytes.force_binary_encoding(str) + begin + if @timeout.nil? or @timeout == 0 + @handle.write(str) + else + len = 0 + start = Time.now + while Time.now - start < @timeout + rd, wr, = IO.select(nil, [@handle], nil, @timeout) + if wr and not wr.empty? + len += @handle.write_nonblock(str[len..-1]) + break if len >= str.length + end + end + if len < str.length + raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out writing #{str.length} bytes to #{@desc}") + else + len + end + end + rescue TransportException => e + # pass this on + raise e + rescue StandardError => e + @handle.close + @handle = nil + raise TransportException.new(TransportException::NOT_OPEN, e.message) + end + end + + def read(sz) + raise IOError, "closed stream" unless open? + + begin + if @timeout.nil? or @timeout == 0 + data = @handle.readpartial(sz) + else + # it's possible to interrupt select for something other than the timeout + # so we need to ensure we've waited long enough, but not too long + start = Time.now + timespent = 0 + rd = loop do + rd, = IO.select([@handle], nil, nil, @timeout - timespent) + timespent = Time.now - start + break rd if (rd and not rd.empty?) or timespent >= @timeout + end + if rd.nil? or rd.empty? + raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out reading #{sz} bytes from #{@desc}") + else + data = @handle.readpartial(sz) + end + end + rescue TransportException => e + # don't let this get caught by the StandardError handler + raise e + rescue StandardError => e + @handle.close unless @handle.closed? + @handle = nil + raise TransportException.new(TransportException::NOT_OPEN, e.message) + end + if (data.nil? or data.length == 0) + raise TransportException.new(TransportException::UNKNOWN, "Socket: Could not read #{sz} bytes from #{@desc}") + end + data + end + + def close + @handle.close unless @handle.nil? or @handle.closed? + @handle = nil + end + + def to_io + @handle + end + end +end diff --git a/lib/rb/lib/thrift/transport/ssl_server_socket.rb b/lib/rb/lib/thrift/transport/ssl_server_socket.rb new file mode 100644 index 0000000..abc1343 --- /dev/null +++ b/lib/rb/lib/thrift/transport/ssl_server_socket.rb @@ -0,0 +1,37 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'socket' + +module Thrift + class SSLServerSocket < ServerSocket + def initialize(host_or_port, port = nil, ssl_context = nil) + super(host_or_port, port) + @ssl_context = ssl_context + end + + attr_accessor :ssl_context + + def listen + socket = TCPServer.new(@host, @port) + @handle = OpenSSL::SSL::SSLServer.new(socket, @ssl_context) + end + end +end diff --git a/lib/rb/lib/thrift/transport/ssl_socket.rb b/lib/rb/lib/thrift/transport/ssl_socket.rb new file mode 100644 index 0000000..dbbcc94 --- /dev/null +++ b/lib/rb/lib/thrift/transport/ssl_socket.rb @@ -0,0 +1,47 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module Thrift + class SSLSocket < Socket + def initialize(host='localhost', port=9090, timeout=nil, ssl_context=nil) + super(host, port, timeout) + @ssl_context = ssl_context + end + + attr_accessor :ssl_context + + def open + socket = super + @handle = OpenSSL::SSL::SSLSocket.new(socket, @ssl_context) + begin + @handle.connect_nonblock + @handle.post_connection_check(@host) + @handle + rescue IO::WaitReadable + IO.select([ @handle ], nil, nil, @timeout) + retry + rescue IO::WaitWritable + IO.select(nil, [ @handle ], nil, @timeout) + retry + rescue StandardError => e + raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: #{e}") + end + end + end +end diff --git a/lib/rb/lib/thrift/transport/unix_server_socket.rb b/lib/rb/lib/thrift/transport/unix_server_socket.rb new file mode 100644 index 0000000..a135d25 --- /dev/null +++ b/lib/rb/lib/thrift/transport/unix_server_socket.rb @@ -0,0 +1,60 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'socket' + +module Thrift + class UNIXServerSocket < BaseServerTransport + def initialize(path) + @path = path + @handle = nil + end + + attr_accessor :handle + + def listen + @handle = ::UNIXServer.new(@path) + end + + def accept + unless @handle.nil? + sock = @handle.accept + trans = UNIXSocket.new(nil) + trans.handle = sock + trans + end + end + + def close + if @handle + @handle.close unless @handle.closed? + @handle = nil + # UNIXServer doesn't delete the socket file, so we have to do it ourselves + File.delete(@path) + end + end + + def closed? + @handle.nil? or @handle.closed? + end + + alias to_io handle + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/transport/unix_socket.rb b/lib/rb/lib/thrift/transport/unix_socket.rb new file mode 100644 index 0000000..8f692e4 --- /dev/null +++ b/lib/rb/lib/thrift/transport/unix_socket.rb @@ -0,0 +1,40 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'socket' + +module Thrift + class UNIXSocket < Socket + def initialize(path, timeout=nil) + @path = path + @timeout = timeout + @desc = @path # for read()'s error + @handle = nil + end + + def open + begin + @handle = ::UNIXSocket.new(@path) + rescue StandardError + raise TransportException.new(TransportException::NOT_OPEN, "Could not open UNIX socket at #{@path}") + end + end + end +end \ No newline at end of file diff --git a/lib/rb/lib/thrift/types.rb b/lib/rb/lib/thrift/types.rb new file mode 100644 index 0000000..cac5269 --- /dev/null +++ b/lib/rb/lib/thrift/types.rb @@ -0,0 +1,101 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'set' + +module Thrift + module Types + STOP = 0 + VOID = 1 + BOOL = 2 + BYTE = 3 + DOUBLE = 4 + I16 = 6 + I32 = 8 + I64 = 10 + STRING = 11 + STRUCT = 12 + MAP = 13 + SET = 14 + LIST = 15 + end + + class << self + attr_accessor :type_checking + end + + class TypeError < Exception + end + + def self.check_type(value, field, name, skip_nil=true) + return if value.nil? and skip_nil + klasses = case field[:type] + when Types::VOID + NilClass + when Types::BOOL + [TrueClass, FalseClass] + when Types::BYTE, Types::I16, Types::I32, Types::I64 + Integer + when Types::DOUBLE + Float + when Types::STRING + String + when Types::STRUCT + [Struct, Union] + when Types::MAP + Hash + when Types::SET + Set + when Types::LIST + Array + end + valid = klasses && [*klasses].any? { |klass| klass === value } + raise TypeError, "Expected #{type_name(field[:type])}, received #{value.class} for field #{name}" unless valid + # check elements now + case field[:type] + when Types::MAP + value.each_pair do |k,v| + check_type(k, field[:key], "#{name}.key", false) + check_type(v, field[:value], "#{name}.value", false) + end + when Types::SET, Types::LIST + value.each do |el| + check_type(el, field[:element], "#{name}.element", false) + end + when Types::STRUCT + raise TypeError, "Expected #{field[:class]}, received #{value.class} for field #{name}" unless field[:class] == value.class + end + end + + def self.type_name(type) + Types.constants.each do |const| + return "Types::#{const}" if Types.const_get(const) == type + end + nil + end + + module MessageTypes + CALL = 1 + REPLY = 2 + EXCEPTION = 3 + ONEWAY = 4 + end +end + +Thrift.type_checking = false if Thrift.type_checking.nil? diff --git a/lib/rb/lib/thrift/union.rb b/lib/rb/lib/thrift/union.rb new file mode 100644 index 0000000..490c55c --- /dev/null +++ b/lib/rb/lib/thrift/union.rb @@ -0,0 +1,176 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Thrift + class Union + def initialize(name=nil, value=nil) + if name + if name.is_a? Hash + if name.size > 1 + raise "#{self.class} cannot be instantiated with more than one field!" + end + + name, value = name.keys.first, name.values.first + end + + if Thrift.type_checking + raise Exception, "#{self.class} does not contain a field named #{name}!" unless name_to_id(name.to_s) + end + + if value.nil? + raise Exception, "Union #{self.class} cannot be instantiated with setfield and nil value!" + end + + Thrift.check_type(value, struct_fields[name_to_id(name.to_s)], name) if Thrift.type_checking + elsif !value.nil? + raise Exception, "Value provided, but no name!" + end + @setfield = name + @value = value + end + + def inspect + if get_set_field + "<#{self.class} #{@setfield}: #{inspect_field(@value, struct_fields[name_to_id(@setfield.to_s)])}>" + else + "<#{self.class} >" + end + end + + def read(iprot) + iprot.read_struct_begin + fname, ftype, fid = iprot.read_field_begin + handle_message(iprot, fid, ftype) + iprot.read_field_end + + fname, ftype, fid = iprot.read_field_begin + raise "Too many fields for union" unless (ftype == Types::STOP) + + iprot.read_struct_end + validate + end + + def write(oprot) + validate + oprot.write_struct_begin(self.class.name) + + fid = self.name_to_id(@setfield.to_s) + + field_info = struct_fields[fid] + type = field_info[:type] + if is_container? type + oprot.write_field_begin(@setfield, type, fid) + write_container(oprot, @value, field_info) + oprot.write_field_end + else + oprot.write_field(@setfield, type, fid, @value) + end + + oprot.write_field_stop + oprot.write_struct_end + end + + def ==(other) + other.equal?(self) || other.instance_of?(self.class) && @setfield == other.get_set_field && @value == other.get_value + end + alias_method :eql?, :== + + def hash + [self.class.name, @setfield, @value].hash + end + + def self.field_accessor(klass, field_info) + klass.send :define_method, field_info[:name] do + if field_info[:name].to_sym == @setfield + @value + else + raise RuntimeError, "#{field_info[:name]} is not union's set field." + end + end + + klass.send :define_method, "#{field_info[:name]}=" do |value| + Thrift.check_type(value, field_info, field_info[:name]) if Thrift.type_checking + @setfield = field_info[:name].to_sym + @value = value + end + end + + def self.qmark_isset_method(klass, field_info) + klass.send :define_method, "#{field_info[:name]}?" do + get_set_field == field_info[:name].to_sym && !get_value.nil? + end + end + + def self.generate_accessors(klass) + klass::FIELDS.values.each do |field_info| + field_accessor(klass, field_info) + qmark_isset_method(klass, field_info) + end + end + + # get the symbol that indicates what the currently set field type is. + def get_set_field + @setfield + end + + # get the current value of this union, regardless of what the set field is. + # generally, you should only use this method when you don't know in advance + # what field to expect. + def get_value + @value + end + + def <=>(other) + if self.class == other.class + if get_set_field == other.get_set_field + if get_set_field.nil? + 0 + else + get_value <=> other.get_value + end + else + if get_set_field && other.get_set_field.nil? + -1 + elsif get_set_field.nil? && other.get_set_field + 1 + elsif get_set_field.nil? && other.get_set_field.nil? + 0 + else + name_to_id(get_set_field.to_s) <=> name_to_id(other.get_set_field.to_s) + end + end + else + self.class <=> other.class + end + end + + protected + + def handle_message(iprot, fid, ftype) + field = struct_fields[fid] + if field and field[:type] == ftype + @value = read_field(iprot, field) + name = field[:name].to_sym + @setfield = name + else + iprot.skip(ftype) + end + end + end +end diff --git a/lib/rb/script/proto_benchmark.rb b/lib/rb/script/proto_benchmark.rb new file mode 100644 index 0000000..bb49e2e --- /dev/null +++ b/lib/rb/script/proto_benchmark.rb @@ -0,0 +1,121 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require File.dirname(__FILE__) + "/../spec/spec_helper.rb" + +require "benchmark" +# require "ruby-prof" + +obj = Fixtures::COMPACT_PROTOCOL_TEST_STRUCT + +HOW_MANY = 1_000 + +binser = Thrift::Serializer.new +bin_data = binser.serialize(obj) +bindeser = Thrift::Deserializer.new +accel_bin_ser = Thrift::Serializer.new(Thrift::BinaryProtocolAcceleratedFactory.new) +accel_bin_deser = Thrift::Deserializer.new(Thrift::BinaryProtocolAcceleratedFactory.new) + +compact_ser = Thrift::Serializer.new(Thrift::CompactProtocolFactory.new) +compact_data = compact_ser.serialize(obj) +compact_deser = Thrift::Deserializer.new(Thrift::CompactProtocolFactory.new) + +Benchmark.bm(60) do |reporter| + reporter.report("binary protocol, write") do + HOW_MANY.times do + binser.serialize(obj) + end + end + + reporter.report("accelerated binary protocol, write") do + HOW_MANY.times do + accel_bin_ser.serialize(obj) + end + end + + reporter.report("compact protocol, write") do + # RubyProf.start + HOW_MANY.times do + compact_ser.serialize(obj) + end + # result = RubyProf.stop + # printer = RubyProf::GraphHtmlPrinter.new(result) + # file = File.open("profile.html", "w+") + # printer.print(file, 0) + # file.close + end + + reporter.report("binary protocol, read") do + HOW_MANY.times do + bindeser.deserialize(obj, bin_data) + end + end + + reporter.report("accelerated binary protocol, read") do + HOW_MANY.times do + accel_bin_deser.deserialize(obj, bin_data) + end + end + + reporter.report("compact protocol, read") do + HOW_MANY.times do + compact_deser.deserialize(obj, compact_data) + end + end + + + # f = File.new("/tmp/testfile", "w") + # proto = Thrift::BinaryProtocolAccelerated.new(Thrift::IOStreamTransport.new(Thrift::MemoryBufferTransport.new, f)) + # reporter.report("accelerated binary protocol, write (to disk)") do + # HOW_MANY.times do + # obj.write(proto) + # end + # f.flush + # end + # f.close + # + # f = File.new("/tmp/testfile", "r") + # proto = Thrift::BinaryProtocolAccelerated.new(Thrift::IOStreamTransport.new(f, Thrift::MemoryBufferTransport.new)) + # reporter.report("accelerated binary protocol, read (from disk)") do + # HOW_MANY.times do + # obj.read(proto) + # end + # end + # f.close + # + # f = File.new("/tmp/testfile", "w") + # reporter.report("compact protocol, write (to disk)") do + # proto = Thrift::CompactProtocol.new(Thrift::IOStreamTransport.new(Thrift::MemoryBufferTransport.new, f)) + # HOW_MANY.times do + # obj.write(proto) + # end + # f.flush + # end + # f.close + # + # f = File.new("/tmp/testfile", "r") + # reporter.report("compact protocol, read (from disk)") do + # proto = Thrift::CompactProtocol.new(Thrift::IOStreamTransport.new(f, Thrift::MemoryBufferTransport.new)) + # HOW_MANY.times do + # obj.read(proto) + # end + # end + # f.close + +end diff --git a/lib/rb/script/read_struct.rb b/lib/rb/script/read_struct.rb new file mode 100644 index 0000000..831fcec --- /dev/null +++ b/lib/rb/script/read_struct.rb @@ -0,0 +1,43 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require "spec/spec_helper" + +path, factory_class = ARGV + +factory = eval(factory_class).new + +deser = Thrift::Deserializer.new(factory) + +cpts = CompactProtoTestStruct.new +CompactProtoTestStruct.constants.each do |const| + cpts.instance_variable_set("@#{const}", nil) +end + +data = File.read(path) + +deser.deserialize(cpts, data) + +if cpts == Fixtures::COMPACT_PROTOCOL_TEST_STRUCT + puts "Object verified successfully!" +else + puts "Object failed verification! Expected #{Fixtures::COMPACT_PROTOCOL_TEST_STRUCT.inspect} but got #{cpts.inspect}" + + puts cpts.differences(Fixtures::COMPACT_PROTOCOL_TEST_STRUCT) +end diff --git a/lib/rb/script/write_struct.rb b/lib/rb/script/write_struct.rb new file mode 100644 index 0000000..da14219 --- /dev/null +++ b/lib/rb/script/write_struct.rb @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require "spec/spec_helper" + +path, factory_class = ARGV + +factory = eval(factory_class).new + +ser = Thrift::Serializer.new(factory) + +File.open(path, "w") do |file| + file.write(ser.serialize(Fixtures::COMPACT_PROTOCOL_TEST_STRUCT)) +end \ No newline at end of file diff --git a/lib/rb/spec/BaseService.thrift b/lib/rb/spec/BaseService.thrift new file mode 100644 index 0000000..5c7d32a --- /dev/null +++ b/lib/rb/spec/BaseService.thrift @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +namespace rb Base + +struct Hello { + 1: string greeting = "hello world" +} + +service BaseService { + Hello greeting(1:bool english) +} diff --git a/lib/rb/spec/ExtendedService.thrift b/lib/rb/spec/ExtendedService.thrift new file mode 100644 index 0000000..1a6b705 --- /dev/null +++ b/lib/rb/spec/ExtendedService.thrift @@ -0,0 +1,25 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +namespace rb Extended + +include "BaseService.thrift" + +service ExtendedService extends BaseService.BaseService { + void ping() +} diff --git a/lib/rb/spec/Referenced.thrift b/lib/rb/spec/Referenced.thrift new file mode 100644 index 0000000..98f183f --- /dev/null +++ b/lib/rb/spec/Referenced.thrift @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +namespace rb OtherNamespace + +enum SomeEnum { + ONE + TWO +} diff --git a/lib/rb/spec/ThriftNamespacedSpec.thrift b/lib/rb/spec/ThriftNamespacedSpec.thrift new file mode 100644 index 0000000..02f2889 --- /dev/null +++ b/lib/rb/spec/ThriftNamespacedSpec.thrift @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +namespace rb NamespacedSpecNamespace + +include "Referenced.thrift" + +struct Hello { + 1: string greeting = "hello world" +} + +service NamespacedNonblockingService { + Hello greeting(1:bool english) + bool block() + oneway void unblock(1:i32 n) + oneway void shutdown() + void sleep(1:double seconds) +} diff --git a/lib/rb/spec/ThriftSpec.thrift b/lib/rb/spec/ThriftSpec.thrift new file mode 100644 index 0000000..b42481b --- /dev/null +++ b/lib/rb/spec/ThriftSpec.thrift @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +namespace rb SpecNamespace + +struct Hello { + 1: string greeting = "hello world" +} + +enum SomeEnum { + ONE + TWO +} + +struct StructWithSomeEnum { + 1: SomeEnum some_enum; +} + +union TestUnion { + /** + * A doc string + */ + 1: string string_field; + 2: i32 i32_field; + 3: i32 other_i32_field; + 4: SomeEnum enum_field; + 5: binary binary_field; +} + +struct Foo { + 1: i32 simple = 53, + 2: string words = "words", + 3: Hello hello = {'greeting' : "hello, world!"}, + 4: list ints = [1, 2, 2, 3], + 5: map> complex, + 6: set shorts = [5, 17, 239], + 7: optional string opt_string + 8: bool my_bool +} + +struct Foo2 { + 1: binary my_binary +} + +struct BoolStruct { + 1: bool yesno = 1 +} + +struct SimpleList { + 1: list bools, + 2: list bytes, + 3: list i16s, + 4: list i32s, + 5: list i64s, + 6: list doubles, + 7: list strings, + 8: list> maps, + 9: list> lists, + 10: list> sets, + 11: list hellos +} + +exception Xception { + 1: string message, + 2: i32 code = 1 +} + +service NonblockingService { + Hello greeting(1:bool english) + bool block() + oneway void unblock(1:i32 n) + oneway void shutdown() + void sleep(1:double seconds) +} + +union My_union { + 1: bool im_true, + 2: byte a_bite, + 3: i16 integer16, + 4: i32 integer32, + 5: i64 integer64, + 6: double double_precision, + 7: string some_characters, + 8: i32 other_i32 + 9: SomeEnum some_enum; + 10: map> my_map; +} + +struct Struct_with_union { + 1: My_union fun_union + 2: i32 integer32 + 3: string some_characters +} + +struct StructWithEnumMap { + 1: map> my_map; +} + +# Nested lists +struct NestedListInList { + 1: list> value +} + +struct NestedListInSet { + 1: set> value +} + +struct NestedListInMapKey { + 1: map, byte> value +} + +struct NestedListInMapValue { + 1: map> value +} + +# Nested sets +struct NestedSetInList { + 1: list> value +} + +struct NestedSetInSet { + 1: set> value +} + +struct NestedSetInMapKey { + 1: map, byte> value +} + +struct NestedSetInMapValue { + 1: map> value +} + +# Nested maps +struct NestedMapInList { + 1: list> value +} + +struct NestedMapInSet { + 1: set> value +} + +struct NestedMapInMapKey { + 2: map, byte> value +} + +struct NestedMapInMapValue { + 2: map> value +} diff --git a/lib/rb/spec/base_protocol_spec.rb b/lib/rb/spec/base_protocol_spec.rb new file mode 100644 index 0000000..ec50c48 --- /dev/null +++ b/lib/rb/spec/base_protocol_spec.rb @@ -0,0 +1,217 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'BaseProtocol' do + + before(:each) do + @trans = mock("MockTransport") + @prot = Thrift::BaseProtocol.new(@trans) + end + + describe Thrift::BaseProtocol do + # most of the methods are stubs, so we can ignore them + + it "should make trans accessible" do + @prot.trans.should eql(@trans) + end + + it 'should write out a field nicely (deprecated write_field signature)' do + @prot.should_receive(:write_field_begin).with('field', 'type', 'fid').ordered + @prot.should_receive(:write_type).with({:name => 'field', :type => 'type'}, 'value').ordered + @prot.should_receive(:write_field_end).ordered + @prot.write_field('field', 'type', 'fid', 'value') + end + + it 'should write out a field nicely' do + @prot.should_receive(:write_field_begin).with('field', 'type', 'fid').ordered + @prot.should_receive(:write_type).with({:name => 'field', :type => 'type', :binary => false}, 'value').ordered + @prot.should_receive(:write_field_end).ordered + @prot.write_field({:name => 'field', :type => 'type', :binary => false}, 'fid', 'value') + end + + it 'should write out the different types (deprecated write_type signature)' do + @prot.should_receive(:write_bool).with('bool').ordered + @prot.should_receive(:write_byte).with('byte').ordered + @prot.should_receive(:write_double).with('double').ordered + @prot.should_receive(:write_i16).with('i16').ordered + @prot.should_receive(:write_i32).with('i32').ordered + @prot.should_receive(:write_i64).with('i64').ordered + @prot.should_receive(:write_string).with('string').ordered + struct = mock('Struct') + struct.should_receive(:write).with(@prot).ordered + @prot.write_type(Thrift::Types::BOOL, 'bool') + @prot.write_type(Thrift::Types::BYTE, 'byte') + @prot.write_type(Thrift::Types::DOUBLE, 'double') + @prot.write_type(Thrift::Types::I16, 'i16') + @prot.write_type(Thrift::Types::I32, 'i32') + @prot.write_type(Thrift::Types::I64, 'i64') + @prot.write_type(Thrift::Types::STRING, 'string') + @prot.write_type(Thrift::Types::STRUCT, struct) + # all other types are not implemented + [Thrift::Types::STOP, Thrift::Types::VOID, Thrift::Types::MAP, Thrift::Types::SET, Thrift::Types::LIST].each do |type| + expect { @prot.write_type(type, type.to_s) }.to raise_error(NotImplementedError) + end + end + + it 'should write out the different types' do + @prot.should_receive(:write_bool).with('bool').ordered + @prot.should_receive(:write_byte).with('byte').ordered + @prot.should_receive(:write_double).with('double').ordered + @prot.should_receive(:write_i16).with('i16').ordered + @prot.should_receive(:write_i32).with('i32').ordered + @prot.should_receive(:write_i64).with('i64').ordered + @prot.should_receive(:write_string).with('string').ordered + @prot.should_receive(:write_binary).with('binary').ordered + struct = mock('Struct') + struct.should_receive(:write).with(@prot).ordered + @prot.write_type({:type => Thrift::Types::BOOL}, 'bool') + @prot.write_type({:type => Thrift::Types::BYTE}, 'byte') + @prot.write_type({:type => Thrift::Types::DOUBLE}, 'double') + @prot.write_type({:type => Thrift::Types::I16}, 'i16') + @prot.write_type({:type => Thrift::Types::I32}, 'i32') + @prot.write_type({:type => Thrift::Types::I64}, 'i64') + @prot.write_type({:type => Thrift::Types::STRING}, 'string') + @prot.write_type({:type => Thrift::Types::STRING, :binary => true}, 'binary') + @prot.write_type({:type => Thrift::Types::STRUCT}, struct) + # all other types are not implemented + [Thrift::Types::STOP, Thrift::Types::VOID, Thrift::Types::MAP, Thrift::Types::SET, Thrift::Types::LIST].each do |type| + expect { @prot.write_type({:type => type}, type.to_s) }.to raise_error(NotImplementedError) + end + end + + it 'should read the different types (deprecated read_type signature)' do + @prot.should_receive(:read_bool).ordered + @prot.should_receive(:read_byte).ordered + @prot.should_receive(:read_i16).ordered + @prot.should_receive(:read_i32).ordered + @prot.should_receive(:read_i64).ordered + @prot.should_receive(:read_double).ordered + @prot.should_receive(:read_string).ordered + @prot.read_type(Thrift::Types::BOOL) + @prot.read_type(Thrift::Types::BYTE) + @prot.read_type(Thrift::Types::I16) + @prot.read_type(Thrift::Types::I32) + @prot.read_type(Thrift::Types::I64) + @prot.read_type(Thrift::Types::DOUBLE) + @prot.read_type(Thrift::Types::STRING) + # all other types are not implemented + [Thrift::Types::STOP, Thrift::Types::VOID, Thrift::Types::MAP, + Thrift::Types::SET, Thrift::Types::LIST, Thrift::Types::STRUCT].each do |type| + expect { @prot.read_type(type) }.to raise_error(NotImplementedError) + end + end + + it 'should read the different types' do + @prot.should_receive(:read_bool).ordered + @prot.should_receive(:read_byte).ordered + @prot.should_receive(:read_i16).ordered + @prot.should_receive(:read_i32).ordered + @prot.should_receive(:read_i64).ordered + @prot.should_receive(:read_double).ordered + @prot.should_receive(:read_string).ordered + @prot.should_receive(:read_binary).ordered + @prot.read_type({:type => Thrift::Types::BOOL}) + @prot.read_type({:type => Thrift::Types::BYTE}) + @prot.read_type({:type => Thrift::Types::I16}) + @prot.read_type({:type => Thrift::Types::I32}) + @prot.read_type({:type => Thrift::Types::I64}) + @prot.read_type({:type => Thrift::Types::DOUBLE}) + @prot.read_type({:type => Thrift::Types::STRING}) + @prot.read_type({:type => Thrift::Types::STRING, :binary => true}) + # all other types are not implemented + [Thrift::Types::STOP, Thrift::Types::VOID, Thrift::Types::MAP, + Thrift::Types::SET, Thrift::Types::LIST, Thrift::Types::STRUCT].each do |type| + expect { @prot.read_type({:type => type}) }.to raise_error(NotImplementedError) + end + end + + it "should skip the basic types" do + @prot.should_receive(:read_bool).ordered + @prot.should_receive(:read_byte).ordered + @prot.should_receive(:read_i16).ordered + @prot.should_receive(:read_i32).ordered + @prot.should_receive(:read_i64).ordered + @prot.should_receive(:read_double).ordered + @prot.should_receive(:read_string).ordered + @prot.skip(Thrift::Types::BOOL) + @prot.skip(Thrift::Types::BYTE) + @prot.skip(Thrift::Types::I16) + @prot.skip(Thrift::Types::I32) + @prot.skip(Thrift::Types::I64) + @prot.skip(Thrift::Types::DOUBLE) + @prot.skip(Thrift::Types::STRING) + @prot.skip(Thrift::Types::STOP) # should do absolutely nothing + end + + it "should skip structs" do + real_skip = @prot.method(:skip) + @prot.should_receive(:read_struct_begin).ordered + @prot.should_receive(:read_field_begin).exactly(4).times.and_return( + ['field 1', Thrift::Types::STRING, 1], + ['field 2', Thrift::Types::I32, 2], + ['field 3', Thrift::Types::MAP, 3], + [nil, Thrift::Types::STOP, 0] + ) + @prot.should_receive(:read_field_end).exactly(3).times + @prot.should_receive(:read_string).exactly(3).times + @prot.should_receive(:read_i32).ordered + @prot.should_receive(:read_map_begin).ordered.and_return([Thrift::Types::STRING, Thrift::Types::STRING, 1]) + # @prot.should_receive(:read_string).exactly(2).times + @prot.should_receive(:read_map_end).ordered + @prot.should_receive(:read_struct_end).ordered + real_skip.call(Thrift::Types::STRUCT) + end + + it "should skip maps" do + real_skip = @prot.method(:skip) + @prot.should_receive(:read_map_begin).ordered.and_return([Thrift::Types::STRING, Thrift::Types::STRUCT, 1]) + @prot.should_receive(:read_string).ordered + @prot.should_receive(:read_struct_begin).ordered.and_return(["some_struct"]) + @prot.should_receive(:read_field_begin).ordered.and_return([nil, Thrift::Types::STOP, nil]); + @prot.should_receive(:read_struct_end).ordered + @prot.should_receive(:read_map_end).ordered + real_skip.call(Thrift::Types::MAP) + end + + it "should skip sets" do + real_skip = @prot.method(:skip) + @prot.should_receive(:read_set_begin).ordered.and_return([Thrift::Types::I64, 9]) + @prot.should_receive(:read_i64).ordered.exactly(9).times + @prot.should_receive(:read_set_end) + real_skip.call(Thrift::Types::SET) + end + + it "should skip lists" do + real_skip = @prot.method(:skip) + @prot.should_receive(:read_list_begin).ordered.and_return([Thrift::Types::DOUBLE, 11]) + @prot.should_receive(:read_double).ordered.exactly(11).times + @prot.should_receive(:read_list_end) + real_skip.call(Thrift::Types::LIST) + end + end + + describe Thrift::BaseProtocolFactory do + it "should raise NotImplementedError" do + # returning nil since Protocol is just an abstract class + lambda {Thrift::BaseProtocolFactory.new.get_protocol(mock("MockTransport"))}.should raise_error(NotImplementedError) + end + end +end diff --git a/lib/rb/spec/base_transport_spec.rb b/lib/rb/spec/base_transport_spec.rb new file mode 100644 index 0000000..4196572 --- /dev/null +++ b/lib/rb/spec/base_transport_spec.rb @@ -0,0 +1,350 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'BaseTransport' do + + describe Thrift::TransportException do + it "should make type accessible" do + exc = Thrift::TransportException.new(Thrift::TransportException::ALREADY_OPEN, "msg") + exc.type.should == Thrift::TransportException::ALREADY_OPEN + exc.message.should == "msg" + end + end + + describe Thrift::BaseTransport do + it "should read the specified size" do + transport = Thrift::BaseTransport.new + transport.should_receive(:read).with(40).ordered.and_return("10 letters") + transport.should_receive(:read).with(30).ordered.and_return("fifteen letters") + transport.should_receive(:read).with(15).ordered.and_return("more characters") + transport.read_all(40).should == "10 lettersfifteen lettersmore characters" + end + + it "should stub out the rest of the methods" do + # can't test for stubbiness, so just make sure they're defined + [:open?, :open, :close, :read, :write, :flush].each do |sym| + Thrift::BaseTransport.method_defined?(sym).should be_true + end + end + + it "should alias << to write" do + Thrift::BaseTransport.instance_method(:<<).should == Thrift::BaseTransport.instance_method(:write) + end + end + + describe Thrift::BaseServerTransport do + it "should stub out its methods" do + [:listen, :accept, :close].each do |sym| + Thrift::BaseServerTransport.method_defined?(sym).should be_true + end + end + end + + describe Thrift::BaseTransportFactory do + it "should return the transport it's given" do + transport = mock("Transport") + Thrift::BaseTransportFactory.new.get_transport(transport).should eql(transport) + end + end + + describe Thrift::BufferedTransport do + it "should pass through everything but write/flush/read" do + trans = mock("Transport") + trans.should_receive(:open?).ordered.and_return("+ open?") + trans.should_receive(:open).ordered.and_return("+ open") + trans.should_receive(:flush).ordered # from the close + trans.should_receive(:close).ordered.and_return("+ close") + btrans = Thrift::BufferedTransport.new(trans) + btrans.open?.should == "+ open?" + btrans.open.should == "+ open" + btrans.close.should == "+ close" + end + + it "should buffer reads in chunks of #{Thrift::BufferedTransport::DEFAULT_BUFFER}" do + trans = mock("Transport") + trans.should_receive(:read).with(Thrift::BufferedTransport::DEFAULT_BUFFER).and_return("lorum ipsum dolor emet") + btrans = Thrift::BufferedTransport.new(trans) + btrans.read(6).should == "lorum " + btrans.read(6).should == "ipsum " + btrans.read(6).should == "dolor " + btrans.read(6).should == "emet" + end + + it "should buffer writes and send them on flush" do + trans = mock("Transport") + btrans = Thrift::BufferedTransport.new(trans) + btrans.write("one/") + btrans.write("two/") + btrans.write("three/") + trans.should_receive(:write).with("one/two/three/").ordered + trans.should_receive(:flush).ordered + btrans.flush + end + + it "should only send buffered data once" do + trans = mock("Transport") + btrans = Thrift::BufferedTransport.new(trans) + btrans.write("one/") + btrans.write("two/") + btrans.write("three/") + trans.should_receive(:write).with("one/two/three/") + trans.stub!(:flush) + btrans.flush + # Nothing to flush with no data + btrans.flush + end + + it "should flush on close" do + trans = mock("Transport") + trans.should_receive(:close) + btrans = Thrift::BufferedTransport.new(trans) + btrans.should_receive(:flush) + btrans.close + end + + it "should not write to socket if there's no data" do + trans = mock("Transport") + trans.should_receive(:flush) + btrans = Thrift::BufferedTransport.new(trans) + btrans.flush + end + end + + describe Thrift::BufferedTransportFactory do + it "should wrap the given transport in a BufferedTransport" do + trans = mock("Transport") + btrans = mock("BufferedTransport") + Thrift::BufferedTransport.should_receive(:new).with(trans).and_return(btrans) + Thrift::BufferedTransportFactory.new.get_transport(trans).should == btrans + end + end + + describe Thrift::FramedTransport do + before(:each) do + @trans = mock("Transport") + end + + it "should pass through open?/open/close" do + ftrans = Thrift::FramedTransport.new(@trans) + @trans.should_receive(:open?).ordered.and_return("+ open?") + @trans.should_receive(:open).ordered.and_return("+ open") + @trans.should_receive(:close).ordered.and_return("+ close") + ftrans.open?.should == "+ open?" + ftrans.open.should == "+ open" + ftrans.close.should == "+ close" + end + + it "should pass through read when read is turned off" do + ftrans = Thrift::FramedTransport.new(@trans, false, true) + @trans.should_receive(:read).with(17).ordered.and_return("+ read") + ftrans.read(17).should == "+ read" + end + + it "should pass through write/flush when write is turned off" do + ftrans = Thrift::FramedTransport.new(@trans, true, false) + @trans.should_receive(:write).with("foo").ordered.and_return("+ write") + @trans.should_receive(:flush).ordered.and_return("+ flush") + ftrans.write("foo").should == "+ write" + ftrans.flush.should == "+ flush" + end + + it "should return a full frame if asked for >= the frame's length" do + frame = "this is a frame" + @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017") + @trans.should_receive(:read_all).with(frame.length).and_return(frame) + Thrift::FramedTransport.new(@trans).read(frame.length + 10).should == frame + end + + it "should return slices of the frame when asked for < the frame's length" do + frame = "this is a frame" + @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017") + @trans.should_receive(:read_all).with(frame.length).and_return(frame) + ftrans = Thrift::FramedTransport.new(@trans) + ftrans.read(4).should == "this" + ftrans.read(4).should == " is " + ftrans.read(16).should == "a frame" + end + + it "should return nothing if asked for <= 0" do + Thrift::FramedTransport.new(@trans).read(-2).should == "" + end + + it "should pull a new frame when the first is exhausted" do + frame = "this is a frame" + frame2 = "yet another frame" + @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021") + @trans.should_receive(:read_all).with(frame.length).and_return(frame) + @trans.should_receive(:read_all).with(frame2.length).and_return(frame2) + ftrans = Thrift::FramedTransport.new(@trans) + ftrans.read(4).should == "this" + ftrans.read(8).should == " is a fr" + ftrans.read(6).should == "ame" + ftrans.read(4).should == "yet " + ftrans.read(16).should == "another frame" + end + + it "should buffer writes" do + ftrans = Thrift::FramedTransport.new(@trans) + @trans.should_not_receive(:write) + ftrans.write("foo") + ftrans.write("bar") + ftrans.write("this is a frame") + end + + it "should write slices of the buffer" do + ftrans = Thrift::FramedTransport.new(@trans) + ftrans.write("foobar", 3) + ftrans.write("barfoo", 1) + @trans.stub!(:flush) + @trans.should_receive(:write).with("\000\000\000\004foob") + ftrans.flush + end + + it "should flush frames with a 4-byte header" do + ftrans = Thrift::FramedTransport.new(@trans) + @trans.should_receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered + @trans.should_receive(:flush).ordered + ftrans.write("one/") + ftrans.write("two/") + ftrans.write("three/") + ftrans.write("this is a frame") + ftrans.flush + end + + it "should not flush the same buffered data twice" do + ftrans = Thrift::FramedTransport.new(@trans) + @trans.should_receive(:write).with("\000\000\000\007foo/bar") + @trans.stub!(:flush) + ftrans.write("foo") + ftrans.write("/bar") + ftrans.flush + @trans.should_receive(:write).with("\000\000\000\000") + ftrans.flush + end + end + + describe Thrift::FramedTransportFactory do + it "should wrap the given transport in a FramedTransport" do + trans = mock("Transport") + Thrift::FramedTransport.should_receive(:new).with(trans) + Thrift::FramedTransportFactory.new.get_transport(trans) + end + end + + describe Thrift::MemoryBufferTransport do + before(:each) do + @buffer = Thrift::MemoryBufferTransport.new + end + + it "should accept a buffer on input and use it directly" do + s = "this is a test" + @buffer = Thrift::MemoryBufferTransport.new(s) + @buffer.read(4).should == "this" + s.slice!(-4..-1) + @buffer.read(@buffer.available).should == " is a " + end + + it "should always remain open" do + @buffer.should be_open + @buffer.close + @buffer.should be_open + end + + it "should respond to peek and available" do + @buffer.write "some data" + @buffer.peek.should be_true + @buffer.available.should == 9 + @buffer.read(4) + @buffer.peek.should be_true + @buffer.available.should == 5 + @buffer.read(5) + @buffer.peek.should be_false + @buffer.available.should == 0 + end + + it "should be able to reset the buffer" do + @buffer.write "test data" + @buffer.reset_buffer("foobar") + @buffer.available.should == 6 + @buffer.read(@buffer.available).should == "foobar" + @buffer.reset_buffer + @buffer.available.should == 0 + end + + it "should copy the given string when resetting the buffer" do + s = "this is a test" + @buffer.reset_buffer(s) + @buffer.available.should == 14 + @buffer.read(10) + @buffer.available.should == 4 + s.should == "this is a test" + end + + it "should return from read what was given in write" do + @buffer.write "test data" + @buffer.read(4).should == "test" + @buffer.read(@buffer.available).should == " data" + @buffer.write "foo" + @buffer.write " bar" + @buffer.read(@buffer.available).should == "foo bar" + end + + it "should throw an EOFError when there isn't enough data in the buffer" do + @buffer.reset_buffer("") + lambda{@buffer.read(1)}.should raise_error(EOFError) + + @buffer.reset_buffer("1234") + lambda{@buffer.read(5)}.should raise_error(EOFError) + end + end + + describe Thrift::IOStreamTransport do + before(:each) do + @input = mock("Input", :closed? => false) + @output = mock("Output", :closed? => false) + @trans = Thrift::IOStreamTransport.new(@input, @output) + end + + it "should be open as long as both input or output are open" do + @trans.should be_open + @input.stub!(:closed?).and_return(true) + @trans.should be_open + @input.stub!(:closed?).and_return(false) + @output.stub!(:closed?).and_return(true) + @trans.should be_open + @input.stub!(:closed?).and_return(true) + @trans.should_not be_open + end + + it "should pass through read/write to input/output" do + @input.should_receive(:read).with(17).and_return("+ read") + @output.should_receive(:write).with("foobar").and_return("+ write") + @trans.read(17).should == "+ read" + @trans.write("foobar").should == "+ write" + end + + it "should close both input and output when closed" do + @input.should_receive(:close) + @output.should_receive(:close) + @trans.close + end + end +end diff --git a/lib/rb/spec/binary_protocol_accelerated_spec.rb b/lib/rb/spec/binary_protocol_accelerated_spec.rb new file mode 100644 index 0000000..bac9ea7 --- /dev/null +++ b/lib/rb/spec/binary_protocol_accelerated_spec.rb @@ -0,0 +1,42 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' +require File.expand_path("#{File.dirname(__FILE__)}/binary_protocol_spec_shared") + +if defined? Thrift::BinaryProtocolAccelerated + + describe 'BinaryProtocolAccelerated' do + # since BinaryProtocolAccelerated should be directly equivalent to + # BinaryProtocol, we don't need any custom specs! + it_should_behave_like 'a binary protocol' + + def protocol_class + Thrift::BinaryProtocolAccelerated + end + + describe Thrift::BinaryProtocolAcceleratedFactory do + it "should create a BinaryProtocolAccelerated" do + Thrift::BinaryProtocolAcceleratedFactory.new.get_protocol(mock("MockTransport")).should be_instance_of(Thrift::BinaryProtocolAccelerated) + end + end + end +else + puts "skipping BinaryProtocolAccelerated spec because it is not defined." +end \ No newline at end of file diff --git a/lib/rb/spec/binary_protocol_spec.rb b/lib/rb/spec/binary_protocol_spec.rb new file mode 100644 index 0000000..32772d3 --- /dev/null +++ b/lib/rb/spec/binary_protocol_spec.rb @@ -0,0 +1,66 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' +require File.expand_path("#{File.dirname(__FILE__)}/binary_protocol_spec_shared") + +describe 'BinaryProtocol' do + + it_should_behave_like 'a binary protocol' + + def protocol_class + Thrift::BinaryProtocol + end + + describe Thrift::BinaryProtocol do + + before(:each) do + @trans = Thrift::MemoryBufferTransport.new + @prot = protocol_class.new(@trans) + end + + it "should read a message header" do + @trans.write([protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::REPLY].pack('N')) + @trans.write([42].pack('N')) + @prot.should_receive(:read_string).and_return('testMessage') + @prot.read_message_begin.should == ['testMessage', Thrift::MessageTypes::REPLY, 42] + end + + it "should raise an exception if the message header has the wrong version" do + @prot.should_receive(:read_i32).and_return(-1) + lambda { @prot.read_message_begin }.should raise_error(Thrift::ProtocolException, 'Missing version identifier') do |e| + e.type == Thrift::ProtocolException::BAD_VERSION + end + end + + it "should raise an exception if the message header does not exist and strict_read is enabled" do + @prot.should_receive(:read_i32).and_return(42) + @prot.should_receive(:strict_read).and_return(true) + lambda { @prot.read_message_begin }.should raise_error(Thrift::ProtocolException, 'No version identifier, old protocol client?') do |e| + e.type == Thrift::ProtocolException::BAD_VERSION + end + end + end + + describe Thrift::BinaryProtocolFactory do + it "should create a BinaryProtocol" do + Thrift::BinaryProtocolFactory.new.get_protocol(mock("MockTransport")).should be_instance_of(Thrift::BinaryProtocol) + end + end +end diff --git a/lib/rb/spec/binary_protocol_spec_shared.rb b/lib/rb/spec/binary_protocol_spec_shared.rb new file mode 100644 index 0000000..7a9d028 --- /dev/null +++ b/lib/rb/spec/binary_protocol_spec_shared.rb @@ -0,0 +1,455 @@ +# encoding: ascii-8bit +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +shared_examples_for 'a binary protocol' do + before(:each) do + @trans = Thrift::MemoryBufferTransport.new + @prot = protocol_class.new(@trans) + end + + it "should define the proper VERSION_1, VERSION_MASK AND TYPE_MASK" do + protocol_class.const_get(:VERSION_MASK).should == 0xffff0000 + protocol_class.const_get(:VERSION_1).should == 0x80010000 + protocol_class.const_get(:TYPE_MASK).should == 0x000000ff + end + + it "should make strict_read readable" do + @prot.strict_read.should eql(true) + end + + it "should make strict_write readable" do + @prot.strict_write.should eql(true) + end + + it "should write the message header" do + @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17) + @trans.read(@trans.available).should == [protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::CALL, "testMessage".size, "testMessage", 17].pack("NNa11N") + end + + it "should write the message header without version when writes are not strict" do + @prot = protocol_class.new(@trans, true, false) # no strict write + @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17) + @trans.read(@trans.available).should == "\000\000\000\vtestMessage\001\000\000\000\021" + end + + it "should write the message header with a version when writes are strict" do + @prot = protocol_class.new(@trans) # strict write + @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17) + @trans.read(@trans.available).should == "\200\001\000\001\000\000\000\vtestMessage\000\000\000\021" + end + + + # message footer is a noop + + it "should write the field header" do + @prot.write_field_begin('foo', Thrift::Types::DOUBLE, 3) + @trans.read(@trans.available).should == [Thrift::Types::DOUBLE, 3].pack("cn") + end + + # field footer is a noop + + it "should write the STOP field" do + @prot.write_field_stop + @trans.read(1).should == "\000" + end + + it "should write the map header" do + @prot.write_map_begin(Thrift::Types::STRING, Thrift::Types::LIST, 17) + @trans.read(@trans.available).should == [Thrift::Types::STRING, Thrift::Types::LIST, 17].pack("ccN"); + end + + # map footer is a noop + + it "should write the list header" do + @prot.write_list_begin(Thrift::Types::I16, 42) + @trans.read(@trans.available).should == [Thrift::Types::I16, 42].pack("cN") + end + + # list footer is a noop + + it "should write the set header" do + @prot.write_set_begin(Thrift::Types::I16, 42) + @trans.read(@trans.available).should == [Thrift::Types::I16, 42].pack("cN") + end + + it "should write a bool" do + @prot.write_bool(true) + @prot.write_bool(false) + @trans.read(@trans.available).should == "\001\000" + end + + it "should treat a nil bool as false" do + @prot.write_bool(nil) + @trans.read(1).should == "\000" + end + + it "should write a byte" do + # byte is small enough, let's check -128..127 + (-128..127).each do |i| + @prot.write_byte(i) + @trans.read(1).should == [i].pack('c') + end + # handing it numbers out of signed range should clip + @trans.rspec_verify + (128..255).each do |i| + @prot.write_byte(i) + @trans.read(1).should == [i].pack('c') + end + # and lastly, a Bignum is going to error out + lambda { @prot.write_byte(2**65) }.should raise_error(RangeError) + end + + it "should error gracefully when trying to write a nil byte" do + lambda { @prot.write_byte(nil) }.should raise_error + end + + it "should write an i16" do + # try a random scattering of values + # include the signed i16 minimum/maximum + [-2**15, -1024, 17, 0, -10000, 1723, 2**15-1].each do |i| + @prot.write_i16(i) + end + # and try something out of signed range, it should clip + @prot.write_i16(2**15 + 5) + + @trans.read(@trans.available).should == "\200\000\374\000\000\021\000\000\330\360\006\273\177\377\200\005" + + # a Bignum should error + # lambda { @prot.write_i16(2**65) }.should raise_error(RangeError) + end + + it "should error gracefully when trying to write a nil i16" do + lambda { @prot.write_i16(nil) }.should raise_error + end + + it "should write an i32" do + # try a random scattering of values + # include the signed i32 minimum/maximum + [-2**31, -123123, -2532, -3, 0, 2351235, 12331, 2**31-1].each do |i| + @prot.write_i32(i) + end + # try something out of signed range, it should clip + @trans.read(@trans.available).should == "\200\000\000\000" + "\377\376\037\r" + "\377\377\366\034" + "\377\377\377\375" + "\000\000\000\000" + "\000#\340\203" + "\000\0000+" + "\177\377\377\377" + [2 ** 31 + 5, 2 ** 65 + 5].each do |i| + lambda { @prot.write_i32(i) }.should raise_error(RangeError) + end + end + + it "should error gracefully when trying to write a nil i32" do + lambda { @prot.write_i32(nil) }.should raise_error + end + + it "should write an i64" do + # try a random scattering of values + # try the signed i64 minimum/maximum + [-2**63, -12356123612323, -23512351, -234, 0, 1231, 2351236, 12361236213, 2**63-1].each do |i| + @prot.write_i64(i) + end + # try something out of signed range, it should clip + @trans.read(@trans.available).should == ["\200\000\000\000\000\000\000\000", + "\377\377\364\303\035\244+]", + "\377\377\377\377\376\231:\341", + "\377\377\377\377\377\377\377\026", + "\000\000\000\000\000\000\000\000", + "\000\000\000\000\000\000\004\317", + "\000\000\000\000\000#\340\204", + "\000\000\000\002\340\311~\365", + "\177\377\377\377\377\377\377\377"].join("") + lambda { @prot.write_i64(2 ** 65 + 5) }.should raise_error(RangeError) + end + + it "should error gracefully when trying to write a nil i64" do + lambda { @prot.write_i64(nil) }.should raise_error + end + + it "should write a double" do + # try a random scattering of values, including min/max + values = [Float::MIN,-1231.15325, -123123.23, -23.23515123, 0, 12351.1325, 523.23, Float::MAX] + values.each do |f| + @prot.write_double(f) + @trans.read(@trans.available).should == [f].pack("G") + end + end + + it "should error gracefully when trying to write a nil double" do + lambda { @prot.write_double(nil) }.should raise_error + end + + if RUBY_VERSION >= '1.9' + it 'should write a string' do + str = 'abc' + @prot.write_string(str) + a = @trans.read(@trans.available) + a.encoding.should == Encoding::BINARY + a.unpack('C*').should == [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63] + end + + it 'should write a string with unicode characters' do + str = "abc \u20AC \u20AD".encode('UTF-8') + @prot.write_string(str) + a = @trans.read(@trans.available) + a.encoding.should == Encoding::BINARY + a.unpack('C*').should == [0x00, 0x00, 0x00, 0x0B, 0x61, 0x62, 0x63, 0x20, + 0xE2, 0x82, 0xAC, 0x20, 0xE2, 0x82, 0xAD] + end + + it 'should write should write a string with unicode characters and transcoding' do + str = "abc \u20AC".encode('ISO-8859-15') + @prot.write_string(str) + a = @trans.read(@trans.available) + a.encoding.should == Encoding::BINARY + a.unpack('C*').should == [0x00, 0x00, 0x00, 0x07, 0x61, 0x62, 0x63, 0x20, 0xE2, 0x82, 0xAC] + end + + it 'should write a binary string' do + buffer = [0, 1, 2, 3].pack('C*') + @prot.write_binary(buffer) + a = @trans.read(@trans.available) + a.encoding.should == Encoding::BINARY + a.unpack('C*').should == [0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03] + end + else + it 'should write a string' do + str = 'abc' + @prot.write_string(str) + a = @trans.read(@trans.available) + a.unpack('C*').should == [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63] + end + + it 'should write a binary string' do + buffer = [0, 1, 2, 3].pack('C*') + @prot.write_binary(buffer) + a = @trans.read(@trans.available) + a.unpack('C*').should == [0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03] + end + end + + it "should error gracefully when trying to write a nil string" do + lambda { @prot.write_string(nil) }.should raise_error + end + + it "should write the message header without version when writes are not strict" do + @prot = protocol_class.new(@trans, true, false) # no strict write + @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17) + @trans.read(@trans.available).should == "\000\000\000\vtestMessage\001\000\000\000\021" + end + + it "should write the message header with a version when writes are strict" do + @prot = protocol_class.new(@trans) # strict write + @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17) + @trans.read(@trans.available).should == "\200\001\000\001\000\000\000\vtestMessage\000\000\000\021" + end + + # message footer is a noop + + it "should read a field header" do + @trans.write([Thrift::Types::STRING, 3].pack("cn")) + @prot.read_field_begin.should == [nil, Thrift::Types::STRING, 3] + end + + # field footer is a noop + + it "should read a stop field" do + @trans.write([Thrift::Types::STOP].pack("c")); + @prot.read_field_begin.should == [nil, Thrift::Types::STOP, 0] + end + + it "should read a map header" do + @trans.write([Thrift::Types::DOUBLE, Thrift::Types::I64, 42].pack("ccN")) + @prot.read_map_begin.should == [Thrift::Types::DOUBLE, Thrift::Types::I64, 42] + end + + # map footer is a noop + + it "should read a list header" do + @trans.write([Thrift::Types::STRING, 17].pack("cN")) + @prot.read_list_begin.should == [Thrift::Types::STRING, 17] + end + + # list footer is a noop + + it "should read a set header" do + @trans.write([Thrift::Types::STRING, 17].pack("cN")) + @prot.read_set_begin.should == [Thrift::Types::STRING, 17] + end + + # set footer is a noop + + it "should read a bool" do + @trans.write("\001\000"); + @prot.read_bool.should == true + @prot.read_bool.should == false + end + + it "should read a byte" do + [-128, -57, -3, 0, 17, 24, 127].each do |i| + @trans.write([i].pack("c")) + @prot.read_byte.should == i + end + end + + it "should read an i16" do + # try a scattering of values, including min/max + [-2**15, -5237, -353, 0, 1527, 2234, 2**15-1].each do |i| + @trans.write([i].pack("n")); + @prot.read_i16.should == i + end + end + + it "should read an i32" do + # try a scattering of values, including min/max + [-2**31, -235125, -6236, 0, 2351, 123123, 2**31-1].each do |i| + @trans.write([i].pack("N")) + @prot.read_i32.should == i + end + end + + it "should read an i64" do + # try a scattering of values, including min/max + [-2**63, -123512312, -6346, 0, 32, 2346322323, 2**63-1].each do |i| + @trans.write([i >> 32, i & 0xFFFFFFFF].pack("NN")) + @prot.read_i64.should == i + end + end + + it "should read a double" do + # try a random scattering of values, including min/max + [Float::MIN, -231231.12351, -323.233513, 0, 123.2351235, 2351235.12351235, Float::MAX].each do |f| + @trans.write([f].pack("G")); + @prot.read_double.should == f + end + end + + if RUBY_VERSION >= '1.9' + it 'should read a string' do + # i32 of value 3, followed by three characters/UTF-8 bytes 'a', 'b', 'c' + buffer = [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63].pack('C*') + @trans.write(buffer) + a = @prot.read_string + a.should == 'abc'.encode('UTF-8') + a.encoding.should == Encoding::UTF_8 + end + + it 'should read a string containing unicode characters from UTF-8 encoded buffer' do + # i32 of value 3, followed by one character U+20AC made up of three bytes + buffer = [0x00, 0x00, 0x00, 0x03, 0xE2, 0x82, 0xAC].pack('C*') + @trans.write(buffer) + a = @prot.read_string + a.should == "\u20AC".encode('UTF-8') + a.encoding.should == Encoding::UTF_8 + end + + it 'should read a binary string' do + buffer = [0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03].pack('C*') + @trans.write(buffer) + a = @prot.read_binary + a.should == [0x00, 0x01, 0x02, 0x03].pack('C*') + a.encoding.should == Encoding::BINARY + end + else + it 'should read a string' do + # i32 of value 3, followed by three characters/UTF-8 bytes 'a', 'b', 'c' + buffer = [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63].pack('C*') + @trans.write(buffer) + @prot.read_string.should == 'abc' + end + + it 'should read a binary string' do + buffer = [0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03].pack('C*') + @trans.write(buffer) + a = @prot.read_binary + a.should == [0x00, 0x01, 0x02, 0x03].pack('C*') + end + end + + it "should perform a complete rpc with no args or return" do + srv_test( + proc {|client| client.send_voidMethod()}, + proc {|client| client.recv_voidMethod.should == nil} + ) + end + + it "should perform a complete rpc with a primitive return type" do + srv_test( + proc {|client| client.send_primitiveMethod()}, + proc {|client| client.recv_primitiveMethod.should == 1} + ) + end + + it "should perform a complete rpc with a struct return type" do + srv_test( + proc {|client| client.send_structMethod()}, + proc {|client| + result = client.recv_structMethod + result.set_byte_map = nil + result.map_byte_map = nil + result.should == Fixtures::COMPACT_PROTOCOL_TEST_STRUCT + } + ) + end + + def get_socket_connection + server = Thrift::ServerSocket.new("localhost", 9090) + server.listen + + clientside = Thrift::Socket.new("localhost", 9090) + clientside.open + serverside = server.accept + [clientside, serverside, server] + end + + def srv_test(firstblock, secondblock) + clientside, serverside, server = get_socket_connection + + clientproto = protocol_class.new(clientside) + serverproto = protocol_class.new(serverside) + + processor = Thrift::Test::Srv::Processor.new(SrvHandler.new) + + client = Thrift::Test::Srv::Client.new(clientproto, clientproto) + + # first block + firstblock.call(client) + + processor.process(serverproto, serverproto) + + # second block + secondblock.call(client) + ensure + clientside.close + serverside.close + server.close + end + + class SrvHandler + def voidMethod() + end + + def primitiveMethod + 1 + end + + def structMethod + Fixtures::COMPACT_PROTOCOL_TEST_STRUCT + end + end +end diff --git a/lib/rb/spec/bytes_spec.rb b/lib/rb/spec/bytes_spec.rb new file mode 100644 index 0000000..b82e304 --- /dev/null +++ b/lib/rb/spec/bytes_spec.rb @@ -0,0 +1,160 @@ +# encoding: UTF-8 +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe Thrift::Bytes do + if RUBY_VERSION >= '1.9' + describe '.empty_byte_buffer' do + it 'should create an empty buffer' do + b = Thrift::Bytes.empty_byte_buffer + b.length.should == 0 + b.encoding.should == Encoding::BINARY + end + + it 'should create an empty buffer of given size' do + b = Thrift::Bytes.empty_byte_buffer 2 + b.length.should == 2 + b.getbyte(0).should == 0 + b.getbyte(1).should == 0 + b.encoding.should == Encoding::BINARY + end + end + + describe '.force_binary_encoding' do + it 'should change encoding' do + e = 'STRING'.encode('UTF-8') + e.encoding.should_not == Encoding::BINARY + a = Thrift::Bytes.force_binary_encoding e + a.encoding.should == Encoding::BINARY + end + end + + describe '.get_string_byte' do + it 'should get the byte at index' do + s = "\x41\x42" + Thrift::Bytes.get_string_byte(s, 0).should == 0x41 + Thrift::Bytes.get_string_byte(s, 1).should == 0x42 + end + end + + describe '.set_string_byte' do + it 'should set byte value at index' do + s = "\x41\x42" + Thrift::Bytes.set_string_byte(s, 0, 0x43) + s.getbyte(0).should == 0x43 + s.should == 'CB' + end + end + + describe '.convert_to_utf8_byte_buffer' do + it 'should convert UTF-8 String to byte buffer' do + e = "\u20AC".encode('UTF-8') # a string with euro sign character U+20AC + e.length.should == 1 + + a = Thrift::Bytes.convert_to_utf8_byte_buffer e + a.encoding.should == Encoding::BINARY + a.length.should == 3 + a.unpack('C*').should == [0xE2, 0x82, 0xAC] + end + + it 'should convert ISO-8859-15 String to UTF-8 byte buffer' do + # Assumptions + e = "\u20AC".encode('ISO-8859-15') # a string with euro sign character U+20AC, then converted to ISO-8859-15 + e.length.should == 1 + e.unpack('C*').should == [0xA4] # euro sign is a different code point in ISO-8859-15 + + a = Thrift::Bytes.convert_to_utf8_byte_buffer e + a.encoding.should == Encoding::BINARY + a.length.should == 3 + a.unpack('C*').should == [0xE2, 0x82, 0xAC] + end + end + + describe '.convert_to_string' do + it 'should convert UTF-8 byte buffer to a UTF-8 String' do + e = [0xE2, 0x82, 0xAC].pack("C*") + e.encoding.should == Encoding::BINARY + a = Thrift::Bytes.convert_to_string e + a.encoding.should == Encoding::UTF_8 + a.should == "\u20AC" + end + end + + else # RUBY_VERSION + describe '.empty_byte_buffer' do + it 'should create an empty buffer' do + b = Thrift::Bytes.empty_byte_buffer + b.length.should == 0 + end + + it 'should create an empty buffer of given size' do + b = Thrift::Bytes.empty_byte_buffer 2 + b.length.should == 2 + b[0].should == 0 + b[1].should == 0 + end + end + + describe '.force_binary_encoding' do + it 'should be a no-op' do + e = 'STRING' + a = Thrift::Bytes.force_binary_encoding e + a.should == e + a.should be(e) + end + end + + describe '.get_string_byte' do + it 'should get the byte at index' do + s = "\x41\x42" + Thrift::Bytes.get_string_byte(s, 0).should == 0x41 + Thrift::Bytes.get_string_byte(s, 1).should == 0x42 + end + end + + describe '.set_string_byte' do + it 'should set byte value at index' do + s = "\x41\x42" + Thrift::Bytes.set_string_byte(s, 0, 0x43) + s[0].should == 0x43 + s.should == 'CB' + end + end + + describe '.convert_to_utf8_byte_buffer' do + it 'should be a no-op' do + e = 'STRING' + a = Thrift::Bytes.convert_to_utf8_byte_buffer e + a.should == e + a.should be(e) + end + end + + describe '.convert_to_string' do + it 'should be a no-op' do + e = 'STRING' + a = Thrift::Bytes.convert_to_string e + a.should == e + a.should be(e) + end + end + end +end diff --git a/lib/rb/spec/client_spec.rb b/lib/rb/spec/client_spec.rb new file mode 100644 index 0000000..f8ffe8a --- /dev/null +++ b/lib/rb/spec/client_spec.rb @@ -0,0 +1,99 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'Client' do + + class ClientSpec + include Thrift::Client + end + + before(:each) do + @prot = mock("MockProtocol") + @client = ClientSpec.new(@prot) + end + + describe Thrift::Client do + it "should re-use iprot for oprot if not otherwise specified" do + @client.instance_variable_get(:'@iprot').should eql(@prot) + @client.instance_variable_get(:'@oprot').should eql(@prot) + end + + it "should send a test message" do + @prot.should_receive(:write_message_begin).with('testMessage', Thrift::MessageTypes::CALL, 0) + mock_args = mock('#') + mock_args.should_receive(:foo=).with('foo') + mock_args.should_receive(:bar=).with(42) + mock_args.should_receive(:write).with(@prot) + @prot.should_receive(:write_message_end) + @prot.should_receive(:trans) do + mock('trans').tap do |trans| + trans.should_receive(:flush) + end + end + klass = stub("TestMessage_args", :new => mock_args) + @client.send_message('testMessage', klass, :foo => 'foo', :bar => 42) + end + + it "should increment the sequence id when sending messages" do + pending "it seems sequence ids are completely ignored right now" do + @prot.should_receive(:write_message_begin).with('testMessage', Thrift::MessageTypes::CALL, 0).ordered + @prot.should_receive(:write_message_begin).with('testMessage2', Thrift::MessageTypes::CALL, 1).ordered + @prot.should_receive(:write_message_begin).with('testMessage3', Thrift::MessageTypes::CALL, 2).ordered + @prot.stub!(:write_message_end) + @prot.stub!(:trans).and_return mock("trans").as_null_object + @client.send_message('testMessage', mock("args class").as_null_object) + @client.send_message('testMessage2', mock("args class").as_null_object) + @client.send_message('testMessage3', mock("args class").as_null_object) + end + end + + it "should receive a test message" do + @prot.should_receive(:read_message_begin).and_return [nil, Thrift::MessageTypes::CALL, 0] + @prot.should_receive(:read_message_end) + mock_klass = mock("#") + mock_klass.should_receive(:read).with(@prot) + @client.receive_message(stub("MockClass", :new => mock_klass)) + end + + it "should handle received exceptions" do + @prot.should_receive(:read_message_begin).and_return [nil, Thrift::MessageTypes::EXCEPTION, 0] + @prot.should_receive(:read_message_end) + Thrift::ApplicationException.should_receive(:new).and_return do + StandardError.new.tap do |mock_exc| + mock_exc.should_receive(:read).with(@prot) + end + end + lambda { @client.receive_message(nil) }.should raise_error(StandardError) + end + + it "should close the transport if an error occurs while sending a message" do + @prot.stub!(:write_message_begin) + @prot.should_not_receive(:write_message_end) + mock_args = mock("#") + mock_args.should_receive(:write).with(@prot).and_raise(StandardError) + trans = mock("MockTransport") + @prot.stub!(:trans).and_return(trans) + trans.should_receive(:close) + klass = mock("TestMessage_args", :new => mock_args) + lambda { @client.send_message("testMessage", klass) }.should raise_error(StandardError) + end + end +end diff --git a/lib/rb/spec/compact_protocol_spec.rb b/lib/rb/spec/compact_protocol_spec.rb new file mode 100644 index 0000000..8a1a228 --- /dev/null +++ b/lib/rb/spec/compact_protocol_spec.rb @@ -0,0 +1,143 @@ +# encoding: UTF-8 +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe Thrift::CompactProtocol do + TESTS = { + :byte => (-127..127).to_a, + :i16 => (0..14).map {|shift| [1 << shift, -(1 << shift)]}.flatten.sort, + :i32 => (0..30).map {|shift| [1 << shift, -(1 << shift)]}.flatten.sort, + :i64 => (0..62).map {|shift| [1 << shift, -(1 << shift)]}.flatten.sort, + :string => ["", "1", "short", "fourteen123456", "fifteen12345678", "unicode characters: \u20AC \u20AD", "1" * 127, "1" * 3000], + :binary => ["", "\001", "\001" * 5, "\001" * 14, "\001" * 15, "\001" * 127, "\001" * 3000], + :double => [0.0, 1.0, -1.0, 1.1, -1.1, 10000000.1, 1.0/0.0, -1.0/0.0], + :bool => [true, false] + } + + it "should encode and decode naked primitives correctly" do + TESTS.each_pair do |primitive_type, test_values| + test_values.each do |value| + # puts "testing #{value}" if primitive_type == :i64 + trans = Thrift::MemoryBufferTransport.new + proto = Thrift::CompactProtocol.new(trans) + + proto.send(writer(primitive_type), value) + # puts "buf: #{trans.inspect_buffer}" if primitive_type == :i64 + read_back = proto.send(reader(primitive_type)) + read_back.should == value + end + end + end + + it "should encode and decode primitives in fields correctly" do + TESTS.each_pair do |primitive_type, test_values| + final_primitive_type = primitive_type == :binary ? :string : primitive_type + thrift_type = Thrift::Types.const_get(final_primitive_type.to_s.upcase) + # puts primitive_type + test_values.each do |value| + trans = Thrift::MemoryBufferTransport.new + proto = Thrift::CompactProtocol.new(trans) + + proto.write_field_begin(nil, thrift_type, 15) + proto.send(writer(primitive_type), value) + proto.write_field_end + + proto = Thrift::CompactProtocol.new(trans) + name, type, id = proto.read_field_begin + type.should == thrift_type + id.should == 15 + read_back = proto.send(reader(primitive_type)) + read_back.should == value + proto.read_field_end + end + end + end + + it "should encode and decode a monster struct correctly" do + trans = Thrift::MemoryBufferTransport.new + proto = Thrift::CompactProtocol.new(trans) + + struct = Thrift::Test::CompactProtoTestStruct.new + # sets and maps don't hash well... not sure what to do here. + struct.write(proto) + + struct2 = Thrift::Test::CompactProtoTestStruct.new + struct2.read(proto) + struct2.should == struct + end + + it "should make method calls correctly" do + client_out_trans = Thrift::MemoryBufferTransport.new + client_out_proto = Thrift::CompactProtocol.new(client_out_trans) + + client_in_trans = Thrift::MemoryBufferTransport.new + client_in_proto = Thrift::CompactProtocol.new(client_in_trans) + + processor = Thrift::Test::Srv::Processor.new(JankyHandler.new) + + client = Thrift::Test::Srv::Client.new(client_in_proto, client_out_proto) + client.send_Janky(1) + # puts client_out_trans.inspect_buffer + processor.process(client_out_proto, client_in_proto) + client.recv_Janky.should == 2 + end + + it "should deal with fields following fields that have non-delta ids" do + brcp = Thrift::Test::BreaksRubyCompactProtocol.new( + :field1 => "blah", + :field2 => Thrift::Test::BigFieldIdStruct.new( + :field1 => "string1", + :field2 => "string2"), + :field3 => 3) + ser = Thrift::Serializer.new(Thrift::CompactProtocolFactory.new) + bytes = ser.serialize(brcp) + + deser = Thrift::Deserializer.new(Thrift::CompactProtocolFactory.new) + brcp2 = Thrift::Test::BreaksRubyCompactProtocol.new + deser.deserialize(brcp2, bytes) + brcp2.should == brcp + end + + it "should deserialize an empty map to an empty hash" do + struct = Thrift::Test::SingleMapTestStruct.new(:i32_map => {}) + ser = Thrift::Serializer.new(Thrift::CompactProtocolFactory.new) + bytes = ser.serialize(struct) + + deser = Thrift::Deserializer.new(Thrift::CompactProtocolFactory.new) + struct2 = Thrift::Test::SingleMapTestStruct.new + deser.deserialize(struct2, bytes) + struct.should == struct2 + end + + class JankyHandler + def Janky(i32arg) + i32arg * 2 + end + end + + def writer(sym) + "write_#{sym.to_s}" + end + + def reader(sym) + "read_#{sym.to_s}" + end +end diff --git a/lib/rb/spec/exception_spec.rb b/lib/rb/spec/exception_spec.rb new file mode 100644 index 0000000..d1da621 --- /dev/null +++ b/lib/rb/spec/exception_spec.rb @@ -0,0 +1,141 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'Exception' do + + describe Thrift::Exception do + it "should have an accessible message" do + e = Thrift::Exception.new("test message") + e.message.should == "test message" + end + end + + describe Thrift::ApplicationException do + it "should inherit from Thrift::Exception" do + Thrift::ApplicationException.superclass.should == Thrift::Exception + end + + it "should have an accessible type and message" do + e = Thrift::ApplicationException.new + e.type.should == Thrift::ApplicationException::UNKNOWN + e.message.should be_nil + e = Thrift::ApplicationException.new(Thrift::ApplicationException::UNKNOWN_METHOD, "test message") + e.type.should == Thrift::ApplicationException::UNKNOWN_METHOD + e.message.should == "test message" + end + + it "should read a struct off of a protocol" do + prot = mock("MockProtocol") + prot.should_receive(:read_struct_begin).ordered + prot.should_receive(:read_field_begin).exactly(3).times.and_return( + ["message", Thrift::Types::STRING, 1], + ["type", Thrift::Types::I32, 2], + [nil, Thrift::Types::STOP, 0] + ) + prot.should_receive(:read_string).ordered.and_return "test message" + prot.should_receive(:read_i32).ordered.and_return Thrift::ApplicationException::BAD_SEQUENCE_ID + prot.should_receive(:read_field_end).exactly(2).times + prot.should_receive(:read_struct_end).ordered + + e = Thrift::ApplicationException.new + e.read(prot) + e.message.should == "test message" + e.type.should == Thrift::ApplicationException::BAD_SEQUENCE_ID + end + + it "should skip bad fields when reading a struct" do + prot = mock("MockProtocol") + prot.should_receive(:read_struct_begin).ordered + prot.should_receive(:read_field_begin).exactly(5).times.and_return( + ["type", Thrift::Types::I32, 2], + ["type", Thrift::Types::STRING, 2], + ["message", Thrift::Types::MAP, 1], + ["message", Thrift::Types::STRING, 3], + [nil, Thrift::Types::STOP, 0] + ) + prot.should_receive(:read_i32).and_return Thrift::ApplicationException::INVALID_MESSAGE_TYPE + prot.should_receive(:skip).with(Thrift::Types::STRING).twice + prot.should_receive(:skip).with(Thrift::Types::MAP) + prot.should_receive(:read_field_end).exactly(4).times + prot.should_receive(:read_struct_end).ordered + + e = Thrift::ApplicationException.new + e.read(prot) + e.message.should be_nil + e.type.should == Thrift::ApplicationException::INVALID_MESSAGE_TYPE + end + + it "should write a Thrift::ApplicationException struct to the oprot" do + prot = mock("MockProtocol") + prot.should_receive(:write_struct_begin).with("Thrift::ApplicationException").ordered + prot.should_receive(:write_field_begin).with("message", Thrift::Types::STRING, 1).ordered + prot.should_receive(:write_string).with("test message").ordered + prot.should_receive(:write_field_begin).with("type", Thrift::Types::I32, 2).ordered + prot.should_receive(:write_i32).with(Thrift::ApplicationException::UNKNOWN_METHOD).ordered + prot.should_receive(:write_field_end).twice + prot.should_receive(:write_field_stop).ordered + prot.should_receive(:write_struct_end).ordered + + e = Thrift::ApplicationException.new(Thrift::ApplicationException::UNKNOWN_METHOD, "test message") + e.write(prot) + end + + it "should skip nil fields when writing to the oprot" do + prot = mock("MockProtocol") + prot.should_receive(:write_struct_begin).with("Thrift::ApplicationException").ordered + prot.should_receive(:write_field_begin).with("message", Thrift::Types::STRING, 1).ordered + prot.should_receive(:write_string).with("test message").ordered + prot.should_receive(:write_field_end).ordered + prot.should_receive(:write_field_stop).ordered + prot.should_receive(:write_struct_end).ordered + + e = Thrift::ApplicationException.new(nil, "test message") + e.write(prot) + + prot = mock("MockProtocol") + prot.should_receive(:write_struct_begin).with("Thrift::ApplicationException").ordered + prot.should_receive(:write_field_begin).with("type", Thrift::Types::I32, 2).ordered + prot.should_receive(:write_i32).with(Thrift::ApplicationException::BAD_SEQUENCE_ID).ordered + prot.should_receive(:write_field_end).ordered + prot.should_receive(:write_field_stop).ordered + prot.should_receive(:write_struct_end).ordered + + e = Thrift::ApplicationException.new(Thrift::ApplicationException::BAD_SEQUENCE_ID) + e.write(prot) + + prot = mock("MockProtocol") + prot.should_receive(:write_struct_begin).with("Thrift::ApplicationException").ordered + prot.should_receive(:write_field_stop).ordered + prot.should_receive(:write_struct_end).ordered + + e = Thrift::ApplicationException.new(nil) + e.write(prot) + end + end + + describe Thrift::ProtocolException do + it "should have an accessible type" do + prot = Thrift::ProtocolException.new(Thrift::ProtocolException::SIZE_LIMIT, "message") + prot.type.should == Thrift::ProtocolException::SIZE_LIMIT + prot.message.should == "message" + end + end +end diff --git a/lib/rb/spec/flat_spec.rb b/lib/rb/spec/flat_spec.rb new file mode 100644 index 0000000..f378782 --- /dev/null +++ b/lib/rb/spec/flat_spec.rb @@ -0,0 +1,62 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'generation' do + before do + require 'namespaced_nonblocking_service' + end + + it "did not generate the wrong files" do + prefix = File.expand_path("../gen-rb/flat", __FILE__) + ["namespaced_spec_namespace/namespaced_nonblocking_service.rb", + "namespaced_spec_namespace/thrift_namespaced_spec_constants.rb", + "namespaced_spec_namespace/thrift_namespaced_spec_types.rb", + "other_namespace/referenced_constants.rb", + "other_namespace/referenced_types.rb" + ].each do |name| + File.exist?(File.join(prefix, name)).should_not be_true + end + end + + it "generated the right files" do + prefix = File.expand_path("../gen-rb/flat", __FILE__) + ["namespaced_nonblocking_service.rb", + "thrift_namespaced_spec_constants.rb", + "thrift_namespaced_spec_types.rb", + "referenced_constants.rb", + "referenced_types.rb" + ].each do |name| + File.exist?(File.join(prefix, name)).should be_true + end + end + + it "has a service class in the right place" do + defined?(NamespacedSpecNamespace::NamespacedNonblockingService).should be_true + end + + it "has a struct in the right place" do + defined?(NamespacedSpecNamespace::Hello).should be_true + end + + it "required an included file" do + defined?(OtherNamespace::SomeEnum).should be_true + end +end diff --git a/lib/rb/spec/http_client_spec.rb b/lib/rb/spec/http_client_spec.rb new file mode 100644 index 0000000..5e8da24 --- /dev/null +++ b/lib/rb/spec/http_client_spec.rb @@ -0,0 +1,135 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'Thrift::HTTPClientTransport' do + + describe Thrift::HTTPClientTransport do + before(:each) do + @client = Thrift::HTTPClientTransport.new("http://my.domain.com/path/to/service?param=value") + end + + it "should always be open" do + @client.should be_open + @client.close + @client.should be_open + end + + it "should post via HTTP and return the results" do + @client.write "a test" + @client.write " frame" + Net::HTTP.should_receive(:new).with("my.domain.com", 80).and_return do + mock("Net::HTTP").tap do |http| + http.should_receive(:use_ssl=).with(false) + http.should_receive(:post).with("/path/to/service?param=value", "a test frame", {"Content-Type"=>"application/x-thrift"}).and_return do + mock("Net::HTTPOK").tap do |response| + response.should_receive(:body).and_return "data" + end + end + end + end + @client.flush + @client.read(10).should == "data" + end + + it "should send custom headers if defined" do + @client.write "test" + custom_headers = {"Cookie" => "Foo"} + headers = {"Content-Type"=>"application/x-thrift"}.merge(custom_headers) + + @client.add_headers(custom_headers) + Net::HTTP.should_receive(:new).with("my.domain.com", 80).and_return do + mock("Net::HTTP").tap do |http| + http.should_receive(:use_ssl=).with(false) + http.should_receive(:post).with("/path/to/service?param=value", "test", headers).and_return do + mock("Net::HTTPOK").tap do |response| + response.should_receive(:body).and_return "data" + end + end + end + end + @client.flush + end + + it 'should reset the outbuf on HTTP failures' do + @client.write "test" + + Net::HTTP.should_receive(:new).with("my.domain.com", 80).and_return do + mock("Net::HTTP").tap do |http| + http.should_receive(:use_ssl=).with(false) + http.should_receive(:post).with("/path/to/service?param=value", "test", {"Content-Type"=>"application/x-thrift"}) { raise Net::ReadTimeout } + end + end + + @client.flush rescue + @client.instance_variable_get(:@outbuf).should eq(Thrift::Bytes.empty_byte_buffer) + end + + end + + describe 'ssl enabled' do + before(:each) do + @service_path = "/path/to/service?param=value" + @server_uri = "https://my.domain.com" + end + + it "should use SSL for https" do + client = Thrift::HTTPClientTransport.new("#{@server_uri}#{@service_path}") + + client.write "test" + + Net::HTTP.should_receive(:new).with("my.domain.com", 443).and_return do + mock("Net::HTTP").tap do |http| + http.should_receive(:use_ssl=).with(true) + http.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER) + http.should_receive(:post).with(@service_path, "test", + "Content-Type" => "application/x-thrift").and_return do + mock("Net::HTTPOK").tap do |response| + response.should_receive(:body).and_return "data" + end + end + end + end + client.flush + client.read(4).should == "data" + end + + it "should set SSL verify mode when specified" do + client = Thrift::HTTPClientTransport.new("#{@server_uri}#{@service_path}", + :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE) + + client.write "test" + Net::HTTP.should_receive(:new).with("my.domain.com", 443).and_return do + mock("Net::HTTP").tap do |http| + http.should_receive(:use_ssl=).with(true) + http.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE) + http.should_receive(:post).with(@service_path, "test", + "Content-Type" => "application/x-thrift").and_return do + mock("Net::HTTPOK").tap do |response| + response.should_receive(:body).and_return "data" + end + end + end + end + client.flush + client.read(4).should == "data" + end + end +end diff --git a/lib/rb/spec/json_protocol_spec.rb b/lib/rb/spec/json_protocol_spec.rb new file mode 100644 index 0000000..b6b46bf --- /dev/null +++ b/lib/rb/spec/json_protocol_spec.rb @@ -0,0 +1,544 @@ +# encoding: UTF-8 +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'JsonProtocol' do + + describe Thrift::JsonProtocol do + before(:each) do + @trans = Thrift::MemoryBufferTransport.new + @prot = Thrift::JsonProtocol.new(@trans) + end + + it "should write json escaped char" do + @prot.write_json_escape_char("\n") + @trans.read(@trans.available).should == '\u000a' + + @prot.write_json_escape_char(" ") + @trans.read(@trans.available).should == '\u0020' + end + + it "should write json char" do + @prot.write_json_char("\n") + @trans.read(@trans.available).should == '\\n' + + @prot.write_json_char(" ") + @trans.read(@trans.available).should == ' ' + + @prot.write_json_char("\\") + @trans.read(@trans.available).should == "\\\\" + + @prot.write_json_char("@") + @trans.read(@trans.available).should == '@' + end + + it "should write json string" do + @prot.write_json_string("this is a \\ json\nstring") + @trans.read(@trans.available).should == "\"this is a \\\\ json\\nstring\"" + end + + it "should write json base64" do + @prot.write_json_base64("this is a base64 string") + @trans.read(@trans.available).should == "\"dGhpcyBpcyBhIGJhc2U2NCBzdHJpbmc=\"" + end + + it "should write json integer" do + @prot.write_json_integer(45) + @trans.read(@trans.available).should == "45" + + @prot.write_json_integer(33000) + @trans.read(@trans.available).should == "33000" + + @prot.write_json_integer(3000000000) + @trans.read(@trans.available).should == "3000000000" + + @prot.write_json_integer(6000000000) + @trans.read(@trans.available).should == "6000000000" + end + + it "should write json double" do + @prot.write_json_double(12.3) + @trans.read(@trans.available).should == "12.3" + + @prot.write_json_double(-3.21) + @trans.read(@trans.available).should == "-3.21" + + @prot.write_json_double(((+1.0/0.0)/(+1.0/0.0))) + @trans.read(@trans.available).should == "\"NaN\"" + + @prot.write_json_double((+1.0/0.0)) + @trans.read(@trans.available).should == "\"Infinity\"" + + @prot.write_json_double((-1.0/0.0)) + @trans.read(@trans.available).should == "\"-Infinity\"" + end + + it "should write json object start" do + @prot.write_json_object_start + @trans.read(@trans.available).should == "{" + end + + it "should write json object end" do + @prot.write_json_object_end + @trans.read(@trans.available).should == "}" + end + + it "should write json array start" do + @prot.write_json_array_start + @trans.read(@trans.available).should == "[" + end + + it "should write json array end" do + @prot.write_json_array_end + @trans.read(@trans.available).should == "]" + end + + it "should write message begin" do + @prot.write_message_begin("name", 12, 32) + @trans.read(@trans.available).should == "[1,\"name\",12,32" + end + + it "should write message end" do + @prot.write_message_end + @trans.read(@trans.available).should == "]" + end + + it "should write struct begin" do + @prot.write_struct_begin("name") + @trans.read(@trans.available).should == "{" + end + + it "should write struct end" do + @prot.write_struct_end + @trans.read(@trans.available).should == "}" + end + + it "should write field begin" do + @prot.write_field_begin("name", Thrift::Types::STRUCT, 32) + @trans.read(@trans.available).should == "32{\"rec\"" + end + + it "should write field end" do + @prot.write_field_end + @trans.read(@trans.available).should == "}" + end + + it "should write field stop" do + @prot.write_field_stop + @trans.read(@trans.available).should == "" + end + + it "should write map begin" do + @prot.write_map_begin(Thrift::Types::STRUCT, Thrift::Types::LIST, 32) + @trans.read(@trans.available).should == "[\"rec\",\"lst\",32,{" + end + + it "should write map end" do + @prot.write_map_end + @trans.read(@trans.available).should == "}]" + end + + it "should write list begin" do + @prot.write_list_begin(Thrift::Types::STRUCT, 32) + @trans.read(@trans.available).should == "[\"rec\",32" + end + + it "should write list end" do + @prot.write_list_end + @trans.read(@trans.available).should == "]" + end + + it "should write set begin" do + @prot.write_set_begin(Thrift::Types::STRUCT, 32) + @trans.read(@trans.available).should == "[\"rec\",32" + end + + it "should write set end" do + @prot.write_set_end + @trans.read(@trans.available).should == "]" + end + + it "should write bool" do + @prot.write_bool(true) + @trans.read(@trans.available).should == "1" + + @prot.write_bool(false) + @trans.read(@trans.available).should == "0" + end + + it "should write byte" do + @prot.write_byte(100) + @trans.read(@trans.available).should == "100" + end + + it "should write i16" do + @prot.write_i16(1000) + @trans.read(@trans.available).should == "1000" + end + + it "should write i32" do + @prot.write_i32(3000000000) + @trans.read(@trans.available).should == "3000000000" + end + + it "should write i64" do + @prot.write_i64(6000000000) + @trans.read(@trans.available).should == "6000000000" + end + + it "should write double" do + @prot.write_double(1.23) + @trans.read(@trans.available).should == "1.23" + + @prot.write_double(-32.1) + @trans.read(@trans.available).should == "-32.1" + + @prot.write_double(((+1.0/0.0)/(+1.0/0.0))) + @trans.read(@trans.available).should == "\"NaN\"" + + @prot.write_double((+1.0/0.0)) + @trans.read(@trans.available).should == "\"Infinity\"" + + @prot.write_double((-1.0/0.0)) + @trans.read(@trans.available).should == "\"-Infinity\"" + end + + if RUBY_VERSION >= '1.9' + it 'should write string' do + @prot.write_string('this is a test string') + a = @trans.read(@trans.available) + a.should == '"this is a test string"'.force_encoding(Encoding::BINARY) + a.encoding.should == Encoding::BINARY + end + + it 'should write string with unicode characters' do + @prot.write_string("this is a test string with unicode characters: \u20AC \u20AD") + a = @trans.read(@trans.available) + a.should == "\"this is a test string with unicode characters: \u20AC \u20AD\"".force_encoding(Encoding::BINARY) + a.encoding.should == Encoding::BINARY + end + else + it 'should write string' do + @prot.write_string('this is a test string') + @trans.read(@trans.available).should == '"this is a test string"' + end + end + + it "should write binary" do + @prot.write_binary("this is a base64 string") + @trans.read(@trans.available).should == "\"dGhpcyBpcyBhIGJhc2U2NCBzdHJpbmc=\"" + end + + it "should write long binary" do + @prot.write_binary((0...256).to_a.pack('C*')) + @trans.read(@trans.available).should == "\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==\"" + end + + it "should get type name for type id" do + expect {@prot.get_type_name_for_type_id(Thrift::Types::STOP)}.to raise_error(NotImplementedError) + expect {@prot.get_type_name_for_type_id(Thrift::Types::VOID)}.to raise_error(NotImplementedError) + @prot.get_type_name_for_type_id(Thrift::Types::BOOL).should == "tf" + @prot.get_type_name_for_type_id(Thrift::Types::BYTE).should == "i8" + @prot.get_type_name_for_type_id(Thrift::Types::DOUBLE).should == "dbl" + @prot.get_type_name_for_type_id(Thrift::Types::I16).should == "i16" + @prot.get_type_name_for_type_id(Thrift::Types::I32).should == "i32" + @prot.get_type_name_for_type_id(Thrift::Types::I64).should == "i64" + @prot.get_type_name_for_type_id(Thrift::Types::STRING).should == "str" + @prot.get_type_name_for_type_id(Thrift::Types::STRUCT).should == "rec" + @prot.get_type_name_for_type_id(Thrift::Types::MAP).should == "map" + @prot.get_type_name_for_type_id(Thrift::Types::SET).should == "set" + @prot.get_type_name_for_type_id(Thrift::Types::LIST).should == "lst" + end + + it "should get type id for type name" do + expect {@prot.get_type_id_for_type_name("pp")}.to raise_error(NotImplementedError) + @prot.get_type_id_for_type_name("tf").should == Thrift::Types::BOOL + @prot.get_type_id_for_type_name("i8").should == Thrift::Types::BYTE + @prot.get_type_id_for_type_name("dbl").should == Thrift::Types::DOUBLE + @prot.get_type_id_for_type_name("i16").should == Thrift::Types::I16 + @prot.get_type_id_for_type_name("i32").should == Thrift::Types::I32 + @prot.get_type_id_for_type_name("i64").should == Thrift::Types::I64 + @prot.get_type_id_for_type_name("str").should == Thrift::Types::STRING + @prot.get_type_id_for_type_name("rec").should == Thrift::Types::STRUCT + @prot.get_type_id_for_type_name("map").should == Thrift::Types::MAP + @prot.get_type_id_for_type_name("set").should == Thrift::Types::SET + @prot.get_type_id_for_type_name("lst").should == Thrift::Types::LIST + end + + it "should read json syntax char" do + @trans.write('F') + expect {@prot.read_json_syntax_char('G')}.to raise_error(Thrift::ProtocolException) + @trans.write('H') + @prot.read_json_syntax_char('H') + end + + it "should read json escape char" do + @trans.write('0054') + @prot.read_json_escape_char.should == 'T' + + @trans.write("\"\\\"\"") + @prot.read_json_string(false).should == "\"" + + @trans.write("\"\\\\\"") + @prot.read_json_string(false).should == "\\" + + @trans.write("\"\\/\"") + @prot.read_json_string(false).should == "\/" + + @trans.write("\"\\b\"") + @prot.read_json_string(false).should == "\b" + + @trans.write("\"\\f\"") + @prot.read_json_string(false).should == "\f" + + @trans.write("\"\\n\"") + @prot.read_json_string(false).should == "\n" + + @trans.write("\"\\r\"") + @prot.read_json_string(false).should == "\r" + + @trans.write("\"\\t\"") + @prot.read_json_string(false).should == "\t" + end + + it "should read json string" do + @trans.write("\"\\P") + expect {@prot.read_json_string(false)}.to raise_error(Thrift::ProtocolException) + + @trans.write("\"this is a test string\"") + @prot.read_json_string.should == "this is a test string" + end + + it "should read json base64" do + @trans.write("\"dGhpcyBpcyBhIHRlc3Qgc3RyaW5n\"") + @prot.read_json_base64.should == "this is a test string" + end + + it "should is json numeric" do + @prot.is_json_numeric("A").should == false + @prot.is_json_numeric("+").should == true + @prot.is_json_numeric("-").should == true + @prot.is_json_numeric(".").should == true + @prot.is_json_numeric("0").should == true + @prot.is_json_numeric("1").should == true + @prot.is_json_numeric("2").should == true + @prot.is_json_numeric("3").should == true + @prot.is_json_numeric("4").should == true + @prot.is_json_numeric("5").should == true + @prot.is_json_numeric("6").should == true + @prot.is_json_numeric("7").should == true + @prot.is_json_numeric("8").should == true + @prot.is_json_numeric("9").should == true + @prot.is_json_numeric("E").should == true + @prot.is_json_numeric("e").should == true + end + + it "should read json numeric chars" do + @trans.write("1.453E45T") + @prot.read_json_numeric_chars.should == "1.453E45" + end + + it "should read json integer" do + @trans.write("1.45\"\"") + expect {@prot.read_json_integer}.to raise_error(Thrift::ProtocolException) + @prot.read_string + + @trans.write("1453T") + @prot.read_json_integer.should == 1453 + end + + it "should read json double" do + @trans.write("1.45e3e01\"\"") + expect {@prot.read_json_double}.to raise_error(Thrift::ProtocolException) + @prot.read_string + + @trans.write("\"1.453e01\"") + expect {@prot.read_json_double}.to raise_error(Thrift::ProtocolException) + + @trans.write("1.453e01\"\"") + @prot.read_json_double.should == 14.53 + @prot.read_string + + @trans.write("\"NaN\"") + @prot.read_json_double.nan?.should == true + + @trans.write("\"Infinity\"") + @prot.read_json_double.should == +1.0/0.0 + + @trans.write("\"-Infinity\"") + @prot.read_json_double.should == -1.0/0.0 + end + + it "should read json object start" do + @trans.write("{") + @prot.read_json_object_start.should == nil + end + + it "should read json object end" do + @trans.write("}") + @prot.read_json_object_end.should == nil + end + + it "should read json array start" do + @trans.write("[") + @prot.read_json_array_start.should == nil + end + + it "should read json array end" do + @trans.write("]") + @prot.read_json_array_end.should == nil + end + + it "should read_message_begin" do + @trans.write("[2,") + expect {@prot.read_message_begin}.to raise_error(Thrift::ProtocolException) + + @trans.write("[1,\"name\",12,32\"\"") + @prot.read_message_begin.should == ["name", 12, 32] + end + + it "should read message end" do + @trans.write("]") + @prot.read_message_end.should == nil + end + + it "should read struct begin" do + @trans.write("{") + @prot.read_struct_begin.should == nil + end + + it "should read struct end" do + @trans.write("}") + @prot.read_struct_end.should == nil + end + + it "should read field begin" do + @trans.write("1{\"rec\"") + @prot.read_field_begin.should == [nil, 12, 1] + end + + it "should read field end" do + @trans.write("}") + @prot.read_field_end.should == nil + end + + it "should read map begin" do + @trans.write("[\"rec\",\"lst\",2,{") + @prot.read_map_begin.should == [12, 15, 2] + end + + it "should read map end" do + @trans.write("}]") + @prot.read_map_end.should == nil + end + + it "should read list begin" do + @trans.write("[\"rec\",2\"\"") + @prot.read_list_begin.should == [12, 2] + end + + it "should read list end" do + @trans.write("]") + @prot.read_list_end.should == nil + end + + it "should read set begin" do + @trans.write("[\"rec\",2\"\"") + @prot.read_set_begin.should == [12, 2] + end + + it "should read set end" do + @trans.write("]") + @prot.read_set_end.should == nil + end + + it "should read bool" do + @trans.write("0\"\"") + @prot.read_bool.should == false + @prot.read_string + + @trans.write("1\"\"") + @prot.read_bool.should == true + end + + it "should read byte" do + @trans.write("60\"\"") + @prot.read_byte.should == 60 + end + + it "should read i16" do + @trans.write("1000\"\"") + @prot.read_i16.should == 1000 + end + + it "should read i32" do + @trans.write("3000000000\"\"") + @prot.read_i32.should == 3000000000 + end + + it "should read i64" do + @trans.write("6000000000\"\"") + @prot.read_i64.should == 6000000000 + end + + it "should read double" do + @trans.write("12.23\"\"") + @prot.read_double.should == 12.23 + end + + if RUBY_VERSION >= '1.9' + it 'should read string' do + @trans.write('"this is a test string"'.force_encoding(Encoding::BINARY)) + a = @prot.read_string + a.should == 'this is a test string' + a.encoding.should == Encoding::UTF_8 + end + + it 'should read string with unicode characters' do + @trans.write('"this is a test string with unicode characters: \u20AC \u20AD"'.force_encoding(Encoding::BINARY)) + a = @prot.read_string + a.should == "this is a test string with unicode characters: \u20AC \u20AD" + a.encoding.should == Encoding::UTF_8 + end + else + it 'should read string' do + @trans.write('"this is a test string"') + @prot.read_string.should == 'this is a test string' + end + end + + it "should read binary" do + @trans.write("\"dGhpcyBpcyBhIHRlc3Qgc3RyaW5n\"") + @prot.read_binary.should == "this is a test string" + end + + it "should read long binary" do + @trans.write("\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==\"") + @prot.read_binary.bytes.to_a.should == (0...256).to_a + end + end + + describe Thrift::JsonProtocolFactory do + it "should create a JsonProtocol" do + Thrift::JsonProtocolFactory.new.get_protocol(mock("MockTransport")).should be_instance_of(Thrift::JsonProtocol) + end + end +end diff --git a/lib/rb/spec/namespaced_spec.rb b/lib/rb/spec/namespaced_spec.rb new file mode 100644 index 0000000..31379d9 --- /dev/null +++ b/lib/rb/spec/namespaced_spec.rb @@ -0,0 +1,67 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'namespaced generation' do + before do + require 'namespaced_spec_namespace/namespaced_nonblocking_service' + end + + it "generated the right files" do + prefix = File.expand_path("../gen-rb", __FILE__) + ["namespaced_spec_namespace/namespaced_nonblocking_service.rb", + "namespaced_spec_namespace/thrift_namespaced_spec_constants.rb", + "namespaced_spec_namespace/thrift_namespaced_spec_types.rb", + "other_namespace/referenced_constants.rb", + "other_namespace/referenced_types.rb" + ].each do |name| + File.exist?(File.join(prefix, name)).should be_true + end + end + + it "did not generate the wrong files" do + prefix = File.expand_path("../gen-rb", __FILE__) + ["namespaced_nonblocking_service.rb", + "thrift_namespaced_spec_constants.rb", + "thrift_namespaced_spec_types.rb", + "referenced_constants.rb", + "referenced_types.rb" + ].each do |name| + File.exist?(File.join(prefix, name)).should_not be_true + end + end + + it "has a service class in the right place" do + defined?(NamespacedSpecNamespace::NamespacedNonblockingService).should be_true + end + + it "has a struct in the right place" do + defined?(NamespacedSpecNamespace::Hello).should be_true + end + + it "required an included file" do + defined?(OtherNamespace::SomeEnum).should be_true + end + + it "extended a service" do + require "extended/extended_service" + end + +end diff --git a/lib/rb/spec/nonblocking_server_spec.rb b/lib/rb/spec/nonblocking_server_spec.rb new file mode 100644 index 0000000..712cf45 --- /dev/null +++ b/lib/rb/spec/nonblocking_server_spec.rb @@ -0,0 +1,263 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'NonblockingServer' do + + class Handler + def initialize + @queue = Queue.new + end + + attr_accessor :server + + def greeting(english) + if english + SpecNamespace::Hello.new + else + SpecNamespace::Hello.new(:greeting => "Aloha!") + end + end + + def block + @queue.pop + end + + def unblock(n) + n.times { @queue.push true } + end + + def sleep(time) + Kernel.sleep time + end + + def shutdown + @server.shutdown(0, false) + end + end + + class SpecTransport < Thrift::BaseTransport + def initialize(transport, queue) + @transport = transport + @queue = queue + @flushed = false + end + + def open? + @transport.open? + end + + def open + @transport.open + end + + def close + @transport.close + end + + def read(sz) + @transport.read(sz) + end + + def write(buf,sz=nil) + @transport.write(buf, sz) + end + + def flush + @queue.push :flushed unless @flushed or @queue.nil? + @flushed = true + @transport.flush + end + end + + class SpecServerSocket < Thrift::ServerSocket + def initialize(host, port, queue) + super(host, port) + @queue = queue + end + + def listen + super + @queue.push :listen + end + end + + describe Thrift::NonblockingServer do + before(:each) do + @port = 43251 + handler = Handler.new + processor = SpecNamespace::NonblockingService::Processor.new(handler) + queue = Queue.new + @transport = SpecServerSocket.new('localhost', @port, queue) + transport_factory = Thrift::FramedTransportFactory.new + logger = Logger.new(STDERR) + logger.level = Logger::WARN + @server = Thrift::NonblockingServer.new(processor, @transport, transport_factory, nil, 5, logger) + handler.server = @server + @server_thread = Thread.new(Thread.current) do |master_thread| + begin + @server.serve + rescue => e + p e + puts e.backtrace * "\n" + master_thread.raise e + end + end + queue.pop + + @clients = [] + @catch_exceptions = false + end + + after(:each) do + @clients.each { |client, trans| trans.close } + # @server.shutdown(1) + @server_thread.kill + @transport.close + end + + def setup_client(queue = nil) + transport = SpecTransport.new(Thrift::FramedTransport.new(Thrift::Socket.new('localhost', @port)), queue) + protocol = Thrift::BinaryProtocol.new(transport) + client = SpecNamespace::NonblockingService::Client.new(protocol) + transport.open + @clients << [client, transport] + client + end + + def setup_client_thread(result) + queue = Queue.new + Thread.new do + begin + client = setup_client + while (cmd = queue.pop) + msg, *args = cmd + case msg + when :block + result << client.block + when :unblock + client.unblock(args.first) + when :hello + result << client.greeting(true) # ignore result + when :sleep + client.sleep(args[0] || 0.5) + result << :slept + when :shutdown + client.shutdown + when :exit + result << :done + break + end + end + @clients.each { |c,t| t.close and break if c == client } #close the transport + rescue => e + raise e unless @catch_exceptions + end + end + queue + end + + it "should handle basic message passing" do + client = setup_client + client.greeting(true).should == SpecNamespace::Hello.new + client.greeting(false).should == SpecNamespace::Hello.new(:greeting => 'Aloha!') + @server.shutdown + end + + it "should handle concurrent clients" do + queue = Queue.new + trans_queue = Queue.new + 4.times do + Thread.new(Thread.current) do |main_thread| + begin + queue.push setup_client(trans_queue).block + rescue => e + main_thread.raise e + end + end + end + 4.times { trans_queue.pop } + setup_client.unblock(4) + 4.times { queue.pop.should be_true } + @server.shutdown + end + + it "should handle messages from more than 5 long-lived connections" do + queues = [] + result = Queue.new + 7.times do |i| + queues << setup_client_thread(result) + Thread.pass if i == 4 # give the server time to accept connections + end + client = setup_client + # block 4 connections + 4.times { |i| queues[i] << :block } + queues[4] << :hello + queues[5] << :hello + queues[6] << :hello + 3.times { result.pop.should == SpecNamespace::Hello.new } + client.greeting(true).should == SpecNamespace::Hello.new + queues[5] << [:unblock, 4] + 4.times { result.pop.should be_true } + queues[2] << :hello + result.pop.should == SpecNamespace::Hello.new + client.greeting(false).should == SpecNamespace::Hello.new(:greeting => 'Aloha!') + 7.times { queues.shift << :exit } + client.greeting(true).should == SpecNamespace::Hello.new + @server.shutdown + end + + it "should shut down when asked" do + # connect first to ensure it's running + client = setup_client + client.greeting(false) # force a message pass + @server.shutdown + @server_thread.join(2).should be_an_instance_of(Thread) + end + + it "should continue processing active messages when shutting down" do + result = Queue.new + client = setup_client_thread(result) + client << :sleep + sleep 0.1 # give the server time to start processing the client's message + @server.shutdown + @server_thread.join(2).should be_an_instance_of(Thread) + result.pop.should == :slept + end + + it "should kill active messages when they don't expire while shutting down" do + result = Queue.new + client = setup_client_thread(result) + client << [:sleep, 10] + sleep 0.1 # start processing the client's message + @server.shutdown(1) + @catch_exceptions = true + @server_thread.join(3).should_not be_nil + result.should be_empty + end + + it "should allow shutting down in response to a message" do + client = setup_client + client.greeting(true).should == SpecNamespace::Hello.new + client.shutdown + @server_thread.join(2).should_not be_nil + end + end +end diff --git a/lib/rb/spec/processor_spec.rb b/lib/rb/spec/processor_spec.rb new file mode 100644 index 0000000..989f5cc --- /dev/null +++ b/lib/rb/spec/processor_spec.rb @@ -0,0 +1,80 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'Processor' do + + class ProcessorSpec + include Thrift::Processor + end + + describe Thrift::Processor do + before(:each) do + @processor = ProcessorSpec.new(mock("MockHandler")) + @prot = mock("MockProtocol") + end + + def mock_trans(obj) + obj.should_receive(:trans).ordered.and_return do + mock("trans").tap do |trans| + trans.should_receive(:flush).ordered + end + end + end + + it "should call process_ when it receives that message" do + @prot.should_receive(:read_message_begin).ordered.and_return ['testMessage', Thrift::MessageTypes::CALL, 17] + @processor.should_receive(:process_testMessage).with(17, @prot, @prot).ordered + @processor.process(@prot, @prot).should == true + end + + it "should raise an ApplicationException when the received message cannot be processed" do + @prot.should_receive(:read_message_begin).ordered.and_return ['testMessage', Thrift::MessageTypes::CALL, 4] + @prot.should_receive(:skip).with(Thrift::Types::STRUCT).ordered + @prot.should_receive(:read_message_end).ordered + @prot.should_receive(:write_message_begin).with('testMessage', Thrift::MessageTypes::EXCEPTION, 4).ordered + e = mock(Thrift::ApplicationException) + e.should_receive(:write).with(@prot).ordered + Thrift::ApplicationException.should_receive(:new).with(Thrift::ApplicationException::UNKNOWN_METHOD, "Unknown function testMessage").and_return(e) + @prot.should_receive(:write_message_end).ordered + mock_trans(@prot) + @processor.process(@prot, @prot) + end + + it "should pass args off to the args class" do + args_class = mock("MockArgsClass") + args = mock("#").tap do |args| + args.should_receive(:read).with(@prot).ordered + end + args_class.should_receive(:new).and_return args + @prot.should_receive(:read_message_end).ordered + @processor.read_args(@prot, args_class).should eql(args) + end + + it "should write out a reply when asked" do + @prot.should_receive(:write_message_begin).with('testMessage', Thrift::MessageTypes::REPLY, 23).ordered + result = mock("MockResult") + result.should_receive(:write).with(@prot).ordered + @prot.should_receive(:write_message_end).ordered + mock_trans(@prot) + @processor.write_result(result, @prot, 'testMessage', 23) + end + end +end diff --git a/lib/rb/spec/serializer_spec.rb b/lib/rb/spec/serializer_spec.rb new file mode 100644 index 0000000..599b454 --- /dev/null +++ b/lib/rb/spec/serializer_spec.rb @@ -0,0 +1,67 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'Serializer' do + + describe Thrift::Serializer do + it "should serialize structs to binary by default" do + serializer = Thrift::Serializer.new(Thrift::BinaryProtocolAcceleratedFactory.new) + data = serializer.serialize(SpecNamespace::Hello.new(:greeting => "'Ello guv'nor!")) + data.should == "\x0B\x00\x01\x00\x00\x00\x0E'Ello guv'nor!\x00" + end + + it "should serialize structs to the given protocol" do + protocol = Thrift::BaseProtocol.new(mock("transport")) + protocol.should_receive(:write_struct_begin).with("SpecNamespace::Hello") + protocol.should_receive(:write_field_begin).with("greeting", Thrift::Types::STRING, 1) + protocol.should_receive(:write_string).with("Good day") + protocol.should_receive(:write_field_end) + protocol.should_receive(:write_field_stop) + protocol.should_receive(:write_struct_end) + protocol_factory = mock("ProtocolFactory") + protocol_factory.stub!(:get_protocol).and_return(protocol) + serializer = Thrift::Serializer.new(protocol_factory) + serializer.serialize(SpecNamespace::Hello.new(:greeting => "Good day")) + end + end + + describe Thrift::Deserializer do + it "should deserialize structs from binary by default" do + deserializer = Thrift::Deserializer.new + data = "\x0B\x00\x01\x00\x00\x00\x0E'Ello guv'nor!\x00" + deserializer.deserialize(SpecNamespace::Hello.new, data).should == SpecNamespace::Hello.new(:greeting => "'Ello guv'nor!") + end + + it "should deserialize structs from the given protocol" do + protocol = Thrift::BaseProtocol.new(mock("transport")) + protocol.should_receive(:read_struct_begin).and_return("SpecNamespace::Hello") + protocol.should_receive(:read_field_begin).and_return(["greeting", Thrift::Types::STRING, 1], + [nil, Thrift::Types::STOP, 0]) + protocol.should_receive(:read_string).and_return("Good day") + protocol.should_receive(:read_field_end) + protocol.should_receive(:read_struct_end) + protocol_factory = mock("ProtocolFactory") + protocol_factory.stub!(:get_protocol).and_return(protocol) + deserializer = Thrift::Deserializer.new(protocol_factory) + deserializer.deserialize(SpecNamespace::Hello.new, "").should == SpecNamespace::Hello.new(:greeting => "Good day") + end + end +end diff --git a/lib/rb/spec/server_socket_spec.rb b/lib/rb/spec/server_socket_spec.rb new file mode 100644 index 0000000..1301d54 --- /dev/null +++ b/lib/rb/spec/server_socket_spec.rb @@ -0,0 +1,79 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' +require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared") + +describe 'Thrift::ServerSocket' do + + describe Thrift::ServerSocket do + before(:each) do + @socket = Thrift::ServerSocket.new(1234) + end + + it "should create a handle when calling listen" do + TCPServer.should_receive(:new).with(nil, 1234) + @socket.listen + end + + it "should accept an optional host argument" do + @socket = Thrift::ServerSocket.new('localhost', 1234) + TCPServer.should_receive(:new).with('localhost', 1234) + @socket.listen + end + + it "should create a Thrift::Socket to wrap accepted sockets" do + handle = mock("TCPServer") + TCPServer.should_receive(:new).with(nil, 1234).and_return(handle) + @socket.listen + sock = mock("sock") + handle.should_receive(:accept).and_return(sock) + trans = mock("Socket") + Thrift::Socket.should_receive(:new).and_return(trans) + trans.should_receive(:handle=).with(sock) + @socket.accept.should == trans + end + + it "should close the handle when closed" do + handle = mock("TCPServer", :closed? => false) + TCPServer.should_receive(:new).with(nil, 1234).and_return(handle) + @socket.listen + handle.should_receive(:close) + @socket.close + end + + it "should return nil when accepting if there is no handle" do + @socket.accept.should be_nil + end + + it "should return true for closed? when appropriate" do + handle = mock("TCPServer", :closed? => false) + TCPServer.stub!(:new).and_return(handle) + @socket.listen + @socket.should_not be_closed + handle.stub!(:close) + @socket.close + @socket.should be_closed + @socket.listen + @socket.should_not be_closed + handle.stub!(:closed?).and_return(true) + @socket.should be_closed + end + end +end diff --git a/lib/rb/spec/server_spec.rb b/lib/rb/spec/server_spec.rb new file mode 100644 index 0000000..93b9195 --- /dev/null +++ b/lib/rb/spec/server_spec.rb @@ -0,0 +1,148 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +require 'spec_helper' + +describe 'Server' do + + describe Thrift::BaseServer do + it "should default to BaseTransportFactory and BinaryProtocolFactory when not specified" do + server = Thrift::BaseServer.new(mock("Processor"), mock("BaseServerTransport")) + server.instance_variable_get(:'@transport_factory').should be_an_instance_of(Thrift::BaseTransportFactory) + server.instance_variable_get(:'@protocol_factory').should be_an_instance_of(Thrift::BinaryProtocolFactory) + end + + # serve is a noop, so can't test that + end + + describe Thrift::SimpleServer do + before(:each) do + @processor = mock("Processor") + @serverTrans = mock("ServerTransport") + @trans = mock("BaseTransport") + @prot = mock("BaseProtocol") + @client = mock("Client") + @server = described_class.new(@processor, @serverTrans, @trans, @prot) + end + + it "should serve in the main thread" do + @serverTrans.should_receive(:listen).ordered + @serverTrans.should_receive(:accept).exactly(3).times.and_return(@client) + @trans.should_receive(:get_transport).exactly(3).times.with(@client).and_return(@trans) + @prot.should_receive(:get_protocol).exactly(3).times.with(@trans).and_return(@prot) + x = 0 + @processor.should_receive(:process).exactly(3).times.with(@prot, @prot).and_return do + case (x += 1) + when 1 then raise Thrift::TransportException + when 2 then raise Thrift::ProtocolException + when 3 then throw :stop + end + end + @trans.should_receive(:close).exactly(3).times + @serverTrans.should_receive(:close).ordered + lambda { @server.serve }.should throw_symbol(:stop) + end + end + + describe Thrift::ThreadedServer do + before(:each) do + @processor = mock("Processor") + @serverTrans = mock("ServerTransport") + @trans = mock("BaseTransport") + @prot = mock("BaseProtocol") + @client = mock("Client") + @server = described_class.new(@processor, @serverTrans, @trans, @prot) + end + + it "should serve using threads" do + @serverTrans.should_receive(:listen).ordered + @serverTrans.should_receive(:accept).exactly(3).times.and_return(@client) + @trans.should_receive(:get_transport).exactly(3).times.with(@client).and_return(@trans) + @prot.should_receive(:get_protocol).exactly(3).times.with(@trans).and_return(@prot) + Thread.should_receive(:new).with(@prot, @trans).exactly(3).times.and_yield(@prot, @trans) + x = 0 + @processor.should_receive(:process).exactly(3).times.with(@prot, @prot).and_return do + case (x += 1) + when 1 then raise Thrift::TransportException + when 2 then raise Thrift::ProtocolException + when 3 then throw :stop + end + end + @trans.should_receive(:close).exactly(3).times + @serverTrans.should_receive(:close).ordered + lambda { @server.serve }.should throw_symbol(:stop) + end + end + + describe Thrift::ThreadPoolServer do + before(:each) do + @processor = mock("Processor") + @server_trans = mock("ServerTransport") + @trans = mock("BaseTransport") + @prot = mock("BaseProtocol") + @client = mock("Client") + @server = described_class.new(@processor, @server_trans, @trans, @prot) + sleep(0.1) + end + + it "should serve inside a thread" do + exception_q = @server.instance_variable_get(:@exception_q) + described_class.any_instance.should_receive(:serve) do + exception_q.push(StandardError.new('ERROR')) + end + expect { @server.rescuable_serve }.to(raise_error('ERROR')) + end + + it "should avoid running the server twice when retrying rescuable_serve" do + exception_q = @server.instance_variable_get(:@exception_q) + described_class.any_instance.should_receive(:serve) do + exception_q.push(StandardError.new('ERROR1')) + exception_q.push(StandardError.new('ERROR2')) + end + expect { @server.rescuable_serve }.to(raise_error('ERROR1')) + expect { @server.rescuable_serve }.to(raise_error('ERROR2')) + end + + it "should serve using a thread pool" do + thread_q = mock("SizedQueue") + exception_q = mock("Queue") + @server.instance_variable_set(:@thread_q, thread_q) + @server.instance_variable_set(:@exception_q, exception_q) + @server_trans.should_receive(:listen).ordered + thread_q.should_receive(:push).with(:token) + thread_q.should_receive(:pop) + Thread.should_receive(:new).and_yield + @server_trans.should_receive(:accept).exactly(3).times.and_return(@client) + @trans.should_receive(:get_transport).exactly(3).times.and_return(@trans) + @prot.should_receive(:get_protocol).exactly(3).times.and_return(@prot) + x = 0 + error = RuntimeError.new("Stopped") + @processor.should_receive(:process).exactly(3).times.with(@prot, @prot).and_return do + case (x += 1) + when 1 then raise Thrift::TransportException + when 2 then raise Thrift::ProtocolException + when 3 then raise error + end + end + @trans.should_receive(:close).exactly(3).times + exception_q.should_receive(:push).with(error).and_throw(:stop) + @server_trans.should_receive(:close) + expect { @server.serve }.to(throw_symbol(:stop)) + end + end +end diff --git a/lib/rb/spec/socket_spec.rb b/lib/rb/spec/socket_spec.rb new file mode 100644 index 0000000..8e1ef50 --- /dev/null +++ b/lib/rb/spec/socket_spec.rb @@ -0,0 +1,61 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' +require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared") + +describe 'Socket' do + + describe Thrift::Socket do + before(:each) do + @socket = Thrift::Socket.new + @handle = mock("Handle", :closed? => false) + @handle.stub!(:close) + @handle.stub!(:connect_nonblock) + @handle.stub!(:setsockopt) + ::Socket.stub!(:new).and_return(@handle) + end + + it_should_behave_like "a socket" + + it "should raise a TransportException when it cannot open a socket" do + ::Socket.should_receive(:getaddrinfo).with("localhost", 9090, nil, ::Socket::SOCK_STREAM).and_return([[]]) + lambda { @socket.open }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::NOT_OPEN } + end + + it "should open a ::Socket with default args" do + ::Socket.should_receive(:new).and_return(mock("Handle", :connect_nonblock => true, :setsockopt => nil)) + ::Socket.should_receive(:getaddrinfo).with("localhost", 9090, nil, ::Socket::SOCK_STREAM).and_return([[]]) + ::Socket.should_receive(:sockaddr_in) + @socket.open + end + + it "should accept host/port options" do + ::Socket.should_receive(:new).and_return(mock("Handle", :connect_nonblock => true, :setsockopt => nil)) + ::Socket.should_receive(:getaddrinfo).with("my.domain", 1234, nil, ::Socket::SOCK_STREAM).and_return([[]]) + ::Socket.should_receive(:sockaddr_in) + Thrift::Socket.new('my.domain', 1234).open + end + + it "should accept an optional timeout" do + ::Socket.stub!(:new) + Thrift::Socket.new('localhost', 8080, 5).timeout.should == 5 + end + end +end diff --git a/lib/rb/spec/socket_spec_shared.rb b/lib/rb/spec/socket_spec_shared.rb new file mode 100644 index 0000000..5fddc16 --- /dev/null +++ b/lib/rb/spec/socket_spec_shared.rb @@ -0,0 +1,104 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +shared_examples_for "a socket" do + it "should open a socket" do + @socket.open.should == @handle + end + + it "should be open whenever it has a handle" do + @socket.should_not be_open + @socket.open + @socket.should be_open + @socket.handle = nil + @socket.should_not be_open + @socket.handle = @handle + @socket.close + @socket.should_not be_open + end + + it "should write data to the handle" do + @socket.open + @handle.should_receive(:write).with("foobar") + @socket.write("foobar") + @handle.should_receive(:write).with("fail").and_raise(StandardError) + lambda { @socket.write("fail") }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::NOT_OPEN } + end + + it "should raise an error when it cannot read from the handle" do + @socket.open + @handle.should_receive(:readpartial).with(17).and_raise(StandardError) + lambda { @socket.read(17) }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::NOT_OPEN } + end + + it "should return the data read when reading from the handle works" do + @socket.open + @handle.should_receive(:readpartial).with(17).and_return("test data") + @socket.read(17).should == "test data" + end + + it "should declare itself as closed when it has an error" do + @socket.open + @handle.should_receive(:write).with("fail").and_raise(StandardError) + @socket.should be_open + lambda { @socket.write("fail") }.should raise_error + @socket.should_not be_open + end + + it "should raise an error when the stream is closed" do + @socket.open + @handle.stub!(:closed?).and_return(true) + @socket.should_not be_open + lambda { @socket.write("fail") }.should raise_error(IOError, "closed stream") + lambda { @socket.read(10) }.should raise_error(IOError, "closed stream") + end + + it "should support the timeout accessor for read" do + @socket.timeout = 3 + @socket.open + IO.should_receive(:select).with([@handle], nil, nil, 3).and_return([[@handle], [], []]) + @handle.should_receive(:readpartial).with(17).and_return("test data") + @socket.read(17).should == "test data" + end + + it "should support the timeout accessor for write" do + @socket.timeout = 3 + @socket.open + IO.should_receive(:select).with(nil, [@handle], nil, 3).twice.and_return([[], [@handle], []]) + @handle.should_receive(:write_nonblock).with("test data").and_return(4) + @handle.should_receive(:write_nonblock).with(" data").and_return(5) + @socket.write("test data").should == 9 + end + + it "should raise an error when read times out" do + @socket.timeout = 0.5 + @socket.open + IO.should_receive(:select).once {sleep(0.5); nil} + lambda { @socket.read(17) }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::TIMED_OUT } + end + + it "should raise an error when write times out" do + @socket.timeout = 0.5 + @socket.open + IO.should_receive(:select).with(nil, [@handle], nil, 0.5).any_number_of_times.and_return(nil) + lambda { @socket.write("test data") }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::TIMED_OUT } + end +end diff --git a/lib/rb/spec/spec_helper.rb b/lib/rb/spec/spec_helper.rb new file mode 100644 index 0000000..5bf98d0 --- /dev/null +++ b/lib/rb/spec/spec_helper.rb @@ -0,0 +1,64 @@ +# encoding: UTF-8 +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'rubygems' +require 'rspec' + +$:.unshift File.join(File.dirname(__FILE__), *%w[.. ext]) + +# pretend we already loaded fastthread, otherwise the nonblocking_server_spec +# will get screwed up +# $" << 'fastthread.bundle' + +require 'thrift' + +unless Object.method_defined? :tap + # if Object#tap isn't defined, then add it; this should only happen in Ruby < 1.8.7 + class Object + def tap(&block) + block.call(self) + self + end + end +end + +RSpec.configure do |configuration| + configuration.before(:each) do + Thrift.type_checking = true + end +end + +$:.unshift File.join(File.dirname(__FILE__), *%w[.. test debug_proto gen-rb]) +require 'srv' +require 'debug_proto_test_constants' + +$:.unshift File.join(File.dirname(__FILE__), *%w[gen-rb]) +require 'thrift_spec_types' +require 'nonblocking_service' + +module Fixtures + COMPACT_PROTOCOL_TEST_STRUCT = Thrift::Test::COMPACT_TEST.dup + COMPACT_PROTOCOL_TEST_STRUCT.a_binary = [0,1,2,3,4,5,6,7,8].pack('c*') + COMPACT_PROTOCOL_TEST_STRUCT.set_byte_map = nil + COMPACT_PROTOCOL_TEST_STRUCT.map_byte_map = nil +end + +$:.unshift File.join(File.dirname(__FILE__), *%w[gen-rb/flat]) + diff --git a/lib/rb/spec/ssl_socket_spec.rb b/lib/rb/spec/ssl_socket_spec.rb new file mode 100644 index 0000000..a8bc785 --- /dev/null +++ b/lib/rb/spec/ssl_socket_spec.rb @@ -0,0 +1,74 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' +require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared") + +describe 'SSLSocket' do + + describe Thrift::SSLSocket do + before(:each) do + @context = OpenSSL::SSL::SSLContext.new + @socket = Thrift::SSLSocket.new + @simple_socket_handle = mock("Handle", :closed? => false) + @simple_socket_handle.stub!(:close) + @simple_socket_handle.stub!(:connect_nonblock) + @simple_socket_handle.stub!(:setsockopt) + + @handle = mock(mock("SSLHandle", :connect_nonblock => true, :post_connection_check => true), :closed? => false) + @handle.stub!(:connect_nonblock) + @handle.stub!(:close) + @handle.stub!(:post_connection_check) + + ::Socket.stub!(:new).and_return(@simple_socket_handle) + OpenSSL::SSL::SSLSocket.stub!(:new).and_return(@handle) + end + + it_should_behave_like "a socket" + + it "should raise a TransportException when it cannot open a ssl socket" do + ::Socket.should_receive(:getaddrinfo).with("localhost", 9090, nil, ::Socket::SOCK_STREAM).and_return([[]]) + lambda { @socket.open }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::NOT_OPEN } + end + + it "should open a ::Socket with default args" do + OpenSSL::SSL::SSLSocket.should_receive(:new).with(@simple_socket_handle, nil).and_return(@handle) + @handle.should_receive(:post_connection_check).with('localhost') + @socket.open + end + + it "should accept host/port options" do + handle = mock("Handle", :connect_nonblock => true, :setsockopt => nil) + ::Socket.stub!(:new).and_return(handle) + ::Socket.should_receive(:getaddrinfo).with("my.domain", 1234, nil, ::Socket::SOCK_STREAM).and_return([[]]) + ::Socket.should_receive(:sockaddr_in) + OpenSSL::SSL::SSLSocket.should_receive(:new).with(handle, nil).and_return(@handle) + @handle.should_receive(:post_connection_check).with('my.domain') + Thrift::SSLSocket.new('my.domain', 1234, 6000, nil).open + end + + it "should accept an optional timeout" do + Thrift::SSLSocket.new('localhost', 8080, 5).timeout.should == 5 + end + + it "should accept an optional context" do + Thrift::SSLSocket.new('localhost', 8080, 5, @context).ssl_context.should == @context + end + end +end diff --git a/lib/rb/spec/struct_nested_containers_spec.rb b/lib/rb/spec/struct_nested_containers_spec.rb new file mode 100644 index 0000000..dc8ce5f --- /dev/null +++ b/lib/rb/spec/struct_nested_containers_spec.rb @@ -0,0 +1,191 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'StructNestedContainers' do + + def with_type_checking + saved_type_checking, Thrift.type_checking = Thrift.type_checking, true + begin + yield + ensure + Thrift.type_checking = saved_type_checking + end + end + + describe Thrift::Struct do + # Nested container tests, see THRIFT-369. + it "should support nested lists inside lists" do + with_type_checking do + a, b = SpecNamespace::NestedListInList.new, SpecNamespace::NestedListInList.new + [a, b].each do |thrift_struct| + thrift_struct.value = [ [1, 2, 3], [2, 3, 4] ] + thrift_struct.validate + end + a.should == b + b.value.push [3, 4, 5] + a.should_not == b + end + end + + it "should support nested lists inside sets" do + with_type_checking do + a, b = SpecNamespace::NestedListInSet.new, SpecNamespace::NestedListInSet.new + [a, b].each do |thrift_struct| + thrift_struct.value = [ [1, 2, 3], [2, 3, 4] ].to_set + thrift_struct.validate + end + a.should == b + b.value.add [3, 4, 5] + a.should_not == b + end + end + + it "should support nested lists in map keys" do + with_type_checking do + a, b = SpecNamespace::NestedListInMapKey.new, SpecNamespace::NestedListInMapKey.new + [a, b].each do |thrift_struct| + thrift_struct.value = { [1, 2, 3] => 1, [2, 3, 4] => 2 } + thrift_struct.validate + end + a.should == b + b.value[[3, 4, 5]] = 3 + a.should_not == b + end + end + + it "should support nested lists in map values" do + with_type_checking do + a, b = SpecNamespace::NestedListInMapValue.new, SpecNamespace::NestedListInMapValue.new + [a, b].each do |thrift_struct| + thrift_struct.value = { 1 => [1, 2, 3], 2 => [2, 3, 4] } + thrift_struct.validate + end + a.should == b + b.value[3] = [3, 4, 5] + a.should_not == b + end + end + + it "should support nested sets inside lists" do + with_type_checking do + a, b = SpecNamespace::NestedSetInList.new, SpecNamespace::NestedSetInList.new + [a, b].each do |thrift_struct| + thrift_struct.value = [ [1, 2, 3].to_set, [2, 3, 4].to_set ] + thrift_struct.validate + end + a.should == b + b.value.push([3, 4, 5].to_set) + a.should_not == b + end + end + + it "should support nested sets inside sets" do + with_type_checking do + a, b = SpecNamespace::NestedSetInSet.new, SpecNamespace::NestedSetInSet.new + [a, b].each do |thrift_struct| + thrift_struct.value = [ [1, 2, 3].to_set, [2, 3, 4].to_set ].to_set + thrift_struct.validate + end + a.should == b + b.value.add([3, 4, 5].to_set) + a.should_not == b + end + end + + it "should support nested sets in map keys" do + with_type_checking do + a, b = SpecNamespace::NestedSetInMapKey.new, SpecNamespace::NestedSetInMapKey.new + [a, b].each do |thrift_struct| + thrift_struct.value = { [1, 2, 3].to_set => 1, [2, 3, 4].to_set => 2 } + thrift_struct.validate + end + a.should == b + b.value[[3, 4, 5].to_set] = 3 + a.should_not == b + end + end + + it "should support nested sets in map values" do + with_type_checking do + a, b = SpecNamespace::NestedSetInMapValue.new, SpecNamespace::NestedSetInMapValue.new + [a, b].each do |thrift_struct| + thrift_struct.value = { 1 => [1, 2, 3].to_set, 2 => [2, 3, 4].to_set } + thrift_struct.validate + end + a.should == b + b.value[3] = [3, 4, 5].to_set + a.should_not == b + end + end + + it "should support nested maps inside lists" do + with_type_checking do + a, b = SpecNamespace::NestedMapInList.new, SpecNamespace::NestedMapInList.new + [a, b].each do |thrift_struct| + thrift_struct.value = [ {1 => 2, 3 => 4}, {2 => 3, 4 => 5} ] + thrift_struct.validate + end + a.should == b + b.value.push({ 3 => 4, 5 => 6 }) + a.should_not == b + end + end + + it "should support nested maps inside sets" do + with_type_checking do + a, b = SpecNamespace::NestedMapInSet.new, SpecNamespace::NestedMapInSet.new + [a, b].each do |thrift_struct| + thrift_struct.value = [ {1 => 2, 3 => 4}, {2 => 3, 4 => 5} ].to_set + thrift_struct.validate + end + a.should == b + b.value.add({ 3 => 4, 5 => 6 }) + a.should_not == b + end + end + + it "should support nested maps in map keys" do + with_type_checking do + a, b = SpecNamespace::NestedMapInMapKey.new, SpecNamespace::NestedMapInMapKey.new + [a, b].each do |thrift_struct| + thrift_struct.value = { { 1 => 2, 3 => 4} => 1, {2 => 3, 4 => 5} => 2 } + thrift_struct.validate + end + a.should == b + b.value[{3 => 4, 5 => 6}] = 3 + a.should_not == b + end + end + + it "should support nested maps in map values" do + with_type_checking do + a, b = SpecNamespace::NestedMapInMapValue.new, SpecNamespace::NestedMapInMapValue.new + [a, b].each do |thrift_struct| + thrift_struct.value = { 1 => { 1 => 2, 3 => 4}, 2 => {2 => 3, 4 => 5} } + thrift_struct.validate + end + a.should == b + b.value[3] = { 3 => 4, 5 => 6 } + a.should_not == b + end + end + end +end diff --git a/lib/rb/spec/struct_spec.rb b/lib/rb/spec/struct_spec.rb new file mode 100644 index 0000000..6534d61 --- /dev/null +++ b/lib/rb/spec/struct_spec.rb @@ -0,0 +1,293 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'Struct' do + + describe Thrift::Struct do + it "should iterate over all fields properly" do + fields = {} + SpecNamespace::Foo.new.each_field { |fid,field_info| fields[fid] = field_info } + fields.should == SpecNamespace::Foo::FIELDS + end + + it "should initialize all fields to defaults" do + validate_default_arguments(SpecNamespace::Foo.new) + end + + it "should initialize all fields to defaults and accept a block argument" do + SpecNamespace::Foo.new do |f| + validate_default_arguments(f) + end + end + + def validate_default_arguments(object) + object.simple.should == 53 + object.words.should == "words" + object.hello.should == SpecNamespace::Hello.new(:greeting => 'hello, world!') + object.ints.should == [1, 2, 2, 3] + object.complex.should be_nil + object.shorts.should == Set.new([5, 17, 239]) + end + + it "should not share default values between instances" do + begin + struct = SpecNamespace::Foo.new + struct.ints << 17 + SpecNamespace::Foo.new.ints.should == [1,2,2,3] + ensure + # ensure no leakage to other tests + SpecNamespace::Foo::FIELDS[4][:default] = [1,2,2,3] + end + end + + it "should properly initialize boolean values" do + struct = SpecNamespace::BoolStruct.new(:yesno => false) + struct.yesno.should be_false + end + + it "should have proper == semantics" do + SpecNamespace::Foo.new.should_not == SpecNamespace::Hello.new + SpecNamespace::Foo.new.should == SpecNamespace::Foo.new + SpecNamespace::Foo.new(:simple => 52).should_not == SpecNamespace::Foo.new + end + + it "should print enum value names in inspect" do + SpecNamespace::StructWithSomeEnum.new(:some_enum => SpecNamespace::SomeEnum::ONE).inspect.should == "" + + SpecNamespace::StructWithEnumMap.new(:my_map => {SpecNamespace::SomeEnum::ONE => [SpecNamespace::SomeEnum::TWO]}).inspect.should == "" + end + + it "should pretty print binary fields" do + SpecNamespace::Foo2.new(:my_binary => "\001\002\003").inspect.should == "" + end + + it "should offer field? methods" do + SpecNamespace::Foo.new.opt_string?.should be_false + SpecNamespace::Foo.new(:simple => 52).simple?.should be_true + SpecNamespace::Foo.new(:my_bool => false).my_bool?.should be_true + SpecNamespace::Foo.new(:my_bool => true).my_bool?.should be_true + end + + it "should be comparable" do + s1 = SpecNamespace::StructWithSomeEnum.new(:some_enum => SpecNamespace::SomeEnum::ONE) + s2 = SpecNamespace::StructWithSomeEnum.new(:some_enum => SpecNamespace::SomeEnum::TWO) + + (s1 <=> s2).should == -1 + (s2 <=> s1).should == 1 + (s1 <=> s1).should == 0 + (s1 <=> SpecNamespace::StructWithSomeEnum.new()).should == -1 + end + + it "should read itself off the wire" do + struct = SpecNamespace::Foo.new + prot = Thrift::BaseProtocol.new(mock("transport")) + prot.should_receive(:read_struct_begin).twice + prot.should_receive(:read_struct_end).twice + prot.should_receive(:read_field_begin).and_return( + ['complex', Thrift::Types::MAP, 5], # Foo + ['words', Thrift::Types::STRING, 2], # Foo + ['hello', Thrift::Types::STRUCT, 3], # Foo + ['greeting', Thrift::Types::STRING, 1], # Hello + [nil, Thrift::Types::STOP, 0], # Hello + ['simple', Thrift::Types::I32, 1], # Foo + ['ints', Thrift::Types::LIST, 4], # Foo + ['shorts', Thrift::Types::SET, 6], # Foo + [nil, Thrift::Types::STOP, 0] # Hello + ) + prot.should_receive(:read_field_end).exactly(7).times + prot.should_receive(:read_map_begin).and_return( + [Thrift::Types::I32, Thrift::Types::MAP, 2], # complex + [Thrift::Types::STRING, Thrift::Types::DOUBLE, 2], # complex/1/value + [Thrift::Types::STRING, Thrift::Types::DOUBLE, 1] # complex/2/value + ) + prot.should_receive(:read_map_end).exactly(3).times + prot.should_receive(:read_list_begin).and_return([Thrift::Types::I32, 4]) + prot.should_receive(:read_list_end) + prot.should_receive(:read_set_begin).and_return([Thrift::Types::I16, 2]) + prot.should_receive(:read_set_end) + prot.should_receive(:read_i32).and_return( + 1, 14, # complex keys + 42, # simple + 4, 23, 4, 29 # ints + ) + prot.should_receive(:read_string).and_return("pi", "e", "feigenbaum", "apple banana", "what's up?") + prot.should_receive(:read_double).and_return(Math::PI, Math::E, 4.669201609) + prot.should_receive(:read_i16).and_return(2, 3) + prot.should_not_receive(:skip) + struct.read(prot) + + struct.simple.should == 42 + struct.complex.should == {1 => {"pi" => Math::PI, "e" => Math::E}, 14 => {"feigenbaum" => 4.669201609}} + struct.hello.should == SpecNamespace::Hello.new(:greeting => "what's up?") + struct.words.should == "apple banana" + struct.ints.should == [4, 23, 4, 29] + struct.shorts.should == Set.new([3, 2]) + end + + it "should serialize false boolean fields correctly" do + b = SpecNamespace::BoolStruct.new(:yesno => false) + prot = Thrift::BinaryProtocol.new(Thrift::MemoryBufferTransport.new) + prot.should_receive(:write_bool).with(false) + b.write(prot) + end + + it "should skip unexpected fields in structs and use default values" do + struct = SpecNamespace::Foo.new + prot = Thrift::BaseProtocol.new(mock("transport")) + prot.should_receive(:read_struct_begin) + prot.should_receive(:read_struct_end) + prot.should_receive(:read_field_begin).and_return( + ['simple', Thrift::Types::I32, 1], + ['complex', Thrift::Types::STRUCT, 5], + ['thinz', Thrift::Types::MAP, 7], + ['foobar', Thrift::Types::I32, 3], + ['words', Thrift::Types::STRING, 2], + [nil, Thrift::Types::STOP, 0] + ) + prot.should_receive(:read_field_end).exactly(5).times + prot.should_receive(:read_i32).and_return(42) + prot.should_receive(:read_string).and_return("foobar") + prot.should_receive(:skip).with(Thrift::Types::STRUCT) + prot.should_receive(:skip).with(Thrift::Types::MAP) + # prot.should_receive(:read_map_begin).and_return([Thrift::Types::I32, Thrift::Types::I32, 0]) + # prot.should_receive(:read_map_end) + prot.should_receive(:skip).with(Thrift::Types::I32) + struct.read(prot) + + struct.simple.should == 42 + struct.complex.should be_nil + struct.words.should == "foobar" + struct.hello.should == SpecNamespace::Hello.new(:greeting => 'hello, world!') + struct.ints.should == [1, 2, 2, 3] + struct.shorts.should == Set.new([5, 17, 239]) + end + + it "should write itself to the wire" do + prot = Thrift::BaseProtocol.new(mock("transport")) #mock("Protocol") + prot.should_receive(:write_struct_begin).with("SpecNamespace::Foo") + prot.should_receive(:write_struct_begin).with("SpecNamespace::Hello") + prot.should_receive(:write_struct_end).twice + prot.should_receive(:write_field_begin).with('ints', Thrift::Types::LIST, 4) + prot.should_receive(:write_i32).with(1) + prot.should_receive(:write_i32).with(2).twice + prot.should_receive(:write_i32).with(3) + prot.should_receive(:write_field_begin).with('complex', Thrift::Types::MAP, 5) + prot.should_receive(:write_i32).with(5) + prot.should_receive(:write_string).with('foo') + prot.should_receive(:write_double).with(1.23) + prot.should_receive(:write_field_begin).with('shorts', Thrift::Types::SET, 6) + prot.should_receive(:write_i16).with(5) + prot.should_receive(:write_i16).with(17) + prot.should_receive(:write_i16).with(239) + prot.should_receive(:write_field_stop).twice + prot.should_receive(:write_field_end).exactly(6).times + prot.should_receive(:write_field_begin).with('simple', Thrift::Types::I32, 1) + prot.should_receive(:write_i32).with(53) + prot.should_receive(:write_field_begin).with('hello', Thrift::Types::STRUCT, 3) + prot.should_receive(:write_field_begin).with('greeting', Thrift::Types::STRING, 1) + prot.should_receive(:write_string).with('hello, world!') + prot.should_receive(:write_map_begin).with(Thrift::Types::I32, Thrift::Types::MAP, 1) + prot.should_receive(:write_map_begin).with(Thrift::Types::STRING, Thrift::Types::DOUBLE, 1) + prot.should_receive(:write_map_end).twice + prot.should_receive(:write_list_begin).with(Thrift::Types::I32, 4) + prot.should_receive(:write_list_end) + prot.should_receive(:write_set_begin).with(Thrift::Types::I16, 3) + prot.should_receive(:write_set_end) + + struct = SpecNamespace::Foo.new + struct.words = nil + struct.complex = {5 => {"foo" => 1.23}} + struct.write(prot) + end + + it "should raise an exception if presented with an unknown container" do + # yeah this is silly, but I'm going for code coverage here + struct = SpecNamespace::Foo.new + lambda { struct.send :write_container, nil, nil, {:type => "foo"} }.should raise_error(StandardError, "Not a container type: foo") + end + + it "should support optional type-checking in Thrift::Struct.new" do + Thrift.type_checking = true + begin + lambda { SpecNamespace::Hello.new(:greeting => 3) }.should raise_error(Thrift::TypeError, "Expected Types::STRING, received Fixnum for field greeting") + ensure + Thrift.type_checking = false + end + lambda { SpecNamespace::Hello.new(:greeting => 3) }.should_not raise_error(Thrift::TypeError) + end + + it "should support optional type-checking in field accessors" do + Thrift.type_checking = true + begin + hello = SpecNamespace::Hello.new + lambda { hello.greeting = 3 }.should raise_error(Thrift::TypeError, "Expected Types::STRING, received Fixnum for field greeting") + ensure + Thrift.type_checking = false + end + lambda { hello.greeting = 3 }.should_not raise_error(Thrift::TypeError) + end + + it "should raise an exception when unknown types are given to Thrift::Struct.new" do + lambda { SpecNamespace::Hello.new(:fish => 'salmon') }.should raise_error(Exception, "Unknown key given to SpecNamespace::Hello.new: fish") + end + + it "should support `raise Xception, 'message'` for Exception structs" do + begin + raise SpecNamespace::Xception, "something happened" + rescue Thrift::Exception => e + e.message.should == "something happened" + e.code.should == 1 + # ensure it gets serialized properly, this is the really important part + prot = Thrift::BaseProtocol.new(mock("trans")) + prot.should_receive(:write_struct_begin).with("SpecNamespace::Xception") + prot.should_receive(:write_struct_end) + prot.should_receive(:write_field_begin).with('message', Thrift::Types::STRING, 1)#, "something happened") + prot.should_receive(:write_string).with("something happened") + prot.should_receive(:write_field_begin).with('code', Thrift::Types::I32, 2)#, 1) + prot.should_receive(:write_i32).with(1) + prot.should_receive(:write_field_stop) + prot.should_receive(:write_field_end).twice + + e.write(prot) + end + end + + it "should support the regular initializer for exception structs" do + begin + raise SpecNamespace::Xception, :message => "something happened", :code => 5 + rescue Thrift::Exception => e + e.message.should == "something happened" + e.code.should == 5 + prot = Thrift::BaseProtocol.new(mock("trans")) + prot.should_receive(:write_struct_begin).with("SpecNamespace::Xception") + prot.should_receive(:write_struct_end) + prot.should_receive(:write_field_begin).with('message', Thrift::Types::STRING, 1) + prot.should_receive(:write_string).with("something happened") + prot.should_receive(:write_field_begin).with('code', Thrift::Types::I32, 2) + prot.should_receive(:write_i32).with(5) + prot.should_receive(:write_field_stop) + prot.should_receive(:write_field_end).twice + + e.write(prot) + end + end + end +end diff --git a/lib/rb/spec/thin_http_server_spec.rb b/lib/rb/spec/thin_http_server_spec.rb new file mode 100644 index 0000000..5520839 --- /dev/null +++ b/lib/rb/spec/thin_http_server_spec.rb @@ -0,0 +1,141 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' +require 'rack/test' +require 'thrift/server/thin_http_server' + +describe Thrift::ThinHTTPServer do + + let(:processor) { mock('processor') } + + describe "#initialize" do + + context "when using the defaults" do + + it "binds to port 80, with host 0.0.0.0, a path of '/'" do + Thin::Server.should_receive(:new).with('0.0.0.0', 80, an_instance_of(Rack::Builder)) + Thrift::ThinHTTPServer.new(processor) + end + + it 'creates a ThinHTTPServer::RackApplicationContext' do + Thrift::ThinHTTPServer::RackApplication.should_receive(:for).with("/", processor, an_instance_of(Thrift::BinaryProtocolFactory)).and_return(anything) + Thrift::ThinHTTPServer.new(processor) + end + + it "uses the BinaryProtocolFactory" do + Thrift::BinaryProtocolFactory.should_receive(:new) + Thrift::ThinHTTPServer.new(processor) + end + + end + + context "when using the options" do + + it 'accepts :ip, :port, :path' do + ip = "192.168.0.1" + port = 3000 + path = "/thin" + Thin::Server.should_receive(:new).with(ip, port, an_instance_of(Rack::Builder)) + Thrift::ThinHTTPServer.new(processor, + :ip => ip, + :port => port, + :path => path) + end + + it 'creates a ThinHTTPServer::RackApplicationContext with a different protocol factory' do + Thrift::ThinHTTPServer::RackApplication.should_receive(:for).with("/", processor, an_instance_of(Thrift::JsonProtocolFactory)).and_return(anything) + Thrift::ThinHTTPServer.new(processor, + :protocol_factory => Thrift::JsonProtocolFactory.new) + end + + end + + end + + describe "#serve" do + + it 'starts the Thin server' do + underlying_thin_server = mock('thin server', :start => true) + Thin::Server.stub(:new).and_return(underlying_thin_server) + + thin_thrift_server = Thrift::ThinHTTPServer.new(processor) + + underlying_thin_server.should_receive(:start) + thin_thrift_server.serve + end + end + +end + +describe Thrift::ThinHTTPServer::RackApplication do + include Rack::Test::Methods + + let(:processor) { mock('processor') } + let(:protocol_factory) { mock('protocol factory') } + + def app + Thrift::ThinHTTPServer::RackApplication.for("/", processor, protocol_factory) + end + + context "404 response" do + + it 'receives a non-POST' do + header('Content-Type', "application/x-thrift") + get "/" + last_response.status.should be 404 + end + + it 'receives a header other than application/x-thrift' do + header('Content-Type', "application/json") + post "/" + last_response.status.should be 404 + end + + end + + context "200 response" do + + before do + protocol_factory.stub(:get_protocol) + processor.stub(:process) + end + + it 'creates an IOStreamTransport' do + header('Content-Type', "application/x-thrift") + Thrift::IOStreamTransport.should_receive(:new).with(an_instance_of(Rack::Lint::InputWrapper), an_instance_of(Rack::Response)) + post "/" + end + + it 'fetches the right protocol based on the Transport' do + header('Content-Type', "application/x-thrift") + protocol_factory.should_receive(:get_protocol).with(an_instance_of(Thrift::IOStreamTransport)) + post "/" + end + + it 'status code 200' do + header('Content-Type', "application/x-thrift") + post "/" + last_response.ok?.should be_true + end + + end + +end + diff --git a/lib/rb/spec/types_spec.rb b/lib/rb/spec/types_spec.rb new file mode 100644 index 0000000..b2c3a20 --- /dev/null +++ b/lib/rb/spec/types_spec.rb @@ -0,0 +1,115 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe Thrift::Types do + + before(:each) do + Thrift.type_checking = true + end + + after(:each) do + Thrift.type_checking = false + end + + context 'type checking' do + it "should return the proper name for each type" do + Thrift.type_name(Thrift::Types::I16).should == "Types::I16" + Thrift.type_name(Thrift::Types::VOID).should == "Types::VOID" + Thrift.type_name(Thrift::Types::LIST).should == "Types::LIST" + Thrift.type_name(42).should be_nil + end + + it "should check types properly" do + # lambda { Thrift.check_type(nil, Thrift::Types::STOP) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(3, {:type => Thrift::Types::STOP}, :foo) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(nil, {:type => Thrift::Types::VOID}, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type(3, {:type => Thrift::Types::VOID}, :foo) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(true, {:type => Thrift::Types::BOOL}, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type(3, {:type => Thrift::Types::BOOL}, :foo) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(42, {:type => Thrift::Types::BYTE}, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type(42, {:type => Thrift::Types::I16}, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type(42, {:type => Thrift::Types::I32}, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type(42, {:type => Thrift::Types::I64}, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type(3.14, {:type => Thrift::Types::I32}, :foo) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(3.14, {:type => Thrift::Types::DOUBLE}, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type(3, {:type => Thrift::Types::DOUBLE}, :foo) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type("3", {:type => Thrift::Types::STRING}, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type(3, {:type => Thrift::Types::STRING}, :foo) }.should raise_error(Thrift::TypeError) + hello = SpecNamespace::Hello.new + lambda { Thrift.check_type(hello, {:type => Thrift::Types::STRUCT, :class => SpecNamespace::Hello}, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type("foo", {:type => Thrift::Types::STRUCT}, :foo) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type({:foo => 1}, {:type => Thrift::Types::MAP}, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type([1], {:type => Thrift::Types::MAP}, :foo) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type([1], {:type => Thrift::Types::LIST}, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type({:foo => 1}, {:type => Thrift::Types::LIST}, :foo) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(Set.new([1,2]), {:type => Thrift::Types::SET}, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type([1,2], {:type => Thrift::Types::SET}, :foo) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type({:foo => true}, {:type => Thrift::Types::SET}, :foo) }.should raise_error(Thrift::TypeError) + end + + it "should error out if nil is passed and skip_types is false" do + lambda { Thrift.check_type(nil, {:type => Thrift::Types::BOOL}, :foo, false) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(nil, {:type => Thrift::Types::BYTE}, :foo, false) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(nil, {:type => Thrift::Types::I16}, :foo, false) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(nil, {:type => Thrift::Types::I32}, :foo, false) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(nil, {:type => Thrift::Types::I64}, :foo, false) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(nil, {:type => Thrift::Types::DOUBLE}, :foo, false) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(nil, {:type => Thrift::Types::STRING}, :foo, false) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(nil, {:type => Thrift::Types::STRUCT}, :foo, false) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(nil, {:type => Thrift::Types::LIST}, :foo, false) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(nil, {:type => Thrift::Types::SET}, :foo, false) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(nil, {:type => Thrift::Types::MAP}, :foo, false) }.should raise_error(Thrift::TypeError) + end + + it "should check element types on containers" do + field = {:type => Thrift::Types::LIST, :element => {:type => Thrift::Types::I32}} + lambda { Thrift.check_type([1, 2], field, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type([1, nil, 2], field, :foo) }.should raise_error(Thrift::TypeError) + field = {:type => Thrift::Types::MAP, :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRING}} + lambda { Thrift.check_type({1 => "one", 2 => "two"}, field, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type({1 => "one", nil => "nil"}, field, :foo) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type({1 => nil, 2 => "two"}, field, :foo) }.should raise_error(Thrift::TypeError) + field = {:type => Thrift::Types::SET, :element => {:type => Thrift::Types::I32}} + lambda { Thrift.check_type(Set.new([1, 2]), field, :foo) }.should_not raise_error(Thrift::TypeError) + lambda { Thrift.check_type(Set.new([1, nil, 2]), field, :foo) }.should raise_error(Thrift::TypeError) + lambda { Thrift.check_type(Set.new([1, 2.3, 2]), field, :foo) }.should raise_error(Thrift::TypeError) + + field = {:type => Thrift::Types::STRUCT, :class => SpecNamespace::Hello} + lambda { Thrift.check_type(SpecNamespace::BoolStruct, field, :foo) }.should raise_error(Thrift::TypeError) + end + + it "should give the Thrift::TypeError a readable message" do + msg = "Expected Types::STRING, received Fixnum for field foo" + lambda { Thrift.check_type(3, {:type => Thrift::Types::STRING}, :foo) }.should raise_error(Thrift::TypeError, msg) + msg = "Expected Types::STRING, received Fixnum for field foo.element" + field = {:type => Thrift::Types::LIST, :element => {:type => Thrift::Types::STRING}} + lambda { Thrift.check_type([3], field, :foo) }.should raise_error(Thrift::TypeError, msg) + msg = "Expected Types::I32, received NilClass for field foo.element.key" + field = {:type => Thrift::Types::LIST, + :element => {:type => Thrift::Types::MAP, + :key => {:type => Thrift::Types::I32}, + :value => {:type => Thrift::Types::I32}}} + lambda { Thrift.check_type([{nil => 3}], field, :foo) }.should raise_error(Thrift::TypeError, msg) + msg = "Expected Types::I32, received NilClass for field foo.element.value" + lambda { Thrift.check_type([{1 => nil}], field, :foo) }.should raise_error(Thrift::TypeError, msg) + end + end +end diff --git a/lib/rb/spec/union_spec.rb b/lib/rb/spec/union_spec.rb new file mode 100644 index 0000000..6ad3194 --- /dev/null +++ b/lib/rb/spec/union_spec.rb @@ -0,0 +1,215 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'Union' do + + describe Thrift::Union do + it "should return nil value in unset union" do + union = SpecNamespace::My_union.new + union.get_set_field.should == nil + union.get_value.should == nil + end + + it "should set a field and be accessible through get_value and the named field accessor" do + union = SpecNamespace::My_union.new + union.integer32 = 25 + union.get_set_field.should == :integer32 + union.get_value.should == 25 + union.integer32.should == 25 + end + + it "should work correctly when instantiated with static field constructors" do + union = SpecNamespace::My_union.integer32(5) + union.get_set_field.should == :integer32 + union.integer32.should == 5 + end + + it "should raise for wrong set field" do + union = SpecNamespace::My_union.new + union.integer32 = 25 + lambda { union.some_characters }.should raise_error(RuntimeError, "some_characters is not union's set field.") + end + + it "should raise for wrong set field when hash initialized and type checking is off" do + Thrift.type_checking = false + union = SpecNamespace::My_union.new({incorrect_field: :incorrect}) + example = lambda { Thrift::Serializer.new.serialize(union) } + example.should raise_error(RuntimeError, "set_field is not valid for this union!") + end + + it "should not be equal to nil" do + union = SpecNamespace::My_union.new + union.should_not == nil + end + + it "should not be equal with an empty String" do + union = SpecNamespace::My_union.new + union.should_not == '' + end + + it "should not equate two different unions, i32 vs. string" do + union = SpecNamespace::My_union.new(:integer32, 25) + other_union = SpecNamespace::My_union.new(:some_characters, "blah!") + union.should_not == other_union + end + + it "should properly reset setfield and setvalue" do + union = SpecNamespace::My_union.new(:integer32, 25) + union.get_set_field.should == :integer32 + union.some_characters = "blah!" + union.get_set_field.should == :some_characters + union.get_value.should == "blah!" + lambda { union.integer32 }.should raise_error(RuntimeError, "integer32 is not union's set field.") + end + + it "should not equate two different unions with different values" do + union = SpecNamespace::My_union.new(:integer32, 25) + other_union = SpecNamespace::My_union.new(:integer32, 400) + union.should_not == other_union + end + + it "should not equate two different unions with different fields" do + union = SpecNamespace::My_union.new(:integer32, 25) + other_union = SpecNamespace::My_union.new(:other_i32, 25) + union.should_not == other_union + end + + it "should inspect properly" do + union = SpecNamespace::My_union.new(:integer32, 25) + union.inspect.should == "" + end + + it "should not allow setting with instance_variable_set" do + union = SpecNamespace::My_union.new(:integer32, 27) + union.instance_variable_set(:@some_characters, "hallo!") + union.get_set_field.should == :integer32 + union.get_value.should == 27 + lambda { union.some_characters }.should raise_error(RuntimeError, "some_characters is not union's set field.") + end + + it "should serialize to binary correctly" do + trans = Thrift::MemoryBufferTransport.new + proto = Thrift::BinaryProtocol.new(trans) + + union = SpecNamespace::My_union.new(:integer32, 25) + union.write(proto) + + other_union = SpecNamespace::My_union.new(:integer32, 25) + other_union.read(proto) + other_union.should == union + end + + it "should serialize to json correctly" do + trans = Thrift::MemoryBufferTransport.new + proto = Thrift::JsonProtocol.new(trans) + + union = SpecNamespace::My_union.new(:integer32, 25) + union.write(proto) + + other_union = SpecNamespace::My_union.new(:integer32, 25) + other_union.read(proto) + other_union.should == union + end + + it "should raise when validating unset union" do + union = SpecNamespace::My_union.new + lambda { union.validate }.should raise_error(StandardError, "Union fields are not set.") + + other_union = SpecNamespace::My_union.new(:integer32, 1) + lambda { other_union.validate }.should_not raise_error(StandardError, "Union fields are not set.") + end + + it "should validate an enum field properly" do + union = SpecNamespace::TestUnion.new(:enum_field, 3) + union.get_set_field.should == :enum_field + lambda { union.validate }.should raise_error(Thrift::ProtocolException, "Invalid value of field enum_field!") + + other_union = SpecNamespace::TestUnion.new(:enum_field, 1) + lambda { other_union.validate }.should_not raise_error(Thrift::ProtocolException, "Invalid value of field enum_field!") + end + + it "should properly serialize and match structs with a union" do + union = SpecNamespace::My_union.new(:integer32, 26) + swu = SpecNamespace::Struct_with_union.new(:fun_union => union) + + trans = Thrift::MemoryBufferTransport.new + proto = Thrift::CompactProtocol.new(trans) + + swu.write(proto) + + other_union = SpecNamespace::My_union.new(:some_characters, "hello there") + swu2 = SpecNamespace::Struct_with_union.new(:fun_union => other_union) + + swu2.should_not == swu + + swu2.read(proto) + swu2.should == swu + end + + it "should support old style constructor" do + union = SpecNamespace::My_union.new(:integer32 => 26) + union.get_set_field.should == :integer32 + union.get_value.should == 26 + end + + it "should not throw an error when inspected and unset" do + lambda{SpecNamespace::TestUnion.new().inspect}.should_not raise_error + end + + it "should print enum value name when inspected" do + SpecNamespace::My_union.new(:some_enum => SpecNamespace::SomeEnum::ONE).inspect.should == "" + + SpecNamespace::My_union.new(:my_map => {SpecNamespace::SomeEnum::ONE => [SpecNamespace::SomeEnum::TWO]}).inspect.should == "" + end + + it "should offer field? methods" do + SpecNamespace::My_union.new.some_enum?.should be_false + SpecNamespace::My_union.new(:some_enum => SpecNamespace::SomeEnum::ONE).some_enum?.should be_true + SpecNamespace::My_union.new(:im_true => false).im_true?.should be_true + SpecNamespace::My_union.new(:im_true => true).im_true?.should be_true + end + + it "should pretty print binary fields" do + SpecNamespace::TestUnion.new(:binary_field => "\001\002\003").inspect.should == "" + end + + it "should be comparable" do + relationships = [ + [0, -1, -1, -1], + [1, 0, -1, -1], + [1, 1, 0, -1], + [1, 1, 1, 0]] + + objs = [ + SpecNamespace::TestUnion.new(:string_field, "blah"), + SpecNamespace::TestUnion.new(:string_field, "blahblah"), + SpecNamespace::TestUnion.new(:i32_field, 1), + SpecNamespace::TestUnion.new()] + + for y in 0..3 + for x in 0..3 + # puts "#{objs[y].inspect} <=> #{objs[x].inspect} should == #{relationships[y][x]}" + (objs[y] <=> objs[x]).should == relationships[y][x] + end + end + end + end +end diff --git a/lib/rb/spec/unix_socket_spec.rb b/lib/rb/spec/unix_socket_spec.rb new file mode 100644 index 0000000..cb6cff3 --- /dev/null +++ b/lib/rb/spec/unix_socket_spec.rb @@ -0,0 +1,107 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' +require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared") + +describe 'UNIXSocket' do + + describe Thrift::UNIXSocket do + before(:each) do + @path = '/tmp/thrift_spec_socket' + @socket = Thrift::UNIXSocket.new(@path) + @handle = mock("Handle", :closed? => false) + @handle.stub!(:close) + ::UNIXSocket.stub!(:new).and_return(@handle) + end + + it_should_behave_like "a socket" + + it "should raise a TransportException when it cannot open a socket" do + ::UNIXSocket.should_receive(:new).and_raise(StandardError) + lambda { @socket.open }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::NOT_OPEN } + end + + it "should accept an optional timeout" do + ::UNIXSocket.stub!(:new) + Thrift::UNIXSocket.new(@path, 5).timeout.should == 5 + end + end + + describe Thrift::UNIXServerSocket do + before(:each) do + @path = '/tmp/thrift_spec_socket' + @socket = Thrift::UNIXServerSocket.new(@path) + end + + it "should create a handle when calling listen" do + UNIXServer.should_receive(:new).with(@path) + @socket.listen + end + + it "should create a Thrift::UNIXSocket to wrap accepted sockets" do + handle = mock("UNIXServer") + UNIXServer.should_receive(:new).with(@path).and_return(handle) + @socket.listen + sock = mock("sock") + handle.should_receive(:accept).and_return(sock) + trans = mock("UNIXSocket") + Thrift::UNIXSocket.should_receive(:new).and_return(trans) + trans.should_receive(:handle=).with(sock) + @socket.accept.should == trans + end + + it "should close the handle when closed" do + handle = mock("UNIXServer", :closed? => false) + UNIXServer.should_receive(:new).with(@path).and_return(handle) + @socket.listen + handle.should_receive(:close) + File.stub!(:delete) + @socket.close + end + + it "should delete the socket when closed" do + handle = mock("UNIXServer", :closed? => false) + UNIXServer.should_receive(:new).with(@path).and_return(handle) + @socket.listen + handle.stub!(:close) + File.should_receive(:delete).with(@path) + @socket.close + end + + it "should return nil when accepting if there is no handle" do + @socket.accept.should be_nil + end + + it "should return true for closed? when appropriate" do + handle = mock("UNIXServer", :closed? => false) + UNIXServer.stub!(:new).and_return(handle) + File.stub!(:delete) + @socket.listen + @socket.should_not be_closed + handle.stub!(:close) + @socket.close + @socket.should be_closed + @socket.listen + @socket.should_not be_closed + handle.stub!(:closed?).and_return(true) + @socket.should be_closed + end + end +end diff --git a/lib/rb/thrift.gemspec b/lib/rb/thrift.gemspec new file mode 100644 index 0000000..291b81f --- /dev/null +++ b/lib/rb/thrift.gemspec @@ -0,0 +1,37 @@ +# -*- encoding: utf-8 -*- +$:.push File.expand_path("../lib", __FILE__) + +Gem::Specification.new do |s| + s.name = 'thrift' + s.version = '0.11.0.0' + s.authors = ['Thrift Developers'] + s.email = ['dev@thrift.apache.org'] + s.homepage = 'http://thrift.apache.org' + s.summary = %q{Ruby bindings for Apache Thrift} + s.description = %q{Ruby bindings for the Apache Thrift RPC system} + s.license = 'Apache 2.0' + s.extensions = ['ext/extconf.rb'] + + s.has_rdoc = true + s.rdoc_options = %w[--line-numbers --inline-source --title Thrift --main README] + + s.rubyforge_project = 'thrift' + + dir = File.expand_path(File.dirname(__FILE__)) + + s.files = Dir.glob("{lib,spec}/**/*") + s.test_files = Dir.glob("{test,spec,benchmark}/**/*") + s.executables = Dir.glob("{bin}/**/*") + + s.extra_rdoc_files = %w[README.md] + Dir.glob("{ext,lib}/**/*.{c,h,rb}") + + s.require_paths = %w[lib ext] + + s.add_development_dependency 'rspec', ['>= 2.10.0', '< 2.14.0'] + s.add_development_dependency "rack", "~> 1.5" + s.add_development_dependency "rack-test", "~> 0.6" + s.add_development_dependency "thin", "~> 1.5" + s.add_development_dependency "bundler", "~> 1" + s.add_development_dependency 'rake', '~> 10.5' +end + diff --git a/lib/rs/Cargo.toml b/lib/rs/Cargo.toml new file mode 100644 index 0000000..8e68175 --- /dev/null +++ b/lib/rs/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "thrift" +description = "Rust bindings for the Apache Thrift RPC system" +version = "0.11.0" +license = "Apache-2.0" +authors = ["Apache Thrift Developers "] +homepage = "http://thrift.apache.org" +documentation = "https://thrift.apache.org" +readme = "README.md" +exclude = ["Makefile*", "test/**"] +keywords = ["thrift"] + +[dependencies] +byteorder = "~1.1.0" +integer-encoding = "~1.0.4" +log = "~0.3.8" +threadpool = "~1.7.1" +try_from = "~0.2.2" + diff --git a/lib/rs/Makefile.am b/lib/rs/Makefile.am new file mode 100644 index 0000000..0a34120 --- /dev/null +++ b/lib/rs/Makefile.am @@ -0,0 +1,46 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +SUBDIRS = . + +if WITH_TESTS +SUBDIRS += test +endif + +install: + @echo '##############################################################' + @echo '##############################################################' + @echo 'The Rust client library should be installed via a Cargo.toml dependency - please see /lib/rs/README.md' + @echo '##############################################################' + @echo '##############################################################' + +check-local: + $(CARGO) test + +all-local: + $(CARGO) build + +clean-local: + $(CARGO) clean + -$(RM) Cargo.lock + +EXTRA_DIST = \ + src \ + Cargo.toml \ + README.md diff --git a/lib/rs/Makefile.in b/lib/rs/Makefile.in new file mode 100644 index 0000000..22856c1 --- /dev/null +++ b/lib/rs/Makefile.in @@ -0,0 +1,827 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@WITH_TESTS_TRUE@am__append_1 = test +subdir = lib/rs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = . test +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . $(am__append_1) +EXTRA_DIST = \ + src \ + Cargo.toml \ + README.md + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/rs/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/rs/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-recursive +all-am: Makefile all-local +installdirs: installdirs-recursive +installdirs-am: +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +style: style-recursive + +style-am: style-local + +uninstall-am: + +.MAKE: $(am__recursive_targets) check-am install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \ + check check-am check-local clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags ctags-am distclean \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +install: + @echo '##############################################################' + @echo '##############################################################' + @echo 'The Rust client library should be installed via a Cargo.toml dependency - please see /lib/rs/README.md' + @echo '##############################################################' + @echo '##############################################################' + +check-local: + $(CARGO) test + +all-local: + $(CARGO) build + +clean-local: + $(CARGO) clean + -$(RM) Cargo.lock + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/rs/README.md b/lib/rs/README.md new file mode 100644 index 0000000..8b35eda --- /dev/null +++ b/lib/rs/README.md @@ -0,0 +1,60 @@ +# Rust Thrift library + +## Overview + +This crate implements the components required to build a working Thrift server +and client. It is divided into the following modules: + + 1. errors + 2. protocol + 3. transport + 4. server + 5. autogen + +The modules are layered as shown. The `generated` layer is code generated by the +Thrift compiler's Rust plugin. It uses the components defined in this crate to +serialize and deserialize types and implement RPC. Users interact with these +types and services by writing their own code on top. + + ```text + +-----------+ + | app dev | + +-----------+ + | generated | <-> errors/results + +-----------+ + | protocol | + +-----------+ + | transport | + +-----------+ + ``` + +## Using this crate + +Add `thrift = "x.y.z"` to your `Cargo.toml`, where `x.y.z` is the version of the +Thrift compiler you're using. + +## API Documentation + +Full [Rustdoc](https://docs.rs/thrift/) + +## Contributing + +Bug reports and PRs are always welcome! Please see the +[Thrift website](https://thrift.apache.org/) for more details. + +Thrift Rust support requires code in several directories: + +* `compiler/cpp/src/thrift/generate/t_rs_generator.cc`: binding code generator +* `lib/rs`: runtime library +* `lib/rs/test`: supplemental tests +* `tutorial/rs`: tutorial client and server +* `test/rs`: cross-language test client and server + +All library code, test code and auto-generated code compiles and passes clippy +without warnings. All new code must do the same! When making changes ensure that: + +* `rustc` does does output any warnings +* `clippy` with default settings does not output any warnings (includes auto-generated code) +* `cargo test` is successful +* `make precross` and `make check` are successful +* `tutorial/bin/tutorial_client` and `tutorial/bin/tutorial_server` communicate diff --git a/lib/rs/src/autogen.rs b/lib/rs/src/autogen.rs new file mode 100644 index 0000000..54d4080 --- /dev/null +++ b/lib/rs/src/autogen.rs @@ -0,0 +1,45 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +//! Thrift compiler auto-generated support. +//! +//! +//! Types and functions used internally by the Thrift compiler's Rust plugin +//! to implement required functionality. Users should never have to use code +//! in this module directly. + +use protocol::{TInputProtocol, TOutputProtocol}; + +/// Specifies the minimum functionality an auto-generated client should provide +/// to communicate with a Thrift server. +pub trait TThriftClient { + /// Returns the input protocol used to read serialized Thrift messages + /// from the Thrift server. + fn i_prot_mut(&mut self) -> &mut TInputProtocol; + /// Returns the output protocol used to write serialized Thrift messages + /// to the Thrift server. + fn o_prot_mut(&mut self) -> &mut TOutputProtocol; + /// Returns the sequence number of the last message written to the Thrift + /// server. Returns `0` if no messages have been written. Sequence + /// numbers should *never* be negative, and this method returns an `i32` + /// simply because the Thrift protocol encodes sequence numbers as `i32` on + /// the wire. + fn sequence_number(&self) -> i32; // FIXME: consider returning a u32 + /// Increments the sequence number, indicating that a message with that + /// number has been sent to the Thrift server. + fn increment_sequence_number(&mut self) -> i32; +} diff --git a/lib/rs/src/errors.rs b/lib/rs/src/errors.rs new file mode 100644 index 0000000..cc0ac78 --- /dev/null +++ b/lib/rs/src/errors.rs @@ -0,0 +1,712 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::convert::{From, Into}; +use std::error::Error as StdError; +use std::fmt::{Debug, Display, Formatter}; +use std::{error, fmt, io, string}; +use try_from::TryFrom; + +use protocol::{TFieldIdentifier, TInputProtocol, TOutputProtocol, TStructIdentifier, TType}; + +// FIXME: should all my error structs impl error::Error as well? +// FIXME: should all fields in TransportError, ProtocolError and ApplicationError be optional? + +/// Error type returned by all runtime library functions. +/// +/// `thrift::Error` is used throughout this crate as well as in auto-generated +/// Rust code. It consists of four variants defined by convention across Thrift +/// implementations: +/// +/// 1. `Transport`: errors encountered while operating on I/O channels +/// 2. `Protocol`: errors encountered during runtime-library processing +/// 3. `Application`: errors encountered within auto-generated code +/// 4. `User`: IDL-defined exception structs +/// +/// The `Application` variant also functions as a catch-all: all handler errors +/// are automatically turned into application errors. +/// +/// All error variants except `Error::User` take an eponymous struct with two +/// required fields: +/// +/// 1. `kind`: variant-specific enum identifying the error sub-type +/// 2. `message`: human-readable error info string +/// +/// `kind` is defined by convention while `message` is freeform. If none of the +/// enumerated kinds are suitable use `Unknown`. +/// +/// To simplify error creation convenience constructors are defined for all +/// variants, and conversions from their structs (`thrift::TransportError`, +/// `thrift::ProtocolError` and `thrift::ApplicationError` into `thrift::Error`. +/// +/// # Examples +/// +/// Create a `TransportError`. +/// +/// ``` +/// use thrift; +/// use thrift::{TransportError, TransportErrorKind}; +/// +/// // explicit +/// let err0: thrift::Result<()> = Err( +/// thrift::Error::Transport( +/// TransportError { +/// kind: TransportErrorKind::TimedOut, +/// message: format!("connection to server timed out") +/// } +/// ) +/// ); +/// +/// // use conversion +/// let err1: thrift::Result<()> = Err( +/// thrift::Error::from( +/// TransportError { +/// kind: TransportErrorKind::TimedOut, +/// message: format!("connection to server timed out") +/// } +/// ) +/// ); +/// +/// // use struct constructor +/// let err2: thrift::Result<()> = Err( +/// thrift::Error::Transport( +/// TransportError::new( +/// TransportErrorKind::TimedOut, +/// "connection to server timed out" +/// ) +/// ) +/// ); +/// +/// +/// // use error variant constructor +/// let err3: thrift::Result<()> = Err( +/// thrift::new_transport_error( +/// TransportErrorKind::TimedOut, +/// "connection to server timed out" +/// ) +/// ); +/// ``` +/// +/// Create an error from a string. +/// +/// ``` +/// use thrift; +/// use thrift::{ApplicationError, ApplicationErrorKind}; +/// +/// // we just use `From::from` to convert a `String` into a `thrift::Error` +/// let err0: thrift::Result<()> = Err( +/// thrift::Error::from("This is an error") +/// ); +/// +/// // err0 is equivalent to... +/// let err1: thrift::Result<()> = Err( +/// thrift::Error::Application( +/// ApplicationError { +/// kind: ApplicationErrorKind::Unknown, +/// message: format!("This is an error") +/// } +/// ) +/// ); +/// ``` +/// +/// Return an IDL-defined exception. +/// +/// ```text +/// // Thrift IDL exception definition. +/// exception Xception { +/// 1: i32 errorCode, +/// 2: string message +/// } +/// ``` +/// +/// ``` +/// use std::convert::From; +/// use std::error::Error; +/// use std::fmt; +/// use std::fmt::{Display, Formatter}; +/// +/// // auto-generated by the Thrift compiler +/// #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +/// pub struct Xception { +/// pub error_code: Option, +/// pub message: Option, +/// } +/// +/// // auto-generated by the Thrift compiler +/// impl Error for Xception { +/// fn description(&self) -> &str { +/// "remote service threw Xception" +/// } +/// } +/// +/// // auto-generated by the Thrift compiler +/// impl From for thrift::Error { +/// fn from(e: Xception) -> Self { +/// thrift::Error::User(Box::new(e)) +/// } +/// } +/// +/// // auto-generated by the Thrift compiler +/// impl Display for Xception { +/// fn fmt(&self, f: &mut Formatter) -> fmt::Result { +/// self.description().fmt(f) +/// } +/// } +/// +/// // in user code... +/// let err: thrift::Result<()> = Err( +/// thrift::Error::from(Xception { error_code: Some(1), message: None }) +/// ); +/// ``` +pub enum Error { + /// Errors encountered while operating on I/O channels. + /// + /// These include *connection closed* and *bind failure*. + Transport(TransportError), + /// Errors encountered during runtime-library processing. + /// + /// These include *message too large* and *unsupported protocol version*. + Protocol(ProtocolError), + /// Errors encountered within auto-generated code, or when incoming + /// or outgoing messages violate the Thrift spec. + /// + /// These include *out-of-order messages* and *missing required struct + /// fields*. + /// + /// This variant also functions as a catch-all: errors from handler + /// functions are automatically returned as an `ApplicationError`. + Application(ApplicationError), + /// IDL-defined exception structs. + User(Box), +} + +impl Error { + /// Create an `ApplicationError` from its wire representation. + /// + /// Application code **should never** call this method directly. + pub fn read_application_error_from_in_protocol(i: &mut TInputProtocol,) + -> ::Result { + let mut message = "general remote error".to_owned(); + let mut kind = ApplicationErrorKind::Unknown; + + i.read_struct_begin()?; + + loop { + let field_ident = i.read_field_begin()?; + + if field_ident.field_type == TType::Stop { + break; + } + + let id = field_ident + .id + .expect("sender should always specify id for non-STOP field"); + + match id { + 1 => { + let remote_message = i.read_string()?; + i.read_field_end()?; + message = remote_message; + } + 2 => { + let remote_type_as_int = i.read_i32()?; + let remote_kind: ApplicationErrorKind = + TryFrom::try_from(remote_type_as_int) + .unwrap_or(ApplicationErrorKind::Unknown); + i.read_field_end()?; + kind = remote_kind; + } + _ => { + i.skip(field_ident.field_type)?; + } + } + } + + i.read_struct_end()?; + + Ok( + ApplicationError { + kind: kind, + message: message, + }, + ) + } + + /// Convert an `ApplicationError` into its wire representation and write + /// it to the remote. + /// + /// Application code **should never** call this method directly. + pub fn write_application_error_to_out_protocol( + e: &ApplicationError, + o: &mut TOutputProtocol, + ) -> ::Result<()> { + o.write_struct_begin(&TStructIdentifier { name: "TApplicationException".to_owned() },)?; + + let message_field = TFieldIdentifier::new("message", TType::String, 1); + let type_field = TFieldIdentifier::new("type", TType::I32, 2); + + o.write_field_begin(&message_field)?; + o.write_string(&e.message)?; + o.write_field_end()?; + + o.write_field_begin(&type_field)?; + o.write_i32(e.kind as i32)?; + o.write_field_end()?; + + o.write_field_stop()?; + o.write_struct_end()?; + + o.flush() + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::Transport(ref e) => TransportError::description(e), + Error::Protocol(ref e) => ProtocolError::description(e), + Error::Application(ref e) => ApplicationError::description(e), + Error::User(ref e) => e.description(), + } + } +} + +impl Debug for Error { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match *self { + Error::Transport(ref e) => Debug::fmt(e, f), + Error::Protocol(ref e) => Debug::fmt(e, f), + Error::Application(ref e) => Debug::fmt(e, f), + Error::User(ref e) => Debug::fmt(e, f), + } + } +} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match *self { + Error::Transport(ref e) => Display::fmt(e, f), + Error::Protocol(ref e) => Display::fmt(e, f), + Error::Application(ref e) => Display::fmt(e, f), + Error::User(ref e) => Display::fmt(e, f), + } + } +} + +impl From for Error { + fn from(s: String) -> Self { + Error::Application( + ApplicationError { + kind: ApplicationErrorKind::Unknown, + message: s, + }, + ) + } +} + +impl<'a> From<&'a str> for Error { + fn from(s: &'a str) -> Self { + Error::Application( + ApplicationError { + kind: ApplicationErrorKind::Unknown, + message: String::from(s), + }, + ) + } +} + +impl From for Error { + fn from(e: TransportError) -> Self { + Error::Transport(e) + } +} + +impl From for Error { + fn from(e: ProtocolError) -> Self { + Error::Protocol(e) + } +} + +impl From for Error { + fn from(e: ApplicationError) -> Self { + Error::Application(e) + } +} + +/// Create a new `Error` instance of type `Transport` that wraps a +/// `TransportError`. +pub fn new_transport_error>(kind: TransportErrorKind, message: S) -> Error { + Error::Transport(TransportError::new(kind, message)) +} + +/// Information about I/O errors. +#[derive(Debug, Eq, PartialEq)] +pub struct TransportError { + /// I/O error variant. + /// + /// If a specific `TransportErrorKind` does not apply use + /// `TransportErrorKind::Unknown`. + pub kind: TransportErrorKind, + /// Human-readable error message. + pub message: String, +} + +impl TransportError { + /// Create a new `TransportError`. + pub fn new>(kind: TransportErrorKind, message: S) -> TransportError { + TransportError { + kind: kind, + message: message.into(), + } + } +} + +/// I/O error categories. +/// +/// This list may grow, and it is not recommended to match against it. +#[derive(Clone, Copy, Eq, Debug, PartialEq)] +pub enum TransportErrorKind { + /// Catch-all I/O error. + Unknown = 0, + /// An I/O operation was attempted when the transport channel was not open. + NotOpen = 1, + /// The transport channel cannot be opened because it was opened previously. + AlreadyOpen = 2, + /// An I/O operation timed out. + TimedOut = 3, + /// A read could not complete because no bytes were available. + EndOfFile = 4, + /// An invalid (buffer/message) size was requested or received. + NegativeSize = 5, + /// Too large a buffer or message size was requested or received. + SizeLimit = 6, +} + +impl TransportError { + fn description(&self) -> &str { + match self.kind { + TransportErrorKind::Unknown => "transport error", + TransportErrorKind::NotOpen => "not open", + TransportErrorKind::AlreadyOpen => "already open", + TransportErrorKind::TimedOut => "timed out", + TransportErrorKind::EndOfFile => "end of file", + TransportErrorKind::NegativeSize => "negative size message", + TransportErrorKind::SizeLimit => "message too long", + } + } +} + +impl Display for TransportError { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +impl TryFrom for TransportErrorKind { + type Err = Error; + fn try_from(from: i32) -> Result { + match from { + 0 => Ok(TransportErrorKind::Unknown), + 1 => Ok(TransportErrorKind::NotOpen), + 2 => Ok(TransportErrorKind::AlreadyOpen), + 3 => Ok(TransportErrorKind::TimedOut), + 4 => Ok(TransportErrorKind::EndOfFile), + 5 => Ok(TransportErrorKind::NegativeSize), + 6 => Ok(TransportErrorKind::SizeLimit), + _ => { + Err( + Error::Protocol( + ProtocolError { + kind: ProtocolErrorKind::Unknown, + message: format!("cannot convert {} to TransportErrorKind", from), + }, + ), + ) + } + } + } +} + +impl From for Error { + fn from(err: io::Error) -> Self { + match err.kind() { + io::ErrorKind::ConnectionReset | + io::ErrorKind::ConnectionRefused | + io::ErrorKind::NotConnected => { + Error::Transport( + TransportError { + kind: TransportErrorKind::NotOpen, + message: err.description().to_owned(), + }, + ) + } + io::ErrorKind::AlreadyExists => { + Error::Transport( + TransportError { + kind: TransportErrorKind::AlreadyOpen, + message: err.description().to_owned(), + }, + ) + } + io::ErrorKind::TimedOut => { + Error::Transport( + TransportError { + kind: TransportErrorKind::TimedOut, + message: err.description().to_owned(), + }, + ) + } + io::ErrorKind::UnexpectedEof => { + Error::Transport( + TransportError { + kind: TransportErrorKind::EndOfFile, + message: err.description().to_owned(), + }, + ) + } + _ => { + Error::Transport( + TransportError { + kind: TransportErrorKind::Unknown, + message: err.description().to_owned(), // FIXME: use io error's debug string + }, + ) + } + } + } +} + +impl From for Error { + fn from(err: string::FromUtf8Error) -> Self { + Error::Protocol( + ProtocolError { + kind: ProtocolErrorKind::InvalidData, + message: err.description().to_owned(), // FIXME: use fmt::Error's debug string + }, + ) + } +} + +/// Create a new `Error` instance of type `Protocol` that wraps a +/// `ProtocolError`. +pub fn new_protocol_error>(kind: ProtocolErrorKind, message: S) -> Error { + Error::Protocol(ProtocolError::new(kind, message)) +} + +/// Information about errors that occur in the runtime library. +#[derive(Debug, Eq, PartialEq)] +pub struct ProtocolError { + /// Protocol error variant. + /// + /// If a specific `ProtocolErrorKind` does not apply use + /// `ProtocolErrorKind::Unknown`. + pub kind: ProtocolErrorKind, + /// Human-readable error message. + pub message: String, +} + +impl ProtocolError { + /// Create a new `ProtocolError`. + pub fn new>(kind: ProtocolErrorKind, message: S) -> ProtocolError { + ProtocolError { + kind: kind, + message: message.into(), + } + } +} + +/// Runtime library error categories. +/// +/// This list may grow, and it is not recommended to match against it. +#[derive(Clone, Copy, Eq, Debug, PartialEq)] +pub enum ProtocolErrorKind { + /// Catch-all runtime-library error. + Unknown = 0, + /// An invalid argument was supplied to a library function, or invalid data + /// was received from a Thrift endpoint. + InvalidData = 1, + /// An invalid size was received in an encoded field. + NegativeSize = 2, + /// Thrift message or field was too long. + SizeLimit = 3, + /// Unsupported or unknown Thrift protocol version. + BadVersion = 4, + /// Unsupported Thrift protocol, server or field type. + NotImplemented = 5, + /// Reached the maximum nested depth to which an encoded Thrift field could + /// be skipped. + DepthLimit = 6, +} + +impl ProtocolError { + fn description(&self) -> &str { + match self.kind { + ProtocolErrorKind::Unknown => "protocol error", + ProtocolErrorKind::InvalidData => "bad data", + ProtocolErrorKind::NegativeSize => "negative message size", + ProtocolErrorKind::SizeLimit => "message too long", + ProtocolErrorKind::BadVersion => "invalid thrift version", + ProtocolErrorKind::NotImplemented => "not implemented", + ProtocolErrorKind::DepthLimit => "maximum skip depth reached", + } + } +} + +impl Display for ProtocolError { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +impl TryFrom for ProtocolErrorKind { + type Err = Error; + fn try_from(from: i32) -> Result { + match from { + 0 => Ok(ProtocolErrorKind::Unknown), + 1 => Ok(ProtocolErrorKind::InvalidData), + 2 => Ok(ProtocolErrorKind::NegativeSize), + 3 => Ok(ProtocolErrorKind::SizeLimit), + 4 => Ok(ProtocolErrorKind::BadVersion), + 5 => Ok(ProtocolErrorKind::NotImplemented), + 6 => Ok(ProtocolErrorKind::DepthLimit), + _ => { + Err( + Error::Protocol( + ProtocolError { + kind: ProtocolErrorKind::Unknown, + message: format!("cannot convert {} to ProtocolErrorKind", from), + }, + ), + ) + } + } + } +} + +/// Create a new `Error` instance of type `Application` that wraps an +/// `ApplicationError`. +pub fn new_application_error>(kind: ApplicationErrorKind, message: S) -> Error { + Error::Application(ApplicationError::new(kind, message)) +} + +/// Information about errors in auto-generated code or in user-implemented +/// service handlers. +#[derive(Debug, Eq, PartialEq)] +pub struct ApplicationError { + /// Application error variant. + /// + /// If a specific `ApplicationErrorKind` does not apply use + /// `ApplicationErrorKind::Unknown`. + pub kind: ApplicationErrorKind, + /// Human-readable error message. + pub message: String, +} + +impl ApplicationError { + /// Create a new `ApplicationError`. + pub fn new>(kind: ApplicationErrorKind, message: S) -> ApplicationError { + ApplicationError { + kind: kind, + message: message.into(), + } + } +} + +/// Auto-generated or user-implemented code error categories. +/// +/// This list may grow, and it is not recommended to match against it. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ApplicationErrorKind { + /// Catch-all application error. + Unknown = 0, + /// Made service call to an unknown service method. + UnknownMethod = 1, + /// Received an unknown Thrift message type. That is, not one of the + /// `thrift::protocol::TMessageType` variants. + InvalidMessageType = 2, + /// Method name in a service reply does not match the name of the + /// receiving service method. + WrongMethodName = 3, + /// Received an out-of-order Thrift message. + BadSequenceId = 4, + /// Service reply is missing required fields. + MissingResult = 5, + /// Auto-generated code failed unexpectedly. + InternalError = 6, + /// Thrift protocol error. When possible use `Error::ProtocolError` with a + /// specific `ProtocolErrorKind` instead. + ProtocolError = 7, + /// *Unknown*. Included only for compatibility with existing Thrift implementations. + InvalidTransform = 8, // ?? + /// Thrift endpoint requested, or is using, an unsupported encoding. + InvalidProtocol = 9, // ?? + /// Thrift endpoint requested, or is using, an unsupported auto-generated client type. + UnsupportedClientType = 10, // ?? +} + +impl ApplicationError { + fn description(&self) -> &str { + match self.kind { + ApplicationErrorKind::Unknown => "service error", + ApplicationErrorKind::UnknownMethod => "unknown service method", + ApplicationErrorKind::InvalidMessageType => "wrong message type received", + ApplicationErrorKind::WrongMethodName => "unknown method reply received", + ApplicationErrorKind::BadSequenceId => "out of order sequence id", + ApplicationErrorKind::MissingResult => "missing method result", + ApplicationErrorKind::InternalError => "remote service threw exception", + ApplicationErrorKind::ProtocolError => "protocol error", + ApplicationErrorKind::InvalidTransform => "invalid transform", + ApplicationErrorKind::InvalidProtocol => "invalid protocol requested", + ApplicationErrorKind::UnsupportedClientType => "unsupported protocol client", + } + } +} + +impl Display for ApplicationError { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +impl TryFrom for ApplicationErrorKind { + type Err = Error; + fn try_from(from: i32) -> Result { + match from { + 0 => Ok(ApplicationErrorKind::Unknown), + 1 => Ok(ApplicationErrorKind::UnknownMethod), + 2 => Ok(ApplicationErrorKind::InvalidMessageType), + 3 => Ok(ApplicationErrorKind::WrongMethodName), + 4 => Ok(ApplicationErrorKind::BadSequenceId), + 5 => Ok(ApplicationErrorKind::MissingResult), + 6 => Ok(ApplicationErrorKind::InternalError), + 7 => Ok(ApplicationErrorKind::ProtocolError), + 8 => Ok(ApplicationErrorKind::InvalidTransform), + 9 => Ok(ApplicationErrorKind::InvalidProtocol), + 10 => Ok(ApplicationErrorKind::UnsupportedClientType), + _ => { + Err( + Error::Application( + ApplicationError { + kind: ApplicationErrorKind::Unknown, + message: format!("cannot convert {} to ApplicationErrorKind", from), + }, + ), + ) + } + } + } +} diff --git a/lib/rs/src/lib.rs b/lib/rs/src/lib.rs new file mode 100644 index 0000000..7ebb10c --- /dev/null +++ b/lib/rs/src/lib.rs @@ -0,0 +1,89 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +//! Rust runtime library for the Apache Thrift RPC system. +//! +//! This crate implements the components required to build a working +//! Thrift server and client. It is divided into the following modules: +//! +//! 1. errors +//! 2. protocol +//! 3. transport +//! 4. server +//! 5. autogen +//! +//! The modules are layered as shown in the diagram below. The `autogen'd` +//! layer is generated by the Thrift compiler's Rust plugin. It uses the +//! types and functions defined in this crate to serialize and deserialize +//! messages and implement RPC. Users interact with these types and services +//! by writing their own code that uses the auto-generated clients and +//! servers. +//! +//! ```text +//! +-----------+ +//! | user app | +//! +-----------+ +//! | autogen'd | (uses errors, autogen) +//! +-----------+ +//! | protocol | +//! +-----------+ +//! | transport | +//! +-----------+ +//! ``` + +#![crate_type = "lib"] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +extern crate byteorder; +extern crate integer_encoding; +extern crate threadpool; +extern crate try_from; + +#[macro_use] +extern crate log; + +// NOTE: this macro has to be defined before any modules. See: +// https://danielkeep.github.io/quick-intro-to-macros.html#some-more-gotchas + +/// Assert that an expression returning a `Result` is a success. If it is, +/// return the value contained in the result, i.e. `expr.unwrap()`. +#[cfg(test)] +macro_rules! assert_success { + ($e: expr) => { + { + let res = $e; + assert!(res.is_ok()); + res.unwrap() + } + } +} + +pub mod protocol; +pub mod server; +pub mod transport; + +mod errors; +pub use errors::*; + +mod autogen; +pub use autogen::*; + +/// Result type returned by all runtime library functions. +/// +/// As is convention this is a typedef of `std::result::Result` +/// with `E` defined as the `thrift::Error` type. +pub type Result = std::result::Result; diff --git a/lib/rs/src/protocol/binary.rs b/lib/rs/src/protocol/binary.rs new file mode 100644 index 0000000..1710733 --- /dev/null +++ b/lib/rs/src/protocol/binary.rs @@ -0,0 +1,926 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt}; +use std::convert::From; +use try_from::TryFrom; + +use {ProtocolError, ProtocolErrorKind}; +use transport::{TReadTransport, TWriteTransport}; +use super::{TFieldIdentifier, TInputProtocol, TInputProtocolFactory, TListIdentifier, + TMapIdentifier, TMessageIdentifier, TMessageType}; +use super::{TOutputProtocol, TOutputProtocolFactory, TSetIdentifier, TStructIdentifier, TType}; + +const BINARY_PROTOCOL_VERSION_1: u32 = 0x80010000; + +/// Read messages encoded in the Thrift simple binary encoding. +/// +/// There are two available modes: `strict` and `non-strict`, where the +/// `non-strict` version does not check for the protocol version in the +/// received message header. +/// +/// # Examples +/// +/// Create and use a `TBinaryInputProtocol`. +/// +/// ```no_run +/// use thrift::protocol::{TBinaryInputProtocol, TInputProtocol}; +/// use thrift::transport::TTcpChannel; +/// +/// let mut channel = TTcpChannel::new(); +/// channel.open("localhost:9090").unwrap(); +/// +/// let mut protocol = TBinaryInputProtocol::new(channel, true); +/// +/// let recvd_bool = protocol.read_bool().unwrap(); +/// let recvd_string = protocol.read_string().unwrap(); +/// ``` +#[derive(Debug)] +pub struct TBinaryInputProtocol +where + T: TReadTransport, +{ + strict: bool, + pub transport: T, // FIXME: shouldn't be public +} + +impl<'a, T> TBinaryInputProtocol +where + T: TReadTransport, +{ + /// Create a `TBinaryInputProtocol` that reads bytes from `transport`. + /// + /// Set `strict` to `true` if all incoming messages contain the protocol + /// version number in the protocol header. + pub fn new(transport: T, strict: bool) -> TBinaryInputProtocol { + TBinaryInputProtocol { + strict: strict, + transport: transport, + } + } +} + +impl TInputProtocol for TBinaryInputProtocol +where + T: TReadTransport, +{ + #[cfg_attr(feature = "cargo-clippy", allow(collapsible_if))] + fn read_message_begin(&mut self) -> ::Result { + let mut first_bytes = vec![0; 4]; + self.transport.read_exact(&mut first_bytes[..])?; + + // the thrift version header is intentionally negative + // so the first check we'll do is see if the sign bit is set + // and if so - assume it's the protocol-version header + if first_bytes[0] >= 8 { + // apparently we got a protocol-version header - check + // it, and if it matches, read the rest of the fields + if first_bytes[0..2] != [0x80, 0x01] { + Err( + ::Error::Protocol( + ProtocolError { + kind: ProtocolErrorKind::BadVersion, + message: format!("received bad version: {:?}", &first_bytes[0..2]), + }, + ), + ) + } else { + let message_type: TMessageType = TryFrom::try_from(first_bytes[3])?; + let name = self.read_string()?; + let sequence_number = self.read_i32()?; + Ok(TMessageIdentifier::new(name, message_type, sequence_number)) + } + } else { + // apparently we didn't get a protocol-version header, + // which happens if the sender is not using the strict protocol + if self.strict { + // we're in strict mode however, and that always + // requires the protocol-version header to be written first + Err( + ::Error::Protocol( + ProtocolError { + kind: ProtocolErrorKind::BadVersion, + message: format!("received bad version: {:?}", &first_bytes[0..2]), + }, + ), + ) + } else { + // in the non-strict version the first message field + // is the message name. strings (byte arrays) are length-prefixed, + // so we've just read the length in the first 4 bytes + let name_size = BigEndian::read_i32(&first_bytes) as usize; + let mut name_buf: Vec = Vec::with_capacity(name_size); + self.transport.read_exact(&mut name_buf)?; + let name = String::from_utf8(name_buf)?; + + // read the rest of the fields + let message_type: TMessageType = self.read_byte().and_then(TryFrom::try_from)?; + let sequence_number = self.read_i32()?; + Ok(TMessageIdentifier::new(name, message_type, sequence_number)) + } + } + } + + fn read_message_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn read_struct_begin(&mut self) -> ::Result> { + Ok(None) + } + + fn read_struct_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn read_field_begin(&mut self) -> ::Result { + let field_type_byte = self.read_byte()?; + let field_type = field_type_from_u8(field_type_byte)?; + let id = match field_type { + TType::Stop => Ok(0), + _ => self.read_i16(), + }?; + Ok(TFieldIdentifier::new::, String, i16>(None, field_type, id),) + } + + fn read_field_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn read_bytes(&mut self) -> ::Result> { + let num_bytes = self.transport.read_i32::()? as usize; + let mut buf = vec![0u8; num_bytes]; + self.transport + .read_exact(&mut buf) + .map(|_| buf) + .map_err(From::from) + } + + fn read_bool(&mut self) -> ::Result { + let b = self.read_i8()?; + match b { + 0 => Ok(false), + _ => Ok(true), + } + } + + fn read_i8(&mut self) -> ::Result { + self.transport.read_i8().map_err(From::from) + } + + fn read_i16(&mut self) -> ::Result { + self.transport + .read_i16::() + .map_err(From::from) + } + + fn read_i32(&mut self) -> ::Result { + self.transport + .read_i32::() + .map_err(From::from) + } + + fn read_i64(&mut self) -> ::Result { + self.transport + .read_i64::() + .map_err(From::from) + } + + fn read_double(&mut self) -> ::Result { + self.transport + .read_f64::() + .map_err(From::from) + } + + fn read_string(&mut self) -> ::Result { + let bytes = self.read_bytes()?; + String::from_utf8(bytes).map_err(From::from) + } + + fn read_list_begin(&mut self) -> ::Result { + let element_type: TType = self.read_byte().and_then(field_type_from_u8)?; + let size = self.read_i32()?; + Ok(TListIdentifier::new(element_type, size)) + } + + fn read_list_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn read_set_begin(&mut self) -> ::Result { + let element_type: TType = self.read_byte().and_then(field_type_from_u8)?; + let size = self.read_i32()?; + Ok(TSetIdentifier::new(element_type, size)) + } + + fn read_set_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn read_map_begin(&mut self) -> ::Result { + let key_type: TType = self.read_byte().and_then(field_type_from_u8)?; + let value_type: TType = self.read_byte().and_then(field_type_from_u8)?; + let size = self.read_i32()?; + Ok(TMapIdentifier::new(key_type, value_type, size)) + } + + fn read_map_end(&mut self) -> ::Result<()> { + Ok(()) + } + + // utility + // + + fn read_byte(&mut self) -> ::Result { + self.transport.read_u8().map_err(From::from) + } +} + +/// Factory for creating instances of `TBinaryInputProtocol`. +#[derive(Default)] +pub struct TBinaryInputProtocolFactory; + +impl TBinaryInputProtocolFactory { + /// Create a `TBinaryInputProtocolFactory`. + pub fn new() -> TBinaryInputProtocolFactory { + TBinaryInputProtocolFactory {} + } +} + +impl TInputProtocolFactory for TBinaryInputProtocolFactory { + fn create(&self, transport: Box) -> Box { + Box::new(TBinaryInputProtocol::new(transport, true)) + } +} + +/// Write messages using the Thrift simple binary encoding. +/// +/// There are two available modes: `strict` and `non-strict`, where the +/// `strict` version writes the protocol version number in the outgoing message +/// header and the `non-strict` version does not. +/// +/// # Examples +/// +/// Create and use a `TBinaryOutputProtocol`. +/// +/// ```no_run +/// use thrift::protocol::{TBinaryOutputProtocol, TOutputProtocol}; +/// use thrift::transport::TTcpChannel; +/// +/// let mut channel = TTcpChannel::new(); +/// channel.open("localhost:9090").unwrap(); +/// +/// let mut protocol = TBinaryOutputProtocol::new(channel, true); +/// +/// protocol.write_bool(true).unwrap(); +/// protocol.write_string("test_string").unwrap(); +/// ``` +#[derive(Debug)] +pub struct TBinaryOutputProtocol +where + T: TWriteTransport, +{ + strict: bool, + pub transport: T, // FIXME: do not make public; only public for testing! +} + +impl TBinaryOutputProtocol +where + T: TWriteTransport, +{ + /// Create a `TBinaryOutputProtocol` that writes bytes to `transport`. + /// + /// Set `strict` to `true` if all outgoing messages should contain the + /// protocol version number in the protocol header. + pub fn new(transport: T, strict: bool) -> TBinaryOutputProtocol { + TBinaryOutputProtocol { + strict: strict, + transport: transport, + } + } + + fn write_transport(&mut self, buf: &[u8]) -> ::Result<()> { + self.transport + .write(buf) + .map(|_| ()) + .map_err(From::from) + } +} + +impl TOutputProtocol for TBinaryOutputProtocol +where + T: TWriteTransport, +{ + fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()> { + if self.strict { + let message_type: u8 = identifier.message_type.into(); + let header = BINARY_PROTOCOL_VERSION_1 | (message_type as u32); + self.transport.write_u32::(header)?; + self.write_string(&identifier.name)?; + self.write_i32(identifier.sequence_number) + } else { + self.write_string(&identifier.name)?; + self.write_byte(identifier.message_type.into())?; + self.write_i32(identifier.sequence_number) + } + } + + fn write_message_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn write_struct_begin(&mut self, _: &TStructIdentifier) -> ::Result<()> { + Ok(()) + } + + fn write_struct_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()> { + if identifier.id.is_none() && identifier.field_type != TType::Stop { + return Err( + ::Error::Protocol( + ProtocolError { + kind: ProtocolErrorKind::Unknown, + message: format!( + "cannot write identifier {:?} without sequence number", + &identifier + ), + }, + ), + ); + } + + self.write_byte(field_type_to_u8(identifier.field_type))?; + if let Some(id) = identifier.id { + self.write_i16(id) + } else { + Ok(()) + } + } + + fn write_field_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn write_field_stop(&mut self) -> ::Result<()> { + self.write_byte(field_type_to_u8(TType::Stop)) + } + + fn write_bytes(&mut self, b: &[u8]) -> ::Result<()> { + self.write_i32(b.len() as i32)?; + self.write_transport(b) + } + + fn write_bool(&mut self, b: bool) -> ::Result<()> { + if b { + self.write_i8(1) + } else { + self.write_i8(0) + } + } + + fn write_i8(&mut self, i: i8) -> ::Result<()> { + self.transport.write_i8(i).map_err(From::from) + } + + fn write_i16(&mut self, i: i16) -> ::Result<()> { + self.transport + .write_i16::(i) + .map_err(From::from) + } + + fn write_i32(&mut self, i: i32) -> ::Result<()> { + self.transport + .write_i32::(i) + .map_err(From::from) + } + + fn write_i64(&mut self, i: i64) -> ::Result<()> { + self.transport + .write_i64::(i) + .map_err(From::from) + } + + fn write_double(&mut self, d: f64) -> ::Result<()> { + self.transport + .write_f64::(d) + .map_err(From::from) + } + + fn write_string(&mut self, s: &str) -> ::Result<()> { + self.write_bytes(s.as_bytes()) + } + + fn write_list_begin(&mut self, identifier: &TListIdentifier) -> ::Result<()> { + self.write_byte(field_type_to_u8(identifier.element_type))?; + self.write_i32(identifier.size) + } + + fn write_list_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> ::Result<()> { + self.write_byte(field_type_to_u8(identifier.element_type))?; + self.write_i32(identifier.size) + } + + fn write_set_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()> { + let key_type = identifier + .key_type + .expect("map identifier to write should contain key type"); + self.write_byte(field_type_to_u8(key_type))?; + let val_type = identifier + .value_type + .expect("map identifier to write should contain value type"); + self.write_byte(field_type_to_u8(val_type))?; + self.write_i32(identifier.size) + } + + fn write_map_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn flush(&mut self) -> ::Result<()> { + self.transport.flush().map_err(From::from) + } + + // utility + // + + fn write_byte(&mut self, b: u8) -> ::Result<()> { + self.transport.write_u8(b).map_err(From::from) + } +} + +/// Factory for creating instances of `TBinaryOutputProtocol`. +#[derive(Default)] +pub struct TBinaryOutputProtocolFactory; + +impl TBinaryOutputProtocolFactory { + /// Create a `TBinaryOutputProtocolFactory`. + pub fn new() -> TBinaryOutputProtocolFactory { + TBinaryOutputProtocolFactory {} + } +} + +impl TOutputProtocolFactory for TBinaryOutputProtocolFactory { + fn create(&self, transport: Box) -> Box { + Box::new(TBinaryOutputProtocol::new(transport, true)) + } +} + +fn field_type_to_u8(field_type: TType) -> u8 { + match field_type { + TType::Stop => 0x00, + TType::Void => 0x01, + TType::Bool => 0x02, + TType::I08 => 0x03, // equivalent to TType::Byte + TType::Double => 0x04, + TType::I16 => 0x06, + TType::I32 => 0x08, + TType::I64 => 0x0A, + TType::String | TType::Utf7 => 0x0B, + TType::Struct => 0x0C, + TType::Map => 0x0D, + TType::Set => 0x0E, + TType::List => 0x0F, + TType::Utf8 => 0x10, + TType::Utf16 => 0x11, + } +} + +fn field_type_from_u8(b: u8) -> ::Result { + match b { + 0x00 => Ok(TType::Stop), + 0x01 => Ok(TType::Void), + 0x02 => Ok(TType::Bool), + 0x03 => Ok(TType::I08), // Equivalent to TType::Byte + 0x04 => Ok(TType::Double), + 0x06 => Ok(TType::I16), + 0x08 => Ok(TType::I32), + 0x0A => Ok(TType::I64), + 0x0B => Ok(TType::String), // technically, also a UTF7, but we'll treat it as string + 0x0C => Ok(TType::Struct), + 0x0D => Ok(TType::Map), + 0x0E => Ok(TType::Set), + 0x0F => Ok(TType::List), + 0x10 => Ok(TType::Utf8), + 0x11 => Ok(TType::Utf16), + unkn => { + Err( + ::Error::Protocol( + ProtocolError { + kind: ProtocolErrorKind::InvalidData, + message: format!("cannot convert {} to TType", unkn), + }, + ), + ) + } + } +} + +#[cfg(test)] +mod tests { + + use protocol::{TFieldIdentifier, TInputProtocol, TListIdentifier, TMapIdentifier, + TMessageIdentifier, TMessageType, TOutputProtocol, TSetIdentifier, + TStructIdentifier, TType}; + use transport::{ReadHalf, TBufferChannel, TIoChannel, WriteHalf}; + + use super::*; + + #[test] + fn must_write_message_call_begin() { + let (_, mut o_prot) = test_objects(); + + let ident = TMessageIdentifier::new("test", TMessageType::Call, 1); + assert!(o_prot.write_message_begin(&ident).is_ok()); + + let expected: [u8; 16] = [ + 0x80, + 0x01, + 0x00, + 0x01, + 0x00, + 0x00, + 0x00, + 0x04, + 0x74, + 0x65, + 0x73, + 0x74, + 0x00, + 0x00, + 0x00, + 0x01, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_write_message_reply_begin() { + let (_, mut o_prot) = test_objects(); + + let ident = TMessageIdentifier::new("test", TMessageType::Reply, 10); + assert!(o_prot.write_message_begin(&ident).is_ok()); + + let expected: [u8; 16] = [ + 0x80, + 0x01, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + 0x04, + 0x74, + 0x65, + 0x73, + 0x74, + 0x00, + 0x00, + 0x00, + 0x0A, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_strict_message_begin() { + let (mut i_prot, mut o_prot) = test_objects(); + + let sent_ident = TMessageIdentifier::new("test", TMessageType::Call, 1); + assert!(o_prot.write_message_begin(&sent_ident).is_ok()); + + copy_write_buffer_to_read_buffer!(o_prot); + + let received_ident = assert_success!(i_prot.read_message_begin()); + assert_eq!(&received_ident, &sent_ident); + } + + #[test] + fn must_write_message_end() { + assert_no_write(|o| o.write_message_end()); + } + + #[test] + fn must_write_struct_begin() { + assert_no_write(|o| o.write_struct_begin(&TStructIdentifier::new("foo"))); + } + + #[test] + fn must_write_struct_end() { + assert_no_write(|o| o.write_struct_end()); + } + + #[test] + fn must_write_field_begin() { + let (_, mut o_prot) = test_objects(); + + assert!( + o_prot + .write_field_begin(&TFieldIdentifier::new("some_field", TType::String, 22)) + .is_ok() + ); + + let expected: [u8; 3] = [0x0B, 0x00, 0x16]; + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_field_begin() { + let (mut i_prot, mut o_prot) = test_objects(); + + let sent_field_ident = TFieldIdentifier::new("foo", TType::I64, 20); + assert!(o_prot.write_field_begin(&sent_field_ident).is_ok()); + + copy_write_buffer_to_read_buffer!(o_prot); + + let expected_ident = TFieldIdentifier { + name: None, + field_type: TType::I64, + id: Some(20), + }; // no name + let received_ident = assert_success!(i_prot.read_field_begin()); + assert_eq!(&received_ident, &expected_ident); + } + + #[test] + fn must_write_stop_field() { + let (_, mut o_prot) = test_objects(); + + assert!(o_prot.write_field_stop().is_ok()); + + let expected: [u8; 1] = [0x00]; + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_field_stop() { + let (mut i_prot, mut o_prot) = test_objects(); + + assert!(o_prot.write_field_stop().is_ok()); + + copy_write_buffer_to_read_buffer!(o_prot); + + let expected_ident = TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: Some(0), + }; // we get id 0 + + let received_ident = assert_success!(i_prot.read_field_begin()); + assert_eq!(&received_ident, &expected_ident); + } + + #[test] + fn must_write_field_end() { + assert_no_write(|o| o.write_field_end()); + } + + #[test] + fn must_write_list_begin() { + let (_, mut o_prot) = test_objects(); + + assert!( + o_prot + .write_list_begin(&TListIdentifier::new(TType::Bool, 5)) + .is_ok() + ); + + let expected: [u8; 5] = [0x02, 0x00, 0x00, 0x00, 0x05]; + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_list_begin() { + let (mut i_prot, mut o_prot) = test_objects(); + + let ident = TListIdentifier::new(TType::List, 900); + assert!(o_prot.write_list_begin(&ident).is_ok()); + + copy_write_buffer_to_read_buffer!(o_prot); + + let received_ident = assert_success!(i_prot.read_list_begin()); + assert_eq!(&received_ident, &ident); + } + + #[test] + fn must_write_list_end() { + assert_no_write(|o| o.write_list_end()); + } + + #[test] + fn must_write_set_begin() { + let (_, mut o_prot) = test_objects(); + + assert!( + o_prot + .write_set_begin(&TSetIdentifier::new(TType::I16, 7)) + .is_ok() + ); + + let expected: [u8; 5] = [0x06, 0x00, 0x00, 0x00, 0x07]; + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_set_begin() { + let (mut i_prot, mut o_prot) = test_objects(); + + let ident = TSetIdentifier::new(TType::I64, 2000); + assert!(o_prot.write_set_begin(&ident).is_ok()); + + copy_write_buffer_to_read_buffer!(o_prot); + + let received_ident_result = i_prot.read_set_begin(); + assert!(received_ident_result.is_ok()); + assert_eq!(&received_ident_result.unwrap(), &ident); + } + + #[test] + fn must_write_set_end() { + assert_no_write(|o| o.write_set_end()); + } + + #[test] + fn must_write_map_begin() { + let (_, mut o_prot) = test_objects(); + + assert!( + o_prot + .write_map_begin(&TMapIdentifier::new(TType::I64, TType::Struct, 32)) + .is_ok() + ); + + let expected: [u8; 6] = [0x0A, 0x0C, 0x00, 0x00, 0x00, 0x20]; + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_map_begin() { + let (mut i_prot, mut o_prot) = test_objects(); + + let ident = TMapIdentifier::new(TType::Map, TType::Set, 100); + assert!(o_prot.write_map_begin(&ident).is_ok()); + + copy_write_buffer_to_read_buffer!(o_prot); + + let received_ident = assert_success!(i_prot.read_map_begin()); + assert_eq!(&received_ident, &ident); + } + + #[test] + fn must_write_map_end() { + assert_no_write(|o| o.write_map_end()); + } + + #[test] + fn must_write_bool_true() { + let (_, mut o_prot) = test_objects(); + + assert!(o_prot.write_bool(true).is_ok()); + + let expected: [u8; 1] = [0x01]; + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_write_bool_false() { + let (_, mut o_prot) = test_objects(); + + assert!(o_prot.write_bool(false).is_ok()); + + let expected: [u8; 1] = [0x00]; + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_read_bool_true() { + let (mut i_prot, _) = test_objects(); + + set_readable_bytes!(i_prot, &[0x01]); + + let read_bool = assert_success!(i_prot.read_bool()); + assert_eq!(read_bool, true); + } + + #[test] + fn must_read_bool_false() { + let (mut i_prot, _) = test_objects(); + + set_readable_bytes!(i_prot, &[0x00]); + + let read_bool = assert_success!(i_prot.read_bool()); + assert_eq!(read_bool, false); + } + + #[test] + fn must_allow_any_non_zero_value_to_be_interpreted_as_bool_true() { + let (mut i_prot, _) = test_objects(); + + set_readable_bytes!(i_prot, &[0xAC]); + + let read_bool = assert_success!(i_prot.read_bool()); + assert_eq!(read_bool, true); + } + + #[test] + fn must_write_bytes() { + let (_, mut o_prot) = test_objects(); + + let bytes: [u8; 10] = [0x0A, 0xCC, 0xD1, 0x84, 0x99, 0x12, 0xAB, 0xBB, 0x45, 0xDF]; + + assert!(o_prot.write_bytes(&bytes).is_ok()); + + let buf = o_prot.transport.write_bytes(); + assert_eq!(&buf[0..4], [0x00, 0x00, 0x00, 0x0A]); // length + assert_eq!(&buf[4..], bytes); // actual bytes + } + + #[test] + fn must_round_trip_bytes() { + let (mut i_prot, mut o_prot) = test_objects(); + + let bytes: [u8; 25] = [ + 0x20, + 0xFD, + 0x18, + 0x84, + 0x99, + 0x12, + 0xAB, + 0xBB, + 0x45, + 0xDF, + 0x34, + 0xDC, + 0x98, + 0xA4, + 0x6D, + 0xF3, + 0x99, + 0xB4, + 0xB7, + 0xD4, + 0x9C, + 0xA5, + 0xB3, + 0xC9, + 0x88, + ]; + + assert!(o_prot.write_bytes(&bytes).is_ok()); + + copy_write_buffer_to_read_buffer!(o_prot); + + let received_bytes = assert_success!(i_prot.read_bytes()); + assert_eq!(&received_bytes, &bytes); + } + + fn test_objects() + -> (TBinaryInputProtocol>, + TBinaryOutputProtocol>) + { + let mem = TBufferChannel::with_capacity(40, 40); + + let (r_mem, w_mem) = mem.split().unwrap(); + + let i_prot = TBinaryInputProtocol::new(r_mem, true); + let o_prot = TBinaryOutputProtocol::new(w_mem, true); + + (i_prot, o_prot) + } + + fn assert_no_write(mut write_fn: F) + where + F: FnMut(&mut TBinaryOutputProtocol>) -> ::Result<()>, + { + let (_, mut o_prot) = test_objects(); + assert!(write_fn(&mut o_prot).is_ok()); + assert_eq!(o_prot.transport.write_bytes().len(), 0); + } +} diff --git a/lib/rs/src/protocol/compact.rs b/lib/rs/src/protocol/compact.rs new file mode 100644 index 0000000..dfe11f8 --- /dev/null +++ b/lib/rs/src/protocol/compact.rs @@ -0,0 +1,2380 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use integer_encoding::{VarIntReader, VarIntWriter}; +use std::convert::From; +use try_from::TryFrom; + +use transport::{TReadTransport, TWriteTransport}; +use super::{TFieldIdentifier, TInputProtocol, TInputProtocolFactory, TListIdentifier, + TMapIdentifier, TMessageIdentifier, TMessageType}; +use super::{TOutputProtocol, TOutputProtocolFactory, TSetIdentifier, TStructIdentifier, TType}; + +const COMPACT_PROTOCOL_ID: u8 = 0x82; +const COMPACT_VERSION: u8 = 0x01; +const COMPACT_VERSION_MASK: u8 = 0x1F; + +/// Read messages encoded in the Thrift compact protocol. +/// +/// # Examples +/// +/// Create and use a `TCompactInputProtocol`. +/// +/// ```no_run +/// use thrift::protocol::{TCompactInputProtocol, TInputProtocol}; +/// use thrift::transport::TTcpChannel; +/// +/// let mut channel = TTcpChannel::new(); +/// channel.open("localhost:9090").unwrap(); +/// +/// let mut protocol = TCompactInputProtocol::new(channel); +/// +/// let recvd_bool = protocol.read_bool().unwrap(); +/// let recvd_string = protocol.read_string().unwrap(); +/// ``` +#[derive(Debug)] +pub struct TCompactInputProtocol +where + T: TReadTransport, +{ + // Identifier of the last field deserialized for a struct. + last_read_field_id: i16, + // Stack of the last read field ids (a new entry is added each time a nested struct is read). + read_field_id_stack: Vec, + // Boolean value for a field. + // Saved because boolean fields and their value are encoded in a single byte, + // and reading the field only occurs after the field id is read. + pending_read_bool_value: Option, + // Underlying transport used for byte-level operations. + transport: T, +} + +impl TCompactInputProtocol +where + T: TReadTransport, +{ + /// Create a `TCompactInputProtocol` that reads bytes from `transport`. + pub fn new(transport: T) -> TCompactInputProtocol { + TCompactInputProtocol { + last_read_field_id: 0, + read_field_id_stack: Vec::new(), + pending_read_bool_value: None, + transport: transport, + } + } + + fn read_list_set_begin(&mut self) -> ::Result<(TType, i32)> { + let header = self.read_byte()?; + let element_type = collection_u8_to_type(header & 0x0F)?; + + let element_count; + let possible_element_count = (header & 0xF0) >> 4; + if possible_element_count != 15 { + // high bits set high if count and type encoded separately + element_count = possible_element_count as i32; + } else { + element_count = self.transport.read_varint::()? as i32; + } + + Ok((element_type, element_count)) + } +} + +impl TInputProtocol for TCompactInputProtocol +where + T: TReadTransport, +{ + fn read_message_begin(&mut self) -> ::Result { + let compact_id = self.read_byte()?; + if compact_id != COMPACT_PROTOCOL_ID { + Err( + ::Error::Protocol( + ::ProtocolError { + kind: ::ProtocolErrorKind::BadVersion, + message: format!("invalid compact protocol header {:?}", compact_id), + }, + ), + ) + } else { + Ok(()) + }?; + + let type_and_byte = self.read_byte()?; + let received_version = type_and_byte & COMPACT_VERSION_MASK; + if received_version != COMPACT_VERSION { + Err( + ::Error::Protocol( + ::ProtocolError { + kind: ::ProtocolErrorKind::BadVersion, + message: format!( + "cannot process compact protocol version {:?}", + received_version + ), + }, + ), + ) + } else { + Ok(()) + }?; + + // NOTE: unsigned right shift will pad with 0s + let message_type: TMessageType = TMessageType::try_from(type_and_byte >> 5)?; + let sequence_number = self.read_i32()?; + let service_call_name = self.read_string()?; + + self.last_read_field_id = 0; + + Ok(TMessageIdentifier::new(service_call_name, message_type, sequence_number),) + } + + fn read_message_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn read_struct_begin(&mut self) -> ::Result> { + self.read_field_id_stack.push(self.last_read_field_id); + self.last_read_field_id = 0; + Ok(None) + } + + fn read_struct_end(&mut self) -> ::Result<()> { + self.last_read_field_id = self.read_field_id_stack + .pop() + .expect("should have previous field ids"); + Ok(()) + } + + fn read_field_begin(&mut self) -> ::Result { + // we can read at least one byte, which is: + // - the type + // - the field delta and the type + let field_type = self.read_byte()?; + let field_delta = (field_type & 0xF0) >> 4; + let field_type = match field_type & 0x0F { + 0x01 => { + self.pending_read_bool_value = Some(true); + Ok(TType::Bool) + } + 0x02 => { + self.pending_read_bool_value = Some(false); + Ok(TType::Bool) + } + ttu8 => u8_to_type(ttu8), + }?; + + match field_type { + TType::Stop => { + Ok( + TFieldIdentifier::new::, String, Option>( + None, + TType::Stop, + None, + ), + ) + } + _ => { + if field_delta != 0 { + self.last_read_field_id += field_delta as i16; + } else { + self.last_read_field_id = self.read_i16()?; + }; + + Ok( + TFieldIdentifier { + name: None, + field_type: field_type, + id: Some(self.last_read_field_id), + }, + ) + } + } + } + + fn read_field_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn read_bool(&mut self) -> ::Result { + match self.pending_read_bool_value.take() { + Some(b) => Ok(b), + None => { + let b = self.read_byte()?; + match b { + 0x01 => Ok(true), + 0x02 => Ok(false), + unkn => { + Err( + ::Error::Protocol( + ::ProtocolError { + kind: ::ProtocolErrorKind::InvalidData, + message: format!("cannot convert {} into bool", unkn), + }, + ), + ) + } + } + } + } + } + + fn read_bytes(&mut self) -> ::Result> { + let len = self.transport.read_varint::()?; + let mut buf = vec![0u8; len as usize]; + self.transport + .read_exact(&mut buf) + .map_err(From::from) + .map(|_| buf) + } + + fn read_i8(&mut self) -> ::Result { + self.read_byte().map(|i| i as i8) + } + + fn read_i16(&mut self) -> ::Result { + self.transport.read_varint::().map_err(From::from) + } + + fn read_i32(&mut self) -> ::Result { + self.transport.read_varint::().map_err(From::from) + } + + fn read_i64(&mut self) -> ::Result { + self.transport.read_varint::().map_err(From::from) + } + + fn read_double(&mut self) -> ::Result { + self.transport + .read_f64::() + .map_err(From::from) + } + + fn read_string(&mut self) -> ::Result { + let bytes = self.read_bytes()?; + String::from_utf8(bytes).map_err(From::from) + } + + fn read_list_begin(&mut self) -> ::Result { + let (element_type, element_count) = self.read_list_set_begin()?; + Ok(TListIdentifier::new(element_type, element_count)) + } + + fn read_list_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn read_set_begin(&mut self) -> ::Result { + let (element_type, element_count) = self.read_list_set_begin()?; + Ok(TSetIdentifier::new(element_type, element_count)) + } + + fn read_set_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn read_map_begin(&mut self) -> ::Result { + let element_count = self.transport.read_varint::()? as i32; + if element_count == 0 { + Ok(TMapIdentifier::new(None, None, 0)) + } else { + let type_header = self.read_byte()?; + let key_type = collection_u8_to_type((type_header & 0xF0) >> 4)?; + let val_type = collection_u8_to_type(type_header & 0x0F)?; + Ok(TMapIdentifier::new(key_type, val_type, element_count)) + } + } + + fn read_map_end(&mut self) -> ::Result<()> { + Ok(()) + } + + // utility + // + + fn read_byte(&mut self) -> ::Result { + let mut buf = [0u8; 1]; + self.transport + .read_exact(&mut buf) + .map_err(From::from) + .map(|_| buf[0]) + } +} + +/// Factory for creating instances of `TCompactInputProtocol`. +#[derive(Default)] +pub struct TCompactInputProtocolFactory; + +impl TCompactInputProtocolFactory { + /// Create a `TCompactInputProtocolFactory`. + pub fn new() -> TCompactInputProtocolFactory { + TCompactInputProtocolFactory {} + } +} + +impl TInputProtocolFactory for TCompactInputProtocolFactory { + fn create(&self, transport: Box) -> Box { + Box::new(TCompactInputProtocol::new(transport)) + } +} + +/// Write messages using the Thrift compact protocol. +/// +/// # Examples +/// +/// Create and use a `TCompactOutputProtocol`. +/// +/// ```no_run +/// use thrift::protocol::{TCompactOutputProtocol, TOutputProtocol}; +/// use thrift::transport::TTcpChannel; +/// +/// let mut channel = TTcpChannel::new(); +/// channel.open("localhost:9090").unwrap(); +/// +/// let mut protocol = TCompactOutputProtocol::new(channel); +/// +/// protocol.write_bool(true).unwrap(); +/// protocol.write_string("test_string").unwrap(); +/// ``` +#[derive(Debug)] +pub struct TCompactOutputProtocol +where + T: TWriteTransport, +{ + // Identifier of the last field serialized for a struct. + last_write_field_id: i16, + // Stack of the last written field ids (new entry added each time a nested struct is written). + write_field_id_stack: Vec, + // Field identifier of the boolean field to be written. + // Saved because boolean fields and their value are encoded in a single byte + pending_write_bool_field_identifier: Option, + // Underlying transport used for byte-level operations. + transport: T, +} + +impl TCompactOutputProtocol +where + T: TWriteTransport, +{ + /// Create a `TCompactOutputProtocol` that writes bytes to `transport`. + pub fn new(transport: T) -> TCompactOutputProtocol { + TCompactOutputProtocol { + last_write_field_id: 0, + write_field_id_stack: Vec::new(), + pending_write_bool_field_identifier: None, + transport: transport, + } + } + + // FIXME: field_type as unconstrained u8 is bad + fn write_field_header(&mut self, field_type: u8, field_id: i16) -> ::Result<()> { + let field_delta = field_id - self.last_write_field_id; + if field_delta > 0 && field_delta < 15 { + self.write_byte(((field_delta as u8) << 4) | field_type)?; + } else { + self.write_byte(field_type)?; + self.write_i16(field_id)?; + } + self.last_write_field_id = field_id; + Ok(()) + } + + fn write_list_set_begin(&mut self, element_type: TType, element_count: i32) -> ::Result<()> { + let elem_identifier = collection_type_to_u8(element_type); + if element_count <= 14 { + let header = (element_count as u8) << 4 | elem_identifier; + self.write_byte(header) + } else { + let header = 0xF0 | elem_identifier; + self.write_byte(header)?; + self.transport + .write_varint(element_count as u32) + .map_err(From::from) + .map(|_| ()) + } + } + + fn assert_no_pending_bool_write(&self) { + if let Some(ref f) = self.pending_write_bool_field_identifier { + panic!("pending bool field {:?} not written", f) + } + } +} + +impl TOutputProtocol for TCompactOutputProtocol +where + T: TWriteTransport, +{ + fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()> { + self.write_byte(COMPACT_PROTOCOL_ID)?; + self.write_byte((u8::from(identifier.message_type) << 5) | COMPACT_VERSION)?; + self.write_i32(identifier.sequence_number)?; + self.write_string(&identifier.name)?; + Ok(()) + } + + fn write_message_end(&mut self) -> ::Result<()> { + self.assert_no_pending_bool_write(); + Ok(()) + } + + fn write_struct_begin(&mut self, _: &TStructIdentifier) -> ::Result<()> { + self.write_field_id_stack.push(self.last_write_field_id); + self.last_write_field_id = 0; + Ok(()) + } + + fn write_struct_end(&mut self) -> ::Result<()> { + self.assert_no_pending_bool_write(); + self.last_write_field_id = self.write_field_id_stack + .pop() + .expect("should have previous field ids"); + Ok(()) + } + + fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()> { + match identifier.field_type { + TType::Bool => { + if self.pending_write_bool_field_identifier.is_some() { + panic!( + "should not have a pending bool while writing another bool with id: \ + {:?}", + identifier + ) + } + self.pending_write_bool_field_identifier = Some(identifier.clone()); + Ok(()) + } + _ => { + let field_type = type_to_u8(identifier.field_type); + let field_id = identifier + .id + .expect("non-stop field should have field id"); + self.write_field_header(field_type, field_id) + } + } + } + + fn write_field_end(&mut self) -> ::Result<()> { + self.assert_no_pending_bool_write(); + Ok(()) + } + + fn write_field_stop(&mut self) -> ::Result<()> { + self.assert_no_pending_bool_write(); + self.write_byte(type_to_u8(TType::Stop)) + } + + fn write_bool(&mut self, b: bool) -> ::Result<()> { + match self.pending_write_bool_field_identifier.take() { + Some(pending) => { + let field_id = pending.id.expect("bool field should have a field id"); + let field_type_as_u8 = if b { 0x01 } else { 0x02 }; + self.write_field_header(field_type_as_u8, field_id) + } + None => { + if b { + self.write_byte(0x01) + } else { + self.write_byte(0x02) + } + } + } + } + + fn write_bytes(&mut self, b: &[u8]) -> ::Result<()> { + self.transport.write_varint(b.len() as u32)?; + self.transport.write_all(b).map_err(From::from) + } + + fn write_i8(&mut self, i: i8) -> ::Result<()> { + self.write_byte(i as u8) + } + + fn write_i16(&mut self, i: i16) -> ::Result<()> { + self.transport + .write_varint(i) + .map_err(From::from) + .map(|_| ()) + } + + fn write_i32(&mut self, i: i32) -> ::Result<()> { + self.transport + .write_varint(i) + .map_err(From::from) + .map(|_| ()) + } + + fn write_i64(&mut self, i: i64) -> ::Result<()> { + self.transport + .write_varint(i) + .map_err(From::from) + .map(|_| ()) + } + + fn write_double(&mut self, d: f64) -> ::Result<()> { + self.transport + .write_f64::(d) + .map_err(From::from) + } + + fn write_string(&mut self, s: &str) -> ::Result<()> { + self.write_bytes(s.as_bytes()) + } + + fn write_list_begin(&mut self, identifier: &TListIdentifier) -> ::Result<()> { + self.write_list_set_begin(identifier.element_type, identifier.size) + } + + fn write_list_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> ::Result<()> { + self.write_list_set_begin(identifier.element_type, identifier.size) + } + + fn write_set_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()> { + if identifier.size == 0 { + self.write_byte(0) + } else { + self.transport.write_varint(identifier.size as u32)?; + + let key_type = identifier + .key_type + .expect("map identifier to write should contain key type"); + let key_type_byte = collection_type_to_u8(key_type) << 4; + + let val_type = identifier + .value_type + .expect("map identifier to write should contain value type"); + let val_type_byte = collection_type_to_u8(val_type); + + let map_type_header = key_type_byte | val_type_byte; + self.write_byte(map_type_header) + } + } + + fn write_map_end(&mut self) -> ::Result<()> { + Ok(()) + } + + fn flush(&mut self) -> ::Result<()> { + self.transport.flush().map_err(From::from) + } + + // utility + // + + fn write_byte(&mut self, b: u8) -> ::Result<()> { + self.transport + .write(&[b]) + .map_err(From::from) + .map(|_| ()) + } +} + +/// Factory for creating instances of `TCompactOutputProtocol`. +#[derive(Default)] +pub struct TCompactOutputProtocolFactory; + +impl TCompactOutputProtocolFactory { + /// Create a `TCompactOutputProtocolFactory`. + pub fn new() -> TCompactOutputProtocolFactory { + TCompactOutputProtocolFactory {} + } +} + +impl TOutputProtocolFactory for TCompactOutputProtocolFactory { + fn create(&self, transport: Box) -> Box { + Box::new(TCompactOutputProtocol::new(transport)) + } +} + +fn collection_type_to_u8(field_type: TType) -> u8 { + match field_type { + TType::Bool => 0x01, + f => type_to_u8(f), + } +} + +fn type_to_u8(field_type: TType) -> u8 { + match field_type { + TType::Stop => 0x00, + TType::I08 => 0x03, // equivalent to TType::Byte + TType::I16 => 0x04, + TType::I32 => 0x05, + TType::I64 => 0x06, + TType::Double => 0x07, + TType::String => 0x08, + TType::List => 0x09, + TType::Set => 0x0A, + TType::Map => 0x0B, + TType::Struct => 0x0C, + _ => panic!(format!("should not have attempted to convert {} to u8", field_type)), + } +} + +fn collection_u8_to_type(b: u8) -> ::Result { + match b { + 0x01 => Ok(TType::Bool), + o => u8_to_type(o), + } +} + +fn u8_to_type(b: u8) -> ::Result { + match b { + 0x00 => Ok(TType::Stop), + 0x03 => Ok(TType::I08), // equivalent to TType::Byte + 0x04 => Ok(TType::I16), + 0x05 => Ok(TType::I32), + 0x06 => Ok(TType::I64), + 0x07 => Ok(TType::Double), + 0x08 => Ok(TType::String), + 0x09 => Ok(TType::List), + 0x0A => Ok(TType::Set), + 0x0B => Ok(TType::Map), + 0x0C => Ok(TType::Struct), + unkn => { + Err( + ::Error::Protocol( + ::ProtocolError { + kind: ::ProtocolErrorKind::InvalidData, + message: format!("cannot convert {} into TType", unkn), + }, + ), + ) + } + } +} + +#[cfg(test)] +mod tests { + + use protocol::{TFieldIdentifier, TInputProtocol, TListIdentifier, TMapIdentifier, + TMessageIdentifier, TMessageType, TOutputProtocol, TSetIdentifier, + TStructIdentifier, TType}; + use transport::{ReadHalf, TBufferChannel, TIoChannel, WriteHalf}; + + use super::*; + + #[test] + fn must_write_message_begin_0() { + let (_, mut o_prot) = test_objects(); + + assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new("foo", TMessageType::Call, 431))); + + let expected: [u8; 8] = [ + 0x82, /* protocol ID */ + 0x21, /* message type | protocol version */ + 0xDE, + 0x06, /* zig-zag varint sequence number */ + 0x03, /* message-name length */ + 0x66, + 0x6F, + 0x6F /* "foo" */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_write_message_begin_1() { + let (_, mut o_prot) = test_objects(); + + assert_success!( + o_prot.write_message_begin(&TMessageIdentifier::new("bar", TMessageType::Reply, 991828)) + ); + + let expected: [u8; 9] = [ + 0x82, /* protocol ID */ + 0x41, /* message type | protocol version */ + 0xA8, + 0x89, + 0x79, /* zig-zag varint sequence number */ + 0x03, /* message-name length */ + 0x62, + 0x61, + 0x72 /* "bar" */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_message_begin() { + let (mut i_prot, mut o_prot) = test_objects(); + + let ident = TMessageIdentifier::new("service_call", TMessageType::Call, 1283948); + + assert_success!(o_prot.write_message_begin(&ident)); + + copy_write_buffer_to_read_buffer!(o_prot); + + let res = assert_success!(i_prot.read_message_begin()); + assert_eq!(&res, &ident); + } + + #[test] + fn must_write_message_end() { + assert_no_write(|o| o.write_message_end()); + } + + // NOTE: structs and fields are tested together + // + + #[test] + fn must_write_struct_with_delta_fields() { + let (_, mut o_prot) = test_objects(); + + // no bytes should be written however + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // write three fields with tiny field ids + // since they're small the field ids will be encoded as deltas + + // since this is the first field (and it's zero) it gets the full varint write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 0))); + assert_success!(o_prot.write_field_end()); + + // since this delta > 0 and < 15 it can be encoded as a delta + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I16, 4))); + assert_success!(o_prot.write_field_end()); + + // since this delta > 0 and < 15 it can be encoded as a delta + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::List, 9))); + assert_success!(o_prot.write_field_end()); + + // now, finish the struct off + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + let expected: [u8; 5] = [ + 0x03, /* field type */ + 0x00, /* first field id */ + 0x44, /* field delta (4) | field type */ + 0x59, /* field delta (5) | field type */ + 0x00 /* field stop */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_struct_with_delta_fields() { + let (mut i_prot, mut o_prot) = test_objects(); + + // no bytes should be written however + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // write three fields with tiny field ids + // since they're small the field ids will be encoded as deltas + + // since this is the first field (and it's zero) it gets the full varint write + let field_ident_1 = TFieldIdentifier::new("foo", TType::I08, 0); + assert_success!(o_prot.write_field_begin(&field_ident_1)); + assert_success!(o_prot.write_field_end()); + + // since this delta > 0 and < 15 it can be encoded as a delta + let field_ident_2 = TFieldIdentifier::new("foo", TType::I16, 4); + assert_success!(o_prot.write_field_begin(&field_ident_2)); + assert_success!(o_prot.write_field_end()); + + // since this delta > 0 and < 15 it can be encoded as a delta + let field_ident_3 = TFieldIdentifier::new("foo", TType::List, 9); + assert_success!(o_prot.write_field_begin(&field_ident_3)); + assert_success!(o_prot.write_field_end()); + + // now, finish the struct off + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + copy_write_buffer_to_read_buffer!(o_prot); + + // read the struct back + assert_success!(i_prot.read_struct_begin()); + + let read_ident_1 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_1, + TFieldIdentifier { + name: None, + ..field_ident_1 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_2 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_2, + TFieldIdentifier { + name: None, + ..field_ident_2 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_3 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_3, + TFieldIdentifier { + name: None, + ..field_ident_3 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_4 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_4, + TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: None, + } + ); + + assert_success!(i_prot.read_struct_end()); + } + + #[test] + fn must_write_struct_with_non_zero_initial_field_and_delta_fields() { + let (_, mut o_prot) = test_objects(); + + // no bytes should be written however + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // write three fields with tiny field ids + // since they're small the field ids will be encoded as deltas + + // gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 1))); + assert_success!(o_prot.write_field_end()); + + // since this delta > 0 and < 15 it can be encoded as a delta + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2))); + assert_success!(o_prot.write_field_end()); + + // since this delta > 0 and < 15 it can be encoded as a delta + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 6))); + assert_success!(o_prot.write_field_end()); + + // now, finish the struct off + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + let expected: [u8; 4] = [ + 0x15, /* field delta (1) | field type */ + 0x1A, /* field delta (1) | field type */ + 0x48, /* field delta (4) | field type */ + 0x00 /* field stop */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_struct_with_non_zero_initial_field_and_delta_fields() { + let (mut i_prot, mut o_prot) = test_objects(); + + // no bytes should be written however + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // write three fields with tiny field ids + // since they're small the field ids will be encoded as deltas + + // gets a delta write + let field_ident_1 = TFieldIdentifier::new("foo", TType::I32, 1); + assert_success!(o_prot.write_field_begin(&field_ident_1)); + assert_success!(o_prot.write_field_end()); + + // since this delta > 0 and < 15 it can be encoded as a delta + let field_ident_2 = TFieldIdentifier::new("foo", TType::Set, 2); + assert_success!(o_prot.write_field_begin(&field_ident_2)); + assert_success!(o_prot.write_field_end()); + + // since this delta > 0 and < 15 it can be encoded as a delta + let field_ident_3 = TFieldIdentifier::new("foo", TType::String, 6); + assert_success!(o_prot.write_field_begin(&field_ident_3)); + assert_success!(o_prot.write_field_end()); + + // now, finish the struct off + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + copy_write_buffer_to_read_buffer!(o_prot); + + // read the struct back + assert_success!(i_prot.read_struct_begin()); + + let read_ident_1 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_1, + TFieldIdentifier { + name: None, + ..field_ident_1 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_2 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_2, + TFieldIdentifier { + name: None, + ..field_ident_2 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_3 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_3, + TFieldIdentifier { + name: None, + ..field_ident_3 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_4 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_4, + TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: None, + } + ); + + assert_success!(i_prot.read_struct_end()); + } + + #[test] + fn must_write_struct_with_long_fields() { + let (_, mut o_prot) = test_objects(); + + // no bytes should be written however + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // write three fields with field ids that cannot be encoded as deltas + + // since this is the first field (and it's zero) it gets the full varint write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 0))); + assert_success!(o_prot.write_field_end()); + + // since this delta is > 15 it is encoded as a zig-zag varint + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 16))); + assert_success!(o_prot.write_field_end()); + + // since this delta is > 15 it is encoded as a zig-zag varint + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 99))); + assert_success!(o_prot.write_field_end()); + + // now, finish the struct off + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + let expected: [u8; 8] = [ + 0x05, /* field type */ + 0x00, /* first field id */ + 0x06, /* field type */ + 0x20, /* zig-zag varint field id */ + 0x0A, /* field type */ + 0xC6, + 0x01, /* zig-zag varint field id */ + 0x00 /* field stop */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_struct_with_long_fields() { + let (mut i_prot, mut o_prot) = test_objects(); + + // no bytes should be written however + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // write three fields with field ids that cannot be encoded as deltas + + // since this is the first field (and it's zero) it gets the full varint write + let field_ident_1 = TFieldIdentifier::new("foo", TType::I32, 0); + assert_success!(o_prot.write_field_begin(&field_ident_1)); + assert_success!(o_prot.write_field_end()); + + // since this delta is > 15 it is encoded as a zig-zag varint + let field_ident_2 = TFieldIdentifier::new("foo", TType::I64, 16); + assert_success!(o_prot.write_field_begin(&field_ident_2)); + assert_success!(o_prot.write_field_end()); + + // since this delta is > 15 it is encoded as a zig-zag varint + let field_ident_3 = TFieldIdentifier::new("foo", TType::Set, 99); + assert_success!(o_prot.write_field_begin(&field_ident_3)); + assert_success!(o_prot.write_field_end()); + + // now, finish the struct off + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + copy_write_buffer_to_read_buffer!(o_prot); + + // read the struct back + assert_success!(i_prot.read_struct_begin()); + + let read_ident_1 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_1, + TFieldIdentifier { + name: None, + ..field_ident_1 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_2 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_2, + TFieldIdentifier { + name: None, + ..field_ident_2 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_3 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_3, + TFieldIdentifier { + name: None, + ..field_ident_3 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_4 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_4, + TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: None, + } + ); + + assert_success!(i_prot.read_struct_end()); + } + + #[test] + fn must_write_struct_with_mix_of_long_and_delta_fields() { + let (_, mut o_prot) = test_objects(); + + // no bytes should be written however + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // write three fields with field ids that cannot be encoded as deltas + + // since the delta is > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1))); + assert_success!(o_prot.write_field_end()); + + // since this delta > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9))); + assert_success!(o_prot.write_field_end()); + + // since this delta is > 15 it is encoded as a zig-zag varint + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 1000))); + assert_success!(o_prot.write_field_end()); + + // since this delta is > 15 it is encoded as a zig-zag varint + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2001))); + assert_success!(o_prot.write_field_end()); + + // since this is only 3 up from the previous it is recorded as a delta + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2004))); + assert_success!(o_prot.write_field_end()); + + // now, finish the struct off + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + let expected: [u8; 10] = [ + 0x16, /* field delta (1) | field type */ + 0x85, /* field delta (8) | field type */ + 0x0A, /* field type */ + 0xD0, + 0x0F, /* zig-zag varint field id */ + 0x0A, /* field type */ + 0xA2, + 0x1F, /* zig-zag varint field id */ + 0x3A, /* field delta (3) | field type */ + 0x00 /* field stop */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_struct_with_mix_of_long_and_delta_fields() { + let (mut i_prot, mut o_prot) = test_objects(); + + // no bytes should be written however + let struct_ident = TStructIdentifier::new("foo"); + assert_success!(o_prot.write_struct_begin(&struct_ident)); + + // write three fields with field ids that cannot be encoded as deltas + + // since the delta is > 0 and < 15 it gets a delta write + let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1); + assert_success!(o_prot.write_field_begin(&field_ident_1)); + assert_success!(o_prot.write_field_end()); + + // since this delta > 0 and < 15 it gets a delta write + let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9); + assert_success!(o_prot.write_field_begin(&field_ident_2)); + assert_success!(o_prot.write_field_end()); + + // since this delta is > 15 it is encoded as a zig-zag varint + let field_ident_3 = TFieldIdentifier::new("foo", TType::Set, 1000); + assert_success!(o_prot.write_field_begin(&field_ident_3)); + assert_success!(o_prot.write_field_end()); + + // since this delta is > 15 it is encoded as a zig-zag varint + let field_ident_4 = TFieldIdentifier::new("foo", TType::Set, 2001); + assert_success!(o_prot.write_field_begin(&field_ident_4)); + assert_success!(o_prot.write_field_end()); + + // since this is only 3 up from the previous it is recorded as a delta + let field_ident_5 = TFieldIdentifier::new("foo", TType::Set, 2004); + assert_success!(o_prot.write_field_begin(&field_ident_5)); + assert_success!(o_prot.write_field_end()); + + // now, finish the struct off + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + copy_write_buffer_to_read_buffer!(o_prot); + + // read the struct back + assert_success!(i_prot.read_struct_begin()); + + let read_ident_1 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_1, + TFieldIdentifier { + name: None, + ..field_ident_1 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_2 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_2, + TFieldIdentifier { + name: None, + ..field_ident_2 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_3 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_3, + TFieldIdentifier { + name: None, + ..field_ident_3 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_4 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_4, + TFieldIdentifier { + name: None, + ..field_ident_4 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_5 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_5, + TFieldIdentifier { + name: None, + ..field_ident_5 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_6 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_6, + TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: None, + } + ); + + assert_success!(i_prot.read_struct_end()); + } + + #[test] + fn must_write_nested_structs_0() { + // last field of the containing struct is a delta + // first field of the the contained struct is a delta + + let (_, mut o_prot) = test_objects(); + + // start containing struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // containing struct + // since the delta is > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1))); + assert_success!(o_prot.write_field_end()); + + // containing struct + // since this delta > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9))); + assert_success!(o_prot.write_field_end()); + + // start contained struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // contained struct + // since the delta is > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 7))); + assert_success!(o_prot.write_field_end()); + + // contained struct + // since this delta > 15 it gets a full write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 24))); + assert_success!(o_prot.write_field_end()); + + // end contained struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + // end containing struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + let expected: [u8; 7] = [ + 0x16, /* field delta (1) | field type */ + 0x85, /* field delta (8) | field type */ + 0x73, /* field delta (7) | field type */ + 0x07, /* field type */ + 0x30, /* zig-zag varint field id */ + 0x00, /* field stop - contained */ + 0x00 /* field stop - containing */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_nested_structs_0() { + // last field of the containing struct is a delta + // first field of the the contained struct is a delta + + let (mut i_prot, mut o_prot) = test_objects(); + + // start containing struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // containing struct + // since the delta is > 0 and < 15 it gets a delta write + let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1); + assert_success!(o_prot.write_field_begin(&field_ident_1)); + assert_success!(o_prot.write_field_end()); + + // containing struct + // since this delta > 0 and < 15 it gets a delta write + let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9); + assert_success!(o_prot.write_field_begin(&field_ident_2)); + assert_success!(o_prot.write_field_end()); + + // start contained struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // contained struct + // since the delta is > 0 and < 15 it gets a delta write + let field_ident_3 = TFieldIdentifier::new("foo", TType::I08, 7); + assert_success!(o_prot.write_field_begin(&field_ident_3)); + assert_success!(o_prot.write_field_end()); + + // contained struct + // since this delta > 15 it gets a full write + let field_ident_4 = TFieldIdentifier::new("foo", TType::Double, 24); + assert_success!(o_prot.write_field_begin(&field_ident_4)); + assert_success!(o_prot.write_field_end()); + + // end contained struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + // end containing struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + copy_write_buffer_to_read_buffer!(o_prot); + + // read containing struct back + assert_success!(i_prot.read_struct_begin()); + + let read_ident_1 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_1, + TFieldIdentifier { + name: None, + ..field_ident_1 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_2 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_2, + TFieldIdentifier { + name: None, + ..field_ident_2 + } + ); + assert_success!(i_prot.read_field_end()); + + // read contained struct back + assert_success!(i_prot.read_struct_begin()); + + let read_ident_3 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_3, + TFieldIdentifier { + name: None, + ..field_ident_3 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_4 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_4, + TFieldIdentifier { + name: None, + ..field_ident_4 + } + ); + assert_success!(i_prot.read_field_end()); + + // end contained struct + let read_ident_6 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_6, + TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: None, + } + ); + assert_success!(i_prot.read_struct_end()); + + // end containing struct + let read_ident_7 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_7, + TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: None, + } + ); + assert_success!(i_prot.read_struct_end()); + } + + #[test] + fn must_write_nested_structs_1() { + // last field of the containing struct is a delta + // first field of the the contained struct is a full write + + let (_, mut o_prot) = test_objects(); + + // start containing struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // containing struct + // since the delta is > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1))); + assert_success!(o_prot.write_field_end()); + + // containing struct + // since this delta > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9))); + assert_success!(o_prot.write_field_end()); + + // start contained struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // contained struct + // since this delta > 15 it gets a full write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 24))); + assert_success!(o_prot.write_field_end()); + + // contained struct + // since the delta is > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 27))); + assert_success!(o_prot.write_field_end()); + + // end contained struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + // end containing struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + let expected: [u8; 7] = [ + 0x16, /* field delta (1) | field type */ + 0x85, /* field delta (8) | field type */ + 0x07, /* field type */ + 0x30, /* zig-zag varint field id */ + 0x33, /* field delta (3) | field type */ + 0x00, /* field stop - contained */ + 0x00 /* field stop - containing */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_nested_structs_1() { + // last field of the containing struct is a delta + // first field of the the contained struct is a full write + + let (mut i_prot, mut o_prot) = test_objects(); + + // start containing struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // containing struct + // since the delta is > 0 and < 15 it gets a delta write + let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1); + assert_success!(o_prot.write_field_begin(&field_ident_1)); + assert_success!(o_prot.write_field_end()); + + // containing struct + // since this delta > 0 and < 15 it gets a delta write + let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9); + assert_success!(o_prot.write_field_begin(&field_ident_2)); + assert_success!(o_prot.write_field_end()); + + // start contained struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // contained struct + // since this delta > 15 it gets a full write + let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 24); + assert_success!(o_prot.write_field_begin(&field_ident_3)); + assert_success!(o_prot.write_field_end()); + + // contained struct + // since the delta is > 0 and < 15 it gets a delta write + let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 27); + assert_success!(o_prot.write_field_begin(&field_ident_4)); + assert_success!(o_prot.write_field_end()); + + // end contained struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + // end containing struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + copy_write_buffer_to_read_buffer!(o_prot); + + // read containing struct back + assert_success!(i_prot.read_struct_begin()); + + let read_ident_1 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_1, + TFieldIdentifier { + name: None, + ..field_ident_1 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_2 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_2, + TFieldIdentifier { + name: None, + ..field_ident_2 + } + ); + assert_success!(i_prot.read_field_end()); + + // read contained struct back + assert_success!(i_prot.read_struct_begin()); + + let read_ident_3 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_3, + TFieldIdentifier { + name: None, + ..field_ident_3 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_4 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_4, + TFieldIdentifier { + name: None, + ..field_ident_4 + } + ); + assert_success!(i_prot.read_field_end()); + + // end contained struct + let read_ident_6 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_6, + TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: None, + } + ); + assert_success!(i_prot.read_struct_end()); + + // end containing struct + let read_ident_7 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_7, + TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: None, + } + ); + assert_success!(i_prot.read_struct_end()); + } + + #[test] + fn must_write_nested_structs_2() { + // last field of the containing struct is a full write + // first field of the the contained struct is a delta write + + let (_, mut o_prot) = test_objects(); + + // start containing struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // containing struct + // since the delta is > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1))); + assert_success!(o_prot.write_field_end()); + + // containing struct + // since this delta > 15 it gets a full write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 21))); + assert_success!(o_prot.write_field_end()); + + // start contained struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // contained struct + // since this delta > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 7))); + assert_success!(o_prot.write_field_end()); + + // contained struct + // since the delta is > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 10))); + assert_success!(o_prot.write_field_end()); + + // end contained struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + // end containing struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + let expected: [u8; 7] = [ + 0x16, /* field delta (1) | field type */ + 0x08, /* field type */ + 0x2A, /* zig-zag varint field id */ + 0x77, /* field delta(7) | field type */ + 0x33, /* field delta (3) | field type */ + 0x00, /* field stop - contained */ + 0x00 /* field stop - containing */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_nested_structs_2() { + let (mut i_prot, mut o_prot) = test_objects(); + + // start containing struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // containing struct + // since the delta is > 0 and < 15 it gets a delta write + let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1); + assert_success!(o_prot.write_field_begin(&field_ident_1)); + assert_success!(o_prot.write_field_end()); + + // containing struct + // since this delta > 15 it gets a full write + let field_ident_2 = TFieldIdentifier::new("foo", TType::String, 21); + assert_success!(o_prot.write_field_begin(&field_ident_2)); + assert_success!(o_prot.write_field_end()); + + // start contained struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // contained struct + // since this delta > 0 and < 15 it gets a delta write + let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 7); + assert_success!(o_prot.write_field_begin(&field_ident_3)); + assert_success!(o_prot.write_field_end()); + + // contained struct + // since the delta is > 0 and < 15 it gets a delta write + let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 10); + assert_success!(o_prot.write_field_begin(&field_ident_4)); + assert_success!(o_prot.write_field_end()); + + // end contained struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + // end containing struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + copy_write_buffer_to_read_buffer!(o_prot); + + // read containing struct back + assert_success!(i_prot.read_struct_begin()); + + let read_ident_1 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_1, + TFieldIdentifier { + name: None, + ..field_ident_1 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_2 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_2, + TFieldIdentifier { + name: None, + ..field_ident_2 + } + ); + assert_success!(i_prot.read_field_end()); + + // read contained struct back + assert_success!(i_prot.read_struct_begin()); + + let read_ident_3 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_3, + TFieldIdentifier { + name: None, + ..field_ident_3 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_4 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_4, + TFieldIdentifier { + name: None, + ..field_ident_4 + } + ); + assert_success!(i_prot.read_field_end()); + + // end contained struct + let read_ident_6 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_6, + TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: None, + } + ); + assert_success!(i_prot.read_struct_end()); + + // end containing struct + let read_ident_7 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_7, + TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: None, + } + ); + assert_success!(i_prot.read_struct_end()); + } + + #[test] + fn must_write_nested_structs_3() { + // last field of the containing struct is a full write + // first field of the the contained struct is a full write + + let (_, mut o_prot) = test_objects(); + + // start containing struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // containing struct + // since the delta is > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1))); + assert_success!(o_prot.write_field_end()); + + // containing struct + // since this delta > 15 it gets a full write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 21))); + assert_success!(o_prot.write_field_end()); + + // start contained struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // contained struct + // since this delta > 15 it gets a full write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 21))); + assert_success!(o_prot.write_field_end()); + + // contained struct + // since the delta is > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 27))); + assert_success!(o_prot.write_field_end()); + + // end contained struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + // end containing struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + let expected: [u8; 8] = [ + 0x16, /* field delta (1) | field type */ + 0x08, /* field type */ + 0x2A, /* zig-zag varint field id */ + 0x07, /* field type */ + 0x2A, /* zig-zag varint field id */ + 0x63, /* field delta (6) | field type */ + 0x00, /* field stop - contained */ + 0x00 /* field stop - containing */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_nested_structs_3() { + // last field of the containing struct is a full write + // first field of the the contained struct is a full write + + let (mut i_prot, mut o_prot) = test_objects(); + + // start containing struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // containing struct + // since the delta is > 0 and < 15 it gets a delta write + let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1); + assert_success!(o_prot.write_field_begin(&field_ident_1)); + assert_success!(o_prot.write_field_end()); + + // containing struct + // since this delta > 15 it gets a full write + let field_ident_2 = TFieldIdentifier::new("foo", TType::String, 21); + assert_success!(o_prot.write_field_begin(&field_ident_2)); + assert_success!(o_prot.write_field_end()); + + // start contained struct + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // contained struct + // since this delta > 15 it gets a full write + let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 21); + assert_success!(o_prot.write_field_begin(&field_ident_3)); + assert_success!(o_prot.write_field_end()); + + // contained struct + // since the delta is > 0 and < 15 it gets a delta write + let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 27); + assert_success!(o_prot.write_field_begin(&field_ident_4)); + assert_success!(o_prot.write_field_end()); + + // end contained struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + // end containing struct + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + copy_write_buffer_to_read_buffer!(o_prot); + + // read containing struct back + assert_success!(i_prot.read_struct_begin()); + + let read_ident_1 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_1, + TFieldIdentifier { + name: None, + ..field_ident_1 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_2 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_2, + TFieldIdentifier { + name: None, + ..field_ident_2 + } + ); + assert_success!(i_prot.read_field_end()); + + // read contained struct back + assert_success!(i_prot.read_struct_begin()); + + let read_ident_3 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_3, + TFieldIdentifier { + name: None, + ..field_ident_3 + } + ); + assert_success!(i_prot.read_field_end()); + + let read_ident_4 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_4, + TFieldIdentifier { + name: None, + ..field_ident_4 + } + ); + assert_success!(i_prot.read_field_end()); + + // end contained struct + let read_ident_6 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_6, + TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: None, + } + ); + assert_success!(i_prot.read_struct_end()); + + // end containing struct + let read_ident_7 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_7, + TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: None, + } + ); + assert_success!(i_prot.read_struct_end()); + } + + #[test] + fn must_write_bool_field() { + let (_, mut o_prot) = test_objects(); + + // no bytes should be written however + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + + // write three fields with field ids that cannot be encoded as deltas + + // since the delta is > 0 and < 16 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1))); + assert_success!(o_prot.write_bool(true)); + assert_success!(o_prot.write_field_end()); + + // since this delta > 0 and < 15 it gets a delta write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 9))); + assert_success!(o_prot.write_bool(false)); + assert_success!(o_prot.write_field_end()); + + // since this delta > 15 it gets a full write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 26))); + assert_success!(o_prot.write_bool(true)); + assert_success!(o_prot.write_field_end()); + + // since this delta > 15 it gets a full write + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 45))); + assert_success!(o_prot.write_bool(false)); + assert_success!(o_prot.write_field_end()); + + // now, finish the struct off + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + let expected: [u8; 7] = [ + 0x11, /* field delta (1) | true */ + 0x82, /* field delta (8) | false */ + 0x01, /* true */ + 0x34, /* field id */ + 0x02, /* false */ + 0x5A, /* field id */ + 0x00 /* stop field */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_bool_field() { + let (mut i_prot, mut o_prot) = test_objects(); + + // no bytes should be written however + let struct_ident = TStructIdentifier::new("foo"); + assert_success!(o_prot.write_struct_begin(&struct_ident)); + + // write two fields + + // since the delta is > 0 and < 16 it gets a delta write + let field_ident_1 = TFieldIdentifier::new("foo", TType::Bool, 1); + assert_success!(o_prot.write_field_begin(&field_ident_1)); + assert_success!(o_prot.write_bool(true)); + assert_success!(o_prot.write_field_end()); + + // since this delta > 0 and < 15 it gets a delta write + let field_ident_2 = TFieldIdentifier::new("foo", TType::Bool, 9); + assert_success!(o_prot.write_field_begin(&field_ident_2)); + assert_success!(o_prot.write_bool(false)); + assert_success!(o_prot.write_field_end()); + + // since this delta > 15 it gets a full write + let field_ident_3 = TFieldIdentifier::new("foo", TType::Bool, 26); + assert_success!(o_prot.write_field_begin(&field_ident_3)); + assert_success!(o_prot.write_bool(true)); + assert_success!(o_prot.write_field_end()); + + // since this delta > 15 it gets a full write + let field_ident_4 = TFieldIdentifier::new("foo", TType::Bool, 45); + assert_success!(o_prot.write_field_begin(&field_ident_4)); + assert_success!(o_prot.write_bool(false)); + assert_success!(o_prot.write_field_end()); + + // now, finish the struct off + assert_success!(o_prot.write_field_stop()); + assert_success!(o_prot.write_struct_end()); + + copy_write_buffer_to_read_buffer!(o_prot); + + // read the struct back + assert_success!(i_prot.read_struct_begin()); + + let read_ident_1 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_1, + TFieldIdentifier { + name: None, + ..field_ident_1 + } + ); + let read_value_1 = assert_success!(i_prot.read_bool()); + assert_eq!(read_value_1, true); + assert_success!(i_prot.read_field_end()); + + let read_ident_2 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_2, + TFieldIdentifier { + name: None, + ..field_ident_2 + } + ); + let read_value_2 = assert_success!(i_prot.read_bool()); + assert_eq!(read_value_2, false); + assert_success!(i_prot.read_field_end()); + + let read_ident_3 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_3, + TFieldIdentifier { + name: None, + ..field_ident_3 + } + ); + let read_value_3 = assert_success!(i_prot.read_bool()); + assert_eq!(read_value_3, true); + assert_success!(i_prot.read_field_end()); + + let read_ident_4 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_4, + TFieldIdentifier { + name: None, + ..field_ident_4 + } + ); + let read_value_4 = assert_success!(i_prot.read_bool()); + assert_eq!(read_value_4, false); + assert_success!(i_prot.read_field_end()); + + let read_ident_5 = assert_success!(i_prot.read_field_begin()); + assert_eq!( + read_ident_5, + TFieldIdentifier { + name: None, + field_type: TType::Stop, + id: None, + } + ); + + assert_success!(i_prot.read_struct_end()); + } + + #[test] + #[should_panic] + fn must_fail_if_write_field_end_without_writing_bool_value() { + let (_, mut o_prot) = test_objects(); + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1))); + o_prot.write_field_end().unwrap(); + } + + #[test] + #[should_panic] + fn must_fail_if_write_stop_field_without_writing_bool_value() { + let (_, mut o_prot) = test_objects(); + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1))); + o_prot.write_field_stop().unwrap(); + } + + #[test] + #[should_panic] + fn must_fail_if_write_struct_end_without_writing_bool_value() { + let (_, mut o_prot) = test_objects(); + assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); + assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1))); + o_prot.write_struct_end().unwrap(); + } + + #[test] + #[should_panic] + fn must_fail_if_write_struct_end_without_any_fields() { + let (_, mut o_prot) = test_objects(); + o_prot.write_struct_end().unwrap(); + } + + #[test] + fn must_write_field_end() { + assert_no_write(|o| o.write_field_end()); + } + + #[test] + fn must_write_small_sized_list_begin() { + let (_, mut o_prot) = test_objects(); + + assert_success!(o_prot.write_list_begin(&TListIdentifier::new(TType::I64, 4))); + + let expected: [u8; 1] = [0x46 /* size | elem_type */]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_small_sized_list_begin() { + let (mut i_prot, mut o_prot) = test_objects(); + + let ident = TListIdentifier::new(TType::I08, 10); + + assert_success!(o_prot.write_list_begin(&ident)); + + copy_write_buffer_to_read_buffer!(o_prot); + + let res = assert_success!(i_prot.read_list_begin()); + assert_eq!(&res, &ident); + } + + #[test] + fn must_write_large_sized_list_begin() { + let (_, mut o_prot) = test_objects(); + + let res = o_prot.write_list_begin(&TListIdentifier::new(TType::List, 9999)); + assert!(res.is_ok()); + + let expected: [u8; 3] = [ + 0xF9, /* 0xF0 | elem_type */ + 0x8F, + 0x4E /* size as varint */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_large_sized_list_begin() { + let (mut i_prot, mut o_prot) = test_objects(); + + let ident = TListIdentifier::new(TType::Set, 47381); + + assert_success!(o_prot.write_list_begin(&ident)); + + copy_write_buffer_to_read_buffer!(o_prot); + + let res = assert_success!(i_prot.read_list_begin()); + assert_eq!(&res, &ident); + } + + #[test] + fn must_write_list_end() { + assert_no_write(|o| o.write_list_end()); + } + + #[test] + fn must_write_small_sized_set_begin() { + let (_, mut o_prot) = test_objects(); + + assert_success!(o_prot.write_set_begin(&TSetIdentifier::new(TType::Struct, 2))); + + let expected: [u8; 1] = [0x2C /* size | elem_type */]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_small_sized_set_begin() { + let (mut i_prot, mut o_prot) = test_objects(); + + let ident = TSetIdentifier::new(TType::I16, 7); + + assert_success!(o_prot.write_set_begin(&ident)); + + copy_write_buffer_to_read_buffer!(o_prot); + + let res = assert_success!(i_prot.read_set_begin()); + assert_eq!(&res, &ident); + } + + #[test] + fn must_write_large_sized_set_begin() { + let (_, mut o_prot) = test_objects(); + + assert_success!(o_prot.write_set_begin(&TSetIdentifier::new(TType::Double, 23891))); + + let expected: [u8; 4] = [ + 0xF7, /* 0xF0 | elem_type */ + 0xD3, + 0xBA, + 0x01 /* size as varint */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_large_sized_set_begin() { + let (mut i_prot, mut o_prot) = test_objects(); + + let ident = TSetIdentifier::new(TType::Map, 3928429); + + assert_success!(o_prot.write_set_begin(&ident)); + + copy_write_buffer_to_read_buffer!(o_prot); + + let res = assert_success!(i_prot.read_set_begin()); + assert_eq!(&res, &ident); + } + + #[test] + fn must_write_set_end() { + assert_no_write(|o| o.write_set_end()); + } + + #[test] + fn must_write_zero_sized_map_begin() { + let (_, mut o_prot) = test_objects(); + + assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::String, TType::I32, 0))); + + let expected: [u8; 1] = [0x00]; // since size is zero we don't write anything + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_read_zero_sized_map_begin() { + let (mut i_prot, mut o_prot) = test_objects(); + + assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Double, TType::I32, 0))); + + copy_write_buffer_to_read_buffer!(o_prot); + + let res = assert_success!(i_prot.read_map_begin()); + assert_eq!( + &res, + &TMapIdentifier { + key_type: None, + value_type: None, + size: 0, + } + ); + } + + #[test] + fn must_write_map_begin() { + let (_, mut o_prot) = test_objects(); + + assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Double, TType::String, 238))); + + let expected: [u8; 3] = [ + 0xEE, + 0x01, /* size as varint */ + 0x78 /* key type | val type */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_map_begin() { + let (mut i_prot, mut o_prot) = test_objects(); + + let ident = TMapIdentifier::new(TType::Map, TType::List, 1928349); + + assert_success!(o_prot.write_map_begin(&ident)); + + copy_write_buffer_to_read_buffer!(o_prot); + + let res = assert_success!(i_prot.read_map_begin()); + assert_eq!(&res, &ident); + } + + #[test] + fn must_write_map_end() { + assert_no_write(|o| o.write_map_end()); + } + + #[test] + fn must_write_map_with_bool_key_and_value() { + let (_, mut o_prot) = test_objects(); + + assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Bool, TType::Bool, 1))); + assert_success!(o_prot.write_bool(true)); + assert_success!(o_prot.write_bool(false)); + assert_success!(o_prot.write_map_end()); + + let expected: [u8; 4] = [ + 0x01, /* size as varint */ + 0x11, /* key type | val type */ + 0x01, /* key: true */ + 0x02 /* val: false */, + ]; + + assert_eq_written_bytes!(o_prot, expected); + } + + #[test] + fn must_round_trip_map_with_bool_value() { + let (mut i_prot, mut o_prot) = test_objects(); + + let map_ident = TMapIdentifier::new(TType::Bool, TType::Bool, 2); + assert_success!(o_prot.write_map_begin(&map_ident)); + assert_success!(o_prot.write_bool(true)); + assert_success!(o_prot.write_bool(false)); + assert_success!(o_prot.write_bool(false)); + assert_success!(o_prot.write_bool(true)); + assert_success!(o_prot.write_map_end()); + + copy_write_buffer_to_read_buffer!(o_prot); + + // map header + let rcvd_ident = assert_success!(i_prot.read_map_begin()); + assert_eq!(&rcvd_ident, &map_ident); + // key 1 + let b = assert_success!(i_prot.read_bool()); + assert_eq!(b, true); + // val 1 + let b = assert_success!(i_prot.read_bool()); + assert_eq!(b, false); + // key 2 + let b = assert_success!(i_prot.read_bool()); + assert_eq!(b, false); + // val 2 + let b = assert_success!(i_prot.read_bool()); + assert_eq!(b, true); + // map end + assert_success!(i_prot.read_map_end()); + } + + #[test] + fn must_read_map_end() { + let (mut i_prot, _) = test_objects(); + assert!(i_prot.read_map_end().is_ok()); // will blow up if we try to read from empty buffer + } + + fn test_objects() + -> (TCompactInputProtocol>, + TCompactOutputProtocol>) + { + let mem = TBufferChannel::with_capacity(80, 80); + + let (r_mem, w_mem) = mem.split().unwrap(); + + let i_prot = TCompactInputProtocol::new(r_mem); + let o_prot = TCompactOutputProtocol::new(w_mem); + + (i_prot, o_prot) + } + + fn assert_no_write(mut write_fn: F) + where + F: FnMut(&mut TCompactOutputProtocol>) -> ::Result<()>, + { + let (_, mut o_prot) = test_objects(); + assert!(write_fn(&mut o_prot).is_ok()); + assert_eq!(o_prot.transport.write_bytes().len(), 0); + } +} diff --git a/lib/rs/src/protocol/mod.rs b/lib/rs/src/protocol/mod.rs new file mode 100644 index 0000000..4f13914 --- /dev/null +++ b/lib/rs/src/protocol/mod.rs @@ -0,0 +1,1009 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +//! Types used to send and receive primitives between a Thrift client and server. +//! +//! # Examples +//! +//! Create and use a `TInputProtocol`. +//! +//! ```no_run +//! use thrift::protocol::{TBinaryInputProtocol, TInputProtocol}; +//! use thrift::transport::TTcpChannel; +//! +//! // create the I/O channel +//! let mut channel = TTcpChannel::new(); +//! channel.open("127.0.0.1:9090").unwrap(); +//! +//! // create the protocol to decode bytes into types +//! let mut protocol = TBinaryInputProtocol::new(channel, true); +//! +//! // read types from the wire +//! let field_identifier = protocol.read_field_begin().unwrap(); +//! let field_contents = protocol.read_string().unwrap(); +//! let field_end = protocol.read_field_end().unwrap(); +//! ``` +//! +//! Create and use a `TOutputProtocol`. +//! +//! ```no_run +//! use thrift::protocol::{TBinaryOutputProtocol, TFieldIdentifier, TOutputProtocol, TType}; +//! use thrift::transport::TTcpChannel; +//! +//! // create the I/O channel +//! let mut channel = TTcpChannel::new(); +//! channel.open("127.0.0.1:9090").unwrap(); +//! +//! // create the protocol to encode types into bytes +//! let mut protocol = TBinaryOutputProtocol::new(channel, true); +//! +//! // write types +//! protocol.write_field_begin(&TFieldIdentifier::new("string_thing", TType::String, 1)).unwrap(); +//! protocol.write_string("foo").unwrap(); +//! protocol.write_field_end().unwrap(); +//! ``` + +use std::fmt; +use std::fmt::{Display, Formatter}; +use std::convert::From; +use try_from::TryFrom; + +use {ProtocolError, ProtocolErrorKind}; +use transport::{TReadTransport, TWriteTransport}; + +#[cfg(test)] +macro_rules! assert_eq_written_bytes { + ($o_prot:ident, $expected_bytes:ident) => { + { + assert_eq!($o_prot.transport.write_bytes(), &$expected_bytes); + } + }; +} + +// FIXME: should take both read and write +#[cfg(test)] +macro_rules! copy_write_buffer_to_read_buffer { + ($o_prot:ident) => { + { + $o_prot.transport.copy_write_buffer_to_read_buffer(); + } + }; +} + +#[cfg(test)] +macro_rules! set_readable_bytes { + ($i_prot:ident, $bytes:expr) => { + $i_prot.transport.set_readable_bytes($bytes); + } +} + +mod binary; +mod compact; +mod multiplexed; +mod stored; + +pub use self::binary::{TBinaryInputProtocol, TBinaryInputProtocolFactory, TBinaryOutputProtocol, + TBinaryOutputProtocolFactory}; +pub use self::compact::{TCompactInputProtocol, TCompactInputProtocolFactory, + TCompactOutputProtocol, TCompactOutputProtocolFactory}; +pub use self::multiplexed::TMultiplexedOutputProtocol; +pub use self::stored::TStoredInputProtocol; + +// Default maximum depth to which `TInputProtocol::skip` will skip a Thrift +// field. A default is necessary because Thrift structs or collections may +// contain nested structs and collections, which could result in indefinite +// recursion. +const MAXIMUM_SKIP_DEPTH: i8 = 64; + +/// Converts a stream of bytes into Thrift identifiers, primitives, +/// containers, or structs. +/// +/// This trait does not deal with higher-level Thrift concepts like structs or +/// exceptions - only with primitives and message or container boundaries. Once +/// bytes are read they are deserialized and an identifier (for example +/// `TMessageIdentifier`) or a primitive is returned. +/// +/// All methods return a `thrift::Result`. If an `Err` is returned the protocol +/// instance and its underlying transport should be terminated. +/// +/// # Examples +/// +/// Create and use a `TInputProtocol` +/// +/// ```no_run +/// use thrift::protocol::{TBinaryInputProtocol, TInputProtocol}; +/// use thrift::transport::TTcpChannel; +/// +/// let mut channel = TTcpChannel::new(); +/// channel.open("127.0.0.1:9090").unwrap(); +/// +/// let mut protocol = TBinaryInputProtocol::new(channel, true); +/// +/// let field_identifier = protocol.read_field_begin().unwrap(); +/// let field_contents = protocol.read_string().unwrap(); +/// let field_end = protocol.read_field_end().unwrap(); +/// ``` +pub trait TInputProtocol { + /// Read the beginning of a Thrift message. + fn read_message_begin(&mut self) -> ::Result; + /// Read the end of a Thrift message. + fn read_message_end(&mut self) -> ::Result<()>; + /// Read the beginning of a Thrift struct. + fn read_struct_begin(&mut self) -> ::Result>; + /// Read the end of a Thrift struct. + fn read_struct_end(&mut self) -> ::Result<()>; + /// Read the beginning of a Thrift struct field. + fn read_field_begin(&mut self) -> ::Result; + /// Read the end of a Thrift struct field. + fn read_field_end(&mut self) -> ::Result<()>; + /// Read a bool. + fn read_bool(&mut self) -> ::Result; + /// Read a fixed-length byte array. + fn read_bytes(&mut self) -> ::Result>; + /// Read a word. + fn read_i8(&mut self) -> ::Result; + /// Read a 16-bit signed integer. + fn read_i16(&mut self) -> ::Result; + /// Read a 32-bit signed integer. + fn read_i32(&mut self) -> ::Result; + /// Read a 64-bit signed integer. + fn read_i64(&mut self) -> ::Result; + /// Read a 64-bit float. + fn read_double(&mut self) -> ::Result; + /// Read a fixed-length string (not null terminated). + fn read_string(&mut self) -> ::Result; + /// Read the beginning of a list. + fn read_list_begin(&mut self) -> ::Result; + /// Read the end of a list. + fn read_list_end(&mut self) -> ::Result<()>; + /// Read the beginning of a set. + fn read_set_begin(&mut self) -> ::Result; + /// Read the end of a set. + fn read_set_end(&mut self) -> ::Result<()>; + /// Read the beginning of a map. + fn read_map_begin(&mut self) -> ::Result; + /// Read the end of a map. + fn read_map_end(&mut self) -> ::Result<()>; + /// Skip a field with type `field_type` recursively until the default + /// maximum skip depth is reached. + fn skip(&mut self, field_type: TType) -> ::Result<()> { + self.skip_till_depth(field_type, MAXIMUM_SKIP_DEPTH) + } + /// Skip a field with type `field_type` recursively up to `depth` levels. + fn skip_till_depth(&mut self, field_type: TType, depth: i8) -> ::Result<()> { + if depth == 0 { + return Err( + ::Error::Protocol( + ProtocolError { + kind: ProtocolErrorKind::DepthLimit, + message: format!("cannot parse past {:?}", field_type), + }, + ), + ); + } + + match field_type { + TType::Bool => self.read_bool().map(|_| ()), + TType::I08 => self.read_i8().map(|_| ()), + TType::I16 => self.read_i16().map(|_| ()), + TType::I32 => self.read_i32().map(|_| ()), + TType::I64 => self.read_i64().map(|_| ()), + TType::Double => self.read_double().map(|_| ()), + TType::String => self.read_string().map(|_| ()), + TType::Struct => { + self.read_struct_begin()?; + loop { + let field_ident = self.read_field_begin()?; + if field_ident.field_type == TType::Stop { + break; + } + self.skip_till_depth(field_ident.field_type, depth - 1)?; + } + self.read_struct_end() + } + TType::List => { + let list_ident = self.read_list_begin()?; + for _ in 0..list_ident.size { + self.skip_till_depth(list_ident.element_type, depth - 1)?; + } + self.read_list_end() + } + TType::Set => { + let set_ident = self.read_set_begin()?; + for _ in 0..set_ident.size { + self.skip_till_depth(set_ident.element_type, depth - 1)?; + } + self.read_set_end() + } + TType::Map => { + let map_ident = self.read_map_begin()?; + for _ in 0..map_ident.size { + let key_type = map_ident + .key_type + .expect("non-zero sized map should contain key type"); + let val_type = map_ident + .value_type + .expect("non-zero sized map should contain value type"); + self.skip_till_depth(key_type, depth - 1)?; + self.skip_till_depth(val_type, depth - 1)?; + } + self.read_map_end() + } + u => { + Err( + ::Error::Protocol( + ProtocolError { + kind: ProtocolErrorKind::Unknown, + message: format!("cannot skip field type {:?}", &u), + }, + ), + ) + } + } + } + + // utility (DO NOT USE IN GENERATED CODE!!!!) + // + + /// Read an unsigned byte. + /// + /// This method should **never** be used in generated code. + fn read_byte(&mut self) -> ::Result; +} + +/// Converts Thrift identifiers, primitives, containers or structs into a +/// stream of bytes. +/// +/// This trait does not deal with higher-level Thrift concepts like structs or +/// exceptions - only with primitives and message or container boundaries. +/// Write methods take an identifier (for example, `TMessageIdentifier`) or a +/// primitive. Any or all of the fields in an identifier may be omitted when +/// writing to the transport. Write methods may even be noops. All of this is +/// transparent to the caller; as long as a matching `TInputProtocol` +/// implementation is used, received messages will be decoded correctly. +/// +/// All methods return a `thrift::Result`. If an `Err` is returned the protocol +/// instance and its underlying transport should be terminated. +/// +/// # Examples +/// +/// Create and use a `TOutputProtocol` +/// +/// ```no_run +/// use thrift::protocol::{TBinaryOutputProtocol, TFieldIdentifier, TOutputProtocol, TType}; +/// use thrift::transport::TTcpChannel; +/// +/// let mut channel = TTcpChannel::new(); +/// channel.open("127.0.0.1:9090").unwrap(); +/// +/// let mut protocol = TBinaryOutputProtocol::new(channel, true); +/// +/// protocol.write_field_begin(&TFieldIdentifier::new("string_thing", TType::String, 1)).unwrap(); +/// protocol.write_string("foo").unwrap(); +/// protocol.write_field_end().unwrap(); +/// ``` +pub trait TOutputProtocol { + /// Write the beginning of a Thrift message. + fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()>; + /// Write the end of a Thrift message. + fn write_message_end(&mut self) -> ::Result<()>; + /// Write the beginning of a Thrift struct. + fn write_struct_begin(&mut self, identifier: &TStructIdentifier) -> ::Result<()>; + /// Write the end of a Thrift struct. + fn write_struct_end(&mut self) -> ::Result<()>; + /// Write the beginning of a Thrift field. + fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()>; + /// Write the end of a Thrift field. + fn write_field_end(&mut self) -> ::Result<()>; + /// Write a STOP field indicating that all the fields in a struct have been + /// written. + fn write_field_stop(&mut self) -> ::Result<()>; + /// Write a bool. + fn write_bool(&mut self, b: bool) -> ::Result<()>; + /// Write a fixed-length byte array. + fn write_bytes(&mut self, b: &[u8]) -> ::Result<()>; + /// Write an 8-bit signed integer. + fn write_i8(&mut self, i: i8) -> ::Result<()>; + /// Write a 16-bit signed integer. + fn write_i16(&mut self, i: i16) -> ::Result<()>; + /// Write a 32-bit signed integer. + fn write_i32(&mut self, i: i32) -> ::Result<()>; + /// Write a 64-bit signed integer. + fn write_i64(&mut self, i: i64) -> ::Result<()>; + /// Write a 64-bit float. + fn write_double(&mut self, d: f64) -> ::Result<()>; + /// Write a fixed-length string. + fn write_string(&mut self, s: &str) -> ::Result<()>; + /// Write the beginning of a list. + fn write_list_begin(&mut self, identifier: &TListIdentifier) -> ::Result<()>; + /// Write the end of a list. + fn write_list_end(&mut self) -> ::Result<()>; + /// Write the beginning of a set. + fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> ::Result<()>; + /// Write the end of a set. + fn write_set_end(&mut self) -> ::Result<()>; + /// Write the beginning of a map. + fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()>; + /// Write the end of a map. + fn write_map_end(&mut self) -> ::Result<()>; + /// Flush buffered bytes to the underlying transport. + fn flush(&mut self) -> ::Result<()>; + + // utility (DO NOT USE IN GENERATED CODE!!!!) + // + + /// Write an unsigned byte. + /// + /// This method should **never** be used in generated code. + fn write_byte(&mut self, b: u8) -> ::Result<()>; // FIXME: REMOVE +} + +impl

TInputProtocol for Box

+where + P: TInputProtocol + ?Sized, +{ + fn read_message_begin(&mut self) -> ::Result { + (**self).read_message_begin() + } + + fn read_message_end(&mut self) -> ::Result<()> { + (**self).read_message_end() + } + + fn read_struct_begin(&mut self) -> ::Result> { + (**self).read_struct_begin() + } + + fn read_struct_end(&mut self) -> ::Result<()> { + (**self).read_struct_end() + } + + fn read_field_begin(&mut self) -> ::Result { + (**self).read_field_begin() + } + + fn read_field_end(&mut self) -> ::Result<()> { + (**self).read_field_end() + } + + fn read_bool(&mut self) -> ::Result { + (**self).read_bool() + } + + fn read_bytes(&mut self) -> ::Result> { + (**self).read_bytes() + } + + fn read_i8(&mut self) -> ::Result { + (**self).read_i8() + } + + fn read_i16(&mut self) -> ::Result { + (**self).read_i16() + } + + fn read_i32(&mut self) -> ::Result { + (**self).read_i32() + } + + fn read_i64(&mut self) -> ::Result { + (**self).read_i64() + } + + fn read_double(&mut self) -> ::Result { + (**self).read_double() + } + + fn read_string(&mut self) -> ::Result { + (**self).read_string() + } + + fn read_list_begin(&mut self) -> ::Result { + (**self).read_list_begin() + } + + fn read_list_end(&mut self) -> ::Result<()> { + (**self).read_list_end() + } + + fn read_set_begin(&mut self) -> ::Result { + (**self).read_set_begin() + } + + fn read_set_end(&mut self) -> ::Result<()> { + (**self).read_set_end() + } + + fn read_map_begin(&mut self) -> ::Result { + (**self).read_map_begin() + } + + fn read_map_end(&mut self) -> ::Result<()> { + (**self).read_map_end() + } + + fn read_byte(&mut self) -> ::Result { + (**self).read_byte() + } +} + +impl

TOutputProtocol for Box

+where + P: TOutputProtocol + ?Sized, +{ + fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()> { + (**self).write_message_begin(identifier) + } + + fn write_message_end(&mut self) -> ::Result<()> { + (**self).write_message_end() + } + + fn write_struct_begin(&mut self, identifier: &TStructIdentifier) -> ::Result<()> { + (**self).write_struct_begin(identifier) + } + + fn write_struct_end(&mut self) -> ::Result<()> { + (**self).write_struct_end() + } + + fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()> { + (**self).write_field_begin(identifier) + } + + fn write_field_end(&mut self) -> ::Result<()> { + (**self).write_field_end() + } + + fn write_field_stop(&mut self) -> ::Result<()> { + (**self).write_field_stop() + } + + fn write_bool(&mut self, b: bool) -> ::Result<()> { + (**self).write_bool(b) + } + + fn write_bytes(&mut self, b: &[u8]) -> ::Result<()> { + (**self).write_bytes(b) + } + + fn write_i8(&mut self, i: i8) -> ::Result<()> { + (**self).write_i8(i) + } + + fn write_i16(&mut self, i: i16) -> ::Result<()> { + (**self).write_i16(i) + } + + fn write_i32(&mut self, i: i32) -> ::Result<()> { + (**self).write_i32(i) + } + + fn write_i64(&mut self, i: i64) -> ::Result<()> { + (**self).write_i64(i) + } + + fn write_double(&mut self, d: f64) -> ::Result<()> { + (**self).write_double(d) + } + + fn write_string(&mut self, s: &str) -> ::Result<()> { + (**self).write_string(s) + } + + fn write_list_begin(&mut self, identifier: &TListIdentifier) -> ::Result<()> { + (**self).write_list_begin(identifier) + } + + fn write_list_end(&mut self) -> ::Result<()> { + (**self).write_list_end() + } + + fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> ::Result<()> { + (**self).write_set_begin(identifier) + } + + fn write_set_end(&mut self) -> ::Result<()> { + (**self).write_set_end() + } + + fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()> { + (**self).write_map_begin(identifier) + } + + fn write_map_end(&mut self) -> ::Result<()> { + (**self).write_map_end() + } + + fn flush(&mut self) -> ::Result<()> { + (**self).flush() + } + + fn write_byte(&mut self, b: u8) -> ::Result<()> { + (**self).write_byte(b) + } +} + +/// Helper type used by servers to create `TInputProtocol` instances for +/// accepted client connections. +/// +/// # Examples +/// +/// Create a `TInputProtocolFactory` and use it to create a `TInputProtocol`. +/// +/// ```no_run +/// use thrift::protocol::{TBinaryInputProtocolFactory, TInputProtocolFactory}; +/// use thrift::transport::TTcpChannel; +/// +/// let mut channel = TTcpChannel::new(); +/// channel.open("127.0.0.1:9090").unwrap(); +/// +/// let factory = TBinaryInputProtocolFactory::new(); +/// let protocol = factory.create(Box::new(channel)); +/// ``` +pub trait TInputProtocolFactory { + // Create a `TInputProtocol` that reads bytes from `transport`. + fn create(&self, transport: Box) -> Box; +} + +impl TInputProtocolFactory for Box +where + T: TInputProtocolFactory + ?Sized, +{ + fn create(&self, transport: Box) -> Box { + (**self).create(transport) + } +} + +/// Helper type used by servers to create `TOutputProtocol` instances for +/// accepted client connections. +/// +/// # Examples +/// +/// Create a `TOutputProtocolFactory` and use it to create a `TOutputProtocol`. +/// +/// ```no_run +/// use thrift::protocol::{TBinaryOutputProtocolFactory, TOutputProtocolFactory}; +/// use thrift::transport::TTcpChannel; +/// +/// let mut channel = TTcpChannel::new(); +/// channel.open("127.0.0.1:9090").unwrap(); +/// +/// let factory = TBinaryOutputProtocolFactory::new(); +/// let protocol = factory.create(Box::new(channel)); +/// ``` +pub trait TOutputProtocolFactory { + /// Create a `TOutputProtocol` that writes bytes to `transport`. + fn create(&self, transport: Box) -> Box; +} + +impl TOutputProtocolFactory for Box +where + T: TOutputProtocolFactory + ?Sized, +{ + fn create(&self, transport: Box) -> Box { + (**self).create(transport) + } +} + +/// Thrift message identifier. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TMessageIdentifier { + /// Service call the message is associated with. + pub name: String, + /// Message type. + pub message_type: TMessageType, + /// Ordered sequence number identifying the message. + pub sequence_number: i32, +} + +impl TMessageIdentifier { + /// Create a `TMessageIdentifier` for a Thrift service-call named `name` + /// with message type `message_type` and sequence number `sequence_number`. + pub fn new>( + name: S, + message_type: TMessageType, + sequence_number: i32, + ) -> TMessageIdentifier { + TMessageIdentifier { + name: name.into(), + message_type: message_type, + sequence_number: sequence_number, + } + } +} + +/// Thrift struct identifier. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TStructIdentifier { + /// Name of the encoded Thrift struct. + pub name: String, +} + +impl TStructIdentifier { + /// Create a `TStructIdentifier` for a struct named `name`. + pub fn new>(name: S) -> TStructIdentifier { + TStructIdentifier { name: name.into() } + } +} + +/// Thrift field identifier. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TFieldIdentifier { + /// Name of the Thrift field. + /// + /// `None` if it's not sent over the wire. + pub name: Option, + /// Field type. + /// + /// This may be a primitive, container, or a struct. + pub field_type: TType, + /// Thrift field id. + /// + /// `None` only if `field_type` is `TType::Stop`. + pub id: Option, +} + +impl TFieldIdentifier { + /// Create a `TFieldIdentifier` for a field named `name` with type + /// `field_type` and field id `id`. + /// + /// `id` should be `None` if `field_type` is `TType::Stop`. + pub fn new(name: N, field_type: TType, id: I) -> TFieldIdentifier + where + N: Into>, + S: Into, + I: Into>, + { + TFieldIdentifier { + name: name.into().map(|n| n.into()), + field_type: field_type, + id: id.into(), + } + } +} + +/// Thrift list identifier. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TListIdentifier { + /// Type of the elements in the list. + pub element_type: TType, + /// Number of elements in the list. + pub size: i32, +} + +impl TListIdentifier { + /// Create a `TListIdentifier` for a list with `size` elements of type + /// `element_type`. + pub fn new(element_type: TType, size: i32) -> TListIdentifier { + TListIdentifier { + element_type: element_type, + size: size, + } + } +} + +/// Thrift set identifier. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TSetIdentifier { + /// Type of the elements in the set. + pub element_type: TType, + /// Number of elements in the set. + pub size: i32, +} + +impl TSetIdentifier { + /// Create a `TSetIdentifier` for a set with `size` elements of type + /// `element_type`. + pub fn new(element_type: TType, size: i32) -> TSetIdentifier { + TSetIdentifier { + element_type: element_type, + size: size, + } + } +} + +/// Thrift map identifier. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TMapIdentifier { + /// Map key type. + pub key_type: Option, + /// Map value type. + pub value_type: Option, + /// Number of entries in the map. + pub size: i32, +} + +impl TMapIdentifier { + /// Create a `TMapIdentifier` for a map with `size` entries of type + /// `key_type -> value_type`. + pub fn new(key_type: K, value_type: V, size: i32) -> TMapIdentifier + where + K: Into>, + V: Into>, + { + TMapIdentifier { + key_type: key_type.into(), + value_type: value_type.into(), + size: size, + } + } +} + +/// Thrift message types. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum TMessageType { + /// Service-call request. + Call, + /// Service-call response. + Reply, + /// Unexpected error in the remote service. + Exception, + /// One-way service-call request (no response is expected). + OneWay, +} + +impl Display for TMessageType { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match *self { + TMessageType::Call => write!(f, "Call"), + TMessageType::Reply => write!(f, "Reply"), + TMessageType::Exception => write!(f, "Exception"), + TMessageType::OneWay => write!(f, "OneWay"), + } + } +} + +impl From for u8 { + fn from(message_type: TMessageType) -> Self { + match message_type { + TMessageType::Call => 0x01, + TMessageType::Reply => 0x02, + TMessageType::Exception => 0x03, + TMessageType::OneWay => 0x04, + } + } +} + +impl TryFrom for TMessageType { + type Err = ::Error; + fn try_from(b: u8) -> ::Result { + match b { + 0x01 => Ok(TMessageType::Call), + 0x02 => Ok(TMessageType::Reply), + 0x03 => Ok(TMessageType::Exception), + 0x04 => Ok(TMessageType::OneWay), + unkn => { + Err( + ::Error::Protocol( + ProtocolError { + kind: ProtocolErrorKind::InvalidData, + message: format!("cannot convert {} to TMessageType", unkn), + }, + ), + ) + } + } + } +} + +/// Thrift struct-field types. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum TType { + /// Indicates that there are no more serialized fields in this Thrift struct. + Stop, + /// Void (`()`) field. + Void, + /// Boolean. + Bool, + /// Signed 8-bit int. + I08, + /// Double-precision number. + Double, + /// Signed 16-bit int. + I16, + /// Signed 32-bit int. + I32, + /// Signed 64-bit int. + I64, + /// UTF-8 string. + String, + /// UTF-7 string. *Unsupported*. + Utf7, + /// Thrift struct. + Struct, + /// Map. + Map, + /// Set. + Set, + /// List. + List, + /// UTF-8 string. + Utf8, + /// UTF-16 string. *Unsupported*. + Utf16, +} + +impl Display for TType { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match *self { + TType::Stop => write!(f, "STOP"), + TType::Void => write!(f, "void"), + TType::Bool => write!(f, "bool"), + TType::I08 => write!(f, "i08"), + TType::Double => write!(f, "double"), + TType::I16 => write!(f, "i16"), + TType::I32 => write!(f, "i32"), + TType::I64 => write!(f, "i64"), + TType::String => write!(f, "string"), + TType::Utf7 => write!(f, "UTF7"), + TType::Struct => write!(f, "struct"), + TType::Map => write!(f, "map"), + TType::Set => write!(f, "set"), + TType::List => write!(f, "list"), + TType::Utf8 => write!(f, "UTF8"), + TType::Utf16 => write!(f, "UTF16"), + } + } +} + +/// Compare the expected message sequence number `expected` with the received +/// message sequence number `actual`. +/// +/// Return `()` if `actual == expected`, `Err` otherwise. +pub fn verify_expected_sequence_number(expected: i32, actual: i32) -> ::Result<()> { + if expected == actual { + Ok(()) + } else { + Err( + ::Error::Application( + ::ApplicationError { + kind: ::ApplicationErrorKind::BadSequenceId, + message: format!("expected {} got {}", expected, actual), + }, + ), + ) + } +} + +/// Compare the expected service-call name `expected` with the received +/// service-call name `actual`. +/// +/// Return `()` if `actual == expected`, `Err` otherwise. +pub fn verify_expected_service_call(expected: &str, actual: &str) -> ::Result<()> { + if expected == actual { + Ok(()) + } else { + Err( + ::Error::Application( + ::ApplicationError { + kind: ::ApplicationErrorKind::WrongMethodName, + message: format!("expected {} got {}", expected, actual), + }, + ), + ) + } +} + +/// Compare the expected message type `expected` with the received message type +/// `actual`. +/// +/// Return `()` if `actual == expected`, `Err` otherwise. +pub fn verify_expected_message_type(expected: TMessageType, actual: TMessageType) -> ::Result<()> { + if expected == actual { + Ok(()) + } else { + Err( + ::Error::Application( + ::ApplicationError { + kind: ::ApplicationErrorKind::InvalidMessageType, + message: format!("expected {} got {}", expected, actual), + }, + ), + ) + } +} + +/// Check if a required Thrift struct field exists. +/// +/// Return `()` if it does, `Err` otherwise. +pub fn verify_required_field_exists(field_name: &str, field: &Option) -> ::Result<()> { + match *field { + Some(_) => Ok(()), + None => { + Err( + ::Error::Protocol( + ::ProtocolError { + kind: ::ProtocolErrorKind::Unknown, + message: format!("missing required field {}", field_name), + }, + ), + ) + } + } +} + +/// Extract the field id from a Thrift field identifier. +/// +/// `field_ident` must *not* have `TFieldIdentifier.field_type` of type `TType::Stop`. +/// +/// Return `TFieldIdentifier.id` if an id exists, `Err` otherwise. +pub fn field_id(field_ident: &TFieldIdentifier) -> ::Result { + field_ident + .id + .ok_or_else( + || { + ::Error::Protocol( + ::ProtocolError { + kind: ::ProtocolErrorKind::Unknown, + message: format!("missing field in in {:?}", field_ident), + }, + ) + }, + ) +} + +#[cfg(test)] +mod tests { + + use std::io::Cursor; + + use super::*; + use transport::{TReadTransport, TWriteTransport}; + + #[test] + fn must_create_usable_input_protocol_from_concrete_input_protocol() { + let r: Box = Box::new(Cursor::new([0, 1, 2])); + let mut t = TCompactInputProtocol::new(r); + takes_input_protocol(&mut t) + } + + #[test] + fn must_create_usable_input_protocol_from_boxed_input() { + let r: Box = Box::new(Cursor::new([0, 1, 2])); + let mut t: Box = Box::new(TCompactInputProtocol::new(r)); + takes_input_protocol(&mut t) + } + + #[test] + fn must_create_usable_output_protocol_from_concrete_output_protocol() { + let w: Box = Box::new(vec![0u8; 10]); + let mut t = TCompactOutputProtocol::new(w); + takes_output_protocol(&mut t) + } + + #[test] + fn must_create_usable_output_protocol_from_boxed_output() { + let w: Box = Box::new(vec![0u8; 10]); + let mut t: Box = Box::new(TCompactOutputProtocol::new(w)); + takes_output_protocol(&mut t) + } + + fn takes_input_protocol(t: &mut R) + where + R: TInputProtocol, + { + t.read_byte().unwrap(); + } + + fn takes_output_protocol(t: &mut W) + where + W: TOutputProtocol, + { + t.flush().unwrap(); + } +} diff --git a/lib/rs/src/protocol/multiplexed.rs b/lib/rs/src/protocol/multiplexed.rs new file mode 100644 index 0000000..db08027 --- /dev/null +++ b/lib/rs/src/protocol/multiplexed.rs @@ -0,0 +1,237 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use super::{TFieldIdentifier, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, + TOutputProtocol, TSetIdentifier, TStructIdentifier}; + +/// `TOutputProtocol` that prefixes the service name to all outgoing Thrift +/// messages. +/// +/// A `TMultiplexedOutputProtocol` should be used when multiple Thrift services +/// send messages over a single I/O channel. By prefixing service identifiers +/// to outgoing messages receivers are able to demux them and route them to the +/// appropriate service processor. Rust receivers must use a `TMultiplexedProcessor` +/// to process incoming messages, while other languages must use their +/// corresponding multiplexed processor implementations. +/// +/// For example, given a service `TestService` and a service call `test_call`, +/// this implementation would identify messages as originating from +/// `TestService:test_call`. +/// +/// # Examples +/// +/// Create and use a `TMultiplexedOutputProtocol`. +/// +/// ```no_run +/// use thrift::protocol::{TMessageIdentifier, TMessageType, TOutputProtocol}; +/// use thrift::protocol::{TBinaryOutputProtocol, TMultiplexedOutputProtocol}; +/// use thrift::transport::TTcpChannel; +/// +/// let mut channel = TTcpChannel::new(); +/// channel.open("localhost:9090").unwrap(); +/// +/// let protocol = TBinaryOutputProtocol::new(channel, true); +/// let mut protocol = TMultiplexedOutputProtocol::new("service_name", protocol); +/// +/// let ident = TMessageIdentifier::new("svc_call", TMessageType::Call, 1); +/// protocol.write_message_begin(&ident).unwrap(); +/// ``` +#[derive(Debug)] +pub struct TMultiplexedOutputProtocol

+where + P: TOutputProtocol, +{ + service_name: String, + inner: P, +} + +impl

TMultiplexedOutputProtocol

+where + P: TOutputProtocol, +{ + /// Create a `TMultiplexedOutputProtocol` that identifies outgoing messages + /// as originating from a service named `service_name` and sends them over + /// the `wrapped` `TOutputProtocol`. Outgoing messages are encoded and sent + /// by `wrapped`, not by this instance. + pub fn new(service_name: &str, wrapped: P) -> TMultiplexedOutputProtocol

{ + TMultiplexedOutputProtocol { + service_name: service_name.to_owned(), + inner: wrapped, + } + } +} + +// FIXME: avoid passthrough methods +impl

TOutputProtocol for TMultiplexedOutputProtocol

+where + P: TOutputProtocol, +{ + fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()> { + match identifier.message_type { // FIXME: is there a better way to override identifier here? + TMessageType::Call | TMessageType::OneWay => { + let identifier = TMessageIdentifier { + name: format!("{}:{}", self.service_name, identifier.name), + ..*identifier + }; + self.inner.write_message_begin(&identifier) + } + _ => self.inner.write_message_begin(identifier), + } + } + + fn write_message_end(&mut self) -> ::Result<()> { + self.inner.write_message_end() + } + + fn write_struct_begin(&mut self, identifier: &TStructIdentifier) -> ::Result<()> { + self.inner.write_struct_begin(identifier) + } + + fn write_struct_end(&mut self) -> ::Result<()> { + self.inner.write_struct_end() + } + + fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()> { + self.inner.write_field_begin(identifier) + } + + fn write_field_end(&mut self) -> ::Result<()> { + self.inner.write_field_end() + } + + fn write_field_stop(&mut self) -> ::Result<()> { + self.inner.write_field_stop() + } + + fn write_bytes(&mut self, b: &[u8]) -> ::Result<()> { + self.inner.write_bytes(b) + } + + fn write_bool(&mut self, b: bool) -> ::Result<()> { + self.inner.write_bool(b) + } + + fn write_i8(&mut self, i: i8) -> ::Result<()> { + self.inner.write_i8(i) + } + + fn write_i16(&mut self, i: i16) -> ::Result<()> { + self.inner.write_i16(i) + } + + fn write_i32(&mut self, i: i32) -> ::Result<()> { + self.inner.write_i32(i) + } + + fn write_i64(&mut self, i: i64) -> ::Result<()> { + self.inner.write_i64(i) + } + + fn write_double(&mut self, d: f64) -> ::Result<()> { + self.inner.write_double(d) + } + + fn write_string(&mut self, s: &str) -> ::Result<()> { + self.inner.write_string(s) + } + + fn write_list_begin(&mut self, identifier: &TListIdentifier) -> ::Result<()> { + self.inner.write_list_begin(identifier) + } + + fn write_list_end(&mut self) -> ::Result<()> { + self.inner.write_list_end() + } + + fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> ::Result<()> { + self.inner.write_set_begin(identifier) + } + + fn write_set_end(&mut self) -> ::Result<()> { + self.inner.write_set_end() + } + + fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()> { + self.inner.write_map_begin(identifier) + } + + fn write_map_end(&mut self) -> ::Result<()> { + self.inner.write_map_end() + } + + fn flush(&mut self) -> ::Result<()> { + self.inner.flush() + } + + // utility + // + + fn write_byte(&mut self, b: u8) -> ::Result<()> { + self.inner.write_byte(b) + } +} + +#[cfg(test)] +mod tests { + + use protocol::{TBinaryOutputProtocol, TMessageIdentifier, TMessageType, TOutputProtocol}; + use transport::{TBufferChannel, TIoChannel, WriteHalf}; + + use super::*; + + #[test] + fn must_write_message_begin_with_prefixed_service_name() { + let mut o_prot = test_objects(); + + let ident = TMessageIdentifier::new("bar", TMessageType::Call, 2); + assert_success!(o_prot.write_message_begin(&ident)); + + let expected: [u8; 19] = [ + 0x80, + 0x01, /* protocol identifier */ + 0x00, + 0x01, /* message type */ + 0x00, + 0x00, + 0x00, + 0x07, + 0x66, + 0x6F, + 0x6F, /* "foo" */ + 0x3A, /* ":" */ + 0x62, + 0x61, + 0x72, /* "bar" */ + 0x00, + 0x00, + 0x00, + 0x02 /* sequence number */, + ]; + + assert_eq!(o_prot.inner.transport.write_bytes(), expected); + } + + fn test_objects + () + -> TMultiplexedOutputProtocol>> + { + let c = TBufferChannel::with_capacity(40, 40); + let (_, w_chan) = c.split().unwrap(); + let prot = TBinaryOutputProtocol::new(w_chan, true); + TMultiplexedOutputProtocol::new("foo", prot) + } +} diff --git a/lib/rs/src/protocol/stored.rs b/lib/rs/src/protocol/stored.rs new file mode 100644 index 0000000..b3f305f --- /dev/null +++ b/lib/rs/src/protocol/stored.rs @@ -0,0 +1,198 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::convert::Into; + +use ProtocolErrorKind; +use super::{TFieldIdentifier, TInputProtocol, TListIdentifier, TMapIdentifier, TMessageIdentifier, + TSetIdentifier, TStructIdentifier}; + +/// `TInputProtocol` required to use a `TMultiplexedProcessor`. +/// +/// A `TMultiplexedProcessor` reads incoming message identifiers to determine to +/// which `TProcessor` requests should be forwarded. However, once read, those +/// message identifier bytes are no longer on the wire. Since downstream +/// processors expect to read message identifiers from the given input protocol +/// we need some way of supplying a `TMessageIdentifier` with the service-name +/// stripped. This implementation stores the received `TMessageIdentifier` +/// (without the service name) and passes it to the wrapped `TInputProtocol` +/// when `TInputProtocol::read_message_begin(...)` is called. It delegates all +/// other calls directly to the wrapped `TInputProtocol`. +/// +/// This type **should not** be used by application code. +/// +/// # Examples +/// +/// Create and use a `TStoredInputProtocol`. +/// +/// ```no_run +/// use thrift; +/// use thrift::protocol::{TInputProtocol, TMessageIdentifier, TMessageType, TOutputProtocol}; +/// use thrift::protocol::{TBinaryInputProtocol, TBinaryOutputProtocol, TStoredInputProtocol}; +/// use thrift::server::TProcessor; +/// use thrift::transport::{TIoChannel, TTcpChannel}; +/// +/// // sample processor +/// struct ActualProcessor; +/// impl TProcessor for ActualProcessor { +/// fn process( +/// &self, +/// _: &mut TInputProtocol, +/// _: &mut TOutputProtocol +/// ) -> thrift::Result<()> { +/// unimplemented!() +/// } +/// } +/// let processor = ActualProcessor {}; +/// +/// // construct the shared transport +/// let mut channel = TTcpChannel::new(); +/// channel.open("localhost:9090").unwrap(); +/// +/// let (i_chan, o_chan) = channel.split().unwrap(); +/// +/// // construct the actual input and output protocols +/// let mut i_prot = TBinaryInputProtocol::new(i_chan, true); +/// let mut o_prot = TBinaryOutputProtocol::new(o_chan, true); +/// +/// // message identifier received from remote and modified to remove the service name +/// let new_msg_ident = TMessageIdentifier::new("service_call", TMessageType::Call, 1); +/// +/// // construct the proxy input protocol +/// let mut proxy_i_prot = TStoredInputProtocol::new(&mut i_prot, new_msg_ident); +/// let res = processor.process(&mut proxy_i_prot, &mut o_prot); +/// ``` +// FIXME: implement Debug +pub struct TStoredInputProtocol<'a> { + inner: &'a mut TInputProtocol, + message_ident: Option, +} + +impl<'a> TStoredInputProtocol<'a> { + /// Create a `TStoredInputProtocol` that delegates all calls other than + /// `TInputProtocol::read_message_begin(...)` to a `wrapped` + /// `TInputProtocol`. `message_ident` is the modified message identifier - + /// with service name stripped - that will be passed to + /// `wrapped.read_message_begin(...)`. + pub fn new( + wrapped: &mut TInputProtocol, + message_ident: TMessageIdentifier, + ) -> TStoredInputProtocol { + TStoredInputProtocol { + inner: wrapped, + message_ident: message_ident.into(), + } + } +} + +impl<'a> TInputProtocol for TStoredInputProtocol<'a> { + fn read_message_begin(&mut self) -> ::Result { + self.message_ident + .take() + .ok_or_else( + || { + ::errors::new_protocol_error( + ProtocolErrorKind::Unknown, + "message identifier already read", + ) + }, + ) + } + + fn read_message_end(&mut self) -> ::Result<()> { + self.inner.read_message_end() + } + + fn read_struct_begin(&mut self) -> ::Result> { + self.inner.read_struct_begin() + } + + fn read_struct_end(&mut self) -> ::Result<()> { + self.inner.read_struct_end() + } + + fn read_field_begin(&mut self) -> ::Result { + self.inner.read_field_begin() + } + + fn read_field_end(&mut self) -> ::Result<()> { + self.inner.read_field_end() + } + + fn read_bytes(&mut self) -> ::Result> { + self.inner.read_bytes() + } + + fn read_bool(&mut self) -> ::Result { + self.inner.read_bool() + } + + fn read_i8(&mut self) -> ::Result { + self.inner.read_i8() + } + + fn read_i16(&mut self) -> ::Result { + self.inner.read_i16() + } + + fn read_i32(&mut self) -> ::Result { + self.inner.read_i32() + } + + fn read_i64(&mut self) -> ::Result { + self.inner.read_i64() + } + + fn read_double(&mut self) -> ::Result { + self.inner.read_double() + } + + fn read_string(&mut self) -> ::Result { + self.inner.read_string() + } + + fn read_list_begin(&mut self) -> ::Result { + self.inner.read_list_begin() + } + + fn read_list_end(&mut self) -> ::Result<()> { + self.inner.read_list_end() + } + + fn read_set_begin(&mut self) -> ::Result { + self.inner.read_set_begin() + } + + fn read_set_end(&mut self) -> ::Result<()> { + self.inner.read_set_end() + } + + fn read_map_begin(&mut self) -> ::Result { + self.inner.read_map_begin() + } + + fn read_map_end(&mut self) -> ::Result<()> { + self.inner.read_map_end() + } + + // utility + // + + fn read_byte(&mut self) -> ::Result { + self.inner.read_byte() + } +} diff --git a/lib/rs/src/server/mod.rs b/lib/rs/src/server/mod.rs new file mode 100644 index 0000000..3d8ccb2 --- /dev/null +++ b/lib/rs/src/server/mod.rs @@ -0,0 +1,124 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +//! Types used to implement a Thrift server. + +use {ApplicationError, ApplicationErrorKind}; +use protocol::{TInputProtocol, TMessageIdentifier, TMessageType, TOutputProtocol}; + +mod multiplexed; +mod threaded; + +pub use self::multiplexed::TMultiplexedProcessor; +pub use self::threaded::TServer; + +/// Handles incoming Thrift messages and dispatches them to the user-defined +/// handler functions. +/// +/// An implementation is auto-generated for each Thrift service. When used by a +/// server (for example, a `TSimpleServer`), it will demux incoming service +/// calls and invoke the corresponding user-defined handler function. +/// +/// # Examples +/// +/// Create and start a server using the auto-generated `TProcessor` for +/// a Thrift service `SimpleService`. +/// +/// ```no_run +/// use thrift; +/// use thrift::protocol::{TInputProtocol, TOutputProtocol}; +/// use thrift::server::TProcessor; +/// +/// // +/// // auto-generated +/// // +/// +/// // processor for `SimpleService` +/// struct SimpleServiceSyncProcessor; +/// impl SimpleServiceSyncProcessor { +/// fn new(processor: H) -> SimpleServiceSyncProcessor { +/// unimplemented!(); +/// } +/// } +/// +/// // `TProcessor` implementation for `SimpleService` +/// impl TProcessor for SimpleServiceSyncProcessor { +/// fn process(&self, i: &mut TInputProtocol, o: &mut TOutputProtocol) -> thrift::Result<()> { +/// unimplemented!(); +/// } +/// } +/// +/// // service functions for SimpleService +/// trait SimpleServiceSyncHandler { +/// fn service_call(&self) -> thrift::Result<()>; +/// } +/// +/// // +/// // user-code follows +/// // +/// +/// // define a handler that will be invoked when `service_call` is received +/// struct SimpleServiceHandlerImpl; +/// impl SimpleServiceSyncHandler for SimpleServiceHandlerImpl { +/// fn service_call(&self) -> thrift::Result<()> { +/// unimplemented!(); +/// } +/// } +/// +/// // instantiate the processor +/// let processor = SimpleServiceSyncProcessor::new(SimpleServiceHandlerImpl {}); +/// +/// // at this point you can pass the processor to the server +/// // let server = TServer::new(..., processor); +/// ``` +pub trait TProcessor { + /// Process a Thrift service call. + /// + /// Reads arguments from `i`, executes the user's handler code, and writes + /// the response to `o`. + /// + /// Returns `()` if the handler was executed; `Err` otherwise. + fn process(&self, i: &mut TInputProtocol, o: &mut TOutputProtocol) -> ::Result<()>; +} + +/// Convenience function used in generated `TProcessor` implementations to +/// return an `ApplicationError` if thrift message processing failed. +pub fn handle_process_result( + msg_ident: &TMessageIdentifier, + res: ::Result<()>, + o_prot: &mut TOutputProtocol, +) -> ::Result<()> { + if let Err(e) = res { + let e = match e { + ::Error::Application(a) => a, + _ => ApplicationError::new(ApplicationErrorKind::Unknown, format!("{:?}", e)), + }; + + let ident = TMessageIdentifier::new( + msg_ident.name.clone(), + TMessageType::Exception, + msg_ident.sequence_number, + ); + + o_prot.write_message_begin(&ident)?; + ::Error::write_application_error_to_out_protocol(&e, o_prot)?; + o_prot.write_message_end()?; + o_prot.flush() + } else { + Ok(()) + } +} diff --git a/lib/rs/src/server/multiplexed.rs b/lib/rs/src/server/multiplexed.rs new file mode 100644 index 0000000..a7f6d04 --- /dev/null +++ b/lib/rs/src/server/multiplexed.rs @@ -0,0 +1,344 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::collections::HashMap; +use std::fmt; +use std::fmt::{Debug, Formatter}; +use std::convert::Into; +use std::sync::{Arc, Mutex}; + +use protocol::{TInputProtocol, TMessageIdentifier, TOutputProtocol, TStoredInputProtocol}; + +use super::{TProcessor, handle_process_result}; + +const MISSING_SEPARATOR_AND_NO_DEFAULT: &'static str = "missing service separator and no default processor set"; +type ThreadSafeProcessor = Box; + +/// A `TProcessor` that can demux service calls to multiple underlying +/// Thrift services. +/// +/// Users register service-specific `TProcessor` instances with a +/// `TMultiplexedProcessor`, and then register that processor with a server +/// implementation. Following that, all incoming service calls are automatically +/// routed to the service-specific `TProcessor`. +/// +/// A `TMultiplexedProcessor` can only handle messages sent by a +/// `TMultiplexedOutputProtocol`. +#[derive(Default)] +pub struct TMultiplexedProcessor { + stored: Mutex, +} + +#[derive(Default)] +struct StoredProcessors { + processors: HashMap>, + default_processor: Option>, +} + +impl TMultiplexedProcessor { + /// Create a new `TMultiplexedProcessor` with no registered service-specific + /// processors. + pub fn new() -> TMultiplexedProcessor { + TMultiplexedProcessor { + stored: Mutex::new( + StoredProcessors { + processors: HashMap::new(), + default_processor: None, + }, + ), + } + } + + /// Register a service-specific `processor` for the service named + /// `service_name`. This implementation is also backwards-compatible with + /// non-multiplexed clients. Set `as_default` to `true` to allow + /// non-namespaced requests to be dispatched to a default processor. + /// + /// Returns success if a new entry was inserted. Returns an error if: + /// * A processor exists for `service_name` + /// * You attempt to register a processor as default, and an existing default exists + #[cfg_attr(feature = "cargo-clippy", allow(map_entry))] + pub fn register>( + &mut self, + service_name: S, + processor: Box, + as_default: bool, + ) -> ::Result<()> { + let mut stored = self.stored.lock().unwrap(); + + let name = service_name.into(); + if !stored.processors.contains_key(&name) { + let processor = Arc::new(processor); + + if as_default { + if stored.default_processor.is_none() { + stored.processors.insert(name, processor.clone()); + stored.default_processor = Some(processor.clone()); + Ok(()) + } else { + Err("cannot reset default processor".into()) + } + } else { + stored.processors.insert(name, processor); + Ok(()) + } + } else { + Err(format!("cannot overwrite existing processor for service {}", name).into(),) + } + } + + fn process_message( + &self, + msg_ident: &TMessageIdentifier, + i_prot: &mut TInputProtocol, + o_prot: &mut TOutputProtocol, + ) -> ::Result<()> { + let (svc_name, svc_call) = split_ident_name(&msg_ident.name); + debug!("routing svc_name {:?} svc_call {}", &svc_name, &svc_call); + + let processor: Option> = { + let stored = self.stored.lock().unwrap(); + if let Some(name) = svc_name { + stored.processors.get(name).cloned() + } else { + stored.default_processor.clone() + } + }; + + match processor { + Some(arc) => { + let new_msg_ident = TMessageIdentifier::new( + svc_call, + msg_ident.message_type, + msg_ident.sequence_number, + ); + let mut proxy_i_prot = TStoredInputProtocol::new(i_prot, new_msg_ident); + (*arc).process(&mut proxy_i_prot, o_prot) + } + None => Err(missing_processor_message(svc_name).into()), + } + } +} + +impl TProcessor for TMultiplexedProcessor { + fn process(&self, i_prot: &mut TInputProtocol, o_prot: &mut TOutputProtocol) -> ::Result<()> { + let msg_ident = i_prot.read_message_begin()?; + + debug!("process incoming msg id:{:?}", &msg_ident); + let res = self.process_message(&msg_ident, i_prot, o_prot); + + handle_process_result(&msg_ident, res, o_prot) + } +} + +impl Debug for TMultiplexedProcessor { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let stored = self.stored.lock().unwrap(); + write!( + f, + "TMultiplexedProcess {{ registered_count: {:?} default: {:?} }}", + stored.processors.keys().len(), + stored.default_processor.is_some() + ) + } +} + +fn split_ident_name(ident_name: &str) -> (Option<&str>, &str) { + ident_name + .find(':') + .map( + |pos| { + let (svc_name, svc_call) = ident_name.split_at(pos); + let (_, svc_call) = svc_call.split_at(1); // remove colon from service call name + (Some(svc_name), svc_call) + }, + ) + .or_else(|| Some((None, ident_name))) + .unwrap() +} + +fn missing_processor_message(svc_name: Option<&str>) -> String { + match svc_name { + Some(name) => format!("no processor found for service {}", name), + None => MISSING_SEPARATOR_AND_NO_DEFAULT.to_owned(), + } +} + +#[cfg(test)] +mod tests { + use std::convert::Into; + use std::sync::Arc; + use std::sync::atomic::{AtomicBool, Ordering}; + + use {ApplicationError, ApplicationErrorKind}; + use protocol::{TBinaryInputProtocol, TBinaryOutputProtocol, TMessageIdentifier, TMessageType}; + use transport::{ReadHalf, TBufferChannel, TIoChannel, WriteHalf}; + + use super::*; + + #[test] + fn should_split_name_into_proper_separator_and_service_call() { + let ident_name = "foo:bar_call"; + let (serv, call) = split_ident_name(&ident_name); + assert_eq!(serv, Some("foo")); + assert_eq!(call, "bar_call"); + } + + #[test] + fn should_return_full_ident_if_no_separator_exists() { + let ident_name = "bar_call"; + let (serv, call) = split_ident_name(&ident_name); + assert_eq!(serv, None); + assert_eq!(call, "bar_call"); + } + + #[test] + fn should_write_error_if_no_separator_found_and_no_default_processor_exists() { + let (mut i, mut o) = build_objects(); + + let sent_ident = TMessageIdentifier::new("foo", TMessageType::Call, 10); + o.write_message_begin(&sent_ident).unwrap(); + o.flush().unwrap(); + o.transport.copy_write_buffer_to_read_buffer(); + o.transport.empty_write_buffer(); + + let p = TMultiplexedProcessor::new(); + p.process(&mut i, &mut o).unwrap(); // at this point an error should be written out + + i.transport + .set_readable_bytes(&o.transport.write_bytes()); + let rcvd_ident = i.read_message_begin().unwrap(); + let expected_ident = TMessageIdentifier::new("foo", TMessageType::Exception, 10); + assert_eq!(rcvd_ident, expected_ident); + let rcvd_err = ::Error::read_application_error_from_in_protocol(&mut i).unwrap(); + let expected_err = ApplicationError::new( + ApplicationErrorKind::Unknown, + MISSING_SEPARATOR_AND_NO_DEFAULT, + ); + assert_eq!(rcvd_err, expected_err); + } + + #[test] + fn should_write_error_if_separator_exists_and_no_processor_found() { + let (mut i, mut o) = build_objects(); + + let sent_ident = TMessageIdentifier::new("missing:call", TMessageType::Call, 10); + o.write_message_begin(&sent_ident).unwrap(); + o.flush().unwrap(); + o.transport.copy_write_buffer_to_read_buffer(); + o.transport.empty_write_buffer(); + + let p = TMultiplexedProcessor::new(); + p.process(&mut i, &mut o).unwrap(); // at this point an error should be written out + + i.transport + .set_readable_bytes(&o.transport.write_bytes()); + let rcvd_ident = i.read_message_begin().unwrap(); + let expected_ident = TMessageIdentifier::new("missing:call", TMessageType::Exception, 10); + assert_eq!(rcvd_ident, expected_ident); + let rcvd_err = ::Error::read_application_error_from_in_protocol(&mut i).unwrap(); + let expected_err = ApplicationError::new( + ApplicationErrorKind::Unknown, + missing_processor_message(Some("missing")), + ); + assert_eq!(rcvd_err, expected_err); + } + + #[derive(Default)] + struct Service { + pub invoked: Arc, + } + + impl TProcessor for Service { + fn process(&self, _: &mut TInputProtocol, _: &mut TOutputProtocol) -> ::Result<()> { + let res = self.invoked + .compare_and_swap(false, true, Ordering::Relaxed); + if res { + Ok(()) + } else { + Err("failed swap".into()) + } + } + } + + #[test] + fn should_route_call_to_correct_processor() { + let (mut i, mut o) = build_objects(); + + // build the services + let svc_1 = Service { invoked: Arc::new(AtomicBool::new(false)) }; + let atm_1 = svc_1.invoked.clone(); + let svc_2 = Service { invoked: Arc::new(AtomicBool::new(false)) }; + let atm_2 = svc_2.invoked.clone(); + + // register them + let mut p = TMultiplexedProcessor::new(); + p.register("service_1", Box::new(svc_1), false).unwrap(); + p.register("service_2", Box::new(svc_2), false).unwrap(); + + // make the service call + let sent_ident = TMessageIdentifier::new("service_1:call", TMessageType::Call, 10); + o.write_message_begin(&sent_ident).unwrap(); + o.flush().unwrap(); + o.transport.copy_write_buffer_to_read_buffer(); + o.transport.empty_write_buffer(); + + p.process(&mut i, &mut o).unwrap(); + + // service 1 should have been invoked, not service 2 + assert_eq!(atm_1.load(Ordering::Relaxed), true); + assert_eq!(atm_2.load(Ordering::Relaxed), false); + } + + #[test] + fn should_route_call_to_correct_processor_if_no_separator_exists_and_default_processor_set() { + let (mut i, mut o) = build_objects(); + + // build the services + let svc_1 = Service { invoked: Arc::new(AtomicBool::new(false)) }; + let atm_1 = svc_1.invoked.clone(); + let svc_2 = Service { invoked: Arc::new(AtomicBool::new(false)) }; + let atm_2 = svc_2.invoked.clone(); + + // register them + let mut p = TMultiplexedProcessor::new(); + p.register("service_1", Box::new(svc_1), false).unwrap(); + p.register("service_2", Box::new(svc_2), true).unwrap(); // second processor is default + + // make the service call (it's an old client, so we have to be backwards compatible) + let sent_ident = TMessageIdentifier::new("old_call", TMessageType::Call, 10); + o.write_message_begin(&sent_ident).unwrap(); + o.flush().unwrap(); + o.transport.copy_write_buffer_to_read_buffer(); + o.transport.empty_write_buffer(); + + p.process(&mut i, &mut o).unwrap(); + + // service 2 should have been invoked, not service 1 + assert_eq!(atm_1.load(Ordering::Relaxed), false); + assert_eq!(atm_2.load(Ordering::Relaxed), true); + } + + fn build_objects() + -> (TBinaryInputProtocol>, + TBinaryOutputProtocol>) + { + let c = TBufferChannel::with_capacity(128, 128); + let (r_c, w_c) = c.split().unwrap(); + (TBinaryInputProtocol::new(r_c, true), TBinaryOutputProtocol::new(w_c, true)) + } +} diff --git a/lib/rs/src/server/threaded.rs b/lib/rs/src/server/threaded.rs new file mode 100644 index 0000000..515b20d --- /dev/null +++ b/lib/rs/src/server/threaded.rs @@ -0,0 +1,240 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::net::{TcpListener, TcpStream}; +use std::sync::Arc; +use threadpool::ThreadPool; + +use {ApplicationError, ApplicationErrorKind}; +use protocol::{TInputProtocol, TInputProtocolFactory, TOutputProtocol, TOutputProtocolFactory}; +use transport::{TIoChannel, TReadTransportFactory, TTcpChannel, TWriteTransportFactory}; + +use super::TProcessor; + +/// Fixed-size thread-pool blocking Thrift server. +/// +/// A `TServer` listens on a given address and submits accepted connections +/// to an **unbounded** queue. Connections from this queue are serviced by +/// the first available worker thread from a **fixed-size** thread pool. Each +/// accepted connection is handled by that worker thread, and communication +/// over this thread occurs sequentially and synchronously (i.e. calls block). +/// Accepted connections have an input half and an output half, each of which +/// uses a `TTransport` and `TInputProtocol`/`TOutputProtocol` to translate +/// messages to and from byes. Any combination of `TInputProtocol`, `TOutputProtocol` +/// and `TTransport` may be used. +/// +/// # Examples +/// +/// Creating and running a `TServer` using Thrift-compiler-generated +/// service code. +/// +/// ```no_run +/// use thrift; +/// use thrift::protocol::{TInputProtocolFactory, TOutputProtocolFactory}; +/// use thrift::protocol::{TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory}; +/// use thrift::protocol::{TInputProtocol, TOutputProtocol}; +/// use thrift::transport::{TBufferedReadTransportFactory, TBufferedWriteTransportFactory, +/// TReadTransportFactory, TWriteTransportFactory}; +/// use thrift::server::{TProcessor, TServer}; +/// +/// // +/// // auto-generated +/// // +/// +/// // processor for `SimpleService` +/// struct SimpleServiceSyncProcessor; +/// impl SimpleServiceSyncProcessor { +/// fn new(processor: H) -> SimpleServiceSyncProcessor { +/// unimplemented!(); +/// } +/// } +/// +/// // `TProcessor` implementation for `SimpleService` +/// impl TProcessor for SimpleServiceSyncProcessor { +/// fn process(&self, i: &mut TInputProtocol, o: &mut TOutputProtocol) -> thrift::Result<()> { +/// unimplemented!(); +/// } +/// } +/// +/// // service functions for SimpleService +/// trait SimpleServiceSyncHandler { +/// fn service_call(&self) -> thrift::Result<()>; +/// } +/// +/// // +/// // user-code follows +/// // +/// +/// // define a handler that will be invoked when `service_call` is received +/// struct SimpleServiceHandlerImpl; +/// impl SimpleServiceSyncHandler for SimpleServiceHandlerImpl { +/// fn service_call(&self) -> thrift::Result<()> { +/// unimplemented!(); +/// } +/// } +/// +/// // instantiate the processor +/// let processor = SimpleServiceSyncProcessor::new(SimpleServiceHandlerImpl {}); +/// +/// // instantiate the server +/// let i_tr_fact: Box = Box::new(TBufferedReadTransportFactory::new()); +/// let i_pr_fact: Box = Box::new(TBinaryInputProtocolFactory::new()); +/// let o_tr_fact: Box = Box::new(TBufferedWriteTransportFactory::new()); +/// let o_pr_fact: Box = Box::new(TBinaryOutputProtocolFactory::new()); +/// +/// let mut server = TServer::new( +/// i_tr_fact, +/// i_pr_fact, +/// o_tr_fact, +/// o_pr_fact, +/// processor, +/// 10 +/// ); +/// +/// // start listening for incoming connections +/// match server.listen("127.0.0.1:8080") { +/// Ok(_) => println!("listen completed"), +/// Err(e) => println!("listen failed with error {:?}", e), +/// } +/// ``` +#[derive(Debug)] +pub struct TServer +where + PRC: TProcessor + Send + Sync + 'static, + RTF: TReadTransportFactory + 'static, + IPF: TInputProtocolFactory + 'static, + WTF: TWriteTransportFactory + 'static, + OPF: TOutputProtocolFactory + 'static, +{ + r_trans_factory: RTF, + i_proto_factory: IPF, + w_trans_factory: WTF, + o_proto_factory: OPF, + processor: Arc, + worker_pool: ThreadPool, +} + +impl TServer + where PRC: TProcessor + Send + Sync + 'static, + RTF: TReadTransportFactory + 'static, + IPF: TInputProtocolFactory + 'static, + WTF: TWriteTransportFactory + 'static, + OPF: TOutputProtocolFactory + 'static { + /// Create a `TServer`. + /// + /// Each accepted connection has an input and output half, each of which + /// requires a `TTransport` and `TProtocol`. `TServer` uses + /// `read_transport_factory` and `input_protocol_factory` to create + /// implementations for the input, and `write_transport_factory` and + /// `output_protocol_factory` to create implementations for the output. + pub fn new( + read_transport_factory: RTF, + input_protocol_factory: IPF, + write_transport_factory: WTF, + output_protocol_factory: OPF, + processor: PRC, + num_workers: usize, + ) -> TServer { + TServer { + r_trans_factory: read_transport_factory, + i_proto_factory: input_protocol_factory, + w_trans_factory: write_transport_factory, + o_proto_factory: output_protocol_factory, + processor: Arc::new(processor), + worker_pool: ThreadPool::with_name( + "Thrift service processor".to_owned(), + num_workers, + ), + } + } + + /// Listen for incoming connections on `listen_address`. + /// + /// `listen_address` should be in the form `host:port`, + /// for example: `127.0.0.1:8080`. + /// + /// Return `()` if successful. + /// + /// Return `Err` when the server cannot bind to `listen_address` or there + /// is an unrecoverable error. + pub fn listen(&mut self, listen_address: &str) -> ::Result<()> { + let listener = TcpListener::bind(listen_address)?; + for stream in listener.incoming() { + match stream { + Ok(s) => { + let (i_prot, o_prot) = self.new_protocols_for_connection(s)?; + let processor = self.processor.clone(); + self.worker_pool + .execute(move || handle_incoming_connection(processor, i_prot, o_prot),); + } + Err(e) => { + warn!("failed to accept remote connection with error {:?}", e); + } + } + } + + Err( + ::Error::Application( + ApplicationError { + kind: ApplicationErrorKind::Unknown, + message: "aborted listen loop".into(), + }, + ), + ) + } + + + fn new_protocols_for_connection( + &mut self, + stream: TcpStream, + ) -> ::Result<(Box, Box)> { + // create the shared tcp stream + let channel = TTcpChannel::with_stream(stream); + + // split it into two - one to be owned by the + // input tran/proto and the other by the output + let (r_chan, w_chan) = channel.split()?; + + // input protocol and transport + let r_tran = self.r_trans_factory.create(Box::new(r_chan)); + let i_prot = self.i_proto_factory.create(r_tran); + + // output protocol and transport + let w_tran = self.w_trans_factory.create(Box::new(w_chan)); + let o_prot = self.o_proto_factory.create(w_tran); + + Ok((i_prot, o_prot)) + } +} + +fn handle_incoming_connection( + processor: Arc, + i_prot: Box, + o_prot: Box, +) where + PRC: TProcessor, +{ + let mut i_prot = i_prot; + let mut o_prot = o_prot; + loop { + let r = processor.process(&mut *i_prot, &mut *o_prot); + if let Err(e) = r { + warn!("processor completed with error: {:?}", e); + break; + } + } +} diff --git a/lib/rs/src/transport/buffered.rs b/lib/rs/src/transport/buffered.rs new file mode 100644 index 0000000..b588ec1 --- /dev/null +++ b/lib/rs/src/transport/buffered.rs @@ -0,0 +1,442 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::cmp; +use std::io; +use std::io::{Read, Write}; + +use super::{TReadTransport, TReadTransportFactory, TWriteTransport, TWriteTransportFactory}; + +/// Default capacity of the read buffer in bytes. +const READ_CAPACITY: usize = 4096; + +/// Default capacity of the write buffer in bytes.. +const WRITE_CAPACITY: usize = 4096; + +/// Transport that reads messages via an internal buffer. +/// +/// A `TBufferedReadTransport` maintains a fixed-size internal read buffer. +/// On a call to `TBufferedReadTransport::read(...)` one full message - both +/// fixed-length header and bytes - is read from the wrapped channel and buffered. +/// Subsequent read calls are serviced from the internal buffer until it is +/// exhausted, at which point the next full message is read from the wrapped +/// channel. +/// +/// # Examples +/// +/// Create and use a `TBufferedReadTransport`. +/// +/// ```no_run +/// use std::io::Read; +/// use thrift::transport::{TBufferedReadTransport, TTcpChannel}; +/// +/// let mut c = TTcpChannel::new(); +/// c.open("localhost:9090").unwrap(); +/// +/// let mut t = TBufferedReadTransport::new(c); +/// +/// t.read(&mut vec![0u8; 1]).unwrap(); +/// ``` +#[derive(Debug)] +pub struct TBufferedReadTransport +where + C: Read, +{ + buf: Box<[u8]>, + pos: usize, + cap: usize, + chan: C, +} + +impl TBufferedReadTransport +where + C: Read, +{ + /// Create a `TBufferedTransport` with default-sized internal read and + /// write buffers that wraps the given `TIoChannel`. + pub fn new(channel: C) -> TBufferedReadTransport { + TBufferedReadTransport::with_capacity(READ_CAPACITY, channel) + } + + /// Create a `TBufferedTransport` with an internal read buffer of size + /// `read_capacity` and an internal write buffer of size + /// `write_capacity` that wraps the given `TIoChannel`. + pub fn with_capacity(read_capacity: usize, channel: C) -> TBufferedReadTransport { + TBufferedReadTransport { + buf: vec![0; read_capacity].into_boxed_slice(), + pos: 0, + cap: 0, + chan: channel, + } + } + + fn get_bytes(&mut self) -> io::Result<&[u8]> { + if self.cap - self.pos == 0 { + self.pos = 0; + self.cap = self.chan.read(&mut self.buf)?; + } + + Ok(&self.buf[self.pos..self.cap]) + } + + fn consume(&mut self, consumed: usize) { + // TODO: was a bug here += <-- test somehow + self.pos = cmp::min(self.cap, self.pos + consumed); + } +} + +impl Read for TBufferedReadTransport +where + C: Read, +{ + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let mut bytes_read = 0; + + loop { + let nread = { + let avail_bytes = self.get_bytes()?; + let avail_space = buf.len() - bytes_read; + let nread = cmp::min(avail_space, avail_bytes.len()); + buf[bytes_read..(bytes_read + nread)].copy_from_slice(&avail_bytes[..nread]); + nread + }; + + self.consume(nread); + bytes_read += nread; + + if bytes_read == buf.len() || nread == 0 { + break; + } + } + + Ok(bytes_read) + } +} + +/// Factory for creating instances of `TBufferedReadTransport`. +#[derive(Default)] +pub struct TBufferedReadTransportFactory; + +impl TBufferedReadTransportFactory { + pub fn new() -> TBufferedReadTransportFactory { + TBufferedReadTransportFactory {} + } +} + +impl TReadTransportFactory for TBufferedReadTransportFactory { + /// Create a `TBufferedReadTransport`. + fn create(&self, channel: Box) -> Box { + Box::new(TBufferedReadTransport::new(channel)) + } +} + +/// Transport that writes messages via an internal buffer. +/// +/// A `TBufferedWriteTransport` maintains a fixed-size internal write buffer. +/// All writes are made to this buffer and are sent to the wrapped channel only +/// when `TBufferedWriteTransport::flush()` is called. On a flush a fixed-length +/// header with a count of the buffered bytes is written, followed by the bytes +/// themselves. +/// +/// # Examples +/// +/// Create and use a `TBufferedWriteTransport`. +/// +/// ```no_run +/// use std::io::Write; +/// use thrift::transport::{TBufferedWriteTransport, TTcpChannel}; +/// +/// let mut c = TTcpChannel::new(); +/// c.open("localhost:9090").unwrap(); +/// +/// let mut t = TBufferedWriteTransport::new(c); +/// +/// t.write(&[0x00]).unwrap(); +/// t.flush().unwrap(); +/// ``` +#[derive(Debug)] +pub struct TBufferedWriteTransport +where + C: Write, +{ + buf: Vec, + channel: C, +} + +impl TBufferedWriteTransport +where + C: Write, +{ + /// Create a `TBufferedTransport` with default-sized internal read and + /// write buffers that wraps the given `TIoChannel`. + pub fn new(channel: C) -> TBufferedWriteTransport { + TBufferedWriteTransport::with_capacity(WRITE_CAPACITY, channel) + } + + /// Create a `TBufferedTransport` with an internal read buffer of size + /// `read_capacity` and an internal write buffer of size + /// `write_capacity` that wraps the given `TIoChannel`. + pub fn with_capacity(write_capacity: usize, channel: C) -> TBufferedWriteTransport { + TBufferedWriteTransport { + buf: Vec::with_capacity(write_capacity), + channel: channel, + } + } +} + +impl Write for TBufferedWriteTransport +where + C: Write, +{ + fn write(&mut self, buf: &[u8]) -> io::Result { + let avail_bytes = cmp::min(buf.len(), self.buf.capacity() - self.buf.len()); + self.buf.extend_from_slice(&buf[..avail_bytes]); + assert!( + self.buf.len() <= self.buf.capacity(), + "copy overflowed buffer" + ); + Ok(avail_bytes) + } + + fn flush(&mut self) -> io::Result<()> { + self.channel.write_all(&self.buf)?; + self.channel.flush()?; + self.buf.clear(); + Ok(()) + } +} + +/// Factory for creating instances of `TBufferedWriteTransport`. +#[derive(Default)] +pub struct TBufferedWriteTransportFactory; + +impl TBufferedWriteTransportFactory { + pub fn new() -> TBufferedWriteTransportFactory { + TBufferedWriteTransportFactory {} + } +} + +impl TWriteTransportFactory for TBufferedWriteTransportFactory { + /// Create a `TBufferedWriteTransport`. + fn create(&self, channel: Box) -> Box { + Box::new(TBufferedWriteTransport::new(channel)) + } +} + +#[cfg(test)] +mod tests { + use std::io::{Read, Write}; + + use super::*; + use transport::TBufferChannel; + + #[test] + fn must_return_zero_if_read_buffer_is_empty() { + let mem = TBufferChannel::with_capacity(10, 0); + let mut t = TBufferedReadTransport::with_capacity(10, mem); + + let mut b = vec![0; 10]; + let read_result = t.read(&mut b); + + assert_eq!(read_result.unwrap(), 0); + } + + #[test] + fn must_return_zero_if_caller_reads_into_zero_capacity_buffer() { + let mem = TBufferChannel::with_capacity(10, 0); + let mut t = TBufferedReadTransport::with_capacity(10, mem); + + let read_result = t.read(&mut []); + + assert_eq!(read_result.unwrap(), 0); + } + + #[test] + fn must_return_zero_if_nothing_more_can_be_read() { + let mem = TBufferChannel::with_capacity(4, 0); + let mut t = TBufferedReadTransport::with_capacity(4, mem); + + t.chan.set_readable_bytes(&[0, 1, 2, 3]); + + // read buffer is exactly the same size as bytes available + let mut buf = vec![0u8; 4]; + let read_result = t.read(&mut buf); + + // we've read exactly 4 bytes + assert_eq!(read_result.unwrap(), 4); + assert_eq!(&buf, &[0, 1, 2, 3]); + + // try read again + let buf_again = vec![0u8; 4]; + let read_result = t.read(&mut buf); + + // this time, 0 bytes and we haven't changed the buffer + assert_eq!(read_result.unwrap(), 0); + assert_eq!(&buf_again, &[0, 0, 0, 0]) + } + + #[test] + fn must_fill_user_buffer_with_only_as_many_bytes_as_available() { + let mem = TBufferChannel::with_capacity(4, 0); + let mut t = TBufferedReadTransport::with_capacity(4, mem); + + t.chan.set_readable_bytes(&[0, 1, 2, 3]); + + // read buffer is much larger than the bytes available + let mut buf = vec![0u8; 8]; + let read_result = t.read(&mut buf); + + // we've read exactly 4 bytes + assert_eq!(read_result.unwrap(), 4); + assert_eq!(&buf[..4], &[0, 1, 2, 3]); + + // try read again + let read_result = t.read(&mut buf[4..]); + + // this time, 0 bytes and we haven't changed the buffer + assert_eq!(read_result.unwrap(), 0); + assert_eq!(&buf, &[0, 1, 2, 3, 0, 0, 0, 0]) + } + + #[test] + fn must_read_successfully() { + // this test involves a few loops within the buffered transport + // itself where it has to drain the underlying transport in order + // to service a read + + // we have a much smaller buffer than the + // underlying transport has bytes available + let mem = TBufferChannel::with_capacity(10, 0); + let mut t = TBufferedReadTransport::with_capacity(2, mem); + + // fill the underlying transport's byte buffer + let mut readable_bytes = [0u8; 10]; + for i in 0..10 { + readable_bytes[i] = i as u8; + } + + t.chan.set_readable_bytes(&readable_bytes); + + // we ask to read into a buffer that's much larger + // than the one the buffered transport has; as a result + // it's going to have to keep asking the underlying + // transport for more bytes + let mut buf = [0u8; 8]; + let read_result = t.read(&mut buf); + + // we should have read 8 bytes + assert_eq!(read_result.unwrap(), 8); + assert_eq!(&buf, &[0, 1, 2, 3, 4, 5, 6, 7]); + + // let's clear out the buffer and try read again + for i in 0..8 { + buf[i] = 0; + } + let read_result = t.read(&mut buf); + + // this time we were only able to read 2 bytes + // (all that's remaining from the underlying transport) + // let's also check that the remaining bytes are untouched + assert_eq!(read_result.unwrap(), 2); + assert_eq!(&buf[0..2], &[8, 9]); + assert_eq!(&buf[2..], &[0, 0, 0, 0, 0, 0]); + + // try read again (we should get 0) + // and all the existing bytes were untouched + let read_result = t.read(&mut buf); + assert_eq!(read_result.unwrap(), 0); + assert_eq!(&buf[0..2], &[8, 9]); + assert_eq!(&buf[2..], &[0, 0, 0, 0, 0, 0]); + } + + #[test] + fn must_return_zero_if_nothing_can_be_written() { + let mem = TBufferChannel::with_capacity(0, 0); + let mut t = TBufferedWriteTransport::with_capacity(0, mem); + + let b = vec![0; 10]; + let r = t.write(&b); + + assert_eq!(r.unwrap(), 0); + } + + #[test] + fn must_return_zero_if_caller_calls_write_with_empty_buffer() { + let mem = TBufferChannel::with_capacity(0, 10); + let mut t = TBufferedWriteTransport::with_capacity(10, mem); + + let r = t.write(&[]); + let expected: [u8; 0] = []; + + assert_eq!(r.unwrap(), 0); + assert_eq_transport_written_bytes!(t, expected); + } + + #[test] + fn must_return_zero_if_write_buffer_full() { + let mem = TBufferChannel::with_capacity(0, 0); + let mut t = TBufferedWriteTransport::with_capacity(4, mem); + + let b = [0x00, 0x01, 0x02, 0x03]; + + // we've now filled the write buffer + let r = t.write(&b); + assert_eq!(r.unwrap(), 4); + + // try write the same bytes again - nothing should be writable + let r = t.write(&b); + assert_eq!(r.unwrap(), 0); + } + + #[test] + fn must_only_write_to_inner_transport_on_flush() { + let mem = TBufferChannel::with_capacity(10, 10); + let mut t = TBufferedWriteTransport::new(mem); + + let b: [u8; 5] = [0, 1, 2, 3, 4]; + assert_eq!(t.write(&b).unwrap(), 5); + assert_eq_transport_num_written_bytes!(t, 0); + + assert!(t.flush().is_ok()); + + assert_eq_transport_written_bytes!(t, b); + } + + #[test] + fn must_write_successfully_after_flush() { + let mem = TBufferChannel::with_capacity(0, 5); + let mut t = TBufferedWriteTransport::with_capacity(5, mem); + + // write and flush + let b: [u8; 5] = [0, 1, 2, 3, 4]; + assert_eq!(t.write(&b).unwrap(), 5); + assert!(t.flush().is_ok()); + + // check the flushed bytes + assert_eq_transport_written_bytes!(t, b); + + // reset our underlying transport + t.channel.empty_write_buffer(); + + // write and flush again + assert_eq!(t.write(&b).unwrap(), 5); + assert!(t.flush().is_ok()); + + // check the flushed bytes + assert_eq_transport_written_bytes!(t, b); + } +} diff --git a/lib/rs/src/transport/framed.rs b/lib/rs/src/transport/framed.rs new file mode 100644 index 0000000..d78d2f7 --- /dev/null +++ b/lib/rs/src/transport/framed.rs @@ -0,0 +1,264 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use std::cmp; +use std::io; +use std::io::{ErrorKind, Read, Write}; + +use super::{TReadTransport, TReadTransportFactory, TWriteTransport, TWriteTransportFactory}; + +/// Default capacity of the read buffer in bytes. +const READ_CAPACITY: usize = 4096; + +/// Default capacity of the write buffer in bytes. +const WRITE_CAPACITY: usize = 4096; + +/// Transport that reads framed messages. +/// +/// A `TFramedReadTransport` maintains a fixed-size internal read buffer. +/// On a call to `TFramedReadTransport::read(...)` one full message - both +/// fixed-length header and bytes - is read from the wrapped channel and +/// buffered. Subsequent read calls are serviced from the internal buffer +/// until it is exhausted, at which point the next full message is read +/// from the wrapped channel. +/// +/// # Examples +/// +/// Create and use a `TFramedReadTransport`. +/// +/// ```no_run +/// use std::io::Read; +/// use thrift::transport::{TFramedReadTransport, TTcpChannel}; +/// +/// let mut c = TTcpChannel::new(); +/// c.open("localhost:9090").unwrap(); +/// +/// let mut t = TFramedReadTransport::new(c); +/// +/// t.read(&mut vec![0u8; 1]).unwrap(); +/// ``` +#[derive(Debug)] +pub struct TFramedReadTransport +where + C: Read, +{ + buf: Box<[u8]>, + pos: usize, + cap: usize, + chan: C, +} + +impl TFramedReadTransport +where + C: Read, +{ + /// Create a `TFramedTransport` with default-sized internal read and + /// write buffers that wraps the given `TIoChannel`. + pub fn new(channel: C) -> TFramedReadTransport { + TFramedReadTransport::with_capacity(READ_CAPACITY, channel) + } + + /// Create a `TFramedTransport` with an internal read buffer of size + /// `read_capacity` and an internal write buffer of size + /// `write_capacity` that wraps the given `TIoChannel`. + pub fn with_capacity(read_capacity: usize, channel: C) -> TFramedReadTransport { + TFramedReadTransport { + buf: vec![0; read_capacity].into_boxed_slice(), + pos: 0, + cap: 0, + chan: channel, + } + } +} + +impl Read for TFramedReadTransport +where + C: Read, +{ + fn read(&mut self, b: &mut [u8]) -> io::Result { + if self.cap - self.pos == 0 { + let message_size = self.chan.read_i32::()? as usize; + if message_size > self.buf.len() { + return Err( + io::Error::new( + ErrorKind::Other, + format!( + "bytes to be read ({}) exceeds buffer \ + capacity ({})", + message_size, + self.buf.len() + ), + ), + ); + } + self.chan.read_exact(&mut self.buf[..message_size])?; + self.pos = 0; + self.cap = message_size as usize; + } + + let nread = cmp::min(b.len(), self.cap - self.pos); + b[..nread].clone_from_slice(&self.buf[self.pos..self.pos + nread]); + self.pos += nread; + + Ok(nread) + } +} + +/// Factory for creating instances of `TFramedReadTransport`. +#[derive(Default)] +pub struct TFramedReadTransportFactory; + +impl TFramedReadTransportFactory { + pub fn new() -> TFramedReadTransportFactory { + TFramedReadTransportFactory {} + } +} + +impl TReadTransportFactory for TFramedReadTransportFactory { + /// Create a `TFramedReadTransport`. + fn create(&self, channel: Box) -> Box { + Box::new(TFramedReadTransport::new(channel)) + } +} + +/// Transport that writes framed messages. +/// +/// A `TFramedWriteTransport` maintains a fixed-size internal write buffer. All +/// writes are made to this buffer and are sent to the wrapped channel only +/// when `TFramedWriteTransport::flush()` is called. On a flush a fixed-length +/// header with a count of the buffered bytes is written, followed by the bytes +/// themselves. +/// +/// # Examples +/// +/// Create and use a `TFramedWriteTransport`. +/// +/// ```no_run +/// use std::io::Write; +/// use thrift::transport::{TFramedWriteTransport, TTcpChannel}; +/// +/// let mut c = TTcpChannel::new(); +/// c.open("localhost:9090").unwrap(); +/// +/// let mut t = TFramedWriteTransport::new(c); +/// +/// t.write(&[0x00]).unwrap(); +/// t.flush().unwrap(); +/// ``` +#[derive(Debug)] +pub struct TFramedWriteTransport +where + C: Write, +{ + buf: Box<[u8]>, + pos: usize, + channel: C, +} + +impl TFramedWriteTransport +where + C: Write, +{ + /// Create a `TFramedTransport` with default-sized internal read and + /// write buffers that wraps the given `TIoChannel`. + pub fn new(channel: C) -> TFramedWriteTransport { + TFramedWriteTransport::with_capacity(WRITE_CAPACITY, channel) + } + + /// Create a `TFramedTransport` with an internal read buffer of size + /// `read_capacity` and an internal write buffer of size + /// `write_capacity` that wraps the given `TIoChannel`. + pub fn with_capacity(write_capacity: usize, channel: C) -> TFramedWriteTransport { + TFramedWriteTransport { + buf: vec![0; write_capacity].into_boxed_slice(), + pos: 0, + channel: channel, + } + } +} + +impl Write for TFramedWriteTransport +where + C: Write, +{ + fn write(&mut self, b: &[u8]) -> io::Result { + if b.len() > (self.buf.len() - self.pos) { + return Err( + io::Error::new( + ErrorKind::Other, + format!( + "bytes to be written ({}) exceeds buffer \ + capacity ({})", + b.len(), + self.buf.len() - self.pos + ), + ), + ); + } + + let nwrite = b.len(); // always less than available write buffer capacity + self.buf[self.pos..(self.pos + nwrite)].clone_from_slice(b); + self.pos += nwrite; + Ok(nwrite) + } + + fn flush(&mut self) -> io::Result<()> { + let message_size = self.pos; + + if let 0 = message_size { + return Ok(()); + } else { + self.channel + .write_i32::(message_size as i32)?; + } + + let mut byte_index = 0; + while byte_index < self.pos { + let nwrite = self.channel.write(&self.buf[byte_index..self.pos])?; + byte_index = cmp::min(byte_index + nwrite, self.pos); + } + + self.pos = 0; + self.channel.flush() + } +} + +/// Factory for creating instances of `TFramedWriteTransport`. +#[derive(Default)] +pub struct TFramedWriteTransportFactory; + +impl TFramedWriteTransportFactory { + pub fn new() -> TFramedWriteTransportFactory { + TFramedWriteTransportFactory {} + } +} + +impl TWriteTransportFactory for TFramedWriteTransportFactory { + /// Create a `TFramedWriteTransport`. + fn create(&self, channel: Box) -> Box { + Box::new(TFramedWriteTransport::new(channel)) + } +} + +#[cfg(test)] +mod tests { + // use std::io::{Read, Write}; + // + // use super::*; + // use ::transport::mem::TBufferChannel; +} diff --git a/lib/rs/src/transport/mem.rs b/lib/rs/src/transport/mem.rs new file mode 100644 index 0000000..86ac6bb --- /dev/null +++ b/lib/rs/src/transport/mem.rs @@ -0,0 +1,393 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::cmp; +use std::io; +use std::sync::{Arc, Mutex}; + +use super::{ReadHalf, TIoChannel, WriteHalf}; + +/// In-memory read and write channel with fixed-size read and write buffers. +/// +/// On a `write` bytes are written to the internal write buffer. Writes are no +/// longer accepted once this buffer is full. Callers must `empty_write_buffer()` +/// before subsequent writes are accepted. +/// +/// You can set readable bytes in the internal read buffer by filling it with +/// `set_readable_bytes(...)`. Callers can then read until the buffer is +/// depleted. No further reads are accepted until the internal read buffer is +/// replenished again. +#[derive(Debug)] +pub struct TBufferChannel { + read: Arc>, + write: Arc>, +} + +#[derive(Debug)] +struct ReadData { + buf: Box<[u8]>, + pos: usize, + idx: usize, + cap: usize, +} + +#[derive(Debug)] +struct WriteData { + buf: Box<[u8]>, + pos: usize, + cap: usize, +} + +impl TBufferChannel { + /// Constructs a new, empty `TBufferChannel` with the given + /// read buffer capacity and write buffer capacity. + pub fn with_capacity(read_capacity: usize, write_capacity: usize) -> TBufferChannel { + TBufferChannel { + read: Arc::new( + Mutex::new( + ReadData { + buf: vec![0; read_capacity].into_boxed_slice(), + idx: 0, + pos: 0, + cap: read_capacity, + }, + ), + ), + write: Arc::new( + Mutex::new( + WriteData { + buf: vec![0; write_capacity].into_boxed_slice(), + pos: 0, + cap: write_capacity, + }, + ), + ), + } + } + + /// Return a copy of the bytes held by the internal read buffer. + /// Returns an empty vector if no readable bytes are present. + pub fn read_bytes(&self) -> Vec { + let rdata = self.read.as_ref().lock().unwrap(); + let mut buf = vec![0u8; rdata.idx]; + buf.copy_from_slice(&rdata.buf[..rdata.idx]); + buf + } + + // FIXME: do I really need this API call? + // FIXME: should this simply reset to the last set of readable bytes? + /// Reset the number of readable bytes to zero. + /// + /// Subsequent calls to `read` will return nothing. + pub fn empty_read_buffer(&mut self) { + let mut rdata = self.read.as_ref().lock().unwrap(); + rdata.pos = 0; + rdata.idx = 0; + } + + /// Copy bytes from the source buffer `buf` into the internal read buffer, + /// overwriting any existing bytes. Returns the number of bytes copied, + /// which is `min(buf.len(), internal_read_buf.len())`. + pub fn set_readable_bytes(&mut self, buf: &[u8]) -> usize { + self.empty_read_buffer(); + let mut rdata = self.read.as_ref().lock().unwrap(); + let max_bytes = cmp::min(rdata.cap, buf.len()); + rdata.buf[..max_bytes].clone_from_slice(&buf[..max_bytes]); + rdata.idx = max_bytes; + max_bytes + } + + /// Return a copy of the bytes held by the internal write buffer. + /// Returns an empty vector if no bytes were written. + pub fn write_bytes(&self) -> Vec { + let wdata = self.write.as_ref().lock().unwrap(); + let mut buf = vec![0u8; wdata.pos]; + buf.copy_from_slice(&wdata.buf[..wdata.pos]); + buf + } + + /// Resets the internal write buffer, making it seem like no bytes were + /// written. Calling `write_buffer` after this returns an empty vector. + pub fn empty_write_buffer(&mut self) { + let mut wdata = self.write.as_ref().lock().unwrap(); + wdata.pos = 0; + } + + /// Overwrites the contents of the read buffer with the contents of the + /// write buffer. The write buffer is emptied after this operation. + pub fn copy_write_buffer_to_read_buffer(&mut self) { + // FIXME: redo this entire method + let buf = { + let wdata = self.write.as_ref().lock().unwrap(); + let b = &wdata.buf[..wdata.pos]; + let mut b_ret = vec![0; b.len()]; + b_ret.copy_from_slice(b); + b_ret + }; + + let bytes_copied = self.set_readable_bytes(&buf); + assert_eq!(bytes_copied, buf.len()); + + self.empty_write_buffer(); + } +} + +impl TIoChannel for TBufferChannel { + fn split(self) -> ::Result<(ReadHalf, WriteHalf)> + where + Self: Sized, + { + Ok( + (ReadHalf { + handle: TBufferChannel { + read: self.read.clone(), + write: self.write.clone(), + }, + }, + WriteHalf { + handle: TBufferChannel { + read: self.read.clone(), + write: self.write.clone(), + }, + }), + ) + } +} + +impl io::Read for TBufferChannel { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let mut rdata = self.read.as_ref().lock().unwrap(); + let nread = cmp::min(buf.len(), rdata.idx - rdata.pos); + buf[..nread].clone_from_slice(&rdata.buf[rdata.pos..rdata.pos + nread]); + rdata.pos += nread; + Ok(nread) + } +} + +impl io::Write for TBufferChannel { + fn write(&mut self, buf: &[u8]) -> io::Result { + let mut wdata = self.write.as_ref().lock().unwrap(); + let nwrite = cmp::min(buf.len(), wdata.cap - wdata.pos); + let (start, end) = (wdata.pos, wdata.pos + nwrite); + wdata.buf[start..end].clone_from_slice(&buf[..nwrite]); + wdata.pos += nwrite; + Ok(nwrite) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) // nothing to do on flush + } +} + +#[cfg(test)] +mod tests { + use std::io::{Read, Write}; + + use super::TBufferChannel; + + #[test] + fn must_empty_write_buffer() { + let mut t = TBufferChannel::with_capacity(0, 1); + + let bytes_to_write: [u8; 1] = [0x01]; + let result = t.write(&bytes_to_write); + assert_eq!(result.unwrap(), 1); + assert_eq!(&t.write_bytes(), &bytes_to_write); + + t.empty_write_buffer(); + assert_eq!(t.write_bytes().len(), 0); + } + + #[test] + fn must_accept_writes_after_buffer_emptied() { + let mut t = TBufferChannel::with_capacity(0, 2); + + let bytes_to_write: [u8; 2] = [0x01, 0x02]; + + // first write (all bytes written) + let result = t.write(&bytes_to_write); + assert_eq!(result.unwrap(), 2); + assert_eq!(&t.write_bytes(), &bytes_to_write); + + // try write again (nothing should be written) + let result = t.write(&bytes_to_write); + assert_eq!(result.unwrap(), 0); + assert_eq!(&t.write_bytes(), &bytes_to_write); // still the same as before + + // now reset the buffer + t.empty_write_buffer(); + assert_eq!(t.write_bytes().len(), 0); + + // now try write again - the write should succeed + let result = t.write(&bytes_to_write); + assert_eq!(result.unwrap(), 2); + assert_eq!(&t.write_bytes(), &bytes_to_write); + } + + #[test] + fn must_accept_multiple_writes_until_buffer_is_full() { + let mut t = TBufferChannel::with_capacity(0, 10); + + // first write (all bytes written) + let bytes_to_write_0: [u8; 2] = [0x01, 0x41]; + let write_0_result = t.write(&bytes_to_write_0); + assert_eq!(write_0_result.unwrap(), 2); + assert_eq!(t.write_bytes(), &bytes_to_write_0); + + // second write (all bytes written, starting at index 2) + let bytes_to_write_1: [u8; 7] = [0x24, 0x41, 0x32, 0x33, 0x11, 0x98, 0xAF]; + let write_1_result = t.write(&bytes_to_write_1); + assert_eq!(write_1_result.unwrap(), 7); + assert_eq!(&t.write_bytes()[2..], &bytes_to_write_1); + + // third write (only 1 byte written - that's all we have space for) + let bytes_to_write_2: [u8; 3] = [0xBF, 0xDA, 0x98]; + let write_2_result = t.write(&bytes_to_write_2); + assert_eq!(write_2_result.unwrap(), 1); + assert_eq!(&t.write_bytes()[9..], &bytes_to_write_2[0..1]); // how does this syntax work?! + + // fourth write (no writes are accepted) + let bytes_to_write_3: [u8; 3] = [0xBF, 0xAA, 0xFD]; + let write_3_result = t.write(&bytes_to_write_3); + assert_eq!(write_3_result.unwrap(), 0); + + // check the full write buffer + let mut expected: Vec = Vec::with_capacity(10); + expected.extend_from_slice(&bytes_to_write_0); + expected.extend_from_slice(&bytes_to_write_1); + expected.extend_from_slice(&bytes_to_write_2[0..1]); + assert_eq!(t.write_bytes(), &expected[..]); + } + + #[test] + fn must_empty_read_buffer() { + let mut t = TBufferChannel::with_capacity(1, 0); + + let bytes_to_read: [u8; 1] = [0x01]; + let result = t.set_readable_bytes(&bytes_to_read); + assert_eq!(result, 1); + assert_eq!(t.read_bytes(), &bytes_to_read); + + t.empty_read_buffer(); + assert_eq!(t.read_bytes().len(), 0); + } + + #[test] + fn must_allow_readable_bytes_to_be_set_after_read_buffer_emptied() { + let mut t = TBufferChannel::with_capacity(1, 0); + + let bytes_to_read_0: [u8; 1] = [0x01]; + let result = t.set_readable_bytes(&bytes_to_read_0); + assert_eq!(result, 1); + assert_eq!(t.read_bytes(), &bytes_to_read_0); + + t.empty_read_buffer(); + assert_eq!(t.read_bytes().len(), 0); + + let bytes_to_read_1: [u8; 1] = [0x02]; + let result = t.set_readable_bytes(&bytes_to_read_1); + assert_eq!(result, 1); + assert_eq!(t.read_bytes(), &bytes_to_read_1); + } + + #[test] + fn must_accept_multiple_reads_until_all_bytes_read() { + let mut t = TBufferChannel::with_capacity(10, 0); + + let readable_bytes: [u8; 10] = [0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0x00, 0x1A, 0x2B, 0x3C, 0x4D]; + + // check that we're able to set the bytes to be read + let result = t.set_readable_bytes(&readable_bytes); + assert_eq!(result, 10); + assert_eq!(t.read_bytes(), &readable_bytes); + + // first read + let mut read_buf_0 = vec![0; 5]; + let read_result = t.read(&mut read_buf_0); + assert_eq!(read_result.unwrap(), 5); + assert_eq!(read_buf_0.as_slice(), &(readable_bytes[0..5])); + + // second read + let mut read_buf_1 = vec![0; 4]; + let read_result = t.read(&mut read_buf_1); + assert_eq!(read_result.unwrap(), 4); + assert_eq!(read_buf_1.as_slice(), &(readable_bytes[5..9])); + + // third read (only 1 byte remains to be read) + let mut read_buf_2 = vec![0; 3]; + let read_result = t.read(&mut read_buf_2); + assert_eq!(read_result.unwrap(), 1); + read_buf_2.truncate(1); // FIXME: does the caller have to do this? + assert_eq!(read_buf_2.as_slice(), &(readable_bytes[9..])); + + // fourth read (nothing should be readable) + let mut read_buf_3 = vec![0; 10]; + let read_result = t.read(&mut read_buf_3); + assert_eq!(read_result.unwrap(), 0); + read_buf_3.truncate(0); + + // check that all the bytes we received match the original (again!) + let mut bytes_read = Vec::with_capacity(10); + bytes_read.extend_from_slice(&read_buf_0); + bytes_read.extend_from_slice(&read_buf_1); + bytes_read.extend_from_slice(&read_buf_2); + bytes_read.extend_from_slice(&read_buf_3); + assert_eq!(&bytes_read, &readable_bytes); + } + + #[test] + fn must_allow_reads_to_succeed_after_read_buffer_replenished() { + let mut t = TBufferChannel::with_capacity(3, 0); + + let readable_bytes_0: [u8; 3] = [0x02, 0xAB, 0x33]; + + // check that we're able to set the bytes to be read + let result = t.set_readable_bytes(&readable_bytes_0); + assert_eq!(result, 3); + assert_eq!(t.read_bytes(), &readable_bytes_0); + + let mut read_buf = vec![0; 4]; + + // drain the read buffer + let read_result = t.read(&mut read_buf); + assert_eq!(read_result.unwrap(), 3); + assert_eq!(t.read_bytes(), &read_buf[0..3]); + + // check that a subsequent read fails + let read_result = t.read(&mut read_buf); + assert_eq!(read_result.unwrap(), 0); + + // we don't modify the read buffer on failure + let mut expected_bytes = Vec::with_capacity(4); + expected_bytes.extend_from_slice(&readable_bytes_0); + expected_bytes.push(0x00); + assert_eq!(&read_buf, &expected_bytes); + + // replenish the read buffer again + let readable_bytes_1: [u8; 2] = [0x91, 0xAA]; + + // check that we're able to set the bytes to be read + let result = t.set_readable_bytes(&readable_bytes_1); + assert_eq!(result, 2); + assert_eq!(t.read_bytes(), &readable_bytes_1); + + // read again + let read_result = t.read(&mut read_buf); + assert_eq!(read_result.unwrap(), 2); + assert_eq!(t.read_bytes(), &read_buf[0..2]); + } +} diff --git a/lib/rs/src/transport/mod.rs b/lib/rs/src/transport/mod.rs new file mode 100644 index 0000000..9392786 --- /dev/null +++ b/lib/rs/src/transport/mod.rs @@ -0,0 +1,280 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +//! Types used to send and receive bytes over an I/O channel. +//! +//! The core types are the `TReadTransport`, `TWriteTransport` and the +//! `TIoChannel` traits, through which `TInputProtocol` or +//! `TOutputProtocol` can receive and send primitives over the wire. While +//! `TInputProtocol` and `TOutputProtocol` instances deal with language primitives +//! the types in this module understand only bytes. + +use std::io; +use std::io::{Read, Write}; +use std::ops::{Deref, DerefMut}; + +#[cfg(test)] +macro_rules! assert_eq_transport_num_written_bytes { + ($transport:ident, $num_written_bytes:expr) => { + { + assert_eq!($transport.channel.write_bytes().len(), $num_written_bytes); + } + }; +} + + +#[cfg(test)] +macro_rules! assert_eq_transport_written_bytes { + ($transport:ident, $expected_bytes:ident) => { + { + assert_eq!($transport.channel.write_bytes(), &$expected_bytes); + } + }; +} + +mod buffered; +mod framed; +mod socket; +mod mem; + +pub use self::buffered::{TBufferedReadTransport, TBufferedReadTransportFactory, + TBufferedWriteTransport, TBufferedWriteTransportFactory}; +pub use self::framed::{TFramedReadTransport, TFramedReadTransportFactory, TFramedWriteTransport, + TFramedWriteTransportFactory}; +pub use self::mem::TBufferChannel; +pub use self::socket::TTcpChannel; + +/// Identifies a transport used by a `TInputProtocol` to receive bytes. +pub trait TReadTransport: Read {} + +/// Helper type used by a server to create `TReadTransport` instances for +/// accepted client connections. +pub trait TReadTransportFactory { + /// Create a `TTransport` that wraps a channel over which bytes are to be read. + fn create(&self, channel: Box) -> Box; +} + +/// Identifies a transport used by `TOutputProtocol` to send bytes. +pub trait TWriteTransport: Write {} + +/// Helper type used by a server to create `TWriteTransport` instances for +/// accepted client connections. +pub trait TWriteTransportFactory { + /// Create a `TTransport` that wraps a channel over which bytes are to be sent. + fn create(&self, channel: Box) -> Box; +} + +impl TReadTransport for T +where + T: Read, +{ +} + +impl TWriteTransport for T +where + T: Write, +{ +} + +// FIXME: implement the Debug trait for boxed transports + +impl TReadTransportFactory for Box +where + T: TReadTransportFactory + ?Sized, +{ + fn create(&self, channel: Box) -> Box { + (**self).create(channel) + } +} + +impl TWriteTransportFactory for Box +where + T: TWriteTransportFactory + ?Sized, +{ + fn create(&self, channel: Box) -> Box { + (**self).create(channel) + } +} + +/// Identifies a splittable bidirectional I/O channel used to send and receive bytes. +pub trait TIoChannel: Read + Write { + /// Split the channel into a readable half and a writable half, where the + /// readable half implements `io::Read` and the writable half implements + /// `io::Write`. Returns `None` if the channel was not initialized, or if it + /// cannot be split safely. + /// + /// Returned halves may share the underlying OS channel or buffer resources. + /// Implementations **should ensure** that these two halves can be safely + /// used independently by concurrent threads. + fn split(self) -> ::Result<(::transport::ReadHalf, ::transport::WriteHalf)> + where + Self: Sized; +} + +/// The readable half of an object returned from `TIoChannel::split`. +#[derive(Debug)] +pub struct ReadHalf +where + C: Read, +{ + handle: C, +} + +/// The writable half of an object returned from `TIoChannel::split`. +#[derive(Debug)] +pub struct WriteHalf +where + C: Write, +{ + handle: C, +} + +impl Read for ReadHalf +where + C: Read, +{ + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.handle.read(buf) + } +} + +impl Write for WriteHalf +where + C: Write, +{ + fn write(&mut self, buf: &[u8]) -> io::Result { + self.handle.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.handle.flush() + } +} + +impl Deref for ReadHalf +where + C: Read, +{ + type Target = C; + + fn deref(&self) -> &Self::Target { + &self.handle + } +} + +impl DerefMut for ReadHalf +where + C: Read, +{ + fn deref_mut(&mut self) -> &mut C { + &mut self.handle + } +} + +impl Deref for WriteHalf +where + C: Write, +{ + type Target = C; + + fn deref(&self) -> &Self::Target { + &self.handle + } +} + +impl DerefMut for WriteHalf +where + C: Write, +{ + fn deref_mut(&mut self) -> &mut C { + &mut self.handle + } +} + +#[cfg(test)] +mod tests { + + use std::io::Cursor; + + use super::*; + + #[test] + fn must_create_usable_read_channel_from_concrete_read_type() { + let r = Cursor::new([0, 1, 2]); + let _ = TBufferedReadTransport::new(r); + } + + #[test] + fn must_create_usable_read_channel_from_boxed_read() { + let r: Box = Box::new(Cursor::new([0, 1, 2])); + let _ = TBufferedReadTransport::new(r); + } + + #[test] + fn must_create_usable_write_channel_from_concrete_write_type() { + let w = vec![0u8; 10]; + let _ = TBufferedWriteTransport::new(w); + } + + #[test] + fn must_create_usable_write_channel_from_boxed_write() { + let w: Box = Box::new(vec![0u8; 10]); + let _ = TBufferedWriteTransport::new(w); + } + + #[test] + fn must_create_usable_read_transport_from_concrete_read_transport() { + let r = Cursor::new([0, 1, 2]); + let mut t = TBufferedReadTransport::new(r); + takes_read_transport(&mut t) + } + + #[test] + fn must_create_usable_read_transport_from_boxed_read() { + let r = Cursor::new([0, 1, 2]); + let mut t: Box = Box::new(TBufferedReadTransport::new(r)); + takes_read_transport(&mut t) + } + + #[test] + fn must_create_usable_write_transport_from_concrete_write_transport() { + let w = vec![0u8; 10]; + let mut t = TBufferedWriteTransport::new(w); + takes_write_transport(&mut t) + } + + #[test] + fn must_create_usable_write_transport_from_boxed_write() { + let w = vec![0u8; 10]; + let mut t: Box = Box::new(TBufferedWriteTransport::new(w)); + takes_write_transport(&mut t) + } + + fn takes_read_transport(t: &mut R) + where + R: TReadTransport, + { + t.bytes(); + } + + fn takes_write_transport(t: &mut W) + where + W: TWriteTransport, + { + t.flush().unwrap(); + } +} diff --git a/lib/rs/src/transport/socket.rs b/lib/rs/src/transport/socket.rs new file mode 100644 index 0000000..727bba3 --- /dev/null +++ b/lib/rs/src/transport/socket.rs @@ -0,0 +1,165 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::convert::From; +use std::io; +use std::io::{ErrorKind, Read, Write}; +use std::net::{Shutdown, TcpStream}; + +use {TransportErrorKind, new_transport_error}; +use super::{ReadHalf, TIoChannel, WriteHalf}; + +/// Bidirectional TCP/IP channel. +/// +/// # Examples +/// +/// Create a `TTcpChannel`. +/// +/// ```no_run +/// use std::io::{Read, Write}; +/// use thrift::transport::TTcpChannel; +/// +/// let mut c = TTcpChannel::new(); +/// c.open("localhost:9090").unwrap(); +/// +/// let mut buf = vec![0u8; 4]; +/// c.read(&mut buf).unwrap(); +/// c.write(&vec![0, 1, 2]).unwrap(); +/// ``` +/// +/// Create a `TTcpChannel` by wrapping an existing `TcpStream`. +/// +/// ```no_run +/// use std::io::{Read, Write}; +/// use std::net::TcpStream; +/// use thrift::transport::TTcpChannel; +/// +/// let stream = TcpStream::connect("127.0.0.1:9189").unwrap(); +/// +/// // no need to call c.open() since we've already connected above +/// let mut c = TTcpChannel::with_stream(stream); +/// +/// let mut buf = vec![0u8; 4]; +/// c.read(&mut buf).unwrap(); +/// c.write(&vec![0, 1, 2]).unwrap(); +/// ``` +#[derive(Debug, Default)] +pub struct TTcpChannel { + stream: Option, +} + +impl TTcpChannel { + /// Create an uninitialized `TTcpChannel`. + /// + /// The returned instance must be opened using `TTcpChannel::open(...)` + /// before it can be used. + pub fn new() -> TTcpChannel { + TTcpChannel { stream: None } + } + + /// Create a `TTcpChannel` that wraps an existing `TcpStream`. + /// + /// The passed-in stream is assumed to have been opened before being wrapped + /// by the created `TTcpChannel` instance. + pub fn with_stream(stream: TcpStream) -> TTcpChannel { + TTcpChannel { stream: Some(stream) } + } + + /// Connect to `remote_address`, which should have the form `host:port`. + pub fn open(&mut self, remote_address: &str) -> ::Result<()> { + if self.stream.is_some() { + Err( + new_transport_error( + TransportErrorKind::AlreadyOpen, + "tcp connection previously opened", + ), + ) + } else { + match TcpStream::connect(&remote_address) { + Ok(s) => { + self.stream = Some(s); + Ok(()) + } + Err(e) => Err(From::from(e)), + } + } + } + + /// Shut down this channel. + /// + /// Both send and receive halves are closed, and this instance can no + /// longer be used to communicate with another endpoint. + pub fn close(&mut self) -> ::Result<()> { + self.if_set(|s| s.shutdown(Shutdown::Both)) + .map_err(From::from) + } + + fn if_set(&mut self, mut stream_operation: F) -> io::Result + where + F: FnMut(&mut TcpStream) -> io::Result, + { + + if let Some(ref mut s) = self.stream { + stream_operation(s) + } else { + Err(io::Error::new(ErrorKind::NotConnected, "tcp endpoint not connected"),) + } + } +} + +impl TIoChannel for TTcpChannel { + fn split(self) -> ::Result<(ReadHalf, WriteHalf)> + where + Self: Sized, + { + let mut s = self; + + s.stream + .as_mut() + .and_then(|s| s.try_clone().ok()) + .map( + |cloned| { + (ReadHalf { handle: TTcpChannel { stream: s.stream.take() } }, + WriteHalf { handle: TTcpChannel { stream: Some(cloned) } }) + }, + ) + .ok_or_else( + || { + new_transport_error( + TransportErrorKind::Unknown, + "cannot clone underlying tcp stream", + ) + }, + ) + } +} + +impl Read for TTcpChannel { + fn read(&mut self, b: &mut [u8]) -> io::Result { + self.if_set(|s| s.read(b)) + } +} + +impl Write for TTcpChannel { + fn write(&mut self, b: &[u8]) -> io::Result { + self.if_set(|s| s.write_all(b)).map(|_| b.len()) + } + + fn flush(&mut self) -> io::Result<()> { + self.if_set(|s| s.flush()) + } +} diff --git a/lib/rs/test/Cargo.toml b/lib/rs/test/Cargo.toml new file mode 100644 index 0000000..50dec19 --- /dev/null +++ b/lib/rs/test/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "kitchen-sink" +version = "0.1.0" +license = "Apache-2.0" +authors = ["Apache Thrift Developers "] +publish = false + +[dependencies] +clap = "<2.28.0" +ordered-float = "0.3.0" +try_from = "0.2.0" + +[dependencies.thrift] +path = "../" + diff --git a/lib/rs/test/Makefile.am b/lib/rs/test/Makefile.am new file mode 100644 index 0000000..8edd756 --- /dev/null +++ b/lib/rs/test/Makefile.am @@ -0,0 +1,54 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +THRIFT = $(top_builddir)/compiler/cpp/thrift + +stubs: thrifts/Base_One.thrift thrifts/Base_Two.thrift thrifts/Midlayer.thrift thrifts/Ultimate.thrift $(top_builddir)/test/Recursive.thrift $(THRIFT) + $(THRIFT) -I ./thrifts -out src --gen rs thrifts/Base_One.thrift + $(THRIFT) -I ./thrifts -out src --gen rs thrifts/Base_Two.thrift + $(THRIFT) -I ./thrifts -out src --gen rs thrifts/Midlayer.thrift + $(THRIFT) -I ./thrifts -out src --gen rs thrifts/Ultimate.thrift + $(THRIFT) -out src --gen rs $(top_builddir)/test/Recursive.thrift + +check: stubs + $(CARGO) build + $(CARGO) test + [ -d bin ] || mkdir bin + cp target/debug/kitchen_sink_server bin/kitchen_sink_server + cp target/debug/kitchen_sink_client bin/kitchen_sink_client + +clean-local: + $(CARGO) clean + -$(RM) Cargo.lock + -$(RM) src/base_one.rs + -$(RM) src/base_two.rs + -$(RM) src/midlayer.rs + -$(RM) src/ultimate.rs + -$(RM) -r bin + +EXTRA_DIST = \ + Cargo.toml \ + thrifts/Base_One.thrift \ + thrifts/Base_Two.thrift \ + thrifts/Midlayer.thrift \ + thrifts/Ultimate.thrift \ + src/lib.rs \ + src/bin/kitchen_sink_server.rs \ + src/bin/kitchen_sink_client.rs + diff --git a/lib/rs/test/Makefile.in b/lib/rs/test/Makefile.in new file mode 100644 index 0000000..ef214ea --- /dev/null +++ b/lib/rs/test/Makefile.in @@ -0,0 +1,655 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/rs/test +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = $(top_builddir)/compiler/cpp/thrift +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + Cargo.toml \ + thrifts/Base_One.thrift \ + thrifts/Base_Two.thrift \ + thrifts/Midlayer.thrift \ + thrifts/Ultimate.thrift \ + src/lib.rs \ + src/bin/kitchen_sink_server.rs \ + src/bin/kitchen_sink_client.rs + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/rs/test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/rs/test/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +stubs: thrifts/Base_One.thrift thrifts/Base_Two.thrift thrifts/Midlayer.thrift thrifts/Ultimate.thrift $(top_builddir)/test/Recursive.thrift $(THRIFT) + $(THRIFT) -I ./thrifts -out src --gen rs thrifts/Base_One.thrift + $(THRIFT) -I ./thrifts -out src --gen rs thrifts/Base_Two.thrift + $(THRIFT) -I ./thrifts -out src --gen rs thrifts/Midlayer.thrift + $(THRIFT) -I ./thrifts -out src --gen rs thrifts/Ultimate.thrift + $(THRIFT) -out src --gen rs $(top_builddir)/test/Recursive.thrift + +check: stubs + $(CARGO) build + $(CARGO) test + [ -d bin ] || mkdir bin + cp target/debug/kitchen_sink_server bin/kitchen_sink_server + cp target/debug/kitchen_sink_client bin/kitchen_sink_client + +clean-local: + $(CARGO) clean + -$(RM) Cargo.lock + -$(RM) src/base_one.rs + -$(RM) src/base_two.rs + -$(RM) src/midlayer.rs + -$(RM) src/ultimate.rs + -$(RM) -r bin + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/rs/test/src/bin/kitchen_sink_client.rs b/lib/rs/test/src/bin/kitchen_sink_client.rs new file mode 100644 index 0000000..fb6ea15 --- /dev/null +++ b/lib/rs/test/src/bin/kitchen_sink_client.rs @@ -0,0 +1,280 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#[macro_use] +extern crate clap; + +extern crate kitchen_sink; +extern crate thrift; + +use std::convert::Into; + +use kitchen_sink::base_two::{TNapkinServiceSyncClient, TRamenServiceSyncClient}; +use kitchen_sink::midlayer::{MealServiceSyncClient, TMealServiceSyncClient}; +use kitchen_sink::recursive; +use kitchen_sink::recursive::{CoRec, CoRec2, RecList, RecTree, TTestServiceSyncClient}; +use kitchen_sink::ultimate::{FullMealServiceSyncClient, TFullMealServiceSyncClient}; +use thrift::transport::{ReadHalf, TFramedReadTransport, TFramedWriteTransport, TIoChannel, + TTcpChannel, WriteHalf}; +use thrift::protocol::{TBinaryInputProtocol, TBinaryOutputProtocol, TCompactInputProtocol, + TCompactOutputProtocol, TInputProtocol, TOutputProtocol}; + +fn main() { + match run() { + Ok(()) => println!("kitchen sink client completed successfully"), + Err(e) => { + println!("kitchen sink client failed with error {:?}", e); + std::process::exit(1); + } + } +} + +fn run() -> thrift::Result<()> { + let matches = clap_app!(rust_kitchen_sink_client => + (version: "0.1.0") + (author: "Apache Thrift Developers ") + (about: "Thrift Rust kitchen sink client") + (@arg host: --host +takes_value "Host on which the Thrift test server is located") + (@arg port: --port +takes_value "Port on which the Thrift test server is listening") + (@arg protocol: --protocol +takes_value "Thrift protocol implementation to use (\"binary\", \"compact\")") + (@arg service: --service +takes_value "Service type to contact (\"part\", \"full\", \"recursive\")") + ) + .get_matches(); + + let host = matches.value_of("host").unwrap_or("127.0.0.1"); + let port = value_t!(matches, "port", u16).unwrap_or(9090); + let protocol = matches.value_of("protocol").unwrap_or("compact"); + let service = matches.value_of("service").unwrap_or("part"); + + let (i_chan, o_chan) = tcp_channel(host, port)?; + let (i_tran, o_tran) = (TFramedReadTransport::new(i_chan), TFramedWriteTransport::new(o_chan)); + + let (i_prot, o_prot): (Box, Box) = match protocol { + "binary" => { + (Box::new(TBinaryInputProtocol::new(i_tran, true)), + Box::new(TBinaryOutputProtocol::new(o_tran, true))) + } + "compact" => { + (Box::new(TCompactInputProtocol::new(i_tran)), + Box::new(TCompactOutputProtocol::new(o_tran))) + } + unmatched => return Err(format!("unsupported protocol {}", unmatched).into()), + }; + + run_client(service, i_prot, o_prot) +} + +fn run_client( + service: &str, + i_prot: Box, + o_prot: Box, +) -> thrift::Result<()> { + match service { + "full" => exec_full_meal_client(i_prot, o_prot), + "part" => exec_meal_client(i_prot, o_prot), + "recursive" => exec_recursive_client(i_prot, o_prot), + _ => Err(thrift::Error::from(format!("unknown service type {}", service)),), + } +} + +fn tcp_channel( + host: &str, + port: u16, +) -> thrift::Result<(ReadHalf, WriteHalf)> { + let mut c = TTcpChannel::new(); + c.open(&format!("{}:{}", host, port))?; + c.split() +} + +fn exec_meal_client( + i_prot: Box, + o_prot: Box, +) -> thrift::Result<()> { + let mut client = MealServiceSyncClient::new(i_prot, o_prot); + + // client.full_meal(); // <-- IMPORTANT: if you uncomment this, compilation *should* fail + // this is because the MealService struct does not contain the appropriate service marker + + // only the following three calls work + execute_call("part", "ramen", || client.ramen(50)) + .map(|_| ())?; + execute_call("part", "meal", || client.meal()) + .map(|_| ())?; + execute_call("part", "napkin", || client.napkin()) + .map(|_| ())?; + + Ok(()) +} + +fn exec_full_meal_client( + i_prot: Box, + o_prot: Box, +) -> thrift::Result<()> { + let mut client = FullMealServiceSyncClient::new(i_prot, o_prot); + + execute_call("full", "ramen", || client.ramen(100)) + .map(|_| ())?; + execute_call("full", "meal", || client.meal()) + .map(|_| ())?; + execute_call("full", "napkin", || client.napkin()) + .map(|_| ())?; + execute_call("full", "full meal", || client.full_meal()) + .map(|_| ())?; + + Ok(()) +} + +fn exec_recursive_client( + i_prot: Box, + o_prot: Box, +) -> thrift::Result<()> { + let mut client = recursive::TestServiceSyncClient::new(i_prot, o_prot); + + let tree = RecTree { + children: Some( + vec![ + Box::new( + RecTree { + children: Some( + vec![ + Box::new( + RecTree { + children: None, + item: Some(3), + }, + ), + Box::new( + RecTree { + children: None, + item: Some(4), + }, + ), + ], + ), + item: Some(2), + }, + ), + ], + ), + item: Some(1), + }; + + let expected_tree = RecTree { + children: Some( + vec![ + Box::new( + RecTree { + children: Some( + vec![ + Box::new( + RecTree { + children: Some(Vec::new()), // remote returns an empty list + item: Some(3), + }, + ), + Box::new( + RecTree { + children: Some(Vec::new()), // remote returns an empty list + item: Some(4), + }, + ), + ], + ), + item: Some(2), + }, + ), + ], + ), + item: Some(1), + }; + + let returned_tree = execute_call("recursive", "echo_tree", || client.echo_tree(tree.clone()))?; + if returned_tree != expected_tree { + return Err( + format!( + "mismatched recursive tree {:?} {:?}", + expected_tree, + returned_tree + ) + .into(), + ); + } + + let list = RecList { + nextitem: Some( + Box::new( + RecList { + nextitem: Some( + Box::new( + RecList { + nextitem: None, + item: Some(3), + }, + ), + ), + item: Some(2), + }, + ), + ), + item: Some(1), + }; + let returned_list = execute_call("recursive", "echo_list", || client.echo_list(list.clone()))?; + if returned_list != list { + return Err(format!("mismatched recursive list {:?} {:?}", list, returned_list).into(),); + } + + let co_rec = CoRec { + other: Some( + Box::new( + CoRec2 { + other: Some(CoRec { other: Some(Box::new(CoRec2 { other: None })) }), + }, + ), + ), + }; + let returned_co_rec = execute_call( + "recursive", + "echo_co_rec", + || client.echo_co_rec(co_rec.clone()), + )?; + if returned_co_rec != co_rec { + return Err(format!("mismatched co_rec {:?} {:?}", co_rec, returned_co_rec).into(),); + } + + Ok(()) +} + +fn execute_call(service_type: &str, call_name: &str, mut f: F) -> thrift::Result +where + F: FnMut() -> thrift::Result, +{ + let res = f(); + + match res { + Ok(_) => println!("{}: completed {} call", service_type, call_name), + Err(ref e) => { + println!( + "{}: failed {} call with error {:?}", + service_type, + call_name, + e + ) + } + } + + res +} diff --git a/lib/rs/test/src/bin/kitchen_sink_server.rs b/lib/rs/test/src/bin/kitchen_sink_server.rs new file mode 100644 index 0000000..15ceb29 --- /dev/null +++ b/lib/rs/test/src/bin/kitchen_sink_server.rs @@ -0,0 +1,304 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#[macro_use] +extern crate clap; + +extern crate kitchen_sink; +extern crate thrift; + +use kitchen_sink::base_one::Noodle; +use kitchen_sink::base_two::{Napkin, NapkinServiceSyncHandler, Ramen, RamenServiceSyncHandler}; +use kitchen_sink::midlayer::{Dessert, Meal, MealServiceSyncHandler, MealServiceSyncProcessor}; +use kitchen_sink::recursive; +use kitchen_sink::ultimate::{Drink, FullMeal, FullMealAndDrinks, + FullMealAndDrinksServiceSyncProcessor, FullMealServiceSyncHandler}; +use kitchen_sink::ultimate::FullMealAndDrinksServiceSyncHandler; +use thrift::protocol::{TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory, + TCompactInputProtocolFactory, TCompactOutputProtocolFactory, + TInputProtocolFactory, TOutputProtocolFactory}; +use thrift::transport::{TFramedReadTransportFactory, TFramedWriteTransportFactory, + TReadTransportFactory, TWriteTransportFactory}; +use thrift::server::TServer; + +fn main() { + match run() { + Ok(()) => println!("kitchen sink server completed successfully"), + Err(e) => { + println!("kitchen sink server failed with error {:?}", e); + std::process::exit(1); + } + } +} + +fn run() -> thrift::Result<()> { + + let matches = clap_app!(rust_kitchen_sink_server => + (version: "0.1.0") + (author: "Apache Thrift Developers ") + (about: "Thrift Rust kitchen sink test server") + (@arg port: --port +takes_value "port on which the test server listens") + (@arg protocol: --protocol +takes_value "Thrift protocol implementation to use (\"binary\", \"compact\")") + (@arg service: --service +takes_value "Service type to contact (\"part\", \"full\", \"recursive\")") + ) + .get_matches(); + + let port = value_t!(matches, "port", u16).unwrap_or(9090); + let protocol = matches.value_of("protocol").unwrap_or("compact"); + let service = matches.value_of("service").unwrap_or("part"); + let listen_address = format!("127.0.0.1:{}", port); + + println!("binding to {}", listen_address); + + let r_transport_factory = TFramedReadTransportFactory::new(); + let w_transport_factory = TFramedWriteTransportFactory::new(); + + let (i_protocol_factory, o_protocol_factory): (Box, + Box) = + match &*protocol { + "binary" => { + (Box::new(TBinaryInputProtocolFactory::new()), + Box::new(TBinaryOutputProtocolFactory::new())) + } + "compact" => { + (Box::new(TCompactInputProtocolFactory::new()), + Box::new(TCompactOutputProtocolFactory::new())) + } + unknown => { + return Err(format!("unsupported transport type {}", unknown).into()); + } + }; + + // FIXME: should processor be boxed as well? + // + // [sigh] I hate Rust generics implementation + // + // I would have preferred to build a server here, return it, and then do + // the common listen-and-handle stuff, but since the server doesn't have a + // common type (because each match arm instantiates a server with a + // different processor) this isn't possible. + // + // Since what I'm doing is uncommon I'm just going to duplicate the code + match &*service { + "part" => { + run_meal_server( + &listen_address, + r_transport_factory, + i_protocol_factory, + w_transport_factory, + o_protocol_factory, + ) + } + "full" => { + run_full_meal_server( + &listen_address, + r_transport_factory, + i_protocol_factory, + w_transport_factory, + o_protocol_factory, + ) + } + "recursive" => { + run_recursive_server( + &listen_address, + r_transport_factory, + i_protocol_factory, + w_transport_factory, + o_protocol_factory, + ) + } + unknown => Err(format!("unsupported service type {}", unknown).into()), + } +} + +fn run_meal_server( + listen_address: &str, + r_transport_factory: RTF, + i_protocol_factory: IPF, + w_transport_factory: WTF, + o_protocol_factory: OPF, +) -> thrift::Result<()> +where + RTF: TReadTransportFactory + 'static, + IPF: TInputProtocolFactory + 'static, + WTF: TWriteTransportFactory + 'static, + OPF: TOutputProtocolFactory + 'static, +{ + let processor = MealServiceSyncProcessor::new(PartHandler {}); + let mut server = TServer::new( + r_transport_factory, + i_protocol_factory, + w_transport_factory, + o_protocol_factory, + processor, + 1, + ); + + server.listen(listen_address) +} + +fn run_full_meal_server( + listen_address: &str, + r_transport_factory: RTF, + i_protocol_factory: IPF, + w_transport_factory: WTF, + o_protocol_factory: OPF, +) -> thrift::Result<()> +where + RTF: TReadTransportFactory + 'static, + IPF: TInputProtocolFactory + 'static, + WTF: TWriteTransportFactory + 'static, + OPF: TOutputProtocolFactory + 'static, +{ + let processor = FullMealAndDrinksServiceSyncProcessor::new(FullHandler {}); + let mut server = TServer::new( + r_transport_factory, + i_protocol_factory, + w_transport_factory, + o_protocol_factory, + processor, + 1, + ); + + server.listen(listen_address) +} + +struct PartHandler; + +impl MealServiceSyncHandler for PartHandler { + fn handle_meal(&self) -> thrift::Result { + println!("part: handling meal call"); + Ok(meal()) + } +} + +impl RamenServiceSyncHandler for PartHandler { + fn handle_ramen(&self, _: i32) -> thrift::Result { + println!("part: handling ramen call"); + Ok(ramen()) + } +} + +impl NapkinServiceSyncHandler for PartHandler { + fn handle_napkin(&self) -> thrift::Result { + println!("part: handling napkin call"); + Ok(napkin()) + } +} + +// full service +// + +struct FullHandler; + +impl FullMealAndDrinksServiceSyncHandler for FullHandler { + fn handle_full_meal_and_drinks(&self) -> thrift::Result { + Ok(FullMealAndDrinks::new(full_meal(), Drink::WHISKEY)) + } +} + +impl FullMealServiceSyncHandler for FullHandler { + fn handle_full_meal(&self) -> thrift::Result { + println!("full: handling full meal call"); + Ok(full_meal()) + } +} + +impl MealServiceSyncHandler for FullHandler { + fn handle_meal(&self) -> thrift::Result { + println!("full: handling meal call"); + Ok(meal()) + } +} + +impl RamenServiceSyncHandler for FullHandler { + fn handle_ramen(&self, _: i32) -> thrift::Result { + println!("full: handling ramen call"); + Ok(ramen()) + } +} + +impl NapkinServiceSyncHandler for FullHandler { + fn handle_napkin(&self) -> thrift::Result { + println!("full: handling napkin call"); + Ok(napkin()) + } +} + +fn full_meal() -> FullMeal { + FullMeal::new(meal(), Dessert::Port("Graham's Tawny".to_owned())) +} + +fn meal() -> Meal { + Meal::new(noodle(), ramen()) +} + +fn noodle() -> Noodle { + Noodle::new("spelt".to_owned(), 100) +} + +fn ramen() -> Ramen { + Ramen::new("Mr Ramen".to_owned(), 72) +} + +fn napkin() -> Napkin { + Napkin {} +} + +fn run_recursive_server( + listen_address: &str, + r_transport_factory: RTF, + i_protocol_factory: IPF, + w_transport_factory: WTF, + o_protocol_factory: OPF, +) -> thrift::Result<()> +where + RTF: TReadTransportFactory + 'static, + IPF: TInputProtocolFactory + 'static, + WTF: TWriteTransportFactory + 'static, + OPF: TOutputProtocolFactory + 'static, +{ + let processor = recursive::TestServiceSyncProcessor::new(RecursiveTestServerHandler {}); + let mut server = TServer::new( + r_transport_factory, + i_protocol_factory, + w_transport_factory, + o_protocol_factory, + processor, + 1, + ); + + server.listen(listen_address) +} + +struct RecursiveTestServerHandler; +impl recursive::TestServiceSyncHandler for RecursiveTestServerHandler { + fn handle_echo_tree(&self, tree: recursive::RecTree) -> thrift::Result { + println!("{:?}", tree); + Ok(tree) + } + + fn handle_echo_list(&self, lst: recursive::RecList) -> thrift::Result { + println!("{:?}", lst); + Ok(lst) + } + + fn handle_echo_co_rec(&self, item: recursive::CoRec) -> thrift::Result { + println!("{:?}", item); + Ok(item) + } +} diff --git a/lib/rs/test/src/lib.rs b/lib/rs/test/src/lib.rs new file mode 100644 index 0000000..e5e176e --- /dev/null +++ b/lib/rs/test/src/lib.rs @@ -0,0 +1,57 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +extern crate ordered_float; +extern crate thrift; +extern crate try_from; + +pub mod base_one; +pub mod base_two; +pub mod midlayer; +pub mod ultimate; +pub mod recursive; + +#[cfg(test)] +mod tests { + + use std::default::Default; + + use super::*; + + #[test] + fn must_be_able_to_use_constructor() { + let _ = midlayer::Meal::new(Some(base_one::Noodle::default()), None); + } + + #[test] + fn must_be_able_to_use_constructor_with_no_fields() { + let _ = midlayer::Meal::new(None, None); + } + + #[test] + fn must_be_able_to_use_constructor_without_option_wrap() { + let _ = midlayer::Meal::new(base_one::Noodle::default(), None); + } + + #[test] + fn must_be_able_to_use_defaults() { + let _ = midlayer::Meal { + noodle: Some(base_one::Noodle::default()), + ..Default::default() + }; + } +} diff --git a/lib/rs/test/thrifts/Base_One.thrift b/lib/rs/test/thrifts/Base_One.thrift new file mode 100644 index 0000000..3da083d --- /dev/null +++ b/lib/rs/test/thrifts/Base_One.thrift @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +typedef i64 Temperature + +typedef i8 Size + +typedef string Location + +const i32 BoilingPoint = 100 + +const list Temperatures = [10, 11, 22, 33] + +// IMPORTANT: temps should end with ".0" because this tests +// that we don't have a problem with const float list generation +const list CommonTemperatures = [300.0, 450.0] + +const double MealsPerDay = 2.5; + +struct Noodle { + 1: string flourType + 2: Temperature cookTemp +} + +struct Spaghetti { + 1: optional list noodles +} + +const Noodle SpeltNoodle = { "flourType": "spelt", "cookTemp": 110 } + +struct MeasuringSpoon { + 1: Size size +} + +struct MeasuringCup { + 1: double millis +} + +union MeasuringAids { + 1: MeasuringSpoon spoon + 2: MeasuringCup cup +} + +struct CookingTemperatures { + 1: set commonTemperatures + 2: list usedTemperatures + 3: map fahrenheitToCentigradeConversions +} + +struct Recipe { + 1: string recipeName + 2: string cuisine + 3: i8 page +} + +union CookingTools { + 1: set measuringSpoons + 2: map measuringCups, + 3: list recipes +} + diff --git a/lib/rs/test/thrifts/Base_Two.thrift b/lib/rs/test/thrifts/Base_Two.thrift new file mode 100644 index 0000000..b4b4ea1 --- /dev/null +++ b/lib/rs/test/thrifts/Base_Two.thrift @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +const i32 WaterWeight = 200 + +struct Ramen { + 1: optional string ramenType + 2: required i32 noodleCount +} + +struct Napkin { + // empty +} + +service NapkinService { + Napkin napkin() +} + +service RamenService extends NapkinService { + Ramen ramen(1: i32 requestedNoodleCount) +} + +/* const struct CookedRamen = { "bar": 10 } */ + diff --git a/lib/rs/test/thrifts/Midlayer.thrift b/lib/rs/test/thrifts/Midlayer.thrift new file mode 100644 index 0000000..cf1157c --- /dev/null +++ b/lib/rs/test/thrifts/Midlayer.thrift @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +include "Base_One.thrift" +include "Base_Two.thrift" + +const i32 WaterBoilingPoint = Base_One.BoilingPoint + +const map TemperatureNames = { "freezing": 0, "boiling": 100 } + +const map, map, string>> MyConstNestedMap = { + [0, 1, 2, 3]: { ["foo"]: "bar" }, + [20]: { ["nut", "ton"] : "bar" }, + [30, 40]: { ["bouncy", "tinkly"]: "castle" } +} + +const list> MyConstNestedList = [ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8] +] + +const set> MyConstNestedSet = [ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8] +] + +struct Meal { + 1: Base_One.Noodle noodle + 2: Base_Two.Ramen ramen +} + +union Dessert { + 1: string port + 2: string iceWine +} + +service MealService extends Base_Two.RamenService { + Meal meal() +} + diff --git a/lib/rs/test/thrifts/Ultimate.thrift b/lib/rs/test/thrifts/Ultimate.thrift new file mode 100644 index 0000000..8154d91 --- /dev/null +++ b/lib/rs/test/thrifts/Ultimate.thrift @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +include "Midlayer.thrift" + +enum Drink { + WATER, + WHISKEY, + WINE, +} + +struct FullMeal { + 1: required Midlayer.Meal meal + 2: required Midlayer.Dessert dessert +} + +struct FullMealAndDrinks { + 1: required FullMeal fullMeal + 2: optional Drink drink +} + +service FullMealService extends Midlayer.MealService { + FullMeal fullMeal() +} + +service FullMealAndDrinksService extends FullMealService { + FullMealAndDrinks fullMealAndDrinks() +} + diff --git a/lib/st/README.md b/lib/st/README.md new file mode 100644 index 0000000..5b5fdee --- /dev/null +++ b/lib/st/README.md @@ -0,0 +1,39 @@ +Thrift SmallTalk Software Library + +Last updated Nov 2007 + +License +======= + +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + +Contains some contributions under the Thrift Software License. +Please see doc/old-thrift-license.txt in the Thrift distribution for +details. + +Library +======= + +To get started, just file in thrift.st with Squeak, run thrift -st +on the tutorial .thrift files (and file in the resulting code), and +then: + +calc := CalculatorClient binaryOnHost: 'localhost' port: '9090' +calc addNum1: 10 num2: 15 + +Tested in Squeak 3.7, but should work fine with anything later. diff --git a/lib/st/coding_standards.md b/lib/st/coding_standards.md new file mode 100644 index 0000000..fa0390b --- /dev/null +++ b/lib/st/coding_standards.md @@ -0,0 +1 @@ +Please follow [General Coding Standards](/doc/coding_standards.md) diff --git a/lib/st/package.xml b/lib/st/package.xml new file mode 100644 index 0000000..5044e2a --- /dev/null +++ b/lib/st/package.xml @@ -0,0 +1,26 @@ + + + + + libthrift-st + thrift.st + thrift.st + + diff --git a/lib/st/thrift.st b/lib/st/thrift.st new file mode 100644 index 0000000..fdb66df --- /dev/null +++ b/lib/st/thrift.st @@ -0,0 +1,815 @@ +" +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +License); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + +Contains some contributions under the Thrift Software License. +Please see doc/old-thrift-license.txt in the Thrift distribution for +details. +" + +SystemOrganization addCategory: #Thrift! +SystemOrganization addCategory: #'Thrift-Protocol'! +SystemOrganization addCategory: #'Thrift-Transport'! + +Error subclass: #TError + instanceVariableNames: 'code' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift'! + +!TError class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:28'! +signalWithCode: anInteger + self new code: anInteger; signal! ! + +!TError methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:28'! +code + ^ code! ! + +!TError methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:28'! +code: anInteger + code := anInteger! ! + +TError subclass: #TProtocolError + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Protocol'! + +!TProtocolError class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 18:39'! +badVersion + ^ 4! ! + +!TProtocolError class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 18:39'! +invalidData + ^ 1! ! + +!TProtocolError class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 18:39'! +negativeSize + ^ 2! ! + +!TProtocolError class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 18:40'! +sizeLimit + ^ 3! ! + +!TProtocolError class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 18:40'! +unknown + ^ 0! ! + +TError subclass: #TTransportError + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Transport'! + +TTransportError subclass: #TTransportClosedError + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Transport'! + +Object subclass: #TClient + instanceVariableNames: 'iprot oprot seqid remoteSeqid' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift'! + +!TClient class methodsFor: 'as yet unclassified' stamp: 'pc 11/7/2007 06:00'! +binaryOnHost: aString port: anInteger + | sock | + sock := TSocket new host: aString; port: anInteger; open; yourself. + ^ self new + inProtocol: (TBinaryProtocol new transport: sock); + yourself! ! + +!TClient methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 23:03'! +inProtocol: aProtocol + iprot := aProtocol. + oprot ifNil: [oprot := aProtocol]! ! + +!TClient methodsFor: 'as yet unclassified' stamp: 'pc 10/26/2007 04:28'! +nextSeqid + ^ seqid + ifNil: [seqid := 0] + ifNotNil: [seqid := seqid + 1]! ! + +!TClient methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:51'! +outProtocol: aProtocol + oprot := aProtocol! ! + +!TClient methodsFor: 'as yet unclassified' stamp: 'pc 10/28/2007 15:32'! +validateRemoteMessage: aMsg + remoteSeqid + ifNil: [remoteSeqid := aMsg seqid] + ifNotNil: + [(remoteSeqid + 1) = aMsg seqid ifFalse: + [TProtocolError signal: 'Bad seqid: ', aMsg seqid asString, + '; wanted: ', remoteSeqid asString]. + remoteSeqid := aMsg seqid]! ! + +Object subclass: #TField + instanceVariableNames: 'name type id' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Protocol'! + +!TField methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:05'! +id + ^ id ifNil: [0]! ! + +!TField methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:44'! +id: anInteger + id := anInteger! ! + +!TField methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:04'! +name + ^ name ifNil: ['']! ! + +!TField methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:44'! +name: anObject + name := anObject! ! + +!TField methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:05'! +type + ^ type ifNil: [TType stop]! ! + +!TField methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:44'! +type: anInteger + type := anInteger! ! + +Object subclass: #TMessage + instanceVariableNames: 'name seqid type' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Protocol'! + +TMessage subclass: #TCallMessage + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Protocol'! + +!TCallMessage methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:53'! +type + ^ 1! ! + +!TMessage methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:05'! +name + ^ name ifNil: ['']! ! + +!TMessage methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:35'! +name: aString + name := aString! ! + +!TMessage methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:05'! +seqid + ^ seqid ifNil: [0]! ! + +!TMessage methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:35'! +seqid: anInteger + seqid := anInteger! ! + +!TMessage methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:06'! +type + ^ type ifNil: [0]! ! + +!TMessage methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:35'! +type: anInteger + type := anInteger! ! + +Object subclass: #TProtocol + instanceVariableNames: 'transport' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Protocol'! + +TProtocol subclass: #TBinaryProtocol + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Protocol'! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 11/1/2007 04:24'! +intFromByteArray: buf + | vals | + vals := Array new: buf size. + 1 to: buf size do: [:n | vals at: n put: ((buf at: n) bitShift: (buf size - n) * 8)]. + ^ vals sum! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 18:46'! +readBool + ^ self readByte isZero not! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/25/2007 00:02'! +readByte + ^ (self transport read: 1) first! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/28/2007 16:24'! +readDouble + | val | + val := Float new: 2. + ^ val basicAt: 1 put: (self readRawInt: 4); + basicAt: 2 put: (self readRawInt: 4); + yourself! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 20:02'! +readFieldBegin + | field | + field := TField new type: self readByte. + + ^ field type = TType stop + ifTrue: [field] + ifFalse: [field id: self readI16; yourself]! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:15'! +readI16 + ^ self readInt: 2! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:20'! +readI32 + ^ self readInt: 4! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:20'! +readI64 + ^ self readInt: 8! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 11/1/2007 02:35'! +readInt: size + | buf val | + buf := transport read: size. + val := self intFromByteArray: buf. + ^ buf first > 16r7F + ifTrue: [self unsignedInt: val size: size] + ifFalse: [val]! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:57'! +readListBegin + ^ TList new + elemType: self readByte; + size: self readI32! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:58'! +readMapBegin + ^ TMap new + keyType: self readByte; + valueType: self readByte; + size: self readI32! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 11/1/2007 04:22'! +readMessageBegin + | version | + version := self readI32. + + (version bitAnd: self versionMask) = self version1 + ifFalse: [TProtocolError signalWithCode: TProtocolError badVersion]. + + ^ TMessage new + type: (version bitAnd: 16r000000FF); + name: self readString; + seqid: self readI32! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/28/2007 16:24'! +readRawInt: size + ^ self intFromByteArray: (transport read: size)! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 11/1/2007 00:59'! +readSetBegin + "element type, size" + ^ TSet new + elemType: self readByte; + size: self readI32! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 02/07/2009 19:00'! +readString + | sz | + sz := self readI32. + ^ sz > 0 ifTrue: [(transport read: sz) asString] ifFalse: ['']! ! + +!TBinaryProtocol methodsFor: 'reading' stamp: 'pc 11/1/2007 04:22'! +unsignedInt: val size: size + ^ 0 - ((val - 1) bitXor: ((2 raisedTo: (size * 8)) - 1))! ! + +!TBinaryProtocol methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:13'! +version1 + ^ 16r80010000 ! ! + +!TBinaryProtocol methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 18:01'! +versionMask + ^ 16rFFFF0000! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 18:35'! +write: aString + transport write: aString! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:23'! +writeBool: bool + bool ifTrue: [self writeByte: 1] + ifFalse: [self writeByte: 0]! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/26/2007 09:31'! +writeByte: aNumber + aNumber > 16rFF ifTrue: [TError signal: 'writeByte too big']. + transport write: (Array with: aNumber)! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/28/2007 16:16'! +writeDouble: aDouble + self writeI32: (aDouble basicAt: 1); + writeI32: (aDouble basicAt: 2)! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:56'! +writeField: aField + self writeByte: aField type; + writeI16: aField id! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/25/2007 00:01'! +writeFieldBegin: aField + self writeByte: aField type. + self writeI16: aField id! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 18:04'! +writeFieldStop + self writeByte: TType stop! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 11/1/2007 02:06'! +writeI16: i16 + self writeInt: i16 size: 2! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 11/1/2007 02:06'! +writeI32: i32 + self writeInt: i32 size: 4! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 11/1/2007 02:06'! +writeI64: i64 + self writeInt: i64 size: 8! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 11/1/2007 04:23'! +writeInt: val size: size + 1 to: size do: [:n | self writeByte: ((val bitShift: (size negated + n) * 8) bitAnd: 16rFF)]! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 11/1/2007 00:48'! +writeListBegin: aList + self writeByte: aList elemType; writeI32: aList size! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:55'! +writeMapBegin: aMap + self writeByte: aMap keyType; + writeByte: aMap valueType; + writeI32: aMap size! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 20:36'! +writeMessageBegin: msg + self writeI32: (self version1 bitOr: msg type); + writeString: msg name; + writeI32: msg seqid! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 11/1/2007 00:56'! +writeSetBegin: aSet + self writeByte: aSet elemType; writeI32: aSet size! ! + +!TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 18:35'! +writeString: aString + self writeI32: aString size; + write: aString! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readBool! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readByte! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readDouble! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readFieldBegin! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readFieldEnd! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readI16! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readI32! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readI64! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readListBegin! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readListEnd! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readMapBegin! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readMapEnd! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:39'! +readMessageBegin! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:39'! +readMessageEnd! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readSetBegin! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readSetEnd! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/25/2007 16:10'! +readSimpleType: aType + aType = TType bool ifTrue: [^ self readBool]. + aType = TType byte ifTrue: [^ self readByte]. + aType = TType double ifTrue: [^ self readDouble]. + aType = TType i16 ifTrue: [^ self readI16]. + aType = TType i32 ifTrue: [^ self readI32]. + aType = TType i64 ifTrue: [^ self readI64]. + aType = TType list ifTrue: [^ self readBool].! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readString! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readStructBegin + ! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! +readStructEnd! ! + +!TProtocol methodsFor: 'reading' stamp: 'pc 10/26/2007 21:34'! +skip: aType + aType = TType stop ifTrue: [^ self]. + aType = TType bool ifTrue: [^ self readBool]. + aType = TType byte ifTrue: [^ self readByte]. + aType = TType i16 ifTrue: [^ self readI16]. + aType = TType i32 ifTrue: [^ self readI32]. + aType = TType i64 ifTrue: [^ self readI64]. + aType = TType string ifTrue: [^ self readString]. + aType = TType double ifTrue: [^ self readDouble]. + aType = TType struct ifTrue: + [| field | + self readStructBegin. + [(field := self readFieldBegin) type = TType stop] whileFalse: + [self skip: field type. self readFieldEnd]. + ^ self readStructEnd]. + aType = TType map ifTrue: + [| map | + map := self readMapBegin. + map size timesRepeat: [self skip: map keyType. self skip: map valueType]. + ^ self readMapEnd]. + aType = TType list ifTrue: + [| list | + list := self readListBegin. + list size timesRepeat: [self skip: list elemType]. + ^ self readListEnd]. + aType = TType set ifTrue: + [| set | + set := self readSetBegin. + set size timesRepeat: [self skip: set elemType]. + ^ self readSetEnd]. + + self error: 'Unknown type'! ! + +!TProtocol methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 23:02'! +transport + ^ transport! ! + +!TProtocol methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:28'! +transport: aTransport + transport := aTransport! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! +writeBool: aBool! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! +writeByte: aByte! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:38'! +writeDouble: aFloat! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:38'! +writeFieldBegin: aField! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! +writeFieldEnd! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! +writeFieldStop! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! +writeI16: i16! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! +writeI32: i32! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! +writeI64: i64! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:39'! +writeListBegin: aList! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! +writeListEnd! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:39'! +writeMapBegin: aMap! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! +writeMapEnd! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:36'! +writeMessageBegin! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:36'! +writeMessageEnd! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:39'! +writeSetBegin: aSet! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! +writeSetEnd! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:38'! +writeString: aString! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:38'! +writeStructBegin: aStruct! ! + +!TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! +writeStructEnd! ! + +Object subclass: #TResult + instanceVariableNames: 'success oprot iprot exception' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift'! + +!TResult methodsFor: 'as yet unclassified' stamp: 'pc 10/26/2007 21:35'! +exception + ^ exception! ! + +!TResult methodsFor: 'as yet unclassified' stamp: 'pc 10/26/2007 21:35'! +exception: anError + exception := anError! ! + +!TResult methodsFor: 'as yet unclassified' stamp: 'pc 10/26/2007 14:43'! +success + ^ success! ! + +!TResult methodsFor: 'as yet unclassified' stamp: 'pc 10/26/2007 14:43'! +success: anObject + success := anObject! ! + +Object subclass: #TSizedObject + instanceVariableNames: 'size' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Protocol'! + +TSizedObject subclass: #TList + instanceVariableNames: 'elemType' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Protocol'! + +!TList methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:04'! +elemType + ^ elemType ifNil: [TType stop]! ! + +!TList methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:42'! +elemType: anInteger + elemType := anInteger! ! + +TList subclass: #TSet + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Protocol'! + +TSizedObject subclass: #TMap + instanceVariableNames: 'keyType valueType' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Protocol'! + +!TMap methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:04'! +keyType + ^ keyType ifNil: [TType stop]! ! + +!TMap methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:45'! +keyType: anInteger + keyType := anInteger! ! + +!TMap methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:04'! +valueType + ^ valueType ifNil: [TType stop]! ! + +!TMap methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:45'! +valueType: anInteger + valueType := anInteger! ! + +!TSizedObject methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 20:03'! +size + ^ size ifNil: [0]! ! + +!TSizedObject methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 20:06'! +size: anInteger + size := anInteger! ! + +Object subclass: #TSocket + instanceVariableNames: 'host port stream' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Transport'! + +!TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:34'! +close + self isOpen ifTrue: [stream close]! ! + +!TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:23'! +connect + ^ (self socketStream openConnectionToHost: + (NetNameResolver addressForName: host) port: port) + timeout: 180; + binary; + yourself! ! + +!TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 20:35'! +flush + stream flush! ! + +!TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:08'! +host: aString + host := aString! ! + +!TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 20:34'! +isOpen + ^ stream isNil not + and: [stream socket isConnected] + and: [stream socket isOtherEndClosed not]! ! + +!TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:22'! +open + stream := self connect! ! + +!TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:09'! +port: anInteger + port := anInteger! ! + +!TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:17'! +read: size + | data | + [data := stream next: size. + data isEmpty ifTrue: [TTransportError signal: 'Could not read ', size asString, ' bytes']. + ^ data] + on: ConnectionClosed + do: [TTransportClosedError signal]! ! + +!TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:18'! +socketStream + ^ Smalltalk at: #FastSocketStream ifAbsent: [SocketStream] ! ! + +!TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:17'! +write: aCollection + [stream nextPutAll: aCollection] + on: ConnectionClosed + do: [TTransportClosedError signal]! ! + +Object subclass: #TStruct + instanceVariableNames: 'name' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Protocol'! + +!TStruct methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:47'! +name + ^ name! ! + +!TStruct methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:47'! +name: aString + name := aString! ! + +Object subclass: #TTransport + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift-Transport'! + +!TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:18'! +close + self subclassResponsibility! ! + +!TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:22'! +flush + self subclassResponsibility! ! + +!TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:18'! +isOpen + self subclassResponsibility! ! + +!TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:18'! +open + self subclassResponsibility! ! + +!TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:18'! +read: anInteger + self subclassResponsibility! ! + +!TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:22'! +readAll: anInteger + ^ String streamContents: [:str | + [str size < anInteger] whileTrue: + [str nextPutAll: (self read: anInteger - str size)]]! ! + +!TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:22'! +write: aString + self subclassResponsibility! ! + +Object subclass: #TType + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Thrift'! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:03'! +bool + ^ 2! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:03'! +byte + ^ 3! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/25/2007 15:55'! +codeOf: aTypeName + self typeMap do: [:each | each first = aTypeName ifTrue: [^ each second]]. + ^ nil! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:03'! +double + ^ 4! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! +i16 + ^ 6! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! +i32 + ^ 8! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! +i64 + ^ 10! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! +list + ^ 15! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! +map + ^ 13! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/25/2007 15:56'! +nameOf: aTypeCode + self typeMap do: [:each | each second = aTypeCode ifTrue: [^ each first]]. + ^ nil! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! +set + ^ 14! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:03'! +stop + ^ 0! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! +string + ^ 11! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! +struct + ^ 12! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/25/2007 15:51'! +typeMap + ^ #((bool 2) (byte 3) (double 4) (i16 6) (i32 8) (i64 10) (list 15) + (map 13) (set 15) (stop 0) (string 11) (struct 12) (void 1))! ! + +!TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:03'! +void + ^ 1! ! diff --git a/lib/ts/coding_standards.md b/lib/ts/coding_standards.md new file mode 100644 index 0000000..fa0390b --- /dev/null +++ b/lib/ts/coding_standards.md @@ -0,0 +1 @@ +Please follow [General Coding Standards](/doc/coding_standards.md) diff --git a/lib/ts/thrift.d.ts b/lib/ts/thrift.d.ts new file mode 100644 index 0000000..0ba46c9 --- /dev/null +++ b/lib/ts/thrift.d.ts @@ -0,0 +1,699 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +declare module Thrift { + /** + * Thrift JavaScript library version. + */ + var Version: string; + + /** + * Thrift IDL type string to Id mapping. + * @property {number} STOP - End of a set of fields. + * @property {number} VOID - No value (only legal for return types). + * @property {number} BOOL - True/False integer. + * @property {number} BYTE - Signed 8 bit integer. + * @property {number} I08 - Signed 8 bit integer. + * @property {number} DOUBLE - 64 bit IEEE 854 floating point. + * @property {number} I16 - Signed 16 bit integer. + * @property {number} I32 - Signed 32 bit integer. + * @property {number} I64 - Signed 64 bit integer. + * @property {number} STRING - Array of bytes representing a string of characters. + * @property {number} UTF7 - Array of bytes representing a string of UTF7 encoded characters. + * @property {number} STRUCT - A multifield type. + * @property {number} MAP - A collection type (map/associative-array/dictionary). + * @property {number} SET - A collection type (unordered and without repeated values). + * @property {number} LIST - A collection type (unordered). + * @property {number} UTF8 - Array of bytes representing a string of UTF8 encoded characters. + * @property {number} UTF16 - Array of bytes representing a string of UTF16 encoded characters. + */ + interface Type { + 'STOP': number; + 'VOID': number; + 'BOOL': number; + 'BYTE': number; + 'I08': number; + 'DOUBLE': number; + 'I16': number; + 'I32': number; + 'I64': number; + 'STRING': number; + 'UTF7': number; + 'STRUCT': number; + 'MAP': number; + 'SET': number; + 'LIST': number; + 'UTF8': number; + 'UTF16': number; + } + var Type: Type; + + /** + * Thrift RPC message type string to Id mapping. + * @property {number} CALL - RPC call sent from client to server. + * @property {number} REPLY - RPC call normal response from server to client. + * @property {number} EXCEPTION - RPC call exception response from server to client. + * @property {number} ONEWAY - Oneway RPC call from client to server with no response. + */ + interface MessageType { + 'CALL': number; + 'REPLY': number; + 'EXCEPTION': number; + 'ONEWAY': number; + } + var MessageType: MessageType; + + /** + * Utility function returning the count of an object's own properties. + * @param {object} obj - Object to test. + * @returns {number} number of object's own properties + */ + function objectLength(obj: Object): number; + + /** + * Utility function to establish prototype inheritance. + * @param {function} constructor - Contstructor function to set as derived. + * @param {function} superConstructor - Contstructor function to set as base. + * @param {string} [name] - Type name to set as name property in derived prototype. + */ + function inherits(constructor: Function, superConstructor: Function, name?: string): void; + + /** + * TException is the base class for all Thrift exceptions types. + */ + class TException implements Error { + name: string; + message: string; + + /** + * Initializes a Thrift TException instance. + * @param {string} message - The TException message (distinct from the Error message). + */ + constructor(message: string); + + /** + * Returns the message set on the exception. + * @returns {string} exception message + */ + getMessage(): string; + } + + /** + * Thrift Application Exception type string to Id mapping. + * @property {number} UNKNOWN - Unknown/undefined. + * @property {number} UNKNOWN_METHOD - Client attempted to call a method unknown to the server. + * @property {number} INVALID_MESSAGE_TYPE - Client passed an unknown/unsupported MessageType. + * @property {number} WRONG_METHOD_NAME - Unused. + * @property {number} BAD_SEQUENCE_ID - Unused in Thrift RPC, used to flag proprietary sequence number errors. + * @property {number} MISSING_RESULT - Raised by a server processor if a handler fails to supply the required return result. + * @property {number} INTERNAL_ERROR - Something bad happened. + * @property {number} PROTOCOL_ERROR - The protocol layer failed to serialize or deserialize data. + * @property {number} INVALID_TRANSFORM - Unused. + * @property {number} INVALID_PROTOCOL - The protocol (or version) is not supported. + * @property {number} UNSUPPORTED_CLIENT_TYPE - Unused. + */ + interface TApplicationExceptionType { + 'UNKNOWN': number; + 'UNKNOWN_METHOD': number; + 'INVALID_MESSAGE_TYPE': number; + 'WRONG_METHOD_NAME': number; + 'BAD_SEQUENCE_ID': number; + 'MISSING_RESULT': number; + 'INTERNAL_ERROR': number; + 'PROTOCOL_ERROR': number; + 'INVALID_TRANSFORM': number; + 'INVALID_PROTOCOL': number; + 'UNSUPPORTED_CLIENT_TYPE': number; + } + var TApplicationExceptionType: TApplicationExceptionType; + + /** + * TApplicationException is the exception class used to propagate exceptions from an RPC server back to a calling client. + */ + class TApplicationException extends TException { + message: string; + code: number; + + /** + * Initializes a Thrift TApplicationException instance. + * @param {string} message - The TApplicationException message (distinct from the Error message). + * @param {Thrift.TApplicationExceptionType} [code] - The TApplicationExceptionType code. + */ + constructor(message: string, code?: number); + + /** + * Read a TApplicationException from the supplied protocol. + * @param {object} input - The input protocol to read from. + */ + read(input: Object): void; + + /** + * Write a TApplicationException to the supplied protocol. + * @param {object} output - The output protocol to write to. + */ + write(output: Object): void; + + /** + * Returns the application exception code set on the exception. + * @returns {Thrift.TApplicationExceptionType} exception code + */ + getCode(): number; + } + + /** + * The Apache Thrift Transport layer performs byte level I/O between RPC + * clients and servers. The JavaScript Transport object type uses Http[s]/XHR and is + * the sole browser based Thrift transport. Target servers must implement the http[s] + * transport (see: node.js example server). + */ + class TXHRTransport { + url: string; + wpos: number; + rpos: number; + useCORS: any; + send_buf: string; + recv_buf: string; + + /** + * If you do not specify a url then you must handle XHR operations on + * your own. This type can also be constructed using the Transport alias + * for backward compatibility. + * @param {string} [url] - The URL to connect to. + * @param {object} [options] - Options. + */ + constructor(url?: string, options?: Object); + + /** + * Gets the browser specific XmlHttpRequest Object. + * @returns {object} the browser XHR interface object + */ + getXmlHttpRequestObject(): Object; + + /** + * Sends the current XRH request if the transport was created with a URL and + * the async parameter if false. If the transport was not created with a URL + * or the async parameter is True or the URL is an empty string, the current + * send buffer is returned. + * @param {object} async - If true the current send buffer is returned. + * @param {function} callback - Optional async completion callback. + * @returns {undefined|string} Nothing or the current send buffer. + */ + flush(async: any, callback?: Function): string; + + /** + * Creates a jQuery XHR object to be used for a Thrift server call. + * @param {object} client - The Thrift Service client object generated by the IDL compiler. + * @param {object} postData - The message to send to the server. + * @param {function} args - The function to call if the request succeeds. + * @param {function} recv_method - The Thrift Service Client receive method for the call. + * @returns {object} A new jQuery XHR object. + */ + jqRequest(client: Object, postData: any, args: Function, recv_method: Function): Object; + + /** + * Sets the buffer to use when receiving server responses. + * @param {string} buf - The buffer to receive server responses. + */ + setRecvBuffer(buf: string): void; + + /** + * Returns true if the transport is open, in browser based JavaScript + * this function always returns true. + * @returns {boolean} Always True. + */ + isOpen(): boolean; + + /** + * Opens the transport connection, in browser based JavaScript + * this function is a nop. + */ + open(): void; + + /** + * Closes the transport connection, in browser based JavaScript + * this function is a nop. + */ + close(): void; + + /** + * Returns the specified number of characters from the response + * buffer. + * @param {number} len - The number of characters to return. + * @returns {string} Characters sent by the server. + */ + read(len: number): string; + + /** + * Returns the entire response buffer. + * @returns {string} Characters sent by the server. + */ + readAll(): string; + + /** + * Sets the send buffer to buf. + * @param {string} buf - The buffer to send. + */ + write(buf: string): void; + + /** + * Returns the send buffer. + * @returns {string} The send buffer. + */ + getSendBuffer(): string; + } + + /** + * Old alias of the TXHRTransport for backwards compatibility. + */ + class Transport extends TXHRTransport { } + + /** + * The Apache Thrift Transport layer performs byte level I/O + * between RPC clients and servers. The JavaScript TWebSocketTransport object + * uses the WebSocket protocol. Target servers must implement WebSocket. + */ + class TWebSocketTransport { + url: string; //Where to connect + socket: any; //The web socket + callbacks: Function[]; //Pending callbacks + send_pending: any[]; //Buffers/Callback pairs waiting to be sent + send_buf: string; //Outbound data, immutable until sent + recv_buf: string; //Inbound data + rb_wpos: number; //Network write position in receive buffer + rb_rpos: number; //Client read position in receive buffer + + /** + * Constructor Function for the WebSocket transport. + * @param {string } [url] - The URL to connect to. + */ + constructor(url: string); + + __reset(url: string): void; + + /** + * Sends the current WS request and registers callback. The async + * parameter is ignored (WS flush is always async) and the callback + * function parameter is required. + * @param {object} async - Ignored. + * @param {function} callback - The client completion callback. + * @returns {undefined|string} Nothing (undefined) + */ + flush(async: any, callback: Function): string; + + __onOpen(): void; + + __onClose(): void; + + __onMessage(): void; + + __onError(): void; + + /** + * Sets the buffer to use when receiving server responses. + * @param {string} buf - The buffer to receive server responses. + */ + setRecvBuffer(buf: string): void; + + /** + * Returns true if the transport is open + * @returns {boolean} + */ + isOpen(): boolean; + + /** + * Opens the transport connection + */ + open(): void; + + /** + * Closes the transport connection + */ + close(): void; + + /** + * Returns the specified number of characters from the response + * buffer. + * @param {number} len - The number of characters to return. + * @returns {string} Characters sent by the server. + */ + read(len: number): string; + + /** + * Returns the entire response buffer. + * @returns {string} Characters sent by the server. + */ + readAll(): string; + + /** + * Sets the send buffer to buf. + * @param {string} buf - The buffer to send. + */ + write(buf: string): void; + + /** + * Returns the send buffer. + * @returns {string} The send buffer. + */ + getSendBuffer(): string; + } + + /** + * Apache Thrift Protocols perform serialization which enables cross + * language RPC. The Protocol type is the JavaScript browser implementation + * of the Apache Thrift TJSONProtocol. + */ + class TJSONProtocol { + transport: Object; + + /** + * Thrift IDL type Id to string mapping. + * The mapping table looks as follows: + * Thrift.Type.BOOL -> "tf": True/False integer. + * Thrift.Type.BYTE -> "i8": Signed 8 bit integer. + * Thrift.Type.I16 -> "i16": Signed 16 bit integer. + * Thrift.Type.I32 -> "i32": Signed 32 bit integer. + * Thrift.Type.I64 -> "i64": Signed 64 bit integer. + * Thrift.Type.DOUBLE -> "dbl": 64 bit IEEE 854 floating point. + * Thrift.Type.STRUCT -> "rec": A multifield type. + * Thrift.Type.STRING -> "str": Array of bytes representing a string of characters. + * Thrift.Type.MAP -> "map": A collection type (map/associative-array/dictionary). + * Thrift.Type.LIST -> "lst": A collection type (unordered). + * Thrift.Type.SET -> "set": A collection type (unordered and without repeated values). + */ + Type: { [k: number]: string }; + + /** + * Thrift IDL type string to Id mapping. + * The mapping table looks as follows: + * "tf" -> Thrift.Type.BOOL + * "i8" -> Thrift.Type.BYTE + * "i16" -> Thrift.Type.I16 + * "i32" -> Thrift.Type.I32 + * "i64" -> Thrift.Type.I64 + * "dbl" -> Thrift.Type.DOUBLE + * "rec" -> Thrift.Type.STRUCT + * "str" -> Thrift.Type.STRING + * "map" -> Thrift.Type.MAP + * "lst" -> Thrift.Type.LIST + * "set" -> Thrift.Type.SET + */ + RType: { [k: string]: number }; + + /** + * The TJSONProtocol version number. + */ + Version: number; + + /** + * Initializes a Thrift JSON protocol instance. + * @param {Thrift.Transport} transport - The transport to serialize to/from. + */ + constructor(transport: Object); + + /** + * Returns the underlying transport. + * @returns {Thrift.Transport} The underlying transport. + */ + getTransport(): Object; + + /** + * Serializes the beginning of a Thrift RPC message. + * @param {string} name - The service method to call. + * @param {Thrift.MessageType} messageType - The type of method call. + * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift). + */ + writeMessageBegin(name: string, messageType: number, seqid: number): void; + + /** + * Serializes the end of a Thrift RPC message. + */ + writeMessageEnd(): void; + + /** + * Serializes the beginning of a struct. + * @param {string} name - The name of the struct. + */ + writeStructBegin(name?: string): void; + + /** + * Serializes the end of a struct. + */ + writeStructEnd(): void; + + /** + * Serializes the beginning of a struct field. + * @param {string} name - The name of the field. + * @param {Thrift.Protocol.Type} fieldType - The data type of the field. + * @param {number} fieldId - The field's unique identifier. + */ + writeFieldBegin(name: string, fieldType: number, fieldId: number): void; + + /** + * Serializes the end of a field. + */ + writeFieldEnd(): void; + + /** + * Serializes the end of the set of fields for a struct. + */ + writeFieldStop(): void; + + /** + * Serializes the beginning of a map collection. + * @param {Thrift.Type} keyType - The data type of the key. + * @param {Thrift.Type} valType - The data type of the value. + * @param {number} [size] - The number of elements in the map (ignored). + */ + writeMapBegin(keyType: number, valType: number, size?: number): void; + + /** + * Serializes the end of a map. + */ + writeMapEnd(): void; + + /** + * Serializes the beginning of a list collection. + * @param {Thrift.Type} elemType - The data type of the elements. + * @param {number} size - The number of elements in the list. + */ + writeListBegin(elemType: number, size: number): void; + + /** + * Serializes the end of a list. + */ + writeListEnd(): void; + + /** + * Serializes the beginning of a set collection. + * @param {Thrift.Type} elemType - The data type of the elements. + * @param {number} size - The number of elements in the list. + */ + writeSetBegin(elemType: number, size: number): void; + + /** + * Serializes the end of a set. + */ + writeSetEnd(): void; + + /** Serializes a boolean */ + writeBool(value: boolean): void; + + /** Serializes a number */ + writeByte(i8: number): void; + + /** Serializes a number */ + writeI16(i16: number): void; + + /** Serializes a number */ + writeI32(i32: number): void; + + /** Serializes a number */ + writeI64(i64: number): void; + + /** Serializes a number */ + writeDouble(dbl: number): void; + + /** Serializes a string */ + writeString(str: string): void; + + /** Serializes a string */ + writeBinary(str: string): void; + + /** + @class + @name AnonReadMessageBeginReturn + @property {string} fname - The name of the service method. + @property {Thrift.MessageType} mtype - The type of message call. + @property {number} rseqid - The sequence number of the message (0 in Thrift RPC). + */ + /** + * Deserializes the beginning of a message. + * @returns {AnonReadMessageBeginReturn} + */ + readMessageBegin(): { fname: string; mtype: number; rseqid: number }; + + /** Deserializes the end of a message. */ + readMessageEnd(): void; + + /** + * Deserializes the beginning of a struct. + * @param {string} [name] - The name of the struct (ignored). + * @returns {object} - An object with an empty string fname property. + */ + readStructBegin(name?: string): { fname: string }; + + /** Deserializes the end of a struct. */ + readStructEnd(): void; + + /** + @class + @name AnonReadFieldBeginReturn + @property {string} fname - The name of the field (always ''). + @property {Thrift.Type} ftype - The data type of the field. + @property {number} fid - The unique identifier of the field. + */ + /** + * Deserializes the beginning of a field. + * @returns {AnonReadFieldBeginReturn} + */ + readFieldBegin(): { fname: string; ftype: number; fid: number }; + + /** Deserializes the end of a field. */ + readFieldEnd(): void; + + /** + @class + @name AnonReadMapBeginReturn + @property {Thrift.Type} ktype - The data type of the key. + @property {Thrift.Type} vtype - The data type of the value. + @property {number} size - The number of elements in the map. + */ + /** + * Deserializes the beginning of a map. + * @returns {AnonReadMapBeginReturn} + */ + readMapBegin(): { ktype: number; vtype: number; size: number }; + + /** Deserializes the end of a map. */ + readMapEnd(): void; + + /** + @class + @name AnonReadColBeginReturn + @property {Thrift.Type} etype - The data type of the element. + @property {number} size - The number of elements in the collection. + */ + /** + * Deserializes the beginning of a list. + * @returns {AnonReadColBeginReturn} + */ + readListBegin(): { etype: number; size: number }; + + /** Deserializes the end of a list. */ + readListEnd(): void; + + /** + * Deserializes the beginning of a set. + * @param {Thrift.Type} elemType - The data type of the elements (ignored). + * @param {number} size - The number of elements in the list (ignored). + * @returns {AnonReadColBeginReturn} + */ + readSetBegin(elemType?: number, size?: number): { etype: number; size: number }; + + /** Deserializes the end of a set. */ + readSetEnd(): void; + + /** Returns an object with a value property set to + * False unless the next number in the protocol buffer + * is 1, in which case the value property is True. */ + readBool(): Object; + + /** Returns an object with a value property set to the + next value found in the protocol buffer. */ + readByte(): Object; + + /** Returns an object with a value property set to the + next value found in the protocol buffer. */ + readI16(): Object; + + /** Returns an object with a value property set to the + next value found in the protocol buffer. */ + readI32(f?: any): Object; + + /** Returns an object with a value property set to the + next value found in the protocol buffer. */ + readI64(): Object; + + /** Returns an object with a value property set to the + next value found in the protocol buffer. */ + readDouble(): Object; + + /** Returns an object with a value property set to the + next value found in the protocol buffer. */ + readString(): Object; + + /** Returns an object with a value property set to the + next value found in the protocol buffer. */ + readBinary(): Object; + + /** + * Method to arbitrarily skip over data (not implemented). + */ + skip(type: number): void; + } + + /** + * Old alias of the TXHRTransport for backwards compatibility. + */ + class Protocol extends TJSONProtocol { } + + class MultiplexProtocol extends TJSONProtocol { + serviceName: string; + + /** + * Initializes a MutilplexProtocol Implementation as a Wrapper for Thrift.Protocol. + * @param {string} srvName + * @param {Thrift.Transport} trans + * @param {any} [strictRead] + * @param {any} [strictWrite] + */ + constructor(srvName: string, trans: Object, strictRead?: any, strictWrite?: any); + + /** + * Override writeMessageBegin method of prototype + * Serializes the beginning of a Thrift RPC message. + * @param {string} name - The service method to call. + * @param {Thrift.MessageType} messageType - The type of method call. + * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift). + */ + writeMessageBegin(name: string, type: number, seqid: number): void; + } + + class Multiplexer { + seqid: number; + + /** + * Instantiates a multiplexed client for a specific service. + * @param {String} serviceName - The transport to serialize to/from. + * @param {Thrift.ServiceClient} SCl - The Service Client Class. + * @param {Thrift.Transport} transport - Thrift.Transport instance which provides remote host:port. + */ + createClient(serviceName: string, SCl: any, transport: Object): any; + } +} diff --git a/lib/xml/Makefile.am b/lib/xml/Makefile.am new file mode 100644 index 0000000..bcad6bd --- /dev/null +++ b/lib/xml/Makefile.am @@ -0,0 +1,29 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +SUBDIRS = + +if WITH_JAVA +# Schema validation test depends on java +SUBDIRS += test +endif + +EXTRA_DIST = \ + thrift-idl.xsd \ + test diff --git a/lib/xml/Makefile.in b/lib/xml/Makefile.in new file mode 100644 index 0000000..bf36bf8 --- /dev/null +++ b/lib/xml/Makefile.in @@ -0,0 +1,811 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ + +# Schema validation test depends on java +@WITH_JAVA_TRUE@am__append_1 = test +subdir = lib/xml +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = test +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = $(am__append_1) +EXTRA_DIST = \ + thrift-idl.xsd \ + test + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/xml/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/xml/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +style: style-recursive + +style-am: style-local + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am style-am style-local tags tags-am uninstall \ + uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/xml/test/Makefile b/lib/xml/test/Makefile new file mode 100644 index 0000000..e2db8f8 --- /dev/null +++ b/lib/xml/test/Makefile @@ -0,0 +1,630 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# lib/xml/test/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/thrift +pkgincludedir = $(includedir)/thrift +pkglibdir = $(libdir)/thrift +pkglibexecdir = $(libexecdir)/thrift +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-pc-linux-gnu +host_triplet = x86_64-pc-linux-gnu +subdir = lib/xml/test +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_$(V)) +am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15 +ALLOCA = +AMTAR = $${TAR-tar} +AM_DEFAULT_VERBOSITY = 1 +ANT = /usr/bin/ant +ANT_FLAGS = +AR = ar +AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf +AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader +AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15 +AWK = gawk +BISON = bison +BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a +BOOST_CPPFLAGS = -I/usr/include +BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a +BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu +BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu +BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a +BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a +BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a +BUNDLER = /usr/bin/bundle +CABAL = /usr/bin/cabal +CABAL_CONFIGURE_FLAGS = +CARGO = /usr/bin/cargo +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 +CLASSPATH = +CPP = gcc -E +CPPFLAGS = +CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \; +CXX = g++ -std=c++11 +CXXCPP = g++ -E -std=c++11 +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -g -O2 +CYGPATH_W = echo +DART = /usr/lib/dart/bin/dart +DARTPUB = /usr/lib/dart/bin/pub +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +DLLTOOL = false +DMD = dmd +DMD_LIBEVENT_FLAGS = +DMD_OF_DIRSEP = / +DMD_OPENSSL_FLAGS = +DOTNETCORE = /usr/bin/dotnet +DOTNETCORE_VERSION = 2.0.3 +DSYMUTIL = +DUMPBIN = +D_EVENT_LIB_NAME = libthriftd-event.a +D_IMPORT_PREFIX = ${prefix}/include/d2 +D_LIB_NAME = libthriftd.a +D_SSL_LIB_NAME = libthriftd-ssl.a +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +ENABLE_COVERAGE = 2 +ERL = /usr/bin/erl +ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib +ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0 +ERLANG_LIB_DIR = /usr/lib/erlang/lib +ERLC = /usr/bin/erlc +ERLCFLAGS = +EXEEXT = +FGREP = /bin/grep -F +GCOV_CFLAGS = +GCOV_CXXFLAGS = +GCOV_LDFLAGS = +GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GLIB_LIBS = -lglib-2.0 +GO = /usr/bin/go +GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0 +GREP = /bin/grep +HAVE_CXX11 = 1 +HAXE = /usr/bin/haxe +HAXE_VERSION = 3.2.1 +INSTALL = /usr/bin/install -c +INSTALLDIRS = vendor +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +JAVA_PREFIX = /usr/local/lib +LD = /usr/bin/ld -m elf_x86_64 +LDFLAGS = +LEX = flex +LEXLIB = -lfl +LEX_OUTPUT_ROOT = lex.yy +LIBEVENT_CPPFLAGS = +LIBEVENT_LDFLAGS = +LIBEVENT_LIBS = -levent +LIBOBJS = +LIBS = -lrt -lpthread +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LIPO = +LN_S = ln -s +LTLIBOBJS = +LT_SYS_LIBRARY_PATH = +LUA = /usr/bin/lua5.3 +LUA_EXEC_PREFIX = ${exec_prefix} +LUA_INCLUDE = -I/usr/include/lua5.3 +LUA_LIB = -llua5.3 -ldl +LUA_PLATFORM = unknown +LUA_PREFIX = ${prefix} +LUA_SHORT_VERSION = 53 +LUA_VERSION = 5.3 +MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo +MANIFEST_TOOL = : +MAYBE_CPP = cpp +MAYBE_CSHARP = csharp +MAYBE_C_GLIB = c_glib +MAYBE_D = +MAYBE_DART = dart +MAYBE_DOTNETCORE = netcore +MAYBE_ERLANG = erl +MAYBE_GO = go +MAYBE_HASKELL = hs +MAYBE_JAVA = java +MAYBE_LUA = lua +MAYBE_NODEJS = nodejs +MAYBE_PERL = perl +MAYBE_PHP = php +MAYBE_PY3 = py3 +MAYBE_PYTHON = py +MAYBE_RS = rs +MAYBE_RUBY = rb +MCS = /usr/bin/mcs +MKDIR_P = /bin/mkdir -p +MONO_CFLAGS = +MONO_LIBS = +NM = /usr/bin/nm -B +NMEDIT = +NODEJS = /usr/bin/nodejs +NPM = /usr/bin/npm +OBJDUMP = objdump +OBJEXT = o +OPENSSL_INCLUDES = +OPENSSL_LDFLAGS = +OPENSSL_LIBS = -lssl -lcrypto +OTOOL = +OTOOL64 = +PACKAGE = thrift +PACKAGE_BUGREPORT = +PACKAGE_NAME = thrift +PACKAGE_STRING = thrift 0.11.0 +PACKAGE_TARNAME = thrift +PACKAGE_URL = +PACKAGE_VERSION = 0.11.0 +PATH_SEPARATOR = : +PERL = /usr/bin/perl +PERL_PREFIX = /usr/local +PHP = /usr/bin/php +PHPUNIT = /usr/bin/phpunit +PHP_CONFIG = /usr/bin/php-config +PHP_CONFIG_PREFIX = /etc/php.d +PHP_PREFIX = /usr/lib/php +PKG_CONFIG = /usr/bin/pkg-config +PKG_CONFIG_LIBDIR = +PKG_CONFIG_PATH = +PYTHON = /usr/bin/python +PYTHON3 = /usr/bin/python3 +PYTHON_EXEC_PREFIX = ${exec_prefix} +PYTHON_PLATFORM = linux2 +PYTHON_PREFIX = ${prefix} +PYTHON_VERSION = 2.7 +PY_PREFIX = /usr +QT5_CFLAGS = +QT5_LIBS = +QT5_MOC = +QT_CFLAGS = +QT_LIBS = +QT_MOC = +RANLIB = ranlib +REBAR = /usr/bin/rebar +RUBY = /usr/bin/ruby +RUBY_PREFIX = +RUNHASKELL = /usr/bin/runhaskell +RUSTC = /usr/bin/rustc +SED = /bin/sed +SET_MAKE = +SHELL = /bin/bash +STRIP = strip +THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift +TRIAL = /usr/bin/trial +VERSION = 0.11.0 +YACC = bison -y +YFLAGS = +ZLIB_CPPFLAGS = +ZLIB_LDFLAGS = +ZLIB_LIBS = -lz +abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/lib/xml/test +abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/lib/xml/test +abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift +abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift +ac_ct_AR = ar +ac_ct_CC = gcc +ac_ct_CXX = g++ +ac_ct_DUMPBIN = +am__include = include +am__leading_dot = . +am__quote = +am__tar = tar --format=ustar -chf - "$$tardir" +am__untar = tar -xf - +bindir = ${exec_prefix}/bin +build = x86_64-pc-linux-gnu +build_alias = +build_cpu = x86_64 +build_os = linux-gnu +build_vendor = pc +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +golang_version = 1.6.2 +have_prog_bison = yes +host = x86_64-pc-linux-gnu +host_alias = +host_cpu = x86_64 +host_os = linux-gnu +host_vendor = pc +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +luadir = ${prefix}/share/lua/5.3 +luaexecdir = ${exec_prefix}/lib/lua/5.3 +mandir = ${datarootdir}/man +mkdir_p = $(MKDIR_P) +oldincludedir = /usr/include +pdfdir = ${docdir} +pkgluadir = ${luadir}/thrift +pkgluaexecdir = ${luaexecdir}/thrift +pkgpyexecdir = ${pyexecdir}/thrift +pkgpythondir = ${pythondir}/thrift +prefix = /usr/local +program_transform_name = s,x,x, +psdir = ${docdir} +pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages +pythondir = ${prefix}/lib/python2.7/dist-packages +runstatedir = ${localstatedir}/run +rustc_version = rustc 1.17.0 +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +subdirs = lib/php/src/ext/thrift_protocol +sysconfdir = ${prefix}/etc +target_alias = +top_build_prefix = ../../../ +top_builddir = ../../.. +top_srcdir = ../../.. +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/xml/test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/xml/test/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +check: + $(ANT) $(ANT_FLAGS) test + +# Make sure this doesn't fail if ant is not configured. +clean-local: + ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ + $$ANT $(ANT_FLAGS) clean + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/xml/test/Makefile.am b/lib/xml/test/Makefile.am new file mode 100644 index 0000000..bb87a52 --- /dev/null +++ b/lib/xml/test/Makefile.am @@ -0,0 +1,26 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +check: + $(ANT) $(ANT_FLAGS) test + +# Make sure this doesn't fail if ant is not configured. +clean-local: + ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ + $$ANT $(ANT_FLAGS) clean diff --git a/lib/xml/test/Makefile.in b/lib/xml/test/Makefile.in new file mode 100644 index 0000000..6daeba9 --- /dev/null +++ b/lib/xml/test/Makefile.in @@ -0,0 +1,630 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/xml/test +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/xml/test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/xml/test/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +check: + $(ANT) $(ANT_FLAGS) test + +# Make sure this doesn't fail if ant is not configured. +clean-local: + ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ + $$ANT $(ANT_FLAGS) clean + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/xml/test/build.xml b/lib/xml/test/build.xml new file mode 100644 index 0000000..f0e95cf --- /dev/null +++ b/lib/xml/test/build.xml @@ -0,0 +1,112 @@ + + + + XML Schema Validation Test + + + + + + + + + + + + + + + + + + + + + Thrift compiler is missing ! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/xml/thrift-idl.xsd b/lib/xml/thrift-idl.xsd new file mode 100644 index 0000000..09dd695 --- /dev/null +++ b/lib/xml/thrift-idl.xsd @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ltmain.sh b/ltmain.sh new file mode 100644 index 0000000..147d758 --- /dev/null +++ b/ltmain.sh @@ -0,0 +1,11156 @@ +#! /bin/sh +## DO NOT EDIT - This file generated from ./build-aux/ltmain.in +## by inline-source v2014-01-03.01 + +# libtool (GNU libtool) 2.4.6 +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996-2015 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +PROGRAM=libtool +PACKAGE=libtool +VERSION="2.4.6 Debian-2.4.6-0.1" +package_revision=2.4.6 + + +## ------ ## +## Usage. ## +## ------ ## + +# Run './libtool --help' for help with using this script from the +# command line. + + +## ------------------------------- ## +## User overridable command paths. ## +## ------------------------------- ## + +# After configure completes, it has a better idea of some of the +# shell tools we need than the defaults used by the functions shared +# with bootstrap, so set those here where they can still be over- +# ridden by the user, but otherwise take precedence. + +: ${AUTOCONF="autoconf"} +: ${AUTOMAKE="automake"} + + +## -------------------------- ## +## Source external libraries. ## +## -------------------------- ## + +# Much of our low-level functionality needs to be sourced from external +# libraries, which are installed to $pkgauxdir. + +# Set a version string for this script. +scriptversion=2015-01-20.17; # UTC + +# General shell script boiler plate, and helper functions. +# Written by Gary V. Vaughan, 2004 + +# Copyright (C) 2004-2015 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# As a special exception to the GNU General Public License, if you distribute +# this file as part of a program or library that is built using GNU Libtool, +# you may include this file under the same distribution terms that you use +# for the rest of that program. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Please report bugs or propose patches to gary@gnu.org. + + +## ------ ## +## Usage. ## +## ------ ## + +# Evaluate this file near the top of your script to gain access to +# the functions and variables defined here: +# +# . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh +# +# If you need to override any of the default environment variable +# settings, do that before evaluating this file. + + +## -------------------- ## +## Shell normalisation. ## +## -------------------- ## + +# Some shells need a little help to be as Bourne compatible as possible. +# Before doing anything else, make sure all that help has been provided! + +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac +fi + +# NLS nuisances: We save the old values in case they are required later. +_G_user_locale= +_G_safe_locale= +for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test set = \"\${$_G_var+set}\"; then + save_$_G_var=\$$_G_var + $_G_var=C + export $_G_var + _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" + _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" + fi" +done + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Make sure IFS has a sensible default +sp=' ' +nl=' +' +IFS="$sp $nl" + +# There are apparently some retarded systems that use ';' as a PATH separator! +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + + +## ------------------------- ## +## Locate command utilities. ## +## ------------------------- ## + + +# func_executable_p FILE +# ---------------------- +# Check that FILE is an executable regular file. +func_executable_p () +{ + test -f "$1" && test -x "$1" +} + + +# func_path_progs PROGS_LIST CHECK_FUNC [PATH] +# -------------------------------------------- +# Search for either a program that responds to --version with output +# containing "GNU", or else returned by CHECK_FUNC otherwise, by +# trying all the directories in PATH with each of the elements of +# PROGS_LIST. +# +# CHECK_FUNC should accept the path to a candidate program, and +# set $func_check_prog_result if it truncates its output less than +# $_G_path_prog_max characters. +func_path_progs () +{ + _G_progs_list=$1 + _G_check_func=$2 + _G_PATH=${3-"$PATH"} + + _G_path_prog_max=0 + _G_path_prog_found=false + _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} + for _G_dir in $_G_PATH; do + IFS=$_G_save_IFS + test -z "$_G_dir" && _G_dir=. + for _G_prog_name in $_G_progs_list; do + for _exeext in '' .EXE; do + _G_path_prog=$_G_dir/$_G_prog_name$_exeext + func_executable_p "$_G_path_prog" || continue + case `"$_G_path_prog" --version 2>&1` in + *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; + *) $_G_check_func $_G_path_prog + func_path_progs_result=$func_check_prog_result + ;; + esac + $_G_path_prog_found && break 3 + done + done + done + IFS=$_G_save_IFS + test -z "$func_path_progs_result" && { + echo "no acceptable sed could be found in \$PATH" >&2 + exit 1 + } +} + + +# We want to be able to use the functions in this file before configure +# has figured out where the best binaries are kept, which means we have +# to search for them ourselves - except when the results are already set +# where we skip the searches. + +# Unless the user overrides by setting SED, search the path for either GNU +# sed, or the sed that truncates its output the least. +test -z "$SED" && { + _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for _G_i in 1 2 3 4 5 6 7; do + _G_sed_script=$_G_sed_script$nl$_G_sed_script + done + echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed + _G_sed_script= + + func_check_prog_sed () + { + _G_path_prog=$1 + + _G_count=0 + printf 0123456789 >conftest.in + while : + do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo '' >> conftest.nl + "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break + diff conftest.out conftest.nl >/dev/null 2>&1 || break + _G_count=`expr $_G_count + 1` + if test "$_G_count" -gt "$_G_path_prog_max"; then + # Best one so far, save it but keep looking for a better one + func_check_prog_result=$_G_path_prog + _G_path_prog_max=$_G_count + fi + # 10*(2^10) chars as input seems more than enough + test 10 -lt "$_G_count" && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out + } + + func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin + rm -f conftest.sed + SED=$func_path_progs_result +} + + +# Unless the user overrides by setting GREP, search the path for either GNU +# grep, or the grep that truncates its output the least. +test -z "$GREP" && { + func_check_prog_grep () + { + _G_path_prog=$1 + + _G_count=0 + _G_path_prog_max=0 + printf 0123456789 >conftest.in + while : + do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo 'GREP' >> conftest.nl + "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break + diff conftest.out conftest.nl >/dev/null 2>&1 || break + _G_count=`expr $_G_count + 1` + if test "$_G_count" -gt "$_G_path_prog_max"; then + # Best one so far, save it but keep looking for a better one + func_check_prog_result=$_G_path_prog + _G_path_prog_max=$_G_count + fi + # 10*(2^10) chars as input seems more than enough + test 10 -lt "$_G_count" && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out + } + + func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin + GREP=$func_path_progs_result +} + + +## ------------------------------- ## +## User overridable command paths. ## +## ------------------------------- ## + +# All uppercase variable names are used for environment variables. These +# variables can be overridden by the user before calling a script that +# uses them if a suitable command of that name is not already available +# in the command search PATH. + +: ${CP="cp -f"} +: ${ECHO="printf %s\n"} +: ${EGREP="$GREP -E"} +: ${FGREP="$GREP -F"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} + + +## -------------------- ## +## Useful sed snippets. ## +## -------------------- ## + +sed_dirname='s|/[^/]*$||' +sed_basename='s|^.*/||' + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s|\([`"$\\]\)|\\\1|g' + +# Same as above, but do not quote variable references. +sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' + +# Sed substitution that converts a w32 file name or path +# that contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Re-'\' parameter expansions in output of sed_double_quote_subst that +# were '\'-ed in input to the same. If an odd number of '\' preceded a +# '$' in input to sed_double_quote_subst, that '$' was protected from +# expansion. Since each input '\' is now two '\'s, look for any number +# of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'. +_G_bs='\\' +_G_bs2='\\\\' +_G_bs4='\\\\\\\\' +_G_dollar='\$' +sed_double_backslash="\ + s/$_G_bs4/&\\ +/g + s/^$_G_bs2$_G_dollar/$_G_bs&/ + s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g + s/\n//g" + + +## ----------------- ## +## Global variables. ## +## ----------------- ## + +# Except for the global variables explicitly listed below, the following +# functions in the '^func_' namespace, and the '^require_' namespace +# variables initialised in the 'Resource management' section, sourcing +# this file will not pollute your global namespace with anything +# else. There's no portable way to scope variables in Bourne shell +# though, so actually running these functions will sometimes place +# results into a variable named after the function, and often use +# temporary variables in the '^_G_' namespace. If you are careful to +# avoid using those namespaces casually in your sourcing script, things +# should continue to work as you expect. And, of course, you can freely +# overwrite any of the functions or variables defined here before +# calling anything to customize them. + +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +# Allow overriding, eg assuming that you follow the convention of +# putting '$debug_cmd' at the start of all your functions, you can get +# bash to show function call trace with: +# +# debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name +debug_cmd=${debug_cmd-":"} +exit_cmd=: + +# By convention, finish your script with: +# +# exit $exit_status +# +# so that you can set exit_status to non-zero if you want to indicate +# something went wrong during execution without actually bailing out at +# the point of failure. +exit_status=$EXIT_SUCCESS + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath=$0 + +# The name of this program. +progname=`$ECHO "$progpath" |$SED "$sed_basename"` + +# Make sure we have an absolute progpath for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` + progdir=`cd "$progdir" && pwd` + progpath=$progdir/$progname + ;; + *) + _G_IFS=$IFS + IFS=${PATH_SEPARATOR-:} + for progdir in $PATH; do + IFS=$_G_IFS + test -x "$progdir/$progname" && break + done + IFS=$_G_IFS + test -n "$progdir" || progdir=`pwd` + progpath=$progdir/$progname + ;; +esac + + +## ----------------- ## +## Standard options. ## +## ----------------- ## + +# The following options affect the operation of the functions defined +# below, and should be set appropriately depending on run-time para- +# meters passed on the command line. + +opt_dry_run=false +opt_quiet=false +opt_verbose=false + +# Categories 'all' and 'none' are always available. Append any others +# you will pass as the first argument to func_warning from your own +# code. +warning_categories= + +# By default, display warnings according to 'opt_warning_types'. Set +# 'warning_func' to ':' to elide all warnings, or func_fatal_error to +# treat the next displayed warning as a fatal error. +warning_func=func_warn_and_continue + +# Set to 'all' to display all warnings, 'none' to suppress all +# warnings, or a space delimited list of some subset of +# 'warning_categories' to display only the listed warnings. +opt_warning_types=all + + +## -------------------- ## +## Resource management. ## +## -------------------- ## + +# This section contains definitions for functions that each ensure a +# particular resource (a file, or a non-empty configuration variable for +# example) is available, and if appropriate to extract default values +# from pertinent package files. Call them using their associated +# 'require_*' variable to ensure that they are executed, at most, once. +# +# It's entirely deliberate that calling these functions can set +# variables that don't obey the namespace limitations obeyed by the rest +# of this file, in order that that they be as useful as possible to +# callers. + + +# require_term_colors +# ------------------- +# Allow display of bold text on terminals that support it. +require_term_colors=func_require_term_colors +func_require_term_colors () +{ + $debug_cmd + + test -t 1 && { + # COLORTERM and USE_ANSI_COLORS environment variables take + # precedence, because most terminfo databases neglect to describe + # whether color sequences are supported. + test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} + + if test 1 = "$USE_ANSI_COLORS"; then + # Standard ANSI escape sequences + tc_reset='' + tc_bold=''; tc_standout='' + tc_red=''; tc_green='' + tc_blue=''; tc_cyan='' + else + # Otherwise trust the terminfo database after all. + test -n "`tput sgr0 2>/dev/null`" && { + tc_reset=`tput sgr0` + test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` + tc_standout=$tc_bold + test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` + test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` + test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` + test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` + test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` + } + fi + } + + require_term_colors=: +} + + +## ----------------- ## +## Function library. ## +## ----------------- ## + +# This section contains a variety of useful functions to call in your +# scripts. Take note of the portable wrappers for features provided by +# some modern shells, which will fall back to slower equivalents on +# less featureful shells. + + +# func_append VAR VALUE +# --------------------- +# Append VALUE onto the existing contents of VAR. + + # We should try to minimise forks, especially on Windows where they are + # unreasonably slow, so skip the feature probes when bash or zsh are + # being used: + if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then + : ${_G_HAVE_ARITH_OP="yes"} + : ${_G_HAVE_XSI_OPS="yes"} + # The += operator was introduced in bash 3.1 + case $BASH_VERSION in + [12].* | 3.0 | 3.0*) ;; + *) + : ${_G_HAVE_PLUSEQ_OP="yes"} + ;; + esac + fi + + # _G_HAVE_PLUSEQ_OP + # Can be empty, in which case the shell is probed, "yes" if += is + # useable or anything else if it does not work. + test -z "$_G_HAVE_PLUSEQ_OP" \ + && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ + && _G_HAVE_PLUSEQ_OP=yes + +if test yes = "$_G_HAVE_PLUSEQ_OP" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_append () + { + $debug_cmd + + eval "$1+=\$2" + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_append () + { + $debug_cmd + + eval "$1=\$$1\$2" + } +fi + + +# func_append_quoted VAR VALUE +# ---------------------------- +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +if test yes = "$_G_HAVE_PLUSEQ_OP"; then + eval 'func_append_quoted () + { + $debug_cmd + + func_quote_for_eval "$2" + eval "$1+=\\ \$func_quote_for_eval_result" + }' +else + func_append_quoted () + { + $debug_cmd + + func_quote_for_eval "$2" + eval "$1=\$$1\\ \$func_quote_for_eval_result" + } +fi + + +# func_append_uniq VAR VALUE +# -------------------------- +# Append unique VALUE onto the existing contents of VAR, assuming +# entries are delimited by the first character of VALUE. For example: +# +# func_append_uniq options " --another-option option-argument" +# +# will only append to $options if " --another-option option-argument " +# is not already present somewhere in $options already (note spaces at +# each end implied by leading space in second argument). +func_append_uniq () +{ + $debug_cmd + + eval _G_current_value='`$ECHO $'$1'`' + _G_delim=`expr "$2" : '\(.\)'` + + case $_G_delim$_G_current_value$_G_delim in + *"$2$_G_delim"*) ;; + *) func_append "$@" ;; + esac +} + + +# func_arith TERM... +# ------------------ +# Set func_arith_result to the result of evaluating TERMs. + test -z "$_G_HAVE_ARITH_OP" \ + && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ + && _G_HAVE_ARITH_OP=yes + +if test yes = "$_G_HAVE_ARITH_OP"; then + eval 'func_arith () + { + $debug_cmd + + func_arith_result=$(( $* )) + }' +else + func_arith () + { + $debug_cmd + + func_arith_result=`expr "$@"` + } +fi + + +# func_basename FILE +# ------------------ +# Set func_basename_result to FILE with everything up to and including +# the last / stripped. +if test yes = "$_G_HAVE_XSI_OPS"; then + # If this shell supports suffix pattern removal, then use it to avoid + # forking. Hide the definitions single quotes in case the shell chokes + # on unsupported syntax... + _b='func_basename_result=${1##*/}' + _d='case $1 in + */*) func_dirname_result=${1%/*}$2 ;; + * ) func_dirname_result=$3 ;; + esac' + +else + # ...otherwise fall back to using sed. + _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' + _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` + if test "X$func_dirname_result" = "X$1"; then + func_dirname_result=$3 + else + func_append func_dirname_result "$2" + fi' +fi + +eval 'func_basename () +{ + $debug_cmd + + '"$_b"' +}' + + +# func_dirname FILE APPEND NONDIR_REPLACEMENT +# ------------------------------------------- +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +eval 'func_dirname () +{ + $debug_cmd + + '"$_d"' +}' + + +# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT +# -------------------------------------------------------- +# Perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# For efficiency, we do not delegate to the functions above but instead +# duplicate the functionality here. +eval 'func_dirname_and_basename () +{ + $debug_cmd + + '"$_b"' + '"$_d"' +}' + + +# func_echo ARG... +# ---------------- +# Echo program name prefixed message. +func_echo () +{ + $debug_cmd + + _G_message=$* + + func_echo_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_IFS + $ECHO "$progname: $_G_line" + done + IFS=$func_echo_IFS +} + + +# func_echo_all ARG... +# -------------------- +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + + +# func_echo_infix_1 INFIX ARG... +# ------------------------------ +# Echo program name, followed by INFIX on the first line, with any +# additional lines not showing INFIX. +func_echo_infix_1 () +{ + $debug_cmd + + $require_term_colors + + _G_infix=$1; shift + _G_indent=$_G_infix + _G_prefix="$progname: $_G_infix: " + _G_message=$* + + # Strip color escape sequences before counting printable length + for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" + do + test -n "$_G_tc" && { + _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` + _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` + } + done + _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes + + func_echo_infix_1_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_infix_1_IFS + $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 + _G_prefix=$_G_indent + done + IFS=$func_echo_infix_1_IFS +} + + +# func_error ARG... +# ----------------- +# Echo program name prefixed message to standard error. +func_error () +{ + $debug_cmd + + $require_term_colors + + func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 +} + + +# func_fatal_error ARG... +# ----------------------- +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + $debug_cmd + + func_error "$*" + exit $EXIT_FAILURE +} + + +# func_grep EXPRESSION FILENAME +# ----------------------------- +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $debug_cmd + + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_len STRING +# --------------- +# Set func_len_result to the length of STRING. STRING may not +# start with a hyphen. + test -z "$_G_HAVE_XSI_OPS" \ + && (eval 'x=a/b/c; + test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ + && _G_HAVE_XSI_OPS=yes + +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_len () + { + $debug_cmd + + func_len_result=${#1} + }' +else + func_len () + { + $debug_cmd + + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` + } +fi + + +# func_mkdir_p DIRECTORY-PATH +# --------------------------- +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + $debug_cmd + + _G_directory_path=$1 + _G_dir_list= + + if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then + + # Protect directory names starting with '-' + case $_G_directory_path in + -*) _G_directory_path=./$_G_directory_path ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$_G_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + _G_dir_list=$_G_directory_path:$_G_dir_list + + # If the last portion added has no slash in it, the list is done + case $_G_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` + done + _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` + + func_mkdir_p_IFS=$IFS; IFS=: + for _G_dir in $_G_dir_list; do + IFS=$func_mkdir_p_IFS + # mkdir can fail with a 'File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$_G_dir" 2>/dev/null || : + done + IFS=$func_mkdir_p_IFS + + # Bail out if we (or some other process) failed to create a directory. + test -d "$_G_directory_path" || \ + func_fatal_error "Failed to create '$1'" + fi +} + + +# func_mktempdir [BASENAME] +# ------------------------- +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, BASENAME is the basename for that directory. +func_mktempdir () +{ + $debug_cmd + + _G_template=${TMPDIR-/tmp}/${1-$progname} + + if test : = "$opt_dry_run"; then + # Return a directory name, but don't create it in dry-run mode + _G_tmpdir=$_G_template-$$ + else + + # If mktemp works, use that first and foremost + _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` + + if test ! -d "$_G_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + _G_tmpdir=$_G_template-${RANDOM-0}$$ + + func_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$_G_tmpdir" + umask $func_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$_G_tmpdir" || \ + func_fatal_error "cannot create temporary directory '$_G_tmpdir'" + fi + + $ECHO "$_G_tmpdir" +} + + +# func_normal_abspath PATH +# ------------------------ +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +func_normal_abspath () +{ + $debug_cmd + + # These SED scripts presuppose an absolute path with a trailing slash. + _G_pathcar='s|^/\([^/]*\).*$|\1|' + _G_pathcdr='s|^/[^/]*||' + _G_removedotparts=':dotsl + s|/\./|/|g + t dotsl + s|/\.$|/|' + _G_collapseslashes='s|/\{1,\}|/|g' + _G_finalslash='s|/*$|/|' + + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` + while :; do + # Processed it all yet? + if test / = "$func_normal_abspath_tpath"; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result"; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + + +# func_notquiet ARG... +# -------------------- +# Echo program name prefixed message only when not in quiet mode. +func_notquiet () +{ + $debug_cmd + + $opt_quiet || func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + + +# func_relative_path SRCDIR DSTDIR +# -------------------------------- +# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. +func_relative_path () +{ + $debug_cmd + + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=$func_dirname_result + if test -z "$func_relative_path_tlibdir"; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test -n "$func_stripname_result"; then + func_append func_relative_path_result "/$func_stripname_result" + fi + + # Normalisation. If bindir is libdir, return '.' else relative path. + if test -n "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + fi + + test -n "$func_relative_path_result" || func_relative_path_result=. + + : +} + + +# func_quote_for_eval ARG... +# -------------------------- +# Aesthetically quote ARGs to be evaled later. +# This function returns two values: +# i) func_quote_for_eval_result +# double-quoted, suitable for a subsequent eval +# ii) func_quote_for_eval_unquoted_result +# has all characters that are still active within double +# quotes backslashified. +func_quote_for_eval () +{ + $debug_cmd + + func_quote_for_eval_unquoted_result= + func_quote_for_eval_result= + while test 0 -lt $#; do + case $1 in + *[\\\`\"\$]*) + _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;; + *) + _G_unquoted_arg=$1 ;; + esac + if test -n "$func_quote_for_eval_unquoted_result"; then + func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg" + else + func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg" + fi + + case $_G_unquoted_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and variable expansion + # for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + _G_quoted_arg=\"$_G_unquoted_arg\" + ;; + *) + _G_quoted_arg=$_G_unquoted_arg + ;; + esac + + if test -n "$func_quote_for_eval_result"; then + func_append func_quote_for_eval_result " $_G_quoted_arg" + else + func_append func_quote_for_eval_result "$_G_quoted_arg" + fi + shift + done +} + + +# func_quote_for_expand ARG +# ------------------------- +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + $debug_cmd + + case $1 in + *[\\\`\"]*) + _G_arg=`$ECHO "$1" | $SED \ + -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;; + *) + _G_arg=$1 ;; + esac + + case $_G_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + _G_arg=\"$_G_arg\" + ;; + esac + + func_quote_for_expand_result=$_G_arg +} + + +# func_stripname PREFIX SUFFIX NAME +# --------------------------------- +# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_stripname () + { + $debug_cmd + + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary variable first. + func_stripname_result=$3 + func_stripname_result=${func_stripname_result#"$1"} + func_stripname_result=${func_stripname_result%"$2"} + }' +else + func_stripname () + { + $debug_cmd + + case $2 in + .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; + *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; + esac + } +fi + + +# func_show_eval CMD [FAIL_EXP] +# ----------------------------- +# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + $debug_cmd + + _G_cmd=$1 + _G_fail_exp=${2-':'} + + func_quote_for_expand "$_G_cmd" + eval "func_notquiet $func_quote_for_expand_result" + + $opt_dry_run || { + eval "$_G_cmd" + _G_status=$? + if test 0 -ne "$_G_status"; then + eval "(exit $_G_status); $_G_fail_exp" + fi + } +} + + +# func_show_eval_locale CMD [FAIL_EXP] +# ------------------------------------ +# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + $debug_cmd + + _G_cmd=$1 + _G_fail_exp=${2-':'} + + $opt_quiet || { + func_quote_for_expand "$_G_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + $opt_dry_run || { + eval "$_G_user_locale + $_G_cmd" + _G_status=$? + eval "$_G_safe_locale" + if test 0 -ne "$_G_status"; then + eval "(exit $_G_status); $_G_fail_exp" + fi + } +} + + +# func_tr_sh +# ---------- +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + $debug_cmd + + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_verbose ARG... +# ------------------- +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $debug_cmd + + $opt_verbose && func_echo "$*" + + : +} + + +# func_warn_and_continue ARG... +# ----------------------------- +# Echo program name prefixed warning message to standard error. +func_warn_and_continue () +{ + $debug_cmd + + $require_term_colors + + func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 +} + + +# func_warning CATEGORY ARG... +# ---------------------------- +# Echo program name prefixed warning message to standard error. Warning +# messages can be filtered according to CATEGORY, where this function +# elides messages where CATEGORY is not listed in the global variable +# 'opt_warning_types'. +func_warning () +{ + $debug_cmd + + # CATEGORY must be in the warning_categories list! + case " $warning_categories " in + *" $1 "*) ;; + *) func_internal_error "invalid warning category '$1'" ;; + esac + + _G_category=$1 + shift + + case " $opt_warning_types " in + *" $_G_category "*) $warning_func ${1+"$@"} ;; + esac +} + + +# func_sort_ver VER1 VER2 +# ----------------------- +# 'sort -V' is not generally available. +# Note this deviates from the version comparison in automake +# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a +# but this should suffice as we won't be specifying old +# version formats or redundant trailing .0 in bootstrap.conf. +# If we did want full compatibility then we should probably +# use m4_version_compare from autoconf. +func_sort_ver () +{ + $debug_cmd + + printf '%s\n%s\n' "$1" "$2" \ + | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n +} + +# func_lt_ver PREV CURR +# --------------------- +# Return true if PREV and CURR are in the correct order according to +# func_sort_ver, otherwise false. Use it like this: +# +# func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." +func_lt_ver () +{ + $debug_cmd + + test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` +} + + +# Local variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" +# time-stamp-time-zone: "UTC" +# End: +#! /bin/sh + +# Set a version string for this script. +scriptversion=2014-01-07.03; # UTC + +# A portable, pluggable option parser for Bourne shell. +# Written by Gary V. Vaughan, 2010 + +# Copyright (C) 2010-2015 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Please report bugs or propose patches to gary@gnu.org. + + +## ------ ## +## Usage. ## +## ------ ## + +# This file is a library for parsing options in your shell scripts along +# with assorted other useful supporting features that you can make use +# of too. +# +# For the simplest scripts you might need only: +# +# #!/bin/sh +# . relative/path/to/funclib.sh +# . relative/path/to/options-parser +# scriptversion=1.0 +# func_options ${1+"$@"} +# eval set dummy "$func_options_result"; shift +# ...rest of your script... +# +# In order for the '--version' option to work, you will need to have a +# suitably formatted comment like the one at the top of this file +# starting with '# Written by ' and ending with '# warranty; '. +# +# For '-h' and '--help' to work, you will also need a one line +# description of your script's purpose in a comment directly above the +# '# Written by ' line, like the one at the top of this file. +# +# The default options also support '--debug', which will turn on shell +# execution tracing (see the comment above debug_cmd below for another +# use), and '--verbose' and the func_verbose function to allow your script +# to display verbose messages only when your user has specified +# '--verbose'. +# +# After sourcing this file, you can plug processing for additional +# options by amending the variables from the 'Configuration' section +# below, and following the instructions in the 'Option parsing' +# section further down. + +## -------------- ## +## Configuration. ## +## -------------- ## + +# You should override these variables in your script after sourcing this +# file so that they reflect the customisations you have added to the +# option parser. + +# The usage line for option parsing errors and the start of '-h' and +# '--help' output messages. You can embed shell variables for delayed +# expansion at the time the message is displayed, but you will need to +# quote other shell meta-characters carefully to prevent them being +# expanded when the contents are evaled. +usage='$progpath [OPTION]...' + +# Short help message in response to '-h' and '--help'. Add to this or +# override it after sourcing this library to reflect the full set of +# options your script accepts. +usage_message="\ + --debug enable verbose shell tracing + -W, --warnings=CATEGORY + report the warnings falling in CATEGORY [all] + -v, --verbose verbosely report processing + --version print version information and exit + -h, --help print short or long help message and exit +" + +# Additional text appended to 'usage_message' in response to '--help'. +long_help_message=" +Warning categories include: + 'all' show all warnings + 'none' turn off all the warnings + 'error' warnings are treated as fatal errors" + +# Help message printed before fatal option parsing errors. +fatal_help="Try '\$progname --help' for more information." + + + +## ------------------------- ## +## Hook function management. ## +## ------------------------- ## + +# This section contains functions for adding, removing, and running hooks +# to the main code. A hook is just a named list of of function, that can +# be run in order later on. + +# func_hookable FUNC_NAME +# ----------------------- +# Declare that FUNC_NAME will run hooks added with +# 'func_add_hook FUNC_NAME ...'. +func_hookable () +{ + $debug_cmd + + func_append hookable_fns " $1" +} + + +# func_add_hook FUNC_NAME HOOK_FUNC +# --------------------------------- +# Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must +# first have been declared "hookable" by a call to 'func_hookable'. +func_add_hook () +{ + $debug_cmd + + case " $hookable_fns " in + *" $1 "*) ;; + *) func_fatal_error "'$1' does not accept hook functions." ;; + esac + + eval func_append ${1}_hooks '" $2"' +} + + +# func_remove_hook FUNC_NAME HOOK_FUNC +# ------------------------------------ +# Remove HOOK_FUNC from the list of functions called by FUNC_NAME. +func_remove_hook () +{ + $debug_cmd + + eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' +} + + +# func_run_hooks FUNC_NAME [ARG]... +# --------------------------------- +# Run all hook functions registered to FUNC_NAME. +# It is assumed that the list of hook functions contains nothing more +# than a whitespace-delimited list of legal shell function names, and +# no effort is wasted trying to catch shell meta-characters or preserve +# whitespace. +func_run_hooks () +{ + $debug_cmd + + case " $hookable_fns " in + *" $1 "*) ;; + *) func_fatal_error "'$1' does not support hook funcions.n" ;; + esac + + eval _G_hook_fns=\$$1_hooks; shift + + for _G_hook in $_G_hook_fns; do + eval $_G_hook '"$@"' + + # store returned options list back into positional + # parameters for next 'cmd' execution. + eval _G_hook_result=\$${_G_hook}_result + eval set dummy "$_G_hook_result"; shift + done + + func_quote_for_eval ${1+"$@"} + func_run_hooks_result=$func_quote_for_eval_result +} + + + +## --------------- ## +## Option parsing. ## +## --------------- ## + +# In order to add your own option parsing hooks, you must accept the +# full positional parameter list in your hook function, remove any +# options that you action, and then pass back the remaining unprocessed +# options in '_result', escaped suitably for +# 'eval'. Like this: +# +# my_options_prep () +# { +# $debug_cmd +# +# # Extend the existing usage message. +# usage_message=$usage_message' +# -s, --silent don'\''t print informational messages +# ' +# +# func_quote_for_eval ${1+"$@"} +# my_options_prep_result=$func_quote_for_eval_result +# } +# func_add_hook func_options_prep my_options_prep +# +# +# my_silent_option () +# { +# $debug_cmd +# +# # Note that for efficiency, we parse as many options as we can +# # recognise in a loop before passing the remainder back to the +# # caller on the first unrecognised argument we encounter. +# while test $# -gt 0; do +# opt=$1; shift +# case $opt in +# --silent|-s) opt_silent=: ;; +# # Separate non-argument short options: +# -s*) func_split_short_opt "$_G_opt" +# set dummy "$func_split_short_opt_name" \ +# "-$func_split_short_opt_arg" ${1+"$@"} +# shift +# ;; +# *) set dummy "$_G_opt" "$*"; shift; break ;; +# esac +# done +# +# func_quote_for_eval ${1+"$@"} +# my_silent_option_result=$func_quote_for_eval_result +# } +# func_add_hook func_parse_options my_silent_option +# +# +# my_option_validation () +# { +# $debug_cmd +# +# $opt_silent && $opt_verbose && func_fatal_help "\ +# '--silent' and '--verbose' options are mutually exclusive." +# +# func_quote_for_eval ${1+"$@"} +# my_option_validation_result=$func_quote_for_eval_result +# } +# func_add_hook func_validate_options my_option_validation +# +# You'll alse need to manually amend $usage_message to reflect the extra +# options you parse. It's preferable to append if you can, so that +# multiple option parsing hooks can be added safely. + + +# func_options [ARG]... +# --------------------- +# All the functions called inside func_options are hookable. See the +# individual implementations for details. +func_hookable func_options +func_options () +{ + $debug_cmd + + func_options_prep ${1+"$@"} + eval func_parse_options \ + ${func_options_prep_result+"$func_options_prep_result"} + eval func_validate_options \ + ${func_parse_options_result+"$func_parse_options_result"} + + eval func_run_hooks func_options \ + ${func_validate_options_result+"$func_validate_options_result"} + + # save modified positional parameters for caller + func_options_result=$func_run_hooks_result +} + + +# func_options_prep [ARG]... +# -------------------------- +# All initialisations required before starting the option parse loop. +# Note that when calling hook functions, we pass through the list of +# positional parameters. If a hook function modifies that list, and +# needs to propogate that back to rest of this script, then the complete +# modified list must be put in 'func_run_hooks_result' before +# returning. +func_hookable func_options_prep +func_options_prep () +{ + $debug_cmd + + # Option defaults: + opt_verbose=false + opt_warning_types= + + func_run_hooks func_options_prep ${1+"$@"} + + # save modified positional parameters for caller + func_options_prep_result=$func_run_hooks_result +} + + +# func_parse_options [ARG]... +# --------------------------- +# The main option parsing loop. +func_hookable func_parse_options +func_parse_options () +{ + $debug_cmd + + func_parse_options_result= + + # this just eases exit handling + while test $# -gt 0; do + # Defer to hook functions for initial option parsing, so they + # get priority in the event of reusing an option name. + func_run_hooks func_parse_options ${1+"$@"} + + # Adjust func_parse_options positional parameters to match + eval set dummy "$func_run_hooks_result"; shift + + # Break out of the loop if we already parsed every option. + test $# -gt 0 || break + + _G_opt=$1 + shift + case $_G_opt in + --debug|-x) debug_cmd='set -x' + func_echo "enabling shell trace mode" + $debug_cmd + ;; + + --no-warnings|--no-warning|--no-warn) + set dummy --warnings none ${1+"$@"} + shift + ;; + + --warnings|--warning|-W) + test $# = 0 && func_missing_arg $_G_opt && break + case " $warning_categories $1" in + *" $1 "*) + # trailing space prevents matching last $1 above + func_append_uniq opt_warning_types " $1" + ;; + *all) + opt_warning_types=$warning_categories + ;; + *none) + opt_warning_types=none + warning_func=: + ;; + *error) + opt_warning_types=$warning_categories + warning_func=func_fatal_error + ;; + *) + func_fatal_error \ + "unsupported warning category: '$1'" + ;; + esac + shift + ;; + + --verbose|-v) opt_verbose=: ;; + --version) func_version ;; + -\?|-h) func_usage ;; + --help) func_help ;; + + # Separate optargs to long options (plugins may need this): + --*=*) func_split_equals "$_G_opt" + set dummy "$func_split_equals_lhs" \ + "$func_split_equals_rhs" ${1+"$@"} + shift + ;; + + # Separate optargs to short options: + -W*) + func_split_short_opt "$_G_opt" + set dummy "$func_split_short_opt_name" \ + "$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-v*|-x*) + func_split_short_opt "$_G_opt" + set dummy "$func_split_short_opt_name" \ + "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) break ;; + -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; + *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; + esac + done + + # save modified positional parameters for caller + func_quote_for_eval ${1+"$@"} + func_parse_options_result=$func_quote_for_eval_result +} + + +# func_validate_options [ARG]... +# ------------------------------ +# Perform any sanity checks on option settings and/or unconsumed +# arguments. +func_hookable func_validate_options +func_validate_options () +{ + $debug_cmd + + # Display all warnings if -W was not given. + test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" + + func_run_hooks func_validate_options ${1+"$@"} + + # Bail if the options were screwed! + $exit_cmd $EXIT_FAILURE + + # save modified positional parameters for caller + func_validate_options_result=$func_run_hooks_result +} + + + +## ----------------- ## +## Helper functions. ## +## ----------------- ## + +# This section contains the helper functions used by the rest of the +# hookable option parser framework in ascii-betical order. + + +# func_fatal_help ARG... +# ---------------------- +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + $debug_cmd + + eval \$ECHO \""Usage: $usage"\" + eval \$ECHO \""$fatal_help"\" + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + + +# func_help +# --------- +# Echo long help message to standard output and exit. +func_help () +{ + $debug_cmd + + func_usage_message + $ECHO "$long_help_message" + exit 0 +} + + +# func_missing_arg ARGNAME +# ------------------------ +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $debug_cmd + + func_error "Missing argument for '$1'." + exit_cmd=exit +} + + +# func_split_equals STRING +# ------------------------ +# Set func_split_equals_lhs and func_split_equals_rhs shell variables after +# splitting STRING at the '=' sign. +test -z "$_G_HAVE_XSI_OPS" \ + && (eval 'x=a/b/c; + test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ + && _G_HAVE_XSI_OPS=yes + +if test yes = "$_G_HAVE_XSI_OPS" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_split_equals () + { + $debug_cmd + + func_split_equals_lhs=${1%%=*} + func_split_equals_rhs=${1#*=} + test "x$func_split_equals_lhs" = "x$1" \ + && func_split_equals_rhs= + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_split_equals () + { + $debug_cmd + + func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` + func_split_equals_rhs= + test "x$func_split_equals_lhs" = "x$1" \ + || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` + } +fi #func_split_equals + + +# func_split_short_opt SHORTOPT +# ----------------------------- +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +if test yes = "$_G_HAVE_XSI_OPS" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_split_short_opt () + { + $debug_cmd + + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"} + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_split_short_opt () + { + $debug_cmd + + func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'` + func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` + } +fi #func_split_short_opt + + +# func_usage +# ---------- +# Echo short help message to standard output and exit. +func_usage () +{ + $debug_cmd + + func_usage_message + $ECHO "Run '$progname --help |${PAGER-more}' for full usage" + exit 0 +} + + +# func_usage_message +# ------------------ +# Echo short help message to standard output. +func_usage_message () +{ + $debug_cmd + + eval \$ECHO \""Usage: $usage"\" + echo + $SED -n 's|^# || + /^Written by/{ + x;p;x + } + h + /^Written by/q' < "$progpath" + echo + eval \$ECHO \""$usage_message"\" +} + + +# func_version +# ------------ +# Echo version message to standard output and exit. +func_version () +{ + $debug_cmd + + printf '%s\n' "$progname $scriptversion" + $SED -n ' + /(C)/!b go + :more + /\./!{ + N + s|\n# | | + b more + } + :go + /^# Written by /,/# warranty; / { + s|^# || + s|^# *$|| + s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| + p + } + /^# Written by / { + s|^# || + p + } + /^warranty; /q' < "$progpath" + + exit $? +} + + +# Local variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" +# time-stamp-time-zone: "UTC" +# End: + +# Set a version string. +scriptversion='(GNU libtool) 2.4.6' + + +# func_echo ARG... +# ---------------- +# Libtool also displays the current mode in messages, so override +# funclib.sh func_echo with this custom definition. +func_echo () +{ + $debug_cmd + + _G_message=$* + + func_echo_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_IFS + $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" + done + IFS=$func_echo_IFS +} + + +# func_warning ARG... +# ------------------- +# Libtool warnings are not categorized, so override funclib.sh +# func_warning with this simpler definition. +func_warning () +{ + $debug_cmd + + $warning_func ${1+"$@"} +} + + +## ---------------- ## +## Options parsing. ## +## ---------------- ## + +# Hook in the functions to make sure our own options are parsed during +# the option parsing loop. + +usage='$progpath [OPTION]... [MODE-ARG]...' + +# Short help message in response to '-h'. +usage_message="Options: + --config show all configuration variables + --debug enable verbose shell tracing + -n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --mode=MODE use operation mode MODE + --no-warnings equivalent to '-Wnone' + --preserve-dup-deps don't remove duplicate dependency libraries + --quiet, --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + -v, --verbose print more informational messages than default + --version print version information + -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] + -h, --help, --help-all print short, long, or detailed help message +" + +# Additional text appended to 'usage_message' in response to '--help'. +func_help () +{ + $debug_cmd + + func_usage_message + $ECHO "$long_help_message + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. When passed as first option, +'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. +Try '$progname --help --mode=MODE' for a more detailed description of MODE. + +When reporting a bug, please describe a test case to reproduce it and +include the following information: + + host-triplet: $host + shell: $SHELL + compiler: $LTCC + compiler flags: $LTCFLAGS + linker: $LD (gnu? $with_gnu_ld) + version: $progname (GNU libtool) 2.4.6 + automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` + autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` + +Report bugs to . +GNU libtool home page: . +General help using GNU software: ." + exit 0 +} + + +# func_lo2o OBJECT-NAME +# --------------------- +# Transform OBJECT-NAME from a '.lo' suffix to the platform specific +# object suffix. + +lo2o=s/\\.lo\$/.$objext/ +o2lo=s/\\.$objext\$/.lo/ + +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_lo2o () + { + case $1 in + *.lo) func_lo2o_result=${1%.lo}.$objext ;; + * ) func_lo2o_result=$1 ;; + esac + }' + + # func_xform LIBOBJ-OR-SOURCE + # --------------------------- + # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) + # suffix to a '.lo' libtool-object suffix. + eval 'func_xform () + { + func_xform_result=${1%.*}.lo + }' +else + # ...otherwise fall back to using sed. + func_lo2o () + { + func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` + } + + func_xform () + { + func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` + } +fi + + +# func_fatal_configuration ARG... +# ------------------------------- +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func__fatal_error ${1+"$@"} \ + "See the $PACKAGE documentation for more information." \ + "Fatal configuration error." +} + + +# func_config +# ----------- +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + + +# func_features +# ------------- +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test yes = "$build_libtool_libs"; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test yes = "$build_old_libs"; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + + +# func_enable_tag TAGNAME +# ----------------------- +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname=$1 + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf=/$re_begincf/,/$re_endcf/p + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + + +# func_check_version_match +# ------------------------ +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +# libtool_options_prep [ARG]... +# ----------------------------- +# Preparation for options parsed by libtool. +libtool_options_prep () +{ + $debug_mode + + # Option defaults: + opt_config=false + opt_dlopen= + opt_dry_run=false + opt_help=false + opt_mode= + opt_preserve_dup_deps=false + opt_quiet=false + + nonopt= + preserve_args= + + # Shorthand for --mode=foo, only valid as the first argument + case $1 in + clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; + compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; + execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; + finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; + install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; + link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; + uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; + esac + + # Pass back the list of options. + func_quote_for_eval ${1+"$@"} + libtool_options_prep_result=$func_quote_for_eval_result +} +func_add_hook func_options_prep libtool_options_prep + + +# libtool_parse_options [ARG]... +# --------------------------------- +# Provide handling for libtool specific options. +libtool_parse_options () +{ + $debug_cmd + + # Perform our own loop to consume as many options as possible in + # each iteration. + while test $# -gt 0; do + _G_opt=$1 + shift + case $_G_opt in + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + + --config) func_config ;; + + --dlopen|-dlopen) + opt_dlopen="${opt_dlopen+$opt_dlopen +}$1" + shift + ;; + + --preserve-dup-deps) + opt_preserve_dup_deps=: ;; + + --features) func_features ;; + + --finish) set dummy --mode finish ${1+"$@"}; shift ;; + + --help) opt_help=: ;; + + --help-all) opt_help=': help-all' ;; + + --mode) test $# = 0 && func_missing_arg $_G_opt && break + opt_mode=$1 + case $1 in + # Valid mode arguments: + clean|compile|execute|finish|install|link|relink|uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $_G_opt" + exit_cmd=exit + break + ;; + esac + shift + ;; + + --no-silent|--no-quiet) + opt_quiet=false + func_append preserve_args " $_G_opt" + ;; + + --no-warnings|--no-warning|--no-warn) + opt_warning=false + func_append preserve_args " $_G_opt" + ;; + + --no-verbose) + opt_verbose=false + func_append preserve_args " $_G_opt" + ;; + + --silent|--quiet) + opt_quiet=: + opt_verbose=false + func_append preserve_args " $_G_opt" + ;; + + --tag) test $# = 0 && func_missing_arg $_G_opt && break + opt_tag=$1 + func_append preserve_args " $_G_opt $1" + func_enable_tag "$1" + shift + ;; + + --verbose|-v) opt_quiet=false + opt_verbose=: + func_append preserve_args " $_G_opt" + ;; + + # An option not handled by this hook function: + *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; + esac + done + + + # save modified positional parameters for caller + func_quote_for_eval ${1+"$@"} + libtool_parse_options_result=$func_quote_for_eval_result +} +func_add_hook func_parse_options libtool_parse_options + + + +# libtool_validate_options [ARG]... +# --------------------------------- +# Perform any sanity checks on option settings and/or unconsumed +# arguments. +libtool_validate_options () +{ + # save first non-option argument + if test 0 -lt $#; then + nonopt=$1 + shift + fi + + # preserve --debug + test : = "$debug_cmd" || func_append preserve_args " --debug" + + case $host in + # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 + # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 + *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + test yes != "$build_libtool_libs" \ + && test yes != "$build_old_libs" \ + && func_fatal_configuration "not configured to build any kind of library" + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test execute != "$opt_mode"; then + func_error "unrecognized option '-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help=$help + help="Try '$progname --help --mode=$opt_mode' for more information." + } + + # Pass back the unparsed argument list + func_quote_for_eval ${1+"$@"} + libtool_validate_options_result=$func_quote_for_eval_result +} +func_add_hook func_validate_options libtool_validate_options + + +# Process options as early as possible so that --help and --version +# can return quickly. +func_options ${1+"$@"} +eval set dummy "$func_options_result"; shift + + + +## ----------- ## +## Main. ## +## ----------- ## + +magic='%%%MAGIC variable%%%' +magic_exe='%%%MAGIC EXE variable%%%' + +# Global variables. +extracted_archives= +extracted_serial=0 + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# func_generated_by_libtool +# True iff stdin has been generated by Libtool. This function is only +# a basic sanity check; it will hardly flush out determined imposters. +func_generated_by_libtool_p () +{ + $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_p file +# True iff FILE is a libtool '.la' library or '.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool '.la' library or '.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if 'file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case $lalib_p_line in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test yes = "$lalib_p" +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + test -f "$1" && + $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $debug_cmd + + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$sp$nl + eval cmd=\"$cmd\" + IFS=$save_ifs + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# 'FILE.' does not work on cygwin managed mounts. +func_source () +{ + $debug_cmd + + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case $lt_sysroot:$1 in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result='='$func_stripname_result + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$1 + ;; + esac +} + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $debug_cmd + + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with '--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=$1 + if test yes = "$build_libtool_libs"; then + write_lobj=\'$2\' + else + write_lobj=none + fi + + if test yes = "$build_old_libs"; then + write_oldobj=\'$3\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T </dev/null` + if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $debug_cmd + + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result= + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result"; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $debug_cmd + + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $debug_cmd + + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $debug_cmd + + if test -z "$2" && test -n "$1"; then + func_error "Could not determine host file name corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result=$1 + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $debug_cmd + + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " '$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result=$3 + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $debug_cmd + + case $4 in + $1 ) func_to_host_path_result=$3$func_to_host_path_result + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via '$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $debug_cmd + + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $debug_cmd + + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result=$1 +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result=$func_convert_core_msys_to_w32_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result=$func_convert_core_file_wine_to_w32_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result=$func_cygpath_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result=$func_cygpath_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via '$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# Path separators are also converted from $build format to $host format. If +# ARG begins or ends with a path separator character, it is preserved (but +# converted to $host format) on output. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $debug_cmd + + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd=func_convert_path_$func_stripname_result + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $debug_cmd + + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result=$1 +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # Remove leading and trailing path separator characters from ARG. MSYS + # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; + # and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result=$func_convert_core_msys_to_w32_result + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result=$func_convert_core_path_wine_to_w32_result + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result=$func_cygpath_result + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result=$func_cygpath_result + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_dll_def_p FILE +# True iff FILE is a Windows DLL '.def' file. +# Keep in sync with _LT_DLL_DEF_P in libtool.m4 +func_dll_def_p () +{ + $debug_cmd + + func_dll_def_p_tmp=`$SED -n \ + -e 's/^[ ]*//' \ + -e '/^\(;.*\)*$/d' \ + -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ + -e q \ + "$1"` + test DEF = "$func_dll_def_p_tmp" +} + + +# func_mode_compile arg... +func_mode_compile () +{ + $debug_cmd + + # Get the compilation command and the source file. + base_compile= + srcfile=$nonopt # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg=$arg + arg_mode=normal + ;; + + target ) + libobj=$arg + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify '-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append later " $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs=$IFS; IFS=, + for arg in $args; do + IFS=$save_ifs + func_append_quoted lastarg "$arg" + done + IFS=$save_ifs + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append base_compile " $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg=$srcfile + srcfile=$arg + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with '-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj=$func_basename_result + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from '$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test yes = "$build_libtool_libs" \ + || func_fatal_configuration "cannot build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name '$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname=$func_basename_result + xdir=$func_dirname_result + lobj=$xdir$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test yes = "$build_old_libs"; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test no = "$compiler_c_o"; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext + lockfile=$output_obj.lock + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test yes = "$need_locks"; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test warn = "$need_locks"; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support '-c' and '-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test yes = "$build_libtool_libs"; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test no != "$pic_mode"; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test warn = "$need_locks" && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support '-c' and '-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test yes = "$suppress_opt"; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test yes = "$build_old_libs"; then + if test yes != "$pic_mode"; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test yes = "$compiler_c_o"; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test warn = "$need_locks" && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support '-c' and '-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test no != "$need_locks"; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test compile = "$opt_mode" && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only + -shared do not build a '.o' file suitable for static linking + -static only build a '.o' file suitable for static linking + -Wc,FLAG pass FLAG directly to the compiler + +COMPILE-COMMAND is a command to be used in creating a 'standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix '.c' with the +library object suffix, '.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to '-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the '--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the 'install' or 'cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE use a list of object files found in FILE to specify objects + -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +All other options (arguments beginning with '-') are ignored. + +Every other argument is treated as a filename. Files ending in '.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in '.la', then a libtool library is created, +only library objects ('.lo' files) may be specified, and '-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created +using 'ar' and 'ranlib', or on Windows using 'lib'. + +If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode '$opt_mode'" + ;; + esac + + echo + $ECHO "Try '$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test : = "$opt_help"; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | $SED -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + $SED '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $debug_cmd + + # The first argument is the command name. + cmd=$nonopt + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "'$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "'$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "'$file' was not linked with '-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir=$func_dirname_result + + if test -f "$dir/$objdir/$dlname"; then + func_append dir "/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir=$func_dirname_result + ;; + + *) + func_warning "'-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir=$absdir + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic=$magic + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file=$progdir/$program + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file=$progdir/$program + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_append_quoted args "$file" + done + + if $opt_dry_run; then + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + echo "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + else + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd=\$cmd$args + fi +} + +test execute = "$opt_mode" && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $debug_cmd + + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "'$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument '$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and '=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_quiet && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the '-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the '$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the '$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the '$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'" + fi + echo + + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test finish = "$opt_mode" && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $debug_cmd + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac + then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=false + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=: ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test X-m = "X$prev" && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_prog " $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the '$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=: + if $isdir; then + destdir=$dest + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir=$func_dirname_result + destname=$func_basename_result + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "'$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "'$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic=$magic + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "'$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir=$func_dirname_result + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking '$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname=$1 + shift + + srcname=$realname + test -n "$relink_command" && srcname=${realname}T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme=$stripme + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme= + ;; + esac + ;; + os2*) + case $realname in + *_dll.a) + tstripme= + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try 'ln -sf' first, because the 'ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib=$destdir/$realname + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name=$func_basename_result + instname=$dir/${name}i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && func_append staticlibs " $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile=$destdir/$destname + else + func_basename "$file" + destfile=$func_basename_result + destfile=$destdir/$destfile + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest=$destfile + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to '$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test yes = "$build_old_libs"; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile=$destdir/$destname + else + func_basename "$file" + destfile=$func_basename_result + destfile=$destdir/$destfile + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext= + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=.exe + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script '$wrapper'" + + finalize=: + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'` + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "'$lib' has not been installed in '$libdir'" + finalize=false + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test no = "$fast_install" && test -n "$relink_command"; then + $opt_dry_run || { + if $finalize; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file=$func_basename_result + outputname=$tmpdir/$file + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_quiet || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink '$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file=$outputname + else + func_warning "cannot relink '$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name=$func_basename_result + + # Set up the ranlib parameters. + oldlib=$destdir/$name + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run '$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test install = "$opt_mode" && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $debug_cmd + + my_outputname=$1 + my_originator=$2 + my_pic_p=${3-false} + my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms=${my_outputname}S.c + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist=$output_objdir/$my_outputname.nm + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) + +/* External symbol declarations for the compiler. */\ +" + + if test yes = "$dlself"; then + func_verbose "generating symbol list for '$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from '$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols=$output_objdir/$outputname.exp + $opt_dry_run || { + $RM $export_symbols + eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from '$dlprefile'" + func_basename "$dlprefile" + name=$func_basename_result + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename= + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname"; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename=$func_basename_result + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename"; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + func_show_eval '$RM "${nlist}I"' + if test -n "$global_symbol_to_import"; then + eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[];\ +" + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ +static void lt_syminit(void) +{ + LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; + for (; symbol->name; ++symbol) + {" + $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" + echo >> "$output_objdir/$my_dlsyms" "\ + } +}" + fi + echo >> "$output_objdir/$my_dlsyms" "\ +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{ {\"$my_originator\", (void *) 0}," + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ + {\"@INIT@\", (void *) <_syminit}," + fi + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + $my_pic_p && pic_flag_for_symtable=" $pic_flag" + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append symtab_cflags " $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' + + # Transform the symbol file into the correct name. + symfileobj=$output_objdir/${my_outputname}S.$objext + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for '$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $debug_cmd + + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $debug_cmd + + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $debug_cmd + + win32_libid_type=unknown + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + case $nm_interface in + "MS dumpbin") + if func_cygming_ms_implib_p "$1" || + func_cygming_gnu_implib_p "$1" + then + win32_nmres=import + else + win32_nmres= + fi + ;; + *) + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s|.*|import| + p + q + } + }'` + ;; + esac + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + +# func_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $debug_cmd + + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $debug_cmd + + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive that possess that section. Heuristic: eliminate + # all those that have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $debug_cmd + + if func_cygming_gnu_implib_p "$1"; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1"; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result= + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $debug_cmd + + f_ex_an_ar_dir=$1; shift + f_ex_an_ar_oldlib=$1 + if test yes = "$lock_old_archive_extraction"; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test yes = "$lock_old_archive_extraction"; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $debug_cmd + + my_gentop=$1; shift + my_oldlibs=${1+"$@"} + my_oldobjs= + my_xlib= + my_xabs= + my_xdir= + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib=$func_basename_result + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir=$my_gentop/$my_xlib_u + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + func_basename "$darwin_archive" + darwin_base_archive=$func_basename_result + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches; do + func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch" + $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive" + cd "unfat-$$/$darwin_base_archive-$darwin_arch" + func_extract_an_archive "`pwd`" "$darwin_base_archive" + cd "$darwin_curdir" + $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` + done + + func_extract_archives_result=$my_oldobjs +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory where it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ that is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options that match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test yes = "$fast_install"; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + \$ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${1+\"\$@\"} + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} + + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) + +/* declarations of non-ANSI functions */ +#if defined __MINGW32__ +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined __CYGWIN__ +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined other_platform || defined ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined _MSC_VER +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +#elif defined __MINGW32__ +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined __CYGWIN__ +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined other platforms ... */ +#endif + +#if defined PATH_MAX +# define LT_PATHMAX PATH_MAX +#elif defined MAXPATHLEN +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \ + defined __OS2__ +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free (stale); stale = 0; } \ +} while (0) + +#if defined LT_DEBUGWRAPPER +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + size_t tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined HAVE_DOS_BASED_FILE_SYSTEM + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined HAVE_DOS_BASED_FILE_SYSTEM + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = (size_t) (q - p); + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (STREQ (str, pat)) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + size_t len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + size_t orig_value_len = strlen (orig_value); + size_t add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + size_t len = strlen (new_value); + while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[--len] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $debug_cmd + + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_suncc_cstd_abi +# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! +# Several compiler flags select an ABI that is incompatible with the +# Cstd library. Avoid specifying it if any are in CXXFLAGS. +func_suncc_cstd_abi () +{ + $debug_cmd + + case " $compile_command " in + *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) + suncc_use_cstd_abi=no + ;; + *) + suncc_use_cstd_abi=yes + ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $debug_cmd + + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # what system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll that has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + os2dllname= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=false + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module=$wl-single_module + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test yes != "$build_libtool_libs" \ + && func_fatal_configuration "cannot build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg=$1 + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir=$arg + prev= + continue + ;; + dlfiles|dlprefiles) + $preload || { + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=: + } + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test no = "$dlself"; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test dlprefiles = "$prev"; then + dlself=yes + elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test dlfiles = "$prev"; then + func_append dlfiles " $arg" + else + func_append dlprefiles " $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols=$arg + test -f "$arg" \ + || func_fatal_error "symbol file '$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex=$arg + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir=$arg + prev= + continue + ;; + mllvm) + # Clang does not use LLVM to link, so we can simply discard any + # '-mllvm $arg' options when doing the link step. + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append moreargs " $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test none = "$pic_object" && + test none = "$non_pic_object"; then + func_fatal_error "cannot find name of object for '$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + if test none != "$pic_object"; then + # Prepend the subdirectory the object is found in. + pic_object=$xdir$pic_object + + if test dlfiles = "$prev"; then + if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test dlprefiles = "$prev"; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg=$pic_object + fi + + # Non-PIC object. + if test none != "$non_pic_object"; then + # Prepend the subdirectory the object is found in. + non_pic_object=$xdir$non_pic_object + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test none = "$pic_object"; then + arg=$non_pic_object + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object=$pic_object + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "'$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file '$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + os2dllname) + os2dllname=$arg + prev= + continue + ;; + precious_regex) + precious_files_regex=$arg + prev= + continue + ;; + release) + release=-$arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test rpath = "$prev"; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds=$arg + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg=$arg + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "'-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test X-export-symbols = "X$arg"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname "-L" '' "$arg" + if test -z "$func_stripname_result"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between '-L' and '$1'" + else + func_fatal_error "need path for '-L' option" + fi + fi + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of '$dir'" + dir=$absdir + ;; + esac + case "$deplibs " in + *" -L$dir "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test X-lc = "X$arg" || test X-lm = "X$arg"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test X-lc = "X$arg" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) + # Do not include libc due to us having libc/libc_r. + test X-lc = "X$arg" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test X-lc = "X$arg" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test X-lc = "X$arg" && continue + ;; + esac + elif test X-lc_r = "X$arg"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -mllvm) + prev=mllvm + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot|--sysroot) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + continue + ;; + + -multi_module) + single_module=$wl-multi_module + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "'-no-install' is ignored for $host" + func_warning "assuming '-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -os2dllname) + prev=os2dllname + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + =*) + func_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs=$IFS; IFS=, + for flag in $args; do + IFS=$save_ifs + func_quote_for_eval "$flag" + func_append arg " $func_quote_for_eval_result" + func_append compiler_flags " $func_quote_for_eval_result" + done + IFS=$save_ifs + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs=$IFS; IFS=, + for flag in $args; do + IFS=$save_ifs + func_quote_for_eval "$flag" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append linker_flags " $func_quote_for_eval_result" + done + IFS=$save_ifs + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # -fstack-protector* stack protector flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + # -specs=* GCC specs files + # -stdlib=* select c++ std lib with clang + # -fsanitize=* Clang/GCC memory and address sanitizer + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ + -specs=*|-fsanitize=*) + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + -Z*) + if test os2 = "`expr $host : '.*\(os2\)'`"; then + # OS/2 uses -Zxxx to specify OS/2-specific options + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case $arg in + -Zlinker | -Zstack) + prev=xcompiler + ;; + esac + continue + else + # Otherwise treat like 'Some other compiler flag' below + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + fi + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + ;; + + *.$objext) + # A standard object. + func_append objs " $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test none = "$pic_object" && + test none = "$non_pic_object"; then + func_fatal_error "cannot find name of object for '$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + test none = "$pic_object" || { + # Prepend the subdirectory the object is found in. + pic_object=$xdir$pic_object + + if test dlfiles = "$prev"; then + if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test dlprefiles = "$prev"; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg=$pic_object + } + + # Non-PIC object. + if test none != "$non_pic_object"; then + # Prepend the subdirectory the object is found in. + non_pic_object=$xdir$non_pic_object + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test none = "$pic_object"; then + arg=$non_pic_object + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object=$pic_object + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "'$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test dlfiles = "$prev"; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test dlprefiles = "$prev"; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the '$prevarg' option requires an argument" + + if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname=$func_basename_result + libobjs_save=$libobjs + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + # Definition is injected by LT_CONFIG during libtool generation. + func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" + + func_dirname "$output" "/" "" + output_objdir=$func_dirname_result$objdir + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_preserve_dup_deps; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test lib = "$linkmode"; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append pre_post_deps " $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can '-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=false + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test lib,link = "$linkmode,$pass"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs=$tmp_deplibs + fi + + if test lib,link = "$linkmode,$pass" || + test prog,scan = "$linkmode,$pass"; then + libs=$deplibs + deplibs= + fi + if test prog = "$linkmode"; then + case $pass in + dlopen) libs=$dlfiles ;; + dlpreopen) libs=$dlprefiles ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test lib,dlpreopen = "$linkmode,$pass"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs=$dlprefiles + fi + if test dlopen = "$pass"; then + # Collect dlpreopened libraries + save_deplibs=$deplibs + deplibs= + fi + + for deplib in $libs; do + lib= + found=false + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test lib = "$linkmode"; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test lib != "$linkmode" && test prog != "$linkmode"; then + func_warning "'-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test lib = "$linkmode"; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib=$searchdir/lib$name$search_ext + if test -f "$lib"; then + if test .la = "$search_ext"; then + found=: + else + found=false + fi + break 2 + fi + done + done + if $found; then + # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll=$l + done + if test "X$ll" = "X$old_library"; then # only static version available + found=false + func_dirname "$lib" "" "." + ladir=$func_dirname_result + lib=$ladir/$old_library + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + else + # deplib doesn't seem to be a libtool library + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + ;; # -l + *.ltframework) + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test lib = "$linkmode"; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test conv = "$pass" && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + continue + fi + if test scan = "$pass"; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "'-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test link = "$pass"; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=false + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=: + fi + ;; + pass_all) + valid_a_lib=: + ;; + esac + if $valid_a_lib; then + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + else + echo + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." + fi + ;; + esac + continue + ;; + prog) + if test link != "$pass"; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + elif test prog = "$linkmode"; then + if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=: + continue + ;; + esac # case $deplib + + $found || test -f "$lib" \ + || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "'$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir=$func_dirname_result + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test lib,link = "$linkmode,$pass" || + test prog,scan = "$linkmode,$pass" || + { test prog != "$linkmode" && test lib != "$linkmode"; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test conv = "$pass"; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for '$lib'" + fi + # It is a libtool convenience library, so add in its objects. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + elif test prog != "$linkmode" && test lib != "$linkmode"; then + func_fatal_error "'$lib' is not a convenience library" + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test yes = "$prefer_static_libs" || + test built,no = "$prefer_static_libs,$installed"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib=$l + done + fi + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for '$lib'" + fi + + # This library was specified with -dlopen. + if test dlopen = "$pass"; then + test -z "$libdir" \ + && func_fatal_error "cannot -dlopen a convenience library: '$lib'" + if test -z "$dlname" || + test yes != "$dlopen_support" || + test no = "$build_libtool_libs" + then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + func_append dlprefiles " $lib $dependency_libs" + else + func_append newdlfiles " $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of '$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir=$ladir + fi + ;; + esac + func_basename "$lib" + laname=$func_basename_result + + # Find the relevant object directory and library name. + if test yes = "$installed"; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library '$lib' was moved." + dir=$ladir + absdir=$abs_ladir + libdir=$abs_ladir + else + dir=$lt_sysroot$libdir + absdir=$lt_sysroot$libdir + fi + test yes = "$hardcode_automatic" && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir=$ladir + absdir=$abs_ladir + # Remove this search path later + func_append notinst_path " $abs_ladir" + else + dir=$ladir/$objdir + absdir=$abs_ladir/$objdir + # Remove this search path later + func_append notinst_path " $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test dlpreopen = "$pass"; then + if test -z "$libdir" && test prog = "$linkmode"; then + func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" + fi + case $host in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test lib = "$linkmode"; then + deplibs="$dir/$old_library $deplibs" + elif test prog,link = "$linkmode,$pass"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test prog = "$linkmode" && test link != "$pass"; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=false + if test no != "$link_all_deplibs" || test -z "$library_names" || + test no = "$build_libtool_libs"; then + linkalldeplibs=: + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if $linkalldeplibs; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test prog,link = "$linkmode,$pass"; then + if test -n "$library_names" && + { { test no = "$prefer_static_libs" || + test built,yes = "$prefer_static_libs,$installed"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then + # Make sure the rpath contains only unique directories. + case $temp_rpath: in + *"$absdir:"*) ;; + *) func_append temp_rpath "$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if $alldeplibs && + { test pass_all = "$deplibs_check_method" || + { test yes = "$build_libtool_libs" && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test built = "$use_static_libs" && test yes = "$installed"; then + use_static_libs=no + fi + if test -n "$library_names" && + { test no = "$use_static_libs" || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc* | *os2*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test no = "$installed"; then + func_append notinst_deplibs " $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule= + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule=$dlpremoduletest + break + fi + done + if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then + echo + if test prog = "$linkmode"; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test lib = "$linkmode" && + test yes = "$hardcode_into_libs"; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname=$1 + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname=$dlname + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc* | *os2*) + func_arith $current - $age + major=$func_arith_result + versuffix=-$major + ;; + esac + eval soname=\"$soname_spec\" + else + soname=$realname + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot=$soname + func_basename "$soroot" + soname=$func_basename_result + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from '$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for '$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test prog = "$linkmode" || test relink != "$opt_mode"; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test no = "$hardcode_direct"; then + add=$dir/$linklib + case $host in + *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;; + *-*-sysv4*uw2*) add_dir=-L$dir ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir=-L$dir ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we cannot + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library"; then + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" + else + add=$dir/$old_library + fi + elif test -n "$old_library"; then + add=$dir/$old_library + fi + fi + esac + elif test no = "$hardcode_minus_L"; then + case $host in + *-*-sunos*) add_shlibpath=$dir ;; + esac + add_dir=-L$dir + add=-l$name + elif test no = "$hardcode_shlibpath_var"; then + add_shlibpath=$dir + add=-l$name + else + lib_linked=no + fi + ;; + relink) + if test yes = "$hardcode_direct" && + test no = "$hardcode_direct_absolute"; then + add=$dir/$linklib + elif test yes = "$hardcode_minus_L"; then + add_dir=-L$absdir + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add=-l$name + elif test yes = "$hardcode_shlibpath_var"; then + add_shlibpath=$dir + add=-l$name + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test yes != "$lib_linked"; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test prog = "$linkmode"; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test yes != "$hardcode_direct" && + test yes != "$hardcode_minus_L" && + test yes = "$hardcode_shlibpath_var"; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test prog = "$linkmode" || test relink = "$opt_mode"; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test yes = "$hardcode_direct" && + test no = "$hardcode_direct_absolute"; then + add=$libdir/$linklib + elif test yes = "$hardcode_minus_L"; then + add_dir=-L$libdir + add=-l$name + elif test yes = "$hardcode_shlibpath_var"; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add=-l$name + elif test yes = "$hardcode_automatic"; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib"; then + add=$inst_prefix_dir$libdir/$linklib + else + add=$libdir/$linklib + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir=-L$libdir + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add=-l$name + fi + + if test prog = "$linkmode"; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test prog = "$linkmode"; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test unsupported != "$hardcode_direct"; then + test -n "$old_library" && linklib=$old_library + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test yes = "$build_libtool_libs"; then + # Not a shared library + if test pass_all != "$deplibs_check_method"; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + $ECHO "*** Warning: This system cannot link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test yes = "$module"; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using 'nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** 'nm' from GNU binutils and a full rebuild may help." + fi + if test no = "$build_old_libs"; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test lib = "$linkmode"; then + if test -n "$dependency_libs" && + { test yes != "$hardcode_into_libs" || + test yes = "$build_old_libs" || + test yes = "$link_static"; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs=$temp_deplibs + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test no != "$link_all_deplibs"; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path=$deplib ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + func_dirname "$deplib" "" "." + dir=$func_dirname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of '$dir'" + absdir=$dir + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names"; then + for tmp in $deplibrary_names; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl"; then + depdepl=$absdir/$objdir/$depdepl + darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" + func_append linker_flags " -dylib_file $darwin_install_name:$depdepl" + path= + fi + fi + ;; + *) + path=-L$absdir/$objdir + ;; + esac + else + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "'$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "'$deplib' seems to be moved" + + path=-L$absdir + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test link = "$pass"; then + if test prog = "$linkmode"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs=$newdependency_libs + if test dlpreopen = "$pass"; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test dlopen != "$pass"; then + test conv = "$pass" || { + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + } + + if test prog,link = "$linkmode,$pass"; then + vars="compile_deplibs finalize_deplibs" + else + vars=deplibs + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + + # Add Sun CC postdeps if required: + test CXX = "$tagname" && { + case $host_os in + linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C++ 5.9 + func_suncc_cstd_abi + + if test no != "$suncc_use_cstd_abi"; then + func_append postdeps ' -library=Cstd -library=Crun' + fi + ;; + esac + ;; + + solaris*) + func_cc_basename "$CC" + case $func_cc_basename_result in + CC* | sunCC*) + func_suncc_cstd_abi + + if test no != "$suncc_use_cstd_abi"; then + func_append postdeps ' -library=Cstd -library=Crun' + fi + ;; + esac + ;; + esac + } + + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i= + ;; + esac + if test -n "$i"; then + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test prog = "$linkmode"; then + dlfiles=$newdlfiles + fi + if test prog = "$linkmode" || test lib = "$linkmode"; then + dlprefiles=$newdlprefiles + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then + func_warning "'-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "'-l' and '-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "'-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "'-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "'-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "'-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "'-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs=$output + func_append objs "$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form 'libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test no = "$module" \ + && func_fatal_help "libtool library '$output' must begin with 'lib'" + + if test no != "$need_lib_prefix"; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test pass_all != "$deplibs_check_method"; then + func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + func_append libobjs " $objs" + fi + fi + + test no = "$dlself" \ + || func_warning "'-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test 1 -lt "$#" \ + && func_warning "ignoring multiple '-rpath's for a libtool library" + + install_libdir=$1 + + oldlibs= + if test -z "$rpath"; then + if test yes = "$build_libtool_libs"; then + # Building a libtool convenience library. + # Some compilers have problems with a '.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "'-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "'-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs=$IFS; IFS=: + set dummy $vinfo 0 0 0 + shift + IFS=$save_ifs + + test -n "$7" && \ + func_fatal_help "too many parameters to '-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major=$1 + number_minor=$2 + number_revision=$3 + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # that has an extra 1 added just for fun + # + case $version_type in + # correct linux to gnu/linux during the next big refactor + darwin|freebsd-elf|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age=$number_minor + revision=$number_revision + ;; + freebsd-aout|qnx|sunos) + current=$number_major + revision=$number_minor + age=0 + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age=$number_minor + revision=$number_minor + lt_irix_increment=no + ;; + *) + func_fatal_configuration "$modename: unknown library version type '$version_type'" + ;; + esac + ;; + no) + current=$1 + revision=$2 + age=$3 + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT '$current' must be a nonnegative integer" + func_fatal_error "'$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION '$revision' must be a nonnegative integer" + func_fatal_error "'$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE '$age' must be a nonnegative integer" + func_fatal_error "'$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE '$age' is greater than the current interface number '$current'" + func_fatal_error "'$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + # On Darwin other compilers + case $CC in + nagfor*) + verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" + ;; + *) + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + esac + ;; + + freebsd-aout) + major=.$current + versuffix=.$current.$revision + ;; + + freebsd-elf) + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + ;; + + irix | nonstopux) + if test no = "$lt_irix_increment"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring=$verstring_prefix$major.$revision + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test 0 -ne "$loop"; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring=$verstring_prefix$major.$iface:$verstring + done + + # Before this point, $major must not contain '.'. + major=.$major + versuffix=$major.$revision + ;; + + linux) # correct to gnu/linux during the next big refactor + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=.$current.$age.$revision + verstring=$current.$age.$revision + + # Add in all the interfaces that we are compatible with. + loop=$age + while test 0 -ne "$loop"; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring=$verstring:$iface.0 + done + + # Make executables depend on our current version. + func_append verstring ":$current.0" + ;; + + qnx) + major=.$current + versuffix=.$current + ;; + + sco) + major=.$current + versuffix=.$current + ;; + + sunos) + major=.$current + versuffix=.$current.$revision + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 file systems. + func_arith $current - $age + major=$func_arith_result + versuffix=-$major + ;; + + *) + func_fatal_configuration "unknown library version type '$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring=0.0 + ;; + esac + if test no = "$need_version"; then + versuffix= + else + versuffix=.0.0 + fi + fi + + # Remove version info from name if versioning should be avoided + if test yes,no = "$avoid_version,$need_version"; then + major= + versuffix= + verstring= + fi + + # Check to see if the archive will have undefined symbols. + if test yes = "$allow_undefined"; then + if test unsupported = "$allow_undefined_flag"; then + if test yes = "$build_old_libs"; then + func_warning "undefined symbols not allowed in $host shared libraries; building static only" + build_libtool_libs=no + else + func_fatal_error "can't build $host shared library unless -no-undefined is specified" + fi + fi + else + # Don't allow undefined symbols. + allow_undefined_flag=$no_undefined_flag + fi + + fi + + func_generate_dlsyms "$libname" "$libname" : + func_append libobjs " $symfileobj" + test " " = "$libobjs" && libobjs= + + if test relink != "$opt_mode"; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*) + if test -n "$precious_files_regex"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles=$dlfiles + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) func_append dlfiles " $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles=$dlprefiles + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test yes = "$build_libtool_libs"; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append deplibs " System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test yes = "$build_libtool_need_lc"; then + func_append deplibs " -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release= + versuffix= + major= + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib=$potent_lib + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | $SED 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;; + *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib= + break 2 + fi + done + done + fi + if test -n "$a_deplib"; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib"; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append newdeplibs " $a_deplib" + a_deplib= + ;; + esac + fi + if test -n "$a_deplib"; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib=$potent_lib # see symlink-check above in file_magic test + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib= + break 2 + fi + done + done + fi + if test -n "$a_deplib"; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib"; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs= + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + for i in $predeps $postdeps; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test none = "$deplibs_check_method"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + ;; + esac + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test yes = "$droppeddeps"; then + if test yes = "$module"; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using 'nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** 'nm' from GNU binutils and a full rebuild may help." + fi + if test no = "$build_old_libs"; then + oldlibs=$output_objdir/$libname.$libext + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test no = "$allow_undefined"; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test no = "$build_old_libs"; then + oldlibs=$output_objdir/$libname.$libext + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + deplibs=$new_libs + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test yes = "$build_libtool_libs"; then + # Remove $wl instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test yes = "$hardcode_into_libs"; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath=$finalize_rpath + test relink = "$opt_mode" || rpath=$compile_rpath$rpath + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + if test -z "$hardcode_libdirs"; then + hardcode_libdirs=$libdir + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir=$hardcode_libdirs + eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath=$finalize_shlibpath + test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname=$1 + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname=$realname + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib=$output_objdir/$realname + linknames= + for link + do + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols=$output_objdir/$libname.uexp + func_append delfiles " $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + func_dll_def_p "$export_symbols" || { + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols=$export_symbols + export_symbols= + always_export_symbols=yes + } + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for '$libname.la'" + export_symbols=$output_objdir/$libname.exp + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs=$IFS; IFS='~' + for cmd1 in $cmds; do + IFS=$save_ifs + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test yes = "$try_normal_branch" \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=$output_objdir/$output_la.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS=$save_ifs + if test -n "$export_symbols_regex" && test : != "$skipped_export"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols=$export_symbols + test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test : != "$skipped_export" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for '$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands, which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs=$tmp_deplibs + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test yes = "$compiler_needs_object" && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test relink = "$opt_mode"; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test yes = "$module" && test -n "$module_cmds"; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test : != "$skipped_export" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then + output=$output_objdir/$output_la.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then + output=$output_objdir/$output_la.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test yes = "$compiler_needs_object"; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-$k.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test -z "$objlist" || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test 1 -eq "$k"; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-$k.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-$k.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + ${skipped_export-false} && { + func_verbose "generating symbol list for '$libname.la'" + export_symbols=$output_objdir/$libname.exp + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + } + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs=$IFS; IFS='~' + for cmd in $concat_cmds; do + IFS=$save_ifs + $opt_quiet || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test relink = "$opt_mode"; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS=$save_ifs + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + ${skipped_export-false} && { + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols=$export_symbols + test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for '$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands, which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + } + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test yes = "$module" && test -n "$module_cmds"; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs=$IFS; IFS='~' + for cmd in $cmds; do + IFS=$sp$nl + eval cmd=\"$cmd\" + IFS=$save_ifs + $opt_quiet || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test relink = "$opt_mode"; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS=$save_ifs + + # Restore the uninstalled library and exit + if test relink = "$opt_mode"; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test yes = "$module" || test yes = "$export_dynamic"; then + # On all known operating systems, these are identical. + dlname=$soname + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then + func_warning "'-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "'-l' and '-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "'-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "'-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "'-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "'-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object '$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj=$output + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # if reload_cmds runs $LD directly, get rid of -Wl from + # whole_archive_flag_spec and hope we can get by with turning comma + # into space. + case $reload_cmds in + *\$LD[\ \$]*) wl= ;; + esac + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags + else + gentop=$output_objdir/${obj}x + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test yes = "$build_libtool_libs" || libobjs=$non_pic_objects + + # Create the old-style object. + reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs + + output=$obj + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + test yes = "$build_libtool_libs" || { + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + } + + if test -n "$pic_flag" || test default != "$pic_mode"; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output=$libobj + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "'-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "'-release' is ignored for programs" + + $preload \ + && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ + && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test CXX = "$tagname"; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " $wl-bind_at_load" + func_append finalize_command " $wl-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs=$new_libs + + + func_append compile_command " $compile_deplibs" + func_append finalize_command " $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs=$libdir + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir=$hardcode_libdirs + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath=$rpath + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs=$libdir + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append finalize_perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir=$hardcode_libdirs + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath=$rpath + + if test -n "$libobjs" && test yes = "$build_old_libs"; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" false + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=: + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=false + ;; + *cygwin* | *mingw* ) + test yes = "$build_libtool_libs" || wrappers_required=false + ;; + *) + if test no = "$need_relink" || test yes != "$build_libtool_libs"; then + wrappers_required=false + fi + ;; + esac + $wrappers_required || { + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command=$compile_command$compile_rpath + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.$objext"; then + func_show_eval '$RM "$output_objdir/${outputname}S.$objext"' + fi + + exit $exit_status + } + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test yes = "$no_install"; then + # We don't need to create a wrapper script. + link_command=$compile_var$compile_command$compile_rpath + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + case $hardcode_action,$fast_install in + relink,*) + # Fast installation is not supported + link_command=$compile_var$compile_command$compile_rpath + relink_command=$finalize_var$finalize_command$finalize_rpath + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "'$output' will be relinked during installation" + ;; + *,yes) + link_command=$finalize_var$compile_command$finalize_rpath + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + ;; + *,no) + link_command=$compile_var$compile_command$compile_rpath + relink_command=$finalize_var$finalize_command$finalize_rpath + ;; + *,needless) + link_command=$finalize_var$compile_command$finalize_rpath + relink_command= + ;; + esac + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource=$output_path/$objdir/lt-$output_name.c + cwrapper=$output_path/$output_name.exe + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host"; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + case $build_libtool_libs in + convenience) + oldobjs="$libobjs_save $symfileobj" + addlibs=$convenience + build_libtool_libs=no + ;; + module) + oldobjs=$libobjs_save + addlibs=$old_convenience + build_libtool_libs=no + ;; + *) + oldobjs="$old_deplibs $non_pic_objects" + $preload && test -f "$symfileobj" \ + && func_append oldobjs " $symfileobj" + addlibs=$old_convenience + ;; + esac + + if test -n "$addlibs"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append oldobjs " $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase=$func_basename_result + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj"; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test -z "$oldobjs"; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test yes = "$build_old_libs" && old_library=$libname.$libext + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + if test yes = "$hardcode_automatic"; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test yes = "$installed"; then + if test -z "$install_libdir"; then + break + fi + output=$output_objdir/${outputname}i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name=$func_basename_result + func_resolve_sysroot "$deplib" + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "'$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append newdependency_libs " $deplib" ;; + esac + done + dependency_libs=$newdependency_libs + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name=$func_basename_result + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "'$lib' is not a valid libtool archive" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append newdlfiles " $lib" ;; + esac + done + dlfiles=$newdlfiles + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name=$func_basename_result + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "'$lib' is not a valid libtool archive" + func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" + ;; + esac + done + dlprefiles=$newdlprefiles + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlfiles " $abs" + done + dlfiles=$newdlfiles + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles=$newdlprefiles + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test -n "$bindir"; then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result/$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that cannot go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test no,yes = "$installed,$need_relink"; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +if test link = "$opt_mode" || test relink = "$opt_mode"; then + func_mode_link ${1+"$@"} +fi + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $debug_cmd + + RM=$nonopt + files= + rmforce=false + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic=$magic + + for arg + do + case $arg in + -f) func_append RM " $arg"; rmforce=: ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir=$func_dirname_result + if test . = "$dir"; then + odir=$objdir + else + odir=$dir/$objdir + fi + func_basename "$file" + name=$func_basename_result + test uninstall = "$opt_mode" && odir=$dir + + # Remember odir for removal later, being careful to avoid duplicates + if test clean = "$opt_mode"; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif $rmforce; then + continue + fi + + rmfiles=$file + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case $opt_mode in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && test none != "$pic_object"; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && test none != "$non_pic_object"; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test clean = "$opt_mode"; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + func_append rmfiles " $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + func_append rmfiles " $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + func_append rmfiles " $odir/$name $odir/${name}S.$objext" + if test yes = "$fast_install" && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name"; then + func_append rmfiles " $odir/lt-$noexename.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # Try to remove the $objdir's in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then + func_mode_uninstall ${1+"$@"} +fi + +test -z "$opt_mode" && { + help=$generic_help + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode '$opt_mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# where we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/missing b/missing new file mode 100755 index 0000000..f62bbae --- /dev/null +++ b/missing @@ -0,0 +1,215 @@ +#! /bin/sh +# Common wrapper for a few potentially missing GNU programs. + +scriptversion=2013-10-28.13; # UTC + +# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# Originally written by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try '$0 --help' for more information" + exit 1 +fi + +case $1 in + + --is-lightweight) + # Used by our autoconf macros to check whether the available missing + # script is modern enough. + exit 0 + ;; + + --run) + # Back-compat with the calling convention used by older automake. + shift + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due +to PROGRAM being missing or too old. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal autoconf autoheader autom4te automake makeinfo + bison yacc flex lex help2man + +Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and +'g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: unknown '$1' option" + echo 1>&2 "Try '$0 --help' for more information" + exit 1 + ;; + +esac + +# Run the given program, remember its exit status. +"$@"; st=$? + +# If it succeeded, we are done. +test $st -eq 0 && exit 0 + +# Also exit now if we it failed (or wasn't found), and '--version' was +# passed; such an option is passed most likely to detect whether the +# program is present and works. +case $2 in --version|--help) exit $st;; esac + +# Exit code 63 means version mismatch. This often happens when the user +# tries to use an ancient version of a tool on a file that requires a +# minimum version. +if test $st -eq 63; then + msg="probably too old" +elif test $st -eq 127; then + # Program was missing. + msg="missing on your system" +else + # Program was found and executed, but failed. Give up. + exit $st +fi + +perl_URL=http://www.perl.org/ +flex_URL=http://flex.sourceforge.net/ +gnu_software_URL=http://www.gnu.org/software + +program_details () +{ + case $1 in + aclocal|automake) + echo "The '$1' program is part of the GNU Automake package:" + echo "<$gnu_software_URL/automake>" + echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/autoconf>" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + autoconf|autom4te|autoheader) + echo "The '$1' program is part of the GNU Autoconf package:" + echo "<$gnu_software_URL/autoconf/>" + echo "It also requires GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + esac +} + +give_advice () +{ + # Normalize program name to check for. + normalized_program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + + printf '%s\n' "'$1' is $msg." + + configure_deps="'configure.ac' or m4 files included by 'configure.ac'" + case $normalized_program in + autoconf*) + echo "You should only need it if you modified 'configure.ac'," + echo "or m4 files included by it." + program_details 'autoconf' + ;; + autoheader*) + echo "You should only need it if you modified 'acconfig.h' or" + echo "$configure_deps." + program_details 'autoheader' + ;; + automake*) + echo "You should only need it if you modified 'Makefile.am' or" + echo "$configure_deps." + program_details 'automake' + ;; + aclocal*) + echo "You should only need it if you modified 'acinclude.m4' or" + echo "$configure_deps." + program_details 'aclocal' + ;; + autom4te*) + echo "You might have modified some maintainer files that require" + echo "the 'autom4te' program to be rebuilt." + program_details 'autom4te' + ;; + bison*|yacc*) + echo "You should only need it if you modified a '.y' file." + echo "You may want to install the GNU Bison package:" + echo "<$gnu_software_URL/bison/>" + ;; + lex*|flex*) + echo "You should only need it if you modified a '.l' file." + echo "You may want to install the Fast Lexical Analyzer package:" + echo "<$flex_URL>" + ;; + help2man*) + echo "You should only need it if you modified a dependency" \ + "of a man page." + echo "You may want to install the GNU Help2man package:" + echo "<$gnu_software_URL/help2man/>" + ;; + makeinfo*) + echo "You should only need it if you modified a '.texi' file, or" + echo "any other file indirectly affecting the aspect of the manual." + echo "You might want to install the Texinfo package:" + echo "<$gnu_software_URL/texinfo/>" + echo "The spurious makeinfo call might also be the consequence of" + echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" + echo "want to install GNU make:" + echo "<$gnu_software_URL/make/>" + ;; + *) + echo "You might have modified some files without having the proper" + echo "tools for further handling them. Check the 'README' file, it" + echo "often tells you about the needed prerequisites for installing" + echo "this package. You may also peek at any GNU archive site, in" + echo "case some other package contains this missing '$1' program." + ;; + esac +} + +give_advice "$1" | sed -e '1s/^/WARNING: /' \ + -e '2,$s/^/ /' >&2 + +# Propagate the correct exit status (expected to be 127 for a program +# not found, 63 for a program that failed due to version mismatch). +exit $st + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/package.json b/package.json new file mode 100644 index 0000000..24851b2 --- /dev/null +++ b/package.json @@ -0,0 +1,58 @@ +{ + "name": "thrift", + "description": "node.js bindings for the Apache Thrift RPC system", + "homepage": "http://thrift.apache.org/", + "repository": { + "type": "git", + "url": "https://git-wip-us.apache.org/repos/asf/thrift.git" + }, + "version": "0.11.0", + "author": { + "name": "Apache Thrift Developers", + "email": "dev@thrift.apache.org", + "url": "http://thrift.apache.org" + }, + "license": "Apache-2.0", + "licenses": [ + { + "type": "Apache-2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0" + } + ], + "bugs": { + "mail": "dev@thrift.apache.org", + "url": "https://issues.apache.org/jira/browse/THRIFT" + }, + "files": [ + "lib/nodejs/lib/thrift", + "lib/nodejs/README.md" + ], + "directories": { + "lib": "./lib/nodejs/lib/thrift" + }, + "main": "./lib/nodejs/lib/thrift", + "engines": { + "node": ">= 4.1.0" + }, + "dependencies": { + "node-int64": "^0.4.0", + "q": "^1.5.0", + "ws": ">= 2.2.3" + }, + "devDependencies": { + "buffer-equals": "^1.0.4", + "commander": "^2.11.0", + "connect": "^3.6.4", + "istanbul": "^0.4.5", + "jsdoc": ">=3.5.5", + "minimatch": "^3.0.4", + "phantomjs-prebuilt": "^2.1.7", + "run-browser": "^2.0.2", + "tape": "^4.8.0", + "utf-8-validate": "^3.0.0" + }, + "scripts": { + "cover": "lib/nodejs/test/testAll.sh COVER", + "test": "lib/nodejs/test/testAll.sh" + } +} diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100755 index 0000000..6bc9989 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,140 @@ +# Apache Thrift © The Apache Software Foundation +# http://www.apache.org/licenses/LICENSE-2.0 +# SPDX-License-Identifier: Apache-2.0 + +# File: sonar-project.properties +# Apache Thrift configuration file for Sonar https://analysis.apache.org/ +# Sonar is an open platform to manage code quality http://www.sonarsource.org/ + + +# required metadata +sonar.projectKey=org.apache.thrift +sonar.projectName=Apache Thrift +sonar.projectDescription= +The Apache Thrift software framework, for scalable cross-language services +development, combines a software stack with a code generation engine to build +services that work efficiently and seamlessly between all major languages. + +# Apache Thrift Version +sonar.projectVersion=0.11.0 +# use this to set another version string +# $ sonar-runner -D sonar.projectVersion=`git rev-parse HEAD` +# set projectDate in combination with projectVersion for imports of old releases +#sonar.projectDate=yyyy-MM-dd + +# TODO add website (sonar.projectUrl does not work) +#sonar.XXXX=http//thrift.apache.org + +# Some properties that will be inherited by the modules +sonar.sources=src +sonar.language=java,js,c++,py,c +sonar.sourceEncoding=UTF-8 + +# scm +sonar.scm.url=scm:git:https://git-wip-us.apache.org/repos/asf/thrift + +# cppcheck -q --error-exitcode=0 --xml . 2> cppcheck-result.xml +sonar.cxx.cppcheck.reportPath=cppcheck-result.xml + +# List of the module identifiers +sonar.modules=module1,module3,module4,module5,module6,module7,module8,module9,module10,module11,module12,module14 + + + +# we need sonar-runner 2.1 for this, see http://jira.codehaus.org/browse/SONARPLUGINS-2421 +#sonar.modules=module2 + +# delph plugin is broken +#sonar.modules=module13 + +# phpunit plugin is broken +#sonar.modules=module15 + +module1.sonar.projectName=Apache Thrift - Java Library +module1.sonar.projectBaseDir=lib/java +module1.sonar.sources=src +module1.sonar.tests=test +module1.sonar.binaries=build/libthrift-0.11.0.jar +module1.sonar.libraries=build/lib/*.jar +module1.sonar.language=java + +module2.sonar.projectName=Apache Thrift - Java Tutorial +module2.sonar.projectBaseDir=. +module2.sonar.sources=tutorial/java/src, tutorial/java/gen-java +module2.sonar.binaries=tutorial/java/tutorial.jar +module2.sonar.libraries=lib/java/build/lib/*.jar,lib/java/build/libthrift-0.11.0.jar +module2.sonar.language=java + +module3.sonar.projectName=Apache Thrift - JavaScript Library +module3.sonar.projectBaseDir=lib/js +module3.sonar.sources=. +module3.sonar.exclusions=test/**/* +module3.sonar.language=js + +module4.sonar.projectName=Apache Thrift - JavaScript Tutorial +module4.sonar.projectBaseDir=tutorial/js +module4.sonar.sources=. +module4.sonar.language=web + +module5.sonar.projectName=Apache Thrift - C++ Library +module5.sonar.projectBaseDir=lib/cpp +module5.sonar.sources=src +module5.sonar.tests=test +module5.sonar.language=c++ + +module6.sonar.projectName=Apache Thrift - C++ Tutorial +module6.sonar.projectBaseDir=tutorial/cpp +module6.sonar.sources=. +module6.sonar.exclusions=gen-cpp/**/* +module6.sonar.language=c++ + +module7.sonar.projectName=Apache Thrift - C++ Cross Language Test +module7.sonar.projectBaseDir=test/cpp +module7.sonar.sources=src +module7.sonar.language=c++ + +module8.sonar.projectName=Apache Thrift - Compiler +module8.sonar.projectBaseDir=compiler/cpp +module8.sonar.sources=src +module8.sonar.language=c++ + +module9.sonar.projectName=Apache Thrift - Python Library +module9.sonar.projectBaseDir=lib/py +module9.sonar.sources=src +module9.sonar.language=py + +module10.sonar.projectName=Apache Thrift - Python Tutorial +module10.sonar.projectBaseDir=tutorial/py +module10.sonar.sources=. +module10.sonar.exclusions=gen-py/**/* +module10.sonar.language=py + +module11.sonar.projectName=Apache Thrift - Python Cross Language Test +module11.sonar.projectBaseDir=test/py +module11.sonar.sources=. +module11.sonar.exclusions=gen-*/**/* +module11.sonar.language=py + +module12.sonar.projectName=Apache Thrift - c_glib Library +module12.sonar.projectBaseDir=lib/c_glib +module12.sonar.sources=src +module12.sonar.language=c + +module13.sonar.projectName=Apache Thrift - Delphi Library +module13.sonar.projectBaseDir=lib/delphi +module13.sonar.sources=src +module13.sonar.tests=test +module13.sonar.language=delph + +module14.sonar.projectName=Apache Thrift - Flex (as3) Library +module14.sonar.projectBaseDir=lib/as3 +module14.sonar.sources=src +module14.sonar.language=flex + +module15.sonar.projectName=Apache Thrift - PHP Library +module15.sonar.projectBaseDir=lib/php +module15.sonar.sources=src +module15.sonar.language=php + +# TODO add some more languages here + diff --git a/test/AnnotationTest.thrift b/test/AnnotationTest.thrift new file mode 100644 index 0000000..7e24e1c --- /dev/null +++ b/test/AnnotationTest.thrift @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +typedef list ( cpp.template = "std::list" ) int_linked_list + +struct foo { + 1: i32 bar ( presence = "required" ); + 2: i32 baz ( presence = "manual", cpp.use_pointer = "", ); + 3: i32 qux; + 4: i32 bop; +} ( + cpp.type = "DenseFoo", + python.type = "DenseFoo", + java.final = "", + annotation.without.value, +) + +exception foo_error { + 1: i32 error_code ( foo="bar" ) + 2: string error_msg +} (foo = "bar") + +typedef string ( unicode.encoding = "UTF-16" ) non_latin_string (foo="bar") +typedef list< double ( cpp.fixed_point = "16" ) > tiny_float_list + +enum weekdays { + SUNDAY ( weekend = "yes" ), + MONDAY, + TUESDAY, + WEDNESDAY, + THURSDAY, + FRIDAY, + SATURDAY ( weekend = "yes" ) +} (foo.bar="baz") + +/* Note that annotations on senum values are not supported. */ +senum seasons { + "Spring", + "Summer", + "Fall", + "Winter" +} ( foo = "bar" ) + +struct ostr_default { + 1: i32 bar; +} + +struct ostr_custom { + 1: i32 bar; +} (cpp.customostream) + + +service foo_service { + void foo() ( foo = "bar" ) +} (a.b="c") + diff --git a/test/BrokenConstants.thrift b/test/BrokenConstants.thrift new file mode 100644 index 0000000..c5aab4a --- /dev/null +++ b/test/BrokenConstants.thrift @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const i64 myint = 68719476736 +const i64 broken = 9876543210987654321 // A little over 2^63 + +enum foo { + bar = 68719476736 +} diff --git a/test/ConstantsDemo.thrift b/test/ConstantsDemo.thrift new file mode 100644 index 0000000..a54534d --- /dev/null +++ b/test/ConstantsDemo.thrift @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +namespace cpp yozone +namespace erl consts_ + +struct thing { + 1: i32 hello, + 2: i32 goodbye +} + +enum enumconstants { + ONE = 1, + TWO = 2 +} + +// struct thing2 { +// /** standard docstring */ +// 1: enumconstants val = TWO +// } + +typedef i32 myIntType +const myIntType myInt = 3 + +//const map GEN_ENUM_NAMES = {ONE : "HOWDY", TWO: "PARTNER"} + +const i32 hex_const = 0x0001F +const i32 negative_hex_constant = -0x0001F + +const i32 GEN_ME = -3523553 +const double GEn_DUB = 325.532 +const double GEn_DU = 085.2355 +const string GEN_STRING = "asldkjasfd" + +const double e10 = 1e10 // fails with 0.9.3 and earlier +const double e11 = -1e10 + +const map GEN_MAP = { 35532 : 233, 43523 : 853 } +const list GEN_LIST = [ 235235, 23598352, 3253523 ] + +const map> GEN_MAPMAP = { 235 : { 532 : 53255, 235:235}} + +const map GEN_MAP2 = { "hello" : 233, "lkj98d" : 853, 'lkjsdf' : 098325 } + +const thing GEN_THING = { 'hello' : 325, 'goodbye' : 325352 } + +const map GEN_WHAT = { 35 : { 'hello' : 325, 'goodbye' : 325352 } } + +const set GEN_SET = [ 235, 235, 53235 ] + +exception Blah { + 1: i32 bing } + +exception Gak {} + +service yowza { + void blingity(), + i32 blangity() throws (1: Blah hoot ) +} diff --git a/test/DebugProtoTest.thrift b/test/DebugProtoTest.thrift new file mode 100644 index 0000000..b6a7659 --- /dev/null +++ b/test/DebugProtoTest.thrift @@ -0,0 +1,378 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +namespace c_glib TTest +namespace cpp thrift.test.debug +namespace java thrift.test +namespace rb thrift.test + +struct Doubles { + 1: double nan, + 2: double inf, + 3: double neginf, + 4: double repeating, + 5: double big, + 6: double tiny, + 7: double zero, + 8: double negzero, +} + +struct OneOfEach { + 1: bool im_true, + 2: bool im_false, + 3: i8 a_bite = 0x7f, + 4: i16 integer16 = 0x7fff, + 5: i32 integer32, + 6: i64 integer64 = 10000000000, + 7: double double_precision, + 8: string some_characters, + 9: string zomg_unicode, + 10: bool what_who, + 11: binary base64, + 12: list byte_list = [1, 2, 3], + 13: list i16_list = [1,2,3], + 14: list i64_list = [1,2,3] +} + +struct Bonk { + 1: i32 type, + 2: string message, +} + +struct Nesting { + 1: Bonk my_bonk, + 2: OneOfEach my_ooe, +} + +struct HolyMoley { + 1: list big, + 2: set (python.immutable = "")> contain, + 3: map> bonks, +} + +struct Backwards { + 2: i32 first_tag2, + 1: i32 second_tag1, +} + +struct Empty { +} ( + python.immutable = "", +) + +struct Wrapper { + 1: Empty foo +} ( + python.immutable = "", +) + +struct RandomStuff { + 1: i32 a, + 2: i32 b, + 3: i32 c, + 4: i32 d, + 5: list myintlist, + 6: map maps, + 7: i64 bigint, + 8: double triple, +} + +struct Base64 { + 1: i32 a, + 2: binary b1, + 3: binary b2, + 4: binary b3, + 5: binary b4, + 6: binary b5, + 7: binary b6, +} + +struct CompactProtoTestStruct { + // primitive fields + 1: i8 a_byte; + 2: i16 a_i16; + 3: i32 a_i32; + 4: i64 a_i64; + 5: double a_double; + 6: string a_string; + 7: binary a_binary; + 8: bool true_field; + 9: bool false_field; + 10: Empty empty_struct_field; + + // primitives in lists + 11: list byte_list; + 12: list i16_list; + 13: list i32_list; + 14: list i64_list; + 15: list double_list; + 16: list string_list; + 17: list binary_list; + 18: list boolean_list; + 19: list struct_list; + + // primitives in sets + 20: set byte_set; + 21: set i16_set; + 22: set i32_set; + 23: set i64_set; + 24: set double_set; + 25: set string_set; + 26: set binary_set; + 27: set boolean_set; + 28: set struct_set; + + // maps + // primitives as keys + 29: map byte_byte_map; + 30: map i16_byte_map; + 31: map i32_byte_map; + 32: map i64_byte_map; + 33: map double_byte_map; + 34: map string_byte_map; + 35: map binary_byte_map; + 36: map boolean_byte_map; + // primitives as values + 37: map byte_i16_map; + 38: map byte_i32_map; + 39: map byte_i64_map; + 40: map byte_double_map; + 41: map byte_string_map; + 42: map byte_binary_map; + 43: map byte_boolean_map; + // collections as keys + 44: map (python.immutable = ""), i8> list_byte_map; + 45: map (python.immutable = ""), i8> set_byte_map; + 46: map (python.immutable = ""), i8> map_byte_map; + // collections as values + 47: map> byte_map_map; + 48: map> byte_set_map; + 49: map> byte_list_map; +} + +// To be used to test the serialization of an empty map +struct SingleMapTestStruct { + 1: required map i32_map; +} + +const CompactProtoTestStruct COMPACT_TEST = { + 'a_byte' : 127, + 'a_i16' : 32000, + 'a_i32' : 1000000000, + 'a_i64' : 0xffffffffff, + 'a_double' : 5.6789, + 'a_string' : "my string", +//'a_binary,' + 'true_field' : 1, + 'false_field' : 0, + 'empty_struct_field' : {}, + 'byte_list' : [-127, -1, 0, 1, 127], + 'i16_list' : [-1, 0, 1, 0x7fff], + 'i32_list' : [-1, 0, 0xff, 0xffff, 0xffffff, 0x7fffffff], + 'i64_list' : [-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff], + 'double_list' : [0.1, 0.2, 0.3], + 'string_list' : ["first", "second", "third"], +//'binary_list,' + 'boolean_list' : [1, 1, 1, 0, 0, 0], + 'struct_list' : [{}, {}], + 'byte_set' : [-127, -1, 0, 1, 127], + 'i16_set' : [-1, 0, 1, 0x7fff], + 'i32_set' : [1, 2, 3], + 'i64_set' : [-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff], + 'double_set' : [0.1, 0.2, 0.3], + 'string_set' : ["first", "second", "third"], +//'binary_set,' + 'boolean_set' : [1, 0], + 'struct_set' : [{}], + 'byte_byte_map' : {1 : 2}, + 'i16_byte_map' : {1 : 1, -1 : 1, 0x7fff : 1}, + 'i32_byte_map' : {1 : 1, -1 : 1, 0x7fffffff : 1}, + 'i64_byte_map' : {0 : 1, 1 : 1, -1 : 1, 0x7fffffffffffffff : 1}, + 'double_byte_map' : {-1.1 : 1, 1.1 : 1}, + 'string_byte_map' : {"first" : 1, "second" : 2, "third" : 3, "" : 0}, +//'binary_byte_map,' + 'boolean_byte_map' : {1 : 1, 0 : 0}, + 'byte_i16_map' : {1 : 1, 2 : -1, 3 : 0x7fff}, + 'byte_i32_map' : {1 : 1, 2 : -1, 3 : 0x7fffffff}, + 'byte_i64_map' : {1 : 1, 2 : -1, 3 : 0x7fffffffffffffff}, + 'byte_double_map' : {1 : 0.1, 2 : -0.1, 3 : 1000000.1}, + 'byte_string_map' : {1 : "", 2 : "blah", 3 : "loooooooooooooong string"}, +//'byte_binary_map,' + 'byte_boolean_map' : {1 : 1, 2 : 0}, + 'list_byte_map' : {[1, 2, 3] : 1, [0, 1] : 2, [] : 0}, + 'set_byte_map' : {[1, 2, 3] : 1, [0, 1] : 2, [] : 0}, + 'map_byte_map' : {{1 : 1} : 1, {2 : 2} : 2, {} : 0}, + 'byte_map_map' : {0 : {}, 1 : {1 : 1}, 2 : {1 : 1, 2 : 2}}, + 'byte_set_map' : {0 : [], 1 : [1], 2 : [1, 2]}, + 'byte_list_map' : {0 : [], 1 : [1], 2 : [1, 2]}, +} + + +const i32 MYCONST = 2 + + +exception ExceptionWithAMap { + 1: string blah; + 2: map map_field; +} + +service ServiceForExceptionWithAMap { + void methodThatThrowsAnException() throws (1: ExceptionWithAMap xwamap); +} + +service Srv { + i32 Janky(1: i32 arg); + + // return type only methods + + void voidMethod(); + i32 primitiveMethod(); + CompactProtoTestStruct structMethod(); + + void methodWithDefaultArgs(1: i32 something = MYCONST); + + oneway void onewayMethod(); + + bool declaredExceptionMethod(1: bool shouldThrow) throws (1: ExceptionWithAMap xwamap); +} + +service Inherited extends Srv { + i32 identity(1: i32 arg) +} + +service EmptyService {} + +// The only purpose of this thing is to increase the size of the generated code +// so that ZlibTest has more highly compressible data to play with. +struct BlowUp { + 1: map(python.immutable = ""),set (python.immutable = "")>> b1; + 2: map(python.immutable = ""),set (python.immutable = "")>> b2; + 3: map(python.immutable = ""),set (python.immutable = "")>> b3; + 4: map(python.immutable = ""),set (python.immutable = "")>> b4; +} + + +struct ReverseOrderStruct { + 4: string first; + 3: i16 second; + 2: i32 third; + 1: i64 fourth; +} + +service ReverseOrderService { + void myMethod(4: string first, 3: i16 second, 2: i32 third, 1: i64 fourth); +} + +enum SomeEnum { + ONE = 1 + TWO = 2 +} + +/** This is a docstring on a constant! */ +const SomeEnum MY_SOME_ENUM = SomeEnum.ONE + +const SomeEnum MY_SOME_ENUM_1 = 1 +/*const SomeEnum MY_SOME_ENUM_2 = 7*/ + +const map MY_ENUM_MAP = { + SomeEnum.ONE : SomeEnum.TWO +} + +struct StructWithSomeEnum { + 1: SomeEnum blah; +} + +const map EXTRA_CRAZY_MAP = { + SomeEnum.ONE : {"blah" : SomeEnum.TWO} +} + +union TestUnion { + /** + * A doc string + */ + 1: string string_field; + 2: i32 i32_field; + 3: OneOfEach struct_field; + 4: list struct_list; + 5: i32 other_i32_field; + 6: SomeEnum enum_field; + 7: set i32_set; + 8: map i32_map; +} + +union TestUnionMinusStringField { + 2: i32 i32_field; + 3: OneOfEach struct_field; + 4: list struct_list; + 5: i32 other_i32_field; + 6: SomeEnum enum_field; + 7: set i32_set; + 8: map i32_map; +} + +union ComparableUnion { + 1: string string_field; + 2: binary binary_field; +} + +struct StructWithAUnion { + 1: TestUnion test_union; +} + +struct PrimitiveThenStruct { + 1: i32 blah; + 2: i32 blah2; + 3: Backwards bw; +} + +typedef map SomeMap + +struct StructWithASomemap { + 1: required SomeMap somemap_field; +} + +struct BigFieldIdStruct { + 1: string field1; + 45: string field2; +} + +struct BreaksRubyCompactProtocol { + 1: string field1; + 2: BigFieldIdStruct field2; + 3: i32 field3; +} + +struct TupleProtocolTestStruct { + optional i32 field1; + optional i32 field2; + optional i32 field3; + optional i32 field4; + optional i32 field5; + optional i32 field6; + optional i32 field7; + optional i32 field8; + optional i32 field9; + optional i32 field10; + optional i32 field11; + optional i32 field12; +} + +struct ListDoublePerf { + 1: list field; +} diff --git a/test/DenseLinkingTest.thrift b/test/DenseLinkingTest.thrift new file mode 100644 index 0000000..3a5b957 --- /dev/null +++ b/test/DenseLinkingTest.thrift @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* +../compiler/cpp/thrift -gen cpp:dense DebugProtoTest.thrift +../compiler/cpp/thrift -gen cpp:dense DenseLinkingTest.thrift +g++ -Wall -g -I../lib/cpp/src -I/usr/local/include/boost-1_33_1 \ + DebugProtoTest.cpp gen-cpp/DebugProtoTest_types.cpp \ + gen-cpp/DenseLinkingTest_types.cpp \ + ../lib/cpp/.libs/libthrift.a -o DebugProtoTest +./DebugProtoTest +*/ + +/* +The idea of this test is that everything is structurally identical to DebugProtoTest. +If I messed up the naming of the reflection local typespecs, +then compiling this should give errors because of doubly defined symbols. +*/ + +namespace cpp thrift.test +namespace java thrift.test + +struct OneOfEachZZ { + 1: bool im_true, + 2: bool im_false, + 3: byte a_bite, + 4: i16 integer16, + 5: i32 integer32, + 6: i64 integer64, + 7: double double_precision, + 8: string some_characters, + 9: string zomg_unicode, + 10: bool what_who, +} + +struct BonkZZ { + 1: i32 type, + 2: string message, +} + +struct NestingZZ { + 1: BonkZZ my_bonk, + 2: OneOfEachZZ my_ooe, +} + +struct HolyMoleyZZ { + 1: list big, + 2: set> contain, + 3: map> bonks, +} + +struct BackwardsZZ { + 2: i32 first_tag2, + 1: i32 second_tag1, +} + +struct EmptyZZ { +} + +struct WrapperZZ { + 1: EmptyZZ foo +} + +struct RandomStuffZZ { + 1: i32 a, + 2: i32 b, + 3: i32 c, + 4: i32 d, + 5: list myintlist, + 6: map maps, + 7: i64 bigint, + 8: double triple, +} + +service Srv { + i32 Janky(1: i32 arg) +} + +service UnderscoreSrv { + i64 some_rpc_call(1: string message) +} + diff --git a/test/DocTest.thrift b/test/DocTest.thrift new file mode 100644 index 0000000..d702b2c --- /dev/null +++ b/test/DocTest.thrift @@ -0,0 +1,287 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Program doctext. + * + * Seriously, this is the documentation for this whole program. + */ + +namespace java thrift.test +namespace cpp thrift.test + +// C++ comment +/* c style comment */ + +# the new unix comment + +/** Some doc text goes here. Wow I am [nesting these] (no more nesting.) */ +enum Numberz +{ + + /** This is how to document a parameter */ + ONE = 1, + + /** And this is a doc for a parameter that has no specific value assigned */ + TWO, + + THREE, + FIVE = 5, + SIX, + EIGHT = 8 +} + +/** This is how you would do a typedef doc */ +typedef i64 UserId + +/** And this is where you would document a struct */ +struct Xtruct +{ + + /** And the members of a struct */ + 1: string string_thing + + /** doct text goes before a comma */ + 4: i8 byte_thing, + + 9: i32 i32_thing, + 11: i64 i64_thing +} + +/** + * You can document constants now too. Yeehaw! + */ +const i32 INT32CONSTANT = 9853 +const i16 INT16CONSTANT = 1616 +/** Everyone get in on the docu-action! */ +const map MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} + +struct Xtruct2 +{ + 1: i8 byte_thing, + 2: Xtruct struct_thing, + 3: i32 i32_thing +} + +/** Struct insanity */ +struct Insanity +{ + + /** This is doc for field 1 */ + 1: map userMap, + + /** And this is doc for field 2 */ + 2: list xtructs +} + +exception Xception { + 1: i32 errorCode, + 2: string message +} + +exception Xception2 { + 1: i32 errorCode, + 2: Xtruct struct_thing +} + +/* C1 */ +/** Doc */ +/* C2 */ +/* C3 */ +struct EmptyStruct {} + +struct OneField { + 1: EmptyStruct field +} + +/** This is where you would document a Service */ +service ThriftTest +{ + + /** And this is how you would document functions in a service */ + void testVoid(), + string testString(1: string thing), + i8 testByte(1: byte thing), + i32 testI32(1: i32 thing), + + /** Like this one */ + i64 testI64(1: i64 thing), + double testDouble(1: double thing), + Xtruct testStruct(1: Xtruct thing), + Xtruct2 testNest(1: Xtruct2 thing), + map testMap(1: map thing), + set testSet(1: set thing), + list testList(1: list thing), + + /** This is an example of a function with params documented */ + Numberz testEnum( + + /** This param is a thing */ + 1: Numberz thing + + ), + + UserId testTypedef(1: UserId thing), + + map> testMapMap(1: i32 hello), + + /* So you think you've got this all worked, out eh? */ + map> testInsanity(1: Insanity argument), + +} + +/// This style of Doxy-comment doesn't work. +typedef i32 SorryNoGo + +/** + * This is a trivial example of a multiline docstring. + */ +typedef i32 TrivialMultiLine + +/** + * This is the canonical example + * of a multiline docstring. + */ +typedef i32 StandardMultiLine + +/** + * The last line is non-blank. + * I said non-blank! */ +typedef i32 LastLine + +/** Both the first line + * are non blank. ;-) + * and the last line */ +typedef i32 FirstAndLastLine + +/** + * INDENTED TITLE + * The text is less indented. + */ +typedef i32 IndentedTitle + +/** First line indented. + * Unfortunately, this does not get indented. + */ +typedef i32 FirstLineIndent + + +/** + * void code_in_comment() { + * printf("hooray code!"); + * } + */ +typedef i32 CodeInComment + + /** + * Indented Docstring. + * This whole docstring is indented. + * This line is indented further. + */ +typedef i32 IndentedDocstring + +/** Irregular docstring. + * We will have to punt + * on this thing */ +typedef i32 Irregular1 + +/** + * note the space + * before these lines +* but not this + * one + */ +typedef i32 Irregular2 + +/** +* Flush against +* the left. +*/ +typedef i32 Flush + +/** + No stars in this one. + It should still work fine, though. + Including indenting. + */ +typedef i32 NoStars + +/** Trailing whitespace +Sloppy trailing whitespace +is truncated. */ +typedef i32 TrailingWhitespace + +/** + * This is a big one. + * + * We'll have some blank lines in it. + * + * void as_well_as(some code) { + * puts("YEEHAW!"); + * } + */ +typedef i32 BigDog + +/** +* +* +*/ +typedef i32 TotallyDegenerate + +/**no room for newline here*/ + +/* * / */ +typedef i32 TestFor3501a + +/** + * / + */ +typedef i32 TestFor3501b + + +/* Comment-end tokens can of course have more than one asterisk */ +struct TestFor3709_00 { /* ? */ 1: i32 foo } +/* Comment-end tokens can of course have more than one asterisk **/ +struct TestFor3709_01 { /* ? */ 1: i32 foo } +/* Comment-end tokens can of course have more than one asterisk ***/ +struct TestFor3709_02 { /* ? */ 1: i32 foo } +/** Comment-end tokens can of course have more than one asterisk */ +struct TestFor3709_03 { /* ? */ 1: i32 foo } +/** Comment-end tokens can of course have more than one asterisk **/ +struct TestFor3709_04 { /* ? */ 1: i32 foo } +/** Comment-end tokens can of course have more than one asterisk ***/ +struct TestFor3709_05 { /* ? */ 1: i32 foo } +/*** Comment-end tokens can of course have more than one asterisk */ +struct TestFor3709_06 { /* ? */ 1: i32 foo } +/*** Comment-end tokens can of course have more than one asterisk **/ +struct TestFor3709_07 { /* ? */ 1: i32 foo } +/*** Comment-end tokens can of course have more than one asterisk ***/ +struct TestFor3709_08 { /* ? */ 1: i32 foo } + +struct TestFor3709 { + /** This is a comment */ + 1: required string id, + /** This is also a comment **/ + 2: required string typeId, + /** Yet another comment! */ + 3: required i32 endTimestamp +} + + +/* THE END */ diff --git a/test/EnumContainersTest.thrift b/test/EnumContainersTest.thrift new file mode 100644 index 0000000..3b6408f --- /dev/null +++ b/test/EnumContainersTest.thrift @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +namespace java thrift.test.enumcontainers + +enum GreekGodGoddess { + ARES, + APHRODITE, + ZEUS, + POSEIDON, + HERA, +} + +typedef GreekGodGoddess GreekGodGoddessType +typedef i32 Power + +struct GodBean { + 1: optional map power, + 2: optional set goddess, + 3: optional map byAlias, + 4: optional set images, +} + +const map ATTRIBUTES = +{ + GreekGodGoddess.ZEUS: "lightning bolt", + GreekGodGoddess.POSEIDON: "trident", +} + +const set BEAUTY = [ GreekGodGoddess.APHRODITE, GreekGodGoddess.HERA ] diff --git a/test/EnumTest.thrift b/test/EnumTest.thrift new file mode 100644 index 0000000..7961f38 --- /dev/null +++ b/test/EnumTest.thrift @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +namespace c_glib TTest + +enum MyEnum1 { + ME1_0 = 0, + ME1_1 = 1, + ME1_2, + ME1_3, + ME1_5 = 5, + ME1_6, +} + +enum MyEnum2 { + ME2_0, + ME2_1, + ME2_2, +} + +enum MyEnum2_again { + // enum value identifiers may appear again in another enum type + ME0_1, + ME1_1, + ME2_1, + ME3_1, +} + +enum MyEnum3 { + ME3_0, + ME3_1, + ME3_N2 = -2, + ME3_N1, + ME3_D0, + ME3_D1, + ME3_9 = 9, + ME3_10, +} + +enum MyEnum4 { + ME4_A = 0x7ffffffd + ME4_B + ME4_C + // attempting to define another enum value here fails + // with an overflow error, as we overflow values that can be + // represented with an i32. +} + +enum MyEnum5 { + e1 // fails with 0.9.3 and earlier + e2 = 42 // fails with 0.9.3 and earlier +} + +enum MyEnumWithCustomOstream { + custom1 = 1, + CustoM2 +} (cpp.customostream) + +struct MyStruct { + 1: MyEnum2 me2_2 = MyEnum1.ME2_2 + 2: MyEnum3 me3_n2 = MyEnum3.ME3_N2 + 3: MyEnum3 me3_d1 = MyEnum3.ME3_D1 +} + +struct EnumTestStruct { + 1: MyEnum3 a_enum; + 2: list enum_list; + 3: set enum_set; + 4: map enum_enum_map; + // collections as keys + 44: map (python.immutable = ""), MyEnum3> list_enum_map; + 45: map (python.immutable = ""), MyEnum3> set_enum_map; + 46: map (python.immutable = ""), MyEnum3> map_enum_map; + // collections as values + 47: map> enum_map_map; + 48: map> enum_set_map; + 49: map> enum_list_map; +} + +const EnumTestStruct ENUM_TEST = { + 'a_enum': MyEnum3.ME3_D1, + 'enum_list': [MyEnum3.ME3_D1, MyEnum3.ME3_0, MyEnum3.ME3_N2], + 'enum_set': [MyEnum3.ME3_D1, MyEnum3.ME3_N1], + 'enum_enum_map': {MyEnum3.ME3_D1: MyEnum3.ME3_0, MyEnum3.ME3_0: MyEnum3.ME3_D1}, + 'list_enum_map': {[MyEnum3.ME3_D1, MyEnum3.ME3_0]: MyEnum3.ME3_0, [MyEnum3.ME3_D1]: MyEnum3.ME3_0, [MyEnum3.ME3_0]: MyEnum3.ME3_D1}, + 'set_enum_map': {[MyEnum3.ME3_D1, MyEnum3.ME3_0]: MyEnum3.ME3_0, [MyEnum3.ME3_D1]: MyEnum3.ME3_0}, + 'map_enum_map': {{MyEnum3.ME3_N1: MyEnum3.ME3_10}: MyEnum3.ME3_1}, + 'enum_map_map': {MyEnum3.ME3_N1: {MyEnum3.ME3_D1: MyEnum3.ME3_D1}}, + 'enum_set_map': {MyEnum3.ME3_N2: [MyEnum3.ME3_D1, MyEnum3.ME3_N1], MyEnum3.ME3_10: [MyEnum3.ME3_D1, MyEnum3.ME3_N1]}, + 'enum_list_map': {MyEnum3.ME3_D1: [MyEnum3.ME3_10], MyEnum3.ME3_0: [MyEnum3.ME3_9, MyEnum3.ME3_10]}, +} + +service EnumTestService { + MyEnum3 testEnum(1: MyEnum3 enum1), + list testEnumList(1: list enum1), + set testEnumSet(1: set enum1), + map testEnumMap(1: map enum1), + EnumTestStruct testEnumStruct(1: EnumTestStruct enum1), +} diff --git a/test/FullCamelTest.thrift b/test/FullCamelTest.thrift new file mode 100644 index 0000000..cee4dd8 --- /dev/null +++ b/test/FullCamelTest.thrift @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +namespace java thrift.test.fullcamel + +struct OneOfEachZZ { + 1: bool im_true, + 2: bool im_false, + 3: byte a_bite, + 4: i16 integer16, + 5: i32 integer32, + 6: i64 integer64, + 7: double double_precision, + 8: string some_characters, + 9: string zomg_unicode, + 10: bool what_who, +} + +service UnderscoreSrv { + i64 some_rpc_call(1: string message) +} + diff --git a/test/Include.thrift b/test/Include.thrift new file mode 100644 index 0000000..562319b --- /dev/null +++ b/test/Include.thrift @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +include "ThriftTest.thrift" + +struct IncludeTest { + 1: required ThriftTest.Bools bools +} \ No newline at end of file diff --git a/test/JavaBeansTest.thrift b/test/JavaBeansTest.thrift new file mode 100644 index 0000000..b6c3ea8 --- /dev/null +++ b/test/JavaBeansTest.thrift @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +namespace java thrift.test + +struct OneOfEachBeans { + 1: bool boolean_field, + 2: byte a_bite, + 3: i16 integer16, + 4: i32 integer32, + 5: i64 integer64, + 6: double double_precision, + 7: string some_characters, + 8: binary base64, + 9: list byte_list, + 10: list i16_list, + 11: list i64_list +} + + +service Service { + i64 mymethod(i64 blah); +} \ No newline at end of file diff --git a/test/JavaDeepCopyTest.thrift b/test/JavaDeepCopyTest.thrift new file mode 100644 index 0000000..fc974ae --- /dev/null +++ b/test/JavaDeepCopyTest.thrift @@ -0,0 +1,19 @@ +include "JavaTypes.thrift" + +namespace java thrift.test + +struct DeepCopyFoo { + 1: optional list l, + 2: optional set s, + 3: optional map m, + 4: optional list li, + 5: optional set si, + 6: optional map mi, + 7: optional DeepCopyBar bar, +} + +struct DeepCopyBar { + 1: optional string a, + 2: optional i32 b, + 3: optional bool c, +} diff --git a/test/JavaTypes.thrift b/test/JavaTypes.thrift new file mode 100644 index 0000000..fcb0ab2 --- /dev/null +++ b/test/JavaTypes.thrift @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +namespace java thrift.test + +struct Integer { + 1: i32 val +} + +struct String { + 1: string val +} + +struct Boolean { + 1: bool val +} + +struct Double { + 1: double val +} + +struct Long { + 1: i64 val +} + +struct Byte { + 1: byte val +} + +struct Float { + 1: double val +} + +struct List { + 1: list vals +} + +struct ArrayList { + 1: list vals +} + +struct SortedMap { + 1: map vals +} + +struct TreeMap { + 1: map vals +} + +struct HashMap { + 1: map vals +} + +struct Map { + 1: map vals +} + +struct Object { + 1: Integer integer, + 2: String str, + 3: Boolean boolean_field, + 4: Double dbl, + 5: Byte bite, + 6: map intmap, + 7: Map somemap, +} + +exception Exception { + 1: string msg +} + +service AsyncNonblockingService { + Object mymethod( + 1: Integer integer, + 2: String str, + 3: Boolean boolean_field, + 4: Double dbl, + 5: Byte bite, + 6: map intmap, + 7: Map somemap, + ) throws (1:Exception ex); +} diff --git a/test/JsDeepConstructorTest.thrift b/test/JsDeepConstructorTest.thrift new file mode 100644 index 0000000..ef5126f --- /dev/null +++ b/test/JsDeepConstructorTest.thrift @@ -0,0 +1,18 @@ +struct Simple { + 1: string value +} + +struct Complex { + 1: Simple struct_field + 2: list struct_list_field + 3: set struct_set_field + 4: map struct_map_field + 5: list>>> struct_nested_containers_field + 6: map> > struct_nested_containers_field2 + 7: list> list_of_list_field + 8: list>> list_of_list_of_list_field +} + +struct ComplexList { + 1: list struct_list_field; +} diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100755 index 0000000..335bae6 --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,162 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +SUBDIRS = features +PRECROSS_TARGET = + +if WITH_C_GLIB +SUBDIRS += c_glib +PRECROSS_TARGET += precross-c_glib +endif + +if WITH_MONO +SUBDIRS += csharp +PRECROSS_TARGET += precross-csharp +endif + +if WITH_CPP +SUBDIRS += cpp +PRECROSS_TARGET += precross-cpp +endif + +if WITH_PERL +SUBDIRS += perl +PRECROSS_TARGET += precross-perl +endif + +if WITH_PHP +SUBDIRS += php +PRECROSS_TARGET += precross-php +endif + +if WITH_DART +SUBDIRS += dart +PRECROSS_TARGET += precross-dart +endif + +if WITH_PYTHON +SUBDIRS += py +PRECROSS_TARGET += precross-py +SUBDIRS += py.tornado +if WITH_TWISTED_TEST +SUBDIRS += py.twisted +endif +endif + +if WITH_RUBY +SUBDIRS += rb +PRECROSS_TARGET += precross-rb +endif + +if WITH_HASKELL +SUBDIRS += hs +endif + +if WITH_HAXE +SUBDIRS += haxe +endif + +if WITH_DOTNETCORE +SUBDIRS += netcore +endif + +if WITH_GO +SUBDIRS += go +PRECROSS_TARGET += precross-go +endif + +if WITH_ERLANG +SUBDIRS += erl +PRECROSS_TARGET += precross-erl +endif + +if WITH_LUA +SUBDIRS += lua +PRECROSS_TARGET += precross-lua +endif + +if WITH_RS +SUBDIRS += rs +PRECROSS_TARGET += precross-rs +endif + +# +# generate html for ThriftTest.thrift +# +check-local: + $(top_builddir)/compiler/cpp/thrift --gen html -r $(top_srcdir)/test/ThriftTest.thrift + +clean-local: + rm -rf $(top_srcdir)/test/gen-html + +EXTRA_DIST = \ + audit \ + crossrunner \ + keys \ + c_glib \ + cpp \ + dart \ + erl \ + hs \ + lua \ + ocaml \ + perl \ + php \ + py \ + py.twisted \ + py.tornado \ + rb \ + rs \ + threads \ + AnnotationTest.thrift \ + BrokenConstants.thrift \ + ConstantsDemo.thrift \ + DebugProtoTest.thrift \ + DenseLinkingTest.thrift \ + DocTest.thrift \ + EnumTest.thrift \ + FullCamelTest.thrift \ + Include.thrift \ + JavaBeansTest.thrift \ + JavaDeepCopyTest.thrift \ + JavaTypes.thrift \ + JsDeepConstructorTest.thrift \ + ManyOptionals.thrift \ + ManyTypedefs.thrift \ + NameConflictTest.thrift \ + OptionalRequiredTest.thrift \ + Recursive.thrift \ + ReuseObjects.thrift \ + EnumContainersTest.thrift \ + SmallTest.thrift \ + StressTest.thrift \ + ThriftTest.thrift \ + TypedefTest.thrift \ + known_failures_Linux.json \ + test.py \ + tests.json \ + rebuild_known_failures.sh \ + result.js \ + index.html \ + README.md \ + valgrind.suppress + +precross-%: + $(MAKE) -C $* precross +precross: $(PRECROSS_TARGET) diff --git a/test/Makefile.in b/test/Makefile.in new file mode 100644 index 0000000..e34f9b9 --- /dev/null +++ b/test/Makefile.in @@ -0,0 +1,908 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@WITH_C_GLIB_TRUE@am__append_1 = c_glib +@WITH_C_GLIB_TRUE@am__append_2 = precross-c_glib +@WITH_MONO_TRUE@am__append_3 = csharp +@WITH_MONO_TRUE@am__append_4 = precross-csharp +@WITH_CPP_TRUE@am__append_5 = cpp +@WITH_CPP_TRUE@am__append_6 = precross-cpp +@WITH_PERL_TRUE@am__append_7 = perl +@WITH_PERL_TRUE@am__append_8 = precross-perl +@WITH_PHP_TRUE@am__append_9 = php +@WITH_PHP_TRUE@am__append_10 = precross-php +@WITH_DART_TRUE@am__append_11 = dart +@WITH_DART_TRUE@am__append_12 = precross-dart +@WITH_PYTHON_TRUE@am__append_13 = py py.tornado +@WITH_PYTHON_TRUE@am__append_14 = precross-py +@WITH_PYTHON_TRUE@@WITH_TWISTED_TEST_TRUE@am__append_15 = py.twisted +@WITH_RUBY_TRUE@am__append_16 = rb +@WITH_RUBY_TRUE@am__append_17 = precross-rb +@WITH_HASKELL_TRUE@am__append_18 = hs +@WITH_HAXE_TRUE@am__append_19 = haxe +@WITH_DOTNETCORE_TRUE@am__append_20 = netcore +@WITH_GO_TRUE@am__append_21 = go +@WITH_GO_TRUE@am__append_22 = precross-go +@WITH_ERLANG_TRUE@am__append_23 = erl +@WITH_ERLANG_TRUE@am__append_24 = precross-erl +@WITH_LUA_TRUE@am__append_25 = lua +@WITH_LUA_TRUE@am__append_26 = precross-lua +@WITH_RS_TRUE@am__append_27 = rs +@WITH_RS_TRUE@am__append_28 = precross-rs +subdir = test +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = features c_glib csharp cpp perl php dart py py.tornado \ + py.twisted rb hs haxe netcore go erl lua rs +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = features $(am__append_1) $(am__append_3) $(am__append_5) \ + $(am__append_7) $(am__append_9) $(am__append_11) \ + $(am__append_13) $(am__append_15) $(am__append_16) \ + $(am__append_18) $(am__append_19) $(am__append_20) \ + $(am__append_21) $(am__append_23) $(am__append_25) \ + $(am__append_27) +PRECROSS_TARGET = $(am__append_2) $(am__append_4) $(am__append_6) \ + $(am__append_8) $(am__append_10) $(am__append_12) \ + $(am__append_14) $(am__append_17) $(am__append_22) \ + $(am__append_24) $(am__append_26) $(am__append_28) +EXTRA_DIST = \ + audit \ + crossrunner \ + keys \ + c_glib \ + cpp \ + dart \ + erl \ + hs \ + lua \ + ocaml \ + perl \ + php \ + py \ + py.twisted \ + py.tornado \ + rb \ + rs \ + threads \ + AnnotationTest.thrift \ + BrokenConstants.thrift \ + ConstantsDemo.thrift \ + DebugProtoTest.thrift \ + DenseLinkingTest.thrift \ + DocTest.thrift \ + EnumTest.thrift \ + FullCamelTest.thrift \ + Include.thrift \ + JavaBeansTest.thrift \ + JavaDeepCopyTest.thrift \ + JavaTypes.thrift \ + JsDeepConstructorTest.thrift \ + ManyOptionals.thrift \ + ManyTypedefs.thrift \ + NameConflictTest.thrift \ + OptionalRequiredTest.thrift \ + Recursive.thrift \ + ReuseObjects.thrift \ + EnumContainersTest.thrift \ + SmallTest.thrift \ + StressTest.thrift \ + ThriftTest.thrift \ + TypedefTest.thrift \ + known_failures_Linux.json \ + test.py \ + tests.json \ + rebuild_known_failures.sh \ + result.js \ + index.html \ + README.md \ + valgrind.suppress + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +style: style-recursive + +style-am: style-local + +uninstall-am: + +.MAKE: $(am__recursive_targets) check-am install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am check-local clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags ctags-am distclean \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# +# generate html for ThriftTest.thrift +# +check-local: + $(top_builddir)/compiler/cpp/thrift --gen html -r $(top_srcdir)/test/ThriftTest.thrift + +clean-local: + rm -rf $(top_srcdir)/test/gen-html + +precross-%: + $(MAKE) -C $* precross +precross: $(PRECROSS_TARGET) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/ManyOptionals.thrift b/test/ManyOptionals.thrift new file mode 100644 index 0000000..3fb1d68 --- /dev/null +++ b/test/ManyOptionals.thrift @@ -0,0 +1,231 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// The java codegenerator has a few different codepaths depending +// on how many optionals the struct has; this attempts to exercise +// them. + +namespace java thrift.test + +struct Opt4 { + 1: i32 def1; + 2: i32 def2; + 3: i32 def3; + 4: i32 def4; +} + +struct Opt13 { + 1: i32 def1; + 2: i32 def2; + 3: i32 def3; + 4: i32 def4; + 5: i32 def5; + 6: i32 def6; + 7: i32 def7; + 8: i32 def8; + 9: i32 def9; + 10: i32 def10; + 11: i32 def11; + 12: i32 def12; + 13: i32 def13; +} + +struct Opt30 { + 1: i32 def1; + 2: i32 def2; + 3: i32 def3; + 4: i32 def4; + 5: i32 def5; + 6: i32 def6; + 7: i32 def7; + 8: i32 def8; + 9: i32 def9; + 10: i32 def10; + 11: i32 def11; + 12: i32 def12; + 13: i32 def13; + 14: i32 def14; + 15: i32 def15; + 16: i32 def16; + 17: i32 def17; + 18: i32 def18; + 19: i32 def19; + 20: i32 def20; + 21: i32 def21; + 22: i32 def22; + 23: i32 def23; + 24: i32 def24; + 25: i32 def25; + 26: i32 def26; + 27: i32 def27; + 28: i32 def28; + 29: i32 def29; + 30: i32 def30; +} + +struct Opt64 { + 1: i32 def1; + 2: i32 def2; + 3: i32 def3; + 4: i32 def4; + 5: i32 def5; + 6: i32 def6; + 7: i32 def7; + 8: i32 def8; + 9: i32 def9; + 10: i32 def10; + 11: i32 def11; + 12: i32 def12; + 13: i32 def13; + 14: i32 def14; + 15: i32 def15; + 16: i32 def16; + 17: i32 def17; + 18: i32 def18; + 19: i32 def19; + 20: i32 def20; + 21: i32 def21; + 22: i32 def22; + 23: i32 def23; + 24: i32 def24; + 25: i32 def25; + 26: i32 def26; + 27: i32 def27; + 28: i32 def28; + 29: i32 def29; + 30: i32 def30; + 31: i32 def31; + 32: i32 def32; + 33: i32 def33; + 34: i32 def34; + 35: i32 def35; + 36: i32 def36; + 37: i32 def37; + 38: i32 def38; + 39: i32 def39; + 40: i32 def40; + 41: i32 def41; + 42: i32 def42; + 43: i32 def43; + 44: i32 def44; + 45: i32 def45; + 46: i32 def46; + 47: i32 def47; + 48: i32 def48; + 49: i32 def49; + 50: i32 def50; + 51: i32 def51; + 52: i32 def52; + 53: i32 def53; + 54: i32 def54; + 55: i32 def55; + 56: i32 def56; + 57: i32 def57; + 58: i32 def58; + 59: i32 def59; + 60: i32 def60; + 61: i32 def61; + 62: i32 def62; + 63: i32 def63; + 64: i32 def64; +} + +struct Opt80 { + 1: i32 def1; + 2: i32 def2; + 3: i32 def3; + 4: i32 def4; + 5: i32 def5; + 6: i32 def6; + 7: i32 def7; + 8: i32 def8; + 9: i32 def9; + 10: i32 def10; + 11: i32 def11; + 12: i32 def12; + 13: i32 def13; + 14: i32 def14; + 15: i32 def15; + 16: i32 def16; + 17: i32 def17; + 18: i32 def18; + 19: i32 def19; + 20: i32 def20; + 21: i32 def21; + 22: i32 def22; + 23: i32 def23; + 24: i32 def24; + 25: i32 def25; + 26: i32 def26; + 27: i32 def27; + 28: i32 def28; + 29: i32 def29; + 30: i32 def30; + 31: i32 def31; + 32: i32 def32; + 33: i32 def33; + 34: i32 def34; + 35: i32 def35; + 36: i32 def36; + 37: i32 def37; + 38: i32 def38; + 39: i32 def39; + 40: i32 def40; + 41: i32 def41; + 42: i32 def42; + 43: i32 def43; + 44: i32 def44; + 45: i32 def45; + 46: i32 def46; + 47: i32 def47; + 48: i32 def48; + 49: i32 def49; + 50: i32 def50; + 51: i32 def51; + 52: i32 def52; + 53: i32 def53; + 54: i32 def54; + 55: i32 def55; + 56: i32 def56; + 57: i32 def57; + 58: i32 def58; + 59: i32 def59; + 60: i32 def60; + 61: i32 def61; + 62: i32 def62; + 63: i32 def63; + 64: i32 def64; + 65: i32 def65; + 66: i32 def66; + 67: i32 def67; + 68: i32 def68; + 69: i32 def69; + 70: i32 def70; + 71: i32 def71; + 72: i32 def72; + 73: i32 def73; + 74: i32 def74; + 75: i32 def75; + 76: i32 def76; + 77: i32 def77; + 78: i32 def78; + 79: i32 def79; + 80: i32 def80; +} + diff --git a/test/ManyTypedefs.thrift b/test/ManyTypedefs.thrift new file mode 100644 index 0000000..d194b63 --- /dev/null +++ b/test/ManyTypedefs.thrift @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// This is to make sure you don't mess something up when you change typedef code. +// Generate it with the old and new thrift and make sure they are the same. +/* +rm -rf gen-* orig-* +mkdir old new +thrift --gen cpp --gen java --gen php --gen phpi --gen py --gen rb --gen xsd --gen perl --gen ocaml --gen erl --gen hs --strict ManyTypedefs.thrift +mv gen-* old +../compiler/cpp/thrift --gen cpp --gen java --gen php --gen phpi --gen py --gen rb --gen xsd --gen perl --gen ocaml --gen erl --gen hs --strict ManyTypedefs.thrift +mv gen-* new +diff -ur old new +rm -rf old new +# There should be no output. +*/ + +typedef i32 int32 +typedef list> biglist + +struct struct1 { + 1: int32 myint; + 2: biglist mylist; +} + +exception exception1 { + 1: biglist alist; + 2: struct1 mystruct; +} + +service AService { + struct1 method1(1: int32 myint) throws (1: exception1 exn); + biglist method2(); +} diff --git a/test/NameConflictTest.thrift b/test/NameConflictTest.thrift new file mode 100644 index 0000000..d3efb47 --- /dev/null +++ b/test/NameConflictTest.thrift @@ -0,0 +1,110 @@ +// Naming testcases, sepcifically for these tickets (but not limited to them) +// THRIFT-2508 Uncompileable C# code due to language keywords in IDL +// THRIFT-2557 error CS0542 member names cannot be the same as their enclosing type + + +struct using { + 1: double single + 2: double integer +} + +struct delegate { + 1: string partial + 2: delegate delegate +} + +struct get { + 1: bool sbyte +} + +struct partial { + 1: using using + 2: bool read + 3: bool write +} + +enum Maybe { + JUST = 1, + TRUE = 2, + FALSE = 3 +} + +enum Either { + LEFT = 1, + RIGHT = 2 +} + +struct foldr { + 1: string id +} + +struct of { + 1: string let + 2: string where +} + +struct ofOf { + 1: of Of +} + + +struct ClassAndProp { + 1: bool ClassAndProp + 2: bool ClassAndProp_ + 3: bool ClassAndProp__ + 4: bool ClassAndProper +} + +struct second_chance { + 1: bool SECOND_CHANCE + 2: bool SECOND_CHANCE_ + 3: bool SECOND_CHANCE__ + 4: bool SECOND_CHANCES +} + +struct NOW_EAT_THIS { + 1: bool now_eat_this + 2: bool now_eat_this_ + 3: bool now_eat_this__ + 4: bool now_eat_this_and_this +} + +struct TheEdgeCase { + 1: bool theEdgeCase + 2: bool theEdgeCase_ + 3: bool theEdgeCase__ + 4: bool TheEdgeCase + 5: bool TheEdgeCase_ + 6: bool TheEdgeCase__ +} + +struct Tricky_ { + 1: bool tricky + 2: bool Tricky +} + +struct Nested { + 1: ClassAndProp ClassAndProp + 2: second_chance second_chance + 3: NOW_EAT_THIS NOW_EAT_THIS + 4: TheEdgeCase TheEdgeCase + 5: Tricky_ Tricky_ + 6: Nested Nested +} + +exception Problem_ { + 1: bool problem + 2: bool Problem +} + + +service extern { + delegate event(1: partial get) + void Foo(1: Nested Foo_args) throws (1: Problem_ Foo_result) +} + +service qualified { + Maybe maybe(1: Maybe foldr) + Either either(1: foldr of) +} +// eof diff --git a/test/OptionalRequiredTest.thrift b/test/OptionalRequiredTest.thrift new file mode 100644 index 0000000..a608898 --- /dev/null +++ b/test/OptionalRequiredTest.thrift @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +namespace c_glib TTest +namespace cpp thrift.test +namespace java thrift.test + +struct OldSchool { + 1: i16 im_int; + 2: string im_str; + 3: list> im_big; +} + +struct Simple { + 1: /* :) */ i16 im_default; + 2: required i16 im_required; + 3: optional i16 im_optional; +} + +struct Tricky1 { + 1: /* :) */ i16 im_default; +} + +struct Tricky2 { + 1: optional i16 im_optional; +} + +struct Tricky3 { + 1: required i16 im_required; +} + +struct OptionalDefault { + 1: optional i16 opt_int = 1234; + 2: optional string opt_str = "default"; +} + +struct Complex { + 1: i16 cp_default; + 2: required i16 cp_required; + 3: optional i16 cp_optional; + 4: map the_map; + 5: required Simple req_simp; + 6: optional Simple opt_simp; +} + +struct ManyOpt { + 1: optional i32 opt1; + 2: optional i32 opt2; + 3: optional i32 opt3; + 4: i32 def4; + 5: optional i32 opt5; + 6: optional i32 opt6; +} + +struct JavaTestHelper { + 1: required i32 req_int; + 2: optional i32 opt_int; + 3: required string req_obj; + 4: optional string opt_obj; + 5: required binary req_bin; + 6: optional binary opt_bin; +} + +struct Binaries { + 4: binary bin; + 5: required binary req_bin; + 6: optional binary opt_bin; +} diff --git a/test/README.md b/test/README.md new file mode 100755 index 0000000..0682f5d --- /dev/null +++ b/test/README.md @@ -0,0 +1,185 @@ +# Apache Thrift - integration test suite + +This is the cross everything integration test suite for Apache Thrift. + +## Run + +### A. Using Make + +The test can be executed by: + + make cross + +This starts the [test.py](test.py) script which does the real cross test with +different transports, protocols and languages. + +Note that this skips any language that is not built locally. It also skips +tests that are known to be failing. If you need more control over which tests +to run, read following section. + +### B. Using test script directly + +Alternatively, you can invoke [test.py](test.py) directly. You need to run`make +precross` once before executing it for the first time. + +For example, if you changed something in `nodejs` library and need to verify +the patch, you can skip everything except `nodejs` itself and some reference +implementation (currently `cpp` and `java` are recommended) like this: + + ./configure --without-c_glib -without-csharp --without-erlang --without-lua ... + make precross -j8 + test/test.py --server cpp,java --client nodejs + test/test.py --server nodejs --client cpp,java + +Another useful flag is --regex. For example, to run all tests that involve +Java TBinaryProtocol: + + test/test.py --regex "java.*binary" + +## Test case definition file + +The cross test cases are defined in [tests.json](tests.json). +The root element is collection of test target definitions. +Each test target definition looks like this: + + { + "name": "somelib", + + "client": { + "command": ["somelib_client_executable"], + "workdir": "somelib/bin", + "protocols": ["binary"], + "transports": ["buffered"], + "sockets": ["ip"], + }, + "server": { + "command": ["somelib_server_executable"], + "workdir": "somelib/bin", + "protocols": ["binary"], + "transports": ["buffered"], + "sockets": ["ip", "ip-ssl"], + } + } + +Either client or server definition or both should be present. + +Parameters that are common to both `client` and `server` can be put to target +definition root: + + { + "name": "somelib", + + "workdir": "somelib/bin", + "protocols": ["binary"], + "transports": ["buffered"], + "sockets": ["ip"], + + "client": { "command": ["somelib_client_executable"] }, + "server": { + "command": ["somelib_server_executable"], + "sockets": ["ip-ssl"] + } + } + +For the complete list of supported keys and their effect, see source code +comment at the opt of [crossrunner/collect.py](crossrunner/collect.py). + + +## List of known failures + +Since many cross tests currently fail (mainly due to partial incompatibility +around exception handling), the test script specifically report for "not known +before" failures. + +For this purpose, test cases known to (occasionally) fail are listed in +`known_failures_.json` where `` matches with python +`platform.system()` string. + +Currently, only Linux version is included. + +FYI, the file is initially generated by + + test/test.py --update-expected-failures=overwrite + +after a full test run, then repeatedly + + test/test.py --skip-known-failures + test/test.py --update-expected-failures=merge + +to update the known failures, run + + make fail + +## Test executable specification + +### Command line parameters + +Unit tests for languages are usually located under lib//test/ +cross language tests according to [ThriftTest.thrift](ThriftTest.thrift) shall be +provided for every language including executables with the following command +line interface: + +**Server command line interface:** + + $ ./cpp/TestServer -h + Allowed options: + -h [ --help ] produce help message + --port arg (=9090) Port number to listen + --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift) + --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe) + --server-type arg (=simple) type of server, "simple", "thread-pool", + "threaded", or "nonblocking" + --transport arg (=buffered) transport: buffered, framed, http, anonpipe + --protocol arg (=binary) protocol: binary, compact, json + --ssl Encrypted Transport using SSL + --processor-events processor-events + -n [ --workers ] arg (=4) Number of thread pools workers. Only valid for + thread-pool server type + +**Client command line interface:** + + $ ./cpp/TestClient -h + Allowed options: + -h [ --help ] produce help message + --host arg (=localhost) Host to connect + --port arg (=9090) Port number to connect + --domain-socket arg Domain Socket (e.g. /tmp/ThriftTest.thrift), + instead of host and port + --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe) + --anon-pipes hRead hWrite Windows Anonymous Pipes pair (handles) + --transport arg (=buffered) Transport: buffered, framed, http, evhttp + --protocol arg (=binary) Protocol: binary, compact, json + --ssl Encrypted Transport using SSL + -n [ --testloops ] arg (=1) Number of Tests + -t [ --threads ] arg (=1) Number of Test threads + +If you have executed the **make check** or **make cross** then you will be able to browse +[gen-html/ThriftTest.html](gen-html/ThriftTest.html) with the test documentation. + +### Return code + +The return code (exit code) shall be 0 on success, or an integer in the range 1 - 255 on errors. +In order to signal failed tests, the return code shall be composed from these bits to indicate +failing tests: + + #define TEST_BASETYPES 1 // 0000 0001 + #define TEST_STRUCTS 2 // 0000 0010 + #define TEST_CONTAINERS 4 // 0000 0100 + #define TEST_EXCEPTIONS 8 // 0000 1000 + #define TEST_UNKNOWN 64 // 0100 0000 (Failed to prepare environemt etc.) + #define TEST_TIMEOUT 128 // 1000 0000 + #define TEST_NOTUSED 48 // 0011 0000 (reserved bits) + +Tests that have not been executed at all count as errors. + +**Example:** + +During tests, the test client notices that some of the Struct tests fail. +Furthermore, due to some other problem none of the Exception tests is executed. +Therefore, the test client returns the code `10 = 2 | 8`, indicating the failure +of both test 2 (TEST_STRUCTS) and test 8 (TEST_EXCEPTIONS). + + +## SSL +Test Keys and Certificates are provided in multiple formats under the following +directory [test/keys](keys) diff --git a/test/Recursive.thrift b/test/Recursive.thrift new file mode 100644 index 0000000..c982582 --- /dev/null +++ b/test/Recursive.thrift @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +struct RecTree { + 1: list children + 2: i16 item +} + +struct RecList { + 1: RecList & nextitem + 3: i16 item +} + +struct CoRec { + 1: CoRec2 & other +} + +struct CoRec2 { + 1: CoRec other +} + +struct VectorTest { + 1: list lister; +} + +service TestService +{ + RecTree echoTree(1:RecTree tree) + RecList echoList(1:RecList lst) + CoRec echoCoRec(1:CoRec item) +} diff --git a/test/ReuseObjects.thrift b/test/ReuseObjects.thrift new file mode 100644 index 0000000..2dd6c6e --- /dev/null +++ b/test/ReuseObjects.thrift @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// The java codegenerator has option to reuse objects for deserialization + +namespace java thrift.test + +include "ThriftTest.thrift" + +struct Reuse { + 1: i32 val1; + 2: set val2; +} + diff --git a/test/SmallTest.thrift b/test/SmallTest.thrift new file mode 100644 index 0000000..d0821c7 --- /dev/null +++ b/test/SmallTest.thrift @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +namespace rb TestNamespace + +struct Goodbyez { + 1: i32 val = 325; +} + +senum Thinger { + "ASDFKJ", + "r32)*F#@", + "ASDFLJASDF" +} + +struct BoolPasser { + 1: bool value = 1 +} + +struct Hello { + 1: i32 simple = 53, + 2: map complex = {23:532, 6243:632, 2355:532}, + 3: map> complexer, + 4: string words = "words", + 5: Goodbyez thinz = {'val' : 36632} +} + +const map> CMAP = { 235: {235:235}, 53:{53:53} } +const i32 CINT = 325; +const Hello WHOA = {'simple' : 532} + +exception Goodbye { + 1: i32 simple, + 2: map complex, + 3: map> complexer, +} + +service SmallService { + Thinger testThinger(1:Thinger bootz), + Hello testMe(1:i32 hello=64, 2: Hello wonk) throws (1: Goodbye g), + void testVoid() throws (1: Goodbye g), + i32 testI32(1:i32 boo) +} diff --git a/test/StressTest.thrift b/test/StressTest.thrift new file mode 100644 index 0000000..431811b --- /dev/null +++ b/test/StressTest.thrift @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +namespace cpp test.stress +namespace d thrift.test.stress +namespace go stress + +service Service { + + void echoVoid(), + i8 echoByte(1: i8 arg), + i32 echoI32(1: i32 arg), + i64 echoI64(1: i64 arg), + string echoString(1: string arg), + list echoList(1: list arg), + set echoSet(1: set arg), + map echoMap(1: map arg), +} + diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift new file mode 100644 index 0000000..24dcbb9 --- /dev/null +++ b/test/ThriftTest.thrift @@ -0,0 +1,411 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +namespace c_glib TTest +namespace java thrift.test +namespace cpp thrift.test +namespace rb Thrift.Test +namespace perl ThriftTest +namespace csharp Thrift.Test +namespace js ThriftTest +namespace st ThriftTest +namespace py ThriftTest +namespace py.twisted ThriftTest +namespace go thrifttest +namespace php ThriftTest +namespace delphi Thrift.Test +namespace cocoa ThriftTest +namespace lua ThriftTest +namespace xsd test (uri = 'http://thrift.apache.org/ns/ThriftTest') +namespace netcore ThriftAsync.Test + +// Presence of namespaces and sub-namespaces for which there is +// no generator should compile with warnings only +namespace noexist ThriftTest +namespace cpp.noexist ThriftTest + +namespace * thrift.test + +/** + * Docstring! + */ +enum Numberz +{ + ONE = 1, + TWO, + THREE, + FIVE = 5, + SIX, + EIGHT = 8 +} + +const Numberz myNumberz = Numberz.ONE; +// the following is expected to fail: +// const Numberz urNumberz = ONE; + +typedef i64 UserId + +struct Bonk +{ + 1: string message, + 2: i32 type +} + +typedef map MapType + +struct Bools { + 1: bool im_true, + 2: bool im_false, +} + +struct Xtruct +{ + 1: string string_thing, + 4: i8 byte_thing, + 9: i32 i32_thing, + 11: i64 i64_thing +} + +struct Xtruct2 +{ + 1: i8 byte_thing, // used to be byte, hence the name + 2: Xtruct struct_thing, + 3: i32 i32_thing +} + +struct Xtruct3 +{ + 1: string string_thing, + 4: i32 changed, + 9: i32 i32_thing, + 11: i64 i64_thing +} + + +struct Insanity +{ + 1: map userMap, + 2: list xtructs +} (python.immutable= "") + +struct CrazyNesting { + 1: string string_field, + 2: optional set set_field, + // Do not insert line break as test/go/Makefile.am is removing this line with pattern match + 3: required list (python.immutable = ""), map(python.immutable = "")> (python.immutable = "")>>>> list_field, + 4: binary binary_field +} + +union SomeUnion { + 1: map map_thing, + 2: string string_thing, + 3: i32 i32_thing, + 4: Xtruct3 xtruct_thing, + 5: Insanity insanity_thing +} + +exception Xception { + 1: i32 errorCode, + 2: string message +} + +exception Xception2 { + 1: i32 errorCode, + 2: Xtruct struct_thing +} + +struct EmptyStruct {} + +struct OneField { + 1: EmptyStruct field +} + +service ThriftTest +{ + /** + * Prints "testVoid()" and returns nothing. + */ + void testVoid(), + + /** + * Prints 'testString("%s")' with thing as '%s' + * @param string thing - the string to print + * @return string - returns the string 'thing' + */ + string testString(1: string thing), + + /** + * Prints 'testBool("%s")' where '%s' with thing as 'true' or 'false' + * @param bool thing - the bool data to print + * @return bool - returns the bool 'thing' + */ + bool testBool(1: bool thing), + + /** + * Prints 'testByte("%d")' with thing as '%d' + * The types i8 and byte are synonyms, use of i8 is encouraged, byte still exists for the sake of compatibility. + * @param byte thing - the i8/byte to print + * @return i8 - returns the i8/byte 'thing' + */ + i8 testByte(1: i8 thing), + + /** + * Prints 'testI32("%d")' with thing as '%d' + * @param i32 thing - the i32 to print + * @return i32 - returns the i32 'thing' + */ + i32 testI32(1: i32 thing), + + /** + * Prints 'testI64("%d")' with thing as '%d' + * @param i64 thing - the i64 to print + * @return i64 - returns the i64 'thing' + */ + i64 testI64(1: i64 thing), + + /** + * Prints 'testDouble("%f")' with thing as '%f' + * @param double thing - the double to print + * @return double - returns the double 'thing' + */ + double testDouble(1: double thing), + + /** + * Prints 'testBinary("%s")' where '%s' is a hex-formatted string of thing's data + * @param binary thing - the binary data to print + * @return binary - returns the binary 'thing' + */ + binary testBinary(1: binary thing), + + /** + * Prints 'testStruct("{%s}")' where thing has been formatted into a string of comma separated values + * @param Xtruct thing - the Xtruct to print + * @return Xtruct - returns the Xtruct 'thing' + */ + Xtruct testStruct(1: Xtruct thing), + + /** + * Prints 'testNest("{%s}")' where thing has been formatted into a string of the nested struct + * @param Xtruct2 thing - the Xtruct2 to print + * @return Xtruct2 - returns the Xtruct2 'thing' + */ + Xtruct2 testNest(1: Xtruct2 thing), + + /** + * Prints 'testMap("{%s")' where thing has been formatted into a string of 'key => value' pairs + * separated by commas and new lines + * @param map thing - the map to print + * @return map - returns the map 'thing' + */ + map testMap(1: map thing), + + /** + * Prints 'testStringMap("{%s}")' where thing has been formatted into a string of 'key => value' pairs + * separated by commas and new lines + * @param map thing - the map to print + * @return map - returns the map 'thing' + */ + map testStringMap(1: map thing), + + /** + * Prints 'testSet("{%s}")' where thing has been formatted into a string of values + * separated by commas and new lines + * @param set thing - the set to print + * @return set - returns the set 'thing' + */ + set testSet(1: set thing), + + /** + * Prints 'testList("{%s}")' where thing has been formatted into a string of values + * separated by commas and new lines + * @param list thing - the list to print + * @return list - returns the list 'thing' + */ + list testList(1: list thing), + + /** + * Prints 'testEnum("%d")' where thing has been formatted into it's numeric value + * @param Numberz thing - the Numberz to print + * @return Numberz - returns the Numberz 'thing' + */ + Numberz testEnum(1: Numberz thing), + + /** + * Prints 'testTypedef("%d")' with thing as '%d' + * @param UserId thing - the UserId to print + * @return UserId - returns the UserId 'thing' + */ + UserId testTypedef(1: UserId thing), + + /** + * Prints 'testMapMap("%d")' with hello as '%d' + * @param i32 hello - the i32 to print + * @return map> - returns a dictionary with these values: + * {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2 => 2, 3 => 3, 4 => 4, }, } + */ + map> testMapMap(1: i32 hello), + + /** + * So you think you've got this all worked, out eh? + * + * Creates a the returned map with these values and prints it out: + * { 1 => { 2 => argument, + * 3 => argument, + * }, + * 2 => { 6 => , }, + * } + * @return map> - a map with the above values + */ + map> testInsanity(1: Insanity argument), + + /** + * Prints 'testMulti()' + * @param i8 arg0 - + * @param i32 arg1 - + * @param i64 arg2 - + * @param map arg3 - + * @param Numberz arg4 - + * @param UserId arg5 - + * @return Xtruct - returns an Xtruct with string_thing = "Hello2, byte_thing = arg0, i32_thing = arg1 + * and i64_thing = arg2 + */ + Xtruct testMulti(1: i8 arg0, 2: i32 arg1, 3: i64 arg2, 4: map arg3, 5: Numberz arg4, 6: UserId arg5), + + /** + * Print 'testException(%s)' with arg as '%s' + * @param string arg - a string indication what type of exception to throw + * if arg == "Xception" throw Xception with errorCode = 1001 and message = arg + * elsen if arg == "TException" throw TException + * else do not throw anything + */ + void testException(1: string arg) throws(1: Xception err1), + + /** + * Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s' + * @param string arg - a string indication what type of exception to throw + * if arg0 == "Xception" throw Xception with errorCode = 1001 and message = "This is an Xception" + * elsen if arg0 == "Xception2" throw Xception2 with errorCode = 2002 and struct_thing.string_thing = "This is an Xception2" + * else do not throw anything + * @return Xtruct - an Xtruct with string_thing = arg1 + */ + Xtruct testMultiException(1: string arg0, 2: string arg1) throws(1: Xception err1, 2: Xception2 err2) + + /** + * Print 'testOneway(%d): Sleeping...' with secondsToSleep as '%d' + * sleep 'secondsToSleep' + * Print 'testOneway(%d): done sleeping!' with secondsToSleep as '%d' + * @param i32 secondsToSleep - the number of seconds to sleep + */ + oneway void testOneway(1:i32 secondsToSleep) +} + +service SecondService +{ + /** + * Prints 'testString("%s")' with thing as '%s' + * @param string thing - the string to print + * @return string - returns the string 'thing' + */ + string secondtestString(1: string thing) +} + +struct VersioningTestV1 { + 1: i32 begin_in_both, + 3: string old_string, + 12: i32 end_in_both +} + +struct VersioningTestV2 { + 1: i32 begin_in_both, + + 2: i32 newint, + 3: i8 newbyte, + 4: i16 newshort, + 5: i64 newlong, + 6: double newdouble + 7: Bonk newstruct, + 8: list newlist, + 9: set newset, + 10: map newmap, + 11: string newstring, + 12: i32 end_in_both +} + +struct ListTypeVersioningV1 { + 1: list myints; + 2: string hello; +} + +struct ListTypeVersioningV2 { + 1: list strings; + 2: string hello; +} + +struct GuessProtocolStruct { + 7: map map_field, +} + +struct LargeDeltas { + 1: Bools b1, + 10: Bools b10, + 100: Bools b100, + 500: bool check_true, + 1000: Bools b1000, + 1500: bool check_false, + 2000: VersioningTestV2 vertwo2000, + 2500: set a_set2500, + 3000: VersioningTestV2 vertwo3000, + 4000: list big_numbers +} + +struct NestedListsI32x2 { + 1: list> integerlist +} +struct NestedListsI32x3 { + 1: list>> integerlist +} +struct NestedMixedx2 { + 1: list> int_set_list + 2: map> map_int_strset + 3: list>> map_int_strset_list +} +struct ListBonks { + 1: list bonk +} +struct NestedListsBonk { + 1: list>> bonk +} + +struct BoolTest { + 1: optional bool b = true; + 2: optional string s = "true"; +} + +struct StructA { + 1: required string s; +} + +struct StructB { + 1: optional StructA aa; + 2: required StructA ab; +} diff --git a/test/TypedefTest.thrift b/test/TypedefTest.thrift new file mode 100644 index 0000000..9437478 --- /dev/null +++ b/test/TypedefTest.thrift @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +namespace cpp thrift.test + +typedef i32 MyInt32 +typedef string MyString; + +struct TypedefTestStruct { + 1: MyInt32 field_MyInt32; + 2: MyString field_MyString; + 3: i32 field_Int32; + 4: string field_String; +} + +typedef TypedefTestStruct MyStruct, \ No newline at end of file diff --git a/test/audit/README.md b/test/audit/README.md new file mode 100644 index 0000000..412f8d5 --- /dev/null +++ b/test/audit/README.md @@ -0,0 +1,40 @@ +Typical usage +============= +``` +thrift.exe --audit +``` +Example run +=========== +``` +> thrift.exe --audit test.thrift break1.thrift +[Thrift Audit Failure:break1.thrift] New Thrift File has missing function base_function3 +[Thrift Audit Warning:break1.thrift] Constant const3 has different value +``` + +Problems that the audit tool can catch +====================================== +Errors +* Removing an enum value +* Changing the type of a struct field +* Changing the required-ness of a struct field +* Removing a struct field +* Adding a required struct field +* Adding a struct field 'in the middle'. This usually indicates an old ID has been recycled +* Struct removed +* Oneway-ness change +* Return type change +* Missing function +* Missing service +* Change in service inheritance + +Warnings +* Removing a language namespace declaration +* Changing a namespace +* Changing an enum value's name +* Removing an enum class +* Default value changed +* Struct field name change +* Removed constant +* Type of constant changed +* Value of constant changed + \ No newline at end of file diff --git a/test/audit/break1.thrift b/test/audit/break1.thrift new file mode 100644 index 0000000..f77f672 --- /dev/null +++ b/test/audit/break1.thrift @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//Thrift Method removed from service base. + +namespace cpp test + +//constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3= [23, 32], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break10.thrift b/test/audit/break10.thrift new file mode 100644 index 0000000..00690aa --- /dev/null +++ b/test/audit/break10.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break10 - Struct field removed from struct2 id =1 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break11.thrift b/test/audit/break11.thrift new file mode 100644 index 0000000..a4e0a7d --- /dev/null +++ b/test/audit/break11.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break11 - Struct field removed from struct3 id =7 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break12.thrift b/test/audit/break12.thrift new file mode 100644 index 0000000..e5522ed --- /dev/null +++ b/test/audit/break12.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// derived1_function1 return type changed from enum1 to enum2 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum2 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break13.thrift b/test/audit/break13.thrift new file mode 100644 index 0000000..66975cd --- /dev/null +++ b/test/audit/break13.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// derived1_function6 return type changed from struct1 to struct2 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct2 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break14.thrift b/test/audit/break14.thrift new file mode 100644 index 0000000..4ccd503 --- /dev/null +++ b/test/audit/break14.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// derived1_function6 return type changed from string to double + +namespace cpp test +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + double derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break15.thrift b/test/audit/break15.thrift new file mode 100644 index 0000000..95f69e6 --- /dev/null +++ b/test/audit/break15.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// break15 - derived2_function1 return type changed from list to list +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break16.thrift b/test/audit/break16.thrift new file mode 100644 index 0000000..cdcff7d --- /dev/null +++ b/test/audit/break16.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// break 16 - derived2_function5 return type changed from map to map + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break17.thrift b/test/audit/break17.thrift new file mode 100644 index 0000000..353b142 --- /dev/null +++ b/test/audit/break17.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break17 - derived2_function6 return type changed from map to map + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break18.thrift b/test/audit/break18.thrift new file mode 100644 index 0000000..c778b6a --- /dev/null +++ b/test/audit/break18.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break18- oneway removed from base_oneway + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break19.thrift b/test/audit/break19.thrift new file mode 100644 index 0000000..1a0b229 --- /dev/null +++ b/test/audit/break19.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break19 - oneway added to base_function1 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + oneway void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break2.thrift b/test/audit/break2.thrift new file mode 100644 index 0000000..6f4fe2d --- /dev/null +++ b/test/audit/break2.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//Struct field changed in test_struct1 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i32 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break20.thrift b/test/audit/break20.thrift new file mode 100644 index 0000000..9ae5f00 --- /dev/null +++ b/test/audit/break20.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// break 20 - first enum value removed from enum1 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break21.thrift b/test/audit/break21.thrift new file mode 100644 index 0000000..f7da400 --- /dev/null +++ b/test/audit/break21.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break21- last enum value removed from enum2 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break22.thrift b/test/audit/break22.thrift new file mode 100644 index 0000000..3808349 --- /dev/null +++ b/test/audit/break22.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break22 - in-between enum value removed from enum1 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break23.thrift b/test/audit/break23.thrift new file mode 100644 index 0000000..ff95a42 --- /dev/null +++ b/test/audit/break23.thrift @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break23 - required struct field added to struct4 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2, + 3: required i64 struct4_member3 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break24.thrift b/test/audit/break24.thrift new file mode 100644 index 0000000..bb4d5b9 --- /dev/null +++ b/test/audit/break24.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break24 - removed inheritance from derived1. + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break25.thrift b/test/audit/break25.thrift new file mode 100644 index 0000000..6efe97e --- /dev/null +++ b/test/audit/break25.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//Changed inheritance of derived2 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends derived1 { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break26.thrift b/test/audit/break26.thrift new file mode 100644 index 0000000..6576d9b --- /dev/null +++ b/test/audit/break26.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break26 - Field type changed in base_function1 argument id=3 +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: double function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} + diff --git a/test/audit/break27.thrift b/test/audit/break27.thrift new file mode 100644 index 0000000..b556706 --- /dev/null +++ b/test/audit/break27.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// break27 - argument changed base_function2 list to list id =8 +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break28.thrift b/test/audit/break28.thrift new file mode 100644 index 0000000..c64e558 --- /dev/null +++ b/test/audit/break28.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break28- derived1_function5 arguement type changed map to list +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: list function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break29.thrift b/test/audit/break29.thrift new file mode 100644 index 0000000..52f3081 --- /dev/null +++ b/test/audit/break29.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break29 - base_function2 arguemnt type changed list to string + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: string function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break3.thrift b/test/audit/break3.thrift new file mode 100644 index 0000000..ded9972 --- /dev/null +++ b/test/audit/break3.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break3 - Struct field changed in test_struct1(enum1 to enum2) + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum2 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break30.thrift b/test/audit/break30.thrift new file mode 100644 index 0000000..818dd6e --- /dev/null +++ b/test/audit/break30.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// break30- derived1_function6 argument changed struct1 to map +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + map derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break31.thrift b/test/audit/break31.thrift new file mode 100644 index 0000000..7ca3804 --- /dev/null +++ b/test/audit/break31.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break31 - Exception removed to base_function2 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break32.thrift b/test/audit/break32.thrift new file mode 100644 index 0000000..ca3f8a8 --- /dev/null +++ b/test/audit/break32.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break32- Exception1 field type changed for id =1 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i64 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break33.thrift b/test/audit/break33.thrift new file mode 100644 index 0000000..42dbb82 --- /dev/null +++ b/test/audit/break33.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break33 - derived1_function1 exception type changed. + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception1 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break34.thrift b/test/audit/break34.thrift new file mode 100644 index 0000000..af93e65 --- /dev/null +++ b/test/audit/break34.thrift @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break34 - Field added to struct with Field ID being in between two existing field IDs + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 6: map struct3_member6, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break4.thrift b/test/audit/break4.thrift new file mode 100644 index 0000000..6a28ec0 --- /dev/null +++ b/test/audit/break4.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//Field type changed in test_struct1(bool to string) +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: string struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 =[23, 32], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break5.thrift b/test/audit/break5.thrift new file mode 100644 index 0000000..18c22d1 --- /dev/null +++ b/test/audit/break5.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// member field type changed in test_struct1(bool to list) + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: list struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break6.thrift b/test/audit/break6.thrift new file mode 100644 index 0000000..9b7a300 --- /dev/null +++ b/test/audit/break6.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// Field type changed in test_struct2 (list to list) + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break7.thrift b/test/audit/break7.thrift new file mode 100644 index 0000000..b31c2df --- /dev/null +++ b/test/audit/break7.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break7 - requiredness removed in struct6 + +namespace cpp test +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break8.thrift b/test/audit/break8.thrift new file mode 100644 index 0000000..9acac09 --- /dev/null +++ b/test/audit/break8.thrift @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break8 - requiredness addedd in struct5 + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: required string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/break9.thrift b/test/audit/break9.thrift new file mode 100644 index 0000000..62b319d --- /dev/null +++ b/test/audit/break9.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//break9 - Struct field removed from struct1 + + +namespace cpp test +//Constants + +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/test.thrift b/test/audit/test.thrift new file mode 100644 index 0000000..e9834b3 --- /dev/null +++ b/test/audit/test.thrift @@ -0,0 +1,189 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +namespace cpp test + +//Constants +const i32 const1 = 123; +const double const2 = 23.3; +const map const3 = {"hello":"world", "thrift":"audit"}; + + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.5, + 5: string struct1_member5 = "Audit test", + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 struct1_member9 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list struct2_member2, + 3: list struct2_member3 = [23, 32 ], + 4: list struct2_member4, + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:2, 3:4}, + 2: map struct3_member2 = {10:1.1, 20:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1, + 2: string struct5_member2 = "Thrift Audit Test" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base { + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/audit/thrift_audit_test.pl b/test/audit/thrift_audit_test.pl new file mode 100644 index 0000000..69ed4dc --- /dev/null +++ b/test/audit/thrift_audit_test.pl @@ -0,0 +1,261 @@ +#!/usr/bin/perl -w + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +#break1 - Thrift method removed from service base +#break2 - Struct field changed in test_struct1(i16 to i32) +#break3 - Struct field changed in test_struct1(enum1 to enum2) +#break4 - Field type changed in test_struct1(bool to string) +#break5- member field type changed in test_struct1(bool to list) +#break6- Field type changed in test_struct2 (list to list) +#break7 - requiredness removed in struct6 +#break8 - requiredness addedd in struct5 +#break9 - Struct field removed from struct1 +#break10 - Struct field removed from struct2 id = 1 +#break11 - Struct field removed from struct3 last id +#break12 - derived1_function1 return type changed from enum1 to enum2 +#break13 - derived1_function6 return type changed from struct1 to struct2 +#break14 - derived1_function4 return type changed from string to double +#break15 - derived2_function1 return type changed from list to list +#break16 - derived2_function5 return type changed from map to map +#break17 - derived2_function6 return type changed from map to map +#break18- oneway removed from base_oneway +#break19 - oneway added to base_function1 +#break20 - first enum value removed from enum1 +#break21- last enum value removed from enum2 +#break22 - in-between enum value removed from enum1 +#break23 - required struct field added to struct4 +#break24 - removed inheritance of derived1. +#break25 - changed inheritance of derived2. +#break26 - Field type changed in base_function1 argument id=3 +#break27 - argument changed base_function2 list to list id =8 +#break28- derived1_function5 arguement type changed map to list +#break29 - base_function2 arguemnt type changed list to string +#break30- derived1_function6 argument changed struct1 to map +#break31 - Exception removed to base_function2 +#break32- Exception1 field type changed for id =1 +#break33 - derived1_function1 exception type changed. +#break34 - Field added to struct with Field ID being in between two existing field IDs + +#warning.thrift +#Changing defaults +#Id=1 struct5 +#id=2 struct5 +#id=4 struct2(list) +#id=3 struct2(list default values removed) +#id 4 struct1 change in double value +#id 5 struct1 (default string value removed) +#id=1 struct3 (change in map values) +#id2 struct3 (change in map keys) + +#change in inheritance for derived1 and derived2 + +#change in struct field names +#id9 struct1 +#id2 struct2 + +use strict; +use warnings; +use Getopt::Std; + +# globals +my $gArguments = ""; # arguments that will be passed to AuditTool +my $gAuditToolPath = ""; +my $gPreviousThriftPath; # previous thrift path +my $gCurrentThriftPath; # current thrift path +my $gThriftFileFolder; +my $gBreakingFilesCount =34; + +my $gVerbose = 0; +#functions +sub auditBreakingChanges; +sub auditNonBreakingChanges; + +main(); + +sub main +{ + parseOptions(); + auditBreakingChanges(); + auditNonBreakingChanges(); +} + +sub parseOptions +{ + my %options = (); + if ( getopts ('vf:o:t:',\%options) ) + { + # current (new) thrift folder + if ($options{'f'}) + { + $gThriftFileFolder = $options{'f'}; + $gPreviousThriftPath = $gThriftFileFolder."/test.thrift"; + } + else + { + die "Missing Folder containing thrift files\n"; + } + + if($options{'t'}) + { + $gAuditToolPath = $options{'t'}; + } + else + { + die "Audit Tool Path required \n"; + } + + if ($options{'v'}) + { + $gVerbose = 1; + } + + } +} + +sub auditBreakingChanges +{ + my $breakingFileBaseName = $gThriftFileFolder."/break"; + my $newThriftFile; + for(my $i=1; $i <= $gBreakingFilesCount; $i++) + { + $newThriftFile = $breakingFileBaseName."$i.thrift"; + my $arguments = $gPreviousThriftPath." ".$newThriftFile; + my ($exitCode, $output) = callThriftAuditTool($arguments); + print $output if $gVerbose eq 1; + + if($exitCode == 1) + { + # thrift_audit returns 1 when it is not able to find files or other non-audit failures + print "exiting with exit code =1 i = ".$i."\n"; + print $output; + exit $exitCode; + } + if($exitCode != 2) + { + # thrift-audit return 2 for audit failures. So for Breaking changes we should get 2 as return value. + print $output; + die "\nTEST FAILURE: Breaking Change not detected for thrift file $newThriftFile, code=$exitCode \n"; + } + if(index($output,getMessageSubString("break$i")) == -1) + { + #Audit tool detected failure, but not the expected one. The change in breaking thrift file does not match getMessageSubString() + print $output; + die "\nTest FAILURE: Audit tool detected failure, but not the expected one!\n"; + } + else + { + #Thrift audit tool has detected audit failure and has returned exited to status code 2 + print "Test Pass: Audit Failure detected for thrift file break$i.thrift \n"; + } + } + +} + +sub auditNonBreakingChanges +{ + my $breakingFileBaseName = $gThriftFileFolder."/warning"; + my $newThriftFile; + $newThriftFile = $breakingFileBaseName.".thrift"; + my $arguments = $gPreviousThriftPath." ".$newThriftFile; + my ($exitCode, $output) = callThriftAuditTool($arguments); + print $output if $gVerbose eq 1; + + if($exitCode == 1) + { + # thrift_audit returns 1 when it is not able to find files or other non-audit failures + print "exiting with exit code = 1 for file warning.thrift\n"; + exit $exitCode; + } + elsif($exitCode != 0) + { + # thrift-audit return 0 if there are no audit failures. + die "\nTEST FAILURE: Non Breaking changes returned failure for thrift file $newThriftFile \n"; + } + else + { + #Thrift audit tool has exited with status 0. + print "Test Pass: Audit tool exits with success for warnings \n"; + } + + +} + +# ----------------------------------------------------------------------------------------------------- +# call thriftAuditTool script +sub callThriftAuditTool ( $ ) +{ + my $args = shift; + + my $command = "$gAuditToolPath --audit $args"; + my $output = `$command 2>&1`; + my $exitCode = $? >> 8; + + return ($exitCode,$output); +} + +sub getMessageSubString( $ ) +{ + my $fileName = shift; + my %lookupTable = ( + "break1" => "base_function3", + "break2" => "test_struct1", + "break3" => "test_struct1", + "break4" => "test_struct1", + "break5" => "test_struct1", + "break6" => "test_struct2", + "break7" => "test_struct6", + "break8" => "test_struct5", + "break9" => "test_struct1", + "break10" => "test_struct2", + "break11" => "test_struct3", + "break12" => "derived1_function1", + "break13" => "derived1_function6", + "break14" => "derived1_function4", + "break15" => "derived2_function1", + "break16" => "derived2_function5", + "break17" => "derived2_function6", + "break18" => "base_oneway", + "break19" => "base_function1", + "break20" => "test_enum1", + "break21" => "test_enum2", + "break22" => "test_enum1", + "break23" => "test_struct4", + "break24" => "derived1", + "break25" => "derived2", + "break26" => "base_function1", + "break27" => "base_function2_args", + "break28" => "derived1_function5_args", + "break29" => "base_function2_args", + "break30" => "derived1_function6", + "break31" => "base_function2_exception", + "break32" => "test_exception1", + "break33" => "derived1_function1_exception", + "break34" => "test_struct3", + ); + if (not exists $lookupTable{ $fileName }) + { + print "in the null case\n"; + return "NULL"; + } + + my $retval = $lookupTable{ $fileName }; + print "$fileName => $retval\n"; + return $lookupTable{ $fileName }; +} diff --git a/test/audit/warning.thrift b/test/audit/warning.thrift new file mode 100644 index 0000000..5392d5c --- /dev/null +++ b/test/audit/warning.thrift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +namespace cpp test + +//Constants + +const i32 const1 = 123; +const double const2 = 23.2; +const map const3 = {"hello":"class", "thrift":"audit"}; + +//Exception +exception test_exception1 { + 1: i32 code; + 2: string json; +} +exception test_exception2 { + 1: i32 code; + 2: string json; +} + +//Enums + +enum test_enum1 { + enum1_value0 = 0, + enum1_value1 = 1, + enum1_value2 = 2, + enum1_value5 = 5, + enum1_value7 = 7, + enum1_value8 = 8 +} + +enum test_enum2 { + enum2_value0 = 0, + enum2_value1 = 1, + enum2_value2 = 2, + enum2_value3 = 3 +} + +enum test_enum3 { + enum3_value1 = 0, + enum3_value2 = 1 +} + +struct test_struct1 { + 1: i16 struct1_member1, + 2: i32 struct1_member2, + 3: i64 struct1_member3, + 4: double struct1_member4 = 2.4, + 5: string struct1_member5, + 6: bool struct1_member6, + 7: byte struct1_member7, + 8: binary struct1_member8, + 9: test_enum1 changed19 +} + +struct test_struct2 { + 1: list struct2_member1, + 2: list changed22, + 3: list struct2_member3, + 4: list struct2_member4 =[1.0, 2.1], + 5: list struct2_member5, + 6: list struct2_member6, + 7: list struct2_member7, + 8: list struct2_member8, + 9: list struct2_member9 +} + +struct test_struct3 { + 1: map struct3_member1 = {1:10, 2:20}, + 2: map struct3_member2 = {1:1.1, 2:2.1}, + 3: map struct3_member3, + 4: map struct3_member4, + 5: map struct3_member5, + 7: map struct3_member7 +} + +struct test_struct4 { + 1: i32 struct4_member1, + 2: optional i32 struct4_member2 +} + +struct test_struct5{ + 1: double struct5_member1 = 1.1, + 2: string struct5_member2 = "Thrift Audit Tess" +} +struct test_struct6 { + 1: i32 struct6_member1, + 2: required i32 struct6_member2 +} + +service base { + oneway void base_oneway( + 1: i32 arg1), + + void base_function1( + 1: i16 function1_arg1, + 2: i32 function1_arg2, + 3: i64 function1_arg3, + 4: double function1_arg4, + 5: string function1_arg5, + 6: bool function1_arg6, + 7: test_enum1 function1_arg7, + 8: test_struct1 function1_arg8), + + void base_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5, + 6: list function2_arg6, + 7: list function2_arg7, + 8: list function2_arg8, + 9: list function2_arg9) throws (1:test_exception2 e), + + void base_function3(), + +} + +service derived1 extends base{ + + test_enum1 derived1_function1( + 1: i64 function1_arg1, + 2: double function1_arg2, + 3: test_enum1 function1_arg3) throws (1:test_exception2 e), + + i64 derived1_function2( + 1: list function2_arg1, + 2: list function2_arg2, + 3: list function2_arg3, + 4: list function2_arg4, + 5: list function2_arg5) throws (1:test_exception2 e), + + double derived1_function3( + 1: string function3_arg1, + 2: bool function3_arg2) throws (1:test_exception2 e), + + string derived1_function4( + 1: string function4_arg1, + 2: bool function4_arg2) throws (1:test_exception2 e), + + + bool derived1_function5( + 1: map function5_arg1, + 2: map function5_arg2, + 3: map function5_arg3) throws (1:test_exception2 e), + + test_struct1 derived1_function6( + 1: double function6_arg1) throws (1:test_exception2 e), +} + +service derived2 extends base { + + list derived2_function1( + 1: i32 function1_arg1) throws (1:test_exception2 e), + + list derived2_function2( + 1:i64 function2_arg2) throws (1:test_exception2 e), + + list derived2_function3( + 1:double function3_arg1) throws(1:test_exception2 e), + + map derived2_function4( + 1:string function4_arg1) throws(1:test_exception2 e), + + map derived2_function5( + 1:bool function5_arg1) throws(1:test_exception2 e), + + map derived2_function6( + 1:bool function6_arg1) throws(1:test_exception2 e), + +} diff --git a/test/c_glib/Makefile b/test/c_glib/Makefile new file mode 100644 index 0000000..eb3968b --- /dev/null +++ b/test/c_glib/Makefile @@ -0,0 +1,896 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# test/c_glib/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + + +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/thrift +pkgincludedir = $(includedir)/thrift +pkglibdir = $(libdir)/thrift +pkglibexecdir = $(libexecdir)/thrift +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-pc-linux-gnu +host_triplet = x86_64-pc-linux-gnu +check_PROGRAMS = test_client$(EXEEXT) test_server$(EXEEXT) +subdir = test/c_glib +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libtestcglib_la_DEPENDENCIES = \ + $(top_builddir)/lib/c_glib/libthrift_c_glib.la +am__dirstamp = $(am__leading_dot)dirstamp +nodist_libtestcglib_la_OBJECTS = gen-c_glib/t_test_second_service.lo \ + gen-c_glib/t_test_thrift_test.lo \ + gen-c_glib/t_test_thrift_test_types.lo +libtestcglib_la_OBJECTS = $(nodist_libtestcglib_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am__v_lt_1 = +am_test_client_OBJECTS = src/test_client.$(OBJEXT) +test_client_OBJECTS = $(am_test_client_OBJECTS) +test_client_DEPENDENCIES = libtestcglib.la \ + $(top_builddir)/lib/c_glib/libthrift_c_glib.la +am_test_server_OBJECTS = src/thrift_test_handler.$(OBJEXT) \ + src/thrift_second_service_handler.$(OBJEXT) \ + src/test_server.$(OBJEXT) +test_server_OBJECTS = $(am_test_server_OBJECTS) +test_server_DEPENDENCIES = libtestcglib.la \ + $(top_builddir)/lib/c_glib/libthrift_c_glib.la +AM_V_P = $(am__v_P_$(V)) +am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I. -I$(top_builddir) -I$(top_builddir)/lib/cpp/src/thrift -I$(top_builddir)/lib/c_glib/src/thrift +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(nodist_libtestcglib_la_SOURCES) $(test_client_SOURCES) \ + $(test_server_SOURCES) +DIST_SOURCES = $(test_client_SOURCES) $(test_server_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15 +ALLOCA = +AMTAR = $${TAR-tar} +AM_DEFAULT_VERBOSITY = 1 +ANT = /usr/bin/ant +ANT_FLAGS = +AR = ar +AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf +AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader +AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15 +AWK = gawk +BISON = bison +BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a +BOOST_CPPFLAGS = -I/usr/include +BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a +BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu +BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu +BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a +BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a +BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a +BUNDLER = /usr/bin/bundle +CABAL = /usr/bin/cabal +CABAL_CONFIGURE_FLAGS = +CARGO = /usr/bin/cargo +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 +CLASSPATH = +CPP = gcc -E +CPPFLAGS = +CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \; +CXX = g++ -std=c++11 +CXXCPP = g++ -E -std=c++11 +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -g -O2 +CYGPATH_W = echo +DART = /usr/lib/dart/bin/dart +DARTPUB = /usr/lib/dart/bin/pub +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +DLLTOOL = false +DMD = dmd +DMD_LIBEVENT_FLAGS = +DMD_OF_DIRSEP = / +DMD_OPENSSL_FLAGS = +DOTNETCORE = /usr/bin/dotnet +DOTNETCORE_VERSION = 2.0.3 +DSYMUTIL = +DUMPBIN = +D_EVENT_LIB_NAME = libthriftd-event.a +D_IMPORT_PREFIX = ${prefix}/include/d2 +D_LIB_NAME = libthriftd.a +D_SSL_LIB_NAME = libthriftd-ssl.a +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +ENABLE_COVERAGE = 2 +ERL = /usr/bin/erl +ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib +ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0 +ERLANG_LIB_DIR = /usr/lib/erlang/lib +ERLC = /usr/bin/erlc +ERLCFLAGS = +EXEEXT = +FGREP = /bin/grep -F +GCOV_CFLAGS = +GCOV_CXXFLAGS = +GCOV_LDFLAGS = +GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GLIB_LIBS = -lglib-2.0 +GO = /usr/bin/go +GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0 +GREP = /bin/grep +HAVE_CXX11 = 1 +HAXE = /usr/bin/haxe +HAXE_VERSION = 3.2.1 +INSTALL = /usr/bin/install -c +INSTALLDIRS = vendor +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +JAVA_PREFIX = /usr/local/lib +LD = /usr/bin/ld -m elf_x86_64 +LDFLAGS = +LEX = flex +LEXLIB = -lfl +LEX_OUTPUT_ROOT = lex.yy +LIBEVENT_CPPFLAGS = +LIBEVENT_LDFLAGS = +LIBEVENT_LIBS = -levent +LIBOBJS = +LIBS = -lrt -lpthread +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LIPO = +LN_S = ln -s +LTLIBOBJS = +LT_SYS_LIBRARY_PATH = +LUA = /usr/bin/lua5.3 +LUA_EXEC_PREFIX = ${exec_prefix} +LUA_INCLUDE = -I/usr/include/lua5.3 +LUA_LIB = -llua5.3 -ldl +LUA_PLATFORM = unknown +LUA_PREFIX = ${prefix} +LUA_SHORT_VERSION = 53 +LUA_VERSION = 5.3 +MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo +MANIFEST_TOOL = : +MAYBE_CPP = cpp +MAYBE_CSHARP = csharp +MAYBE_C_GLIB = c_glib +MAYBE_D = +MAYBE_DART = dart +MAYBE_DOTNETCORE = netcore +MAYBE_ERLANG = erl +MAYBE_GO = go +MAYBE_HASKELL = hs +MAYBE_JAVA = java +MAYBE_LUA = lua +MAYBE_NODEJS = nodejs +MAYBE_PERL = perl +MAYBE_PHP = php +MAYBE_PY3 = py3 +MAYBE_PYTHON = py +MAYBE_RS = rs +MAYBE_RUBY = rb +MCS = /usr/bin/mcs +MKDIR_P = /bin/mkdir -p +MONO_CFLAGS = +MONO_LIBS = +NM = /usr/bin/nm -B +NMEDIT = +NODEJS = /usr/bin/nodejs +NPM = /usr/bin/npm +OBJDUMP = objdump +OBJEXT = o +OPENSSL_INCLUDES = +OPENSSL_LDFLAGS = +OPENSSL_LIBS = -lssl -lcrypto +OTOOL = +OTOOL64 = +PACKAGE = thrift +PACKAGE_BUGREPORT = +PACKAGE_NAME = thrift +PACKAGE_STRING = thrift 0.11.0 +PACKAGE_TARNAME = thrift +PACKAGE_URL = +PACKAGE_VERSION = 0.11.0 +PATH_SEPARATOR = : +PERL = /usr/bin/perl +PERL_PREFIX = /usr/local +PHP = /usr/bin/php +PHPUNIT = /usr/bin/phpunit +PHP_CONFIG = /usr/bin/php-config +PHP_CONFIG_PREFIX = /etc/php.d +PHP_PREFIX = /usr/lib/php +PKG_CONFIG = /usr/bin/pkg-config +PKG_CONFIG_LIBDIR = +PKG_CONFIG_PATH = +PYTHON = /usr/bin/python +PYTHON3 = /usr/bin/python3 +PYTHON_EXEC_PREFIX = ${exec_prefix} +PYTHON_PLATFORM = linux2 +PYTHON_PREFIX = ${prefix} +PYTHON_VERSION = 2.7 +PY_PREFIX = /usr +QT5_CFLAGS = +QT5_LIBS = +QT5_MOC = +QT_CFLAGS = +QT_LIBS = +QT_MOC = +RANLIB = ranlib +REBAR = /usr/bin/rebar +RUBY = /usr/bin/ruby +RUBY_PREFIX = +RUNHASKELL = /usr/bin/runhaskell +RUSTC = /usr/bin/rustc +SED = /bin/sed +SET_MAKE = +SHELL = /bin/bash +STRIP = strip +THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift +TRIAL = /usr/bin/trial +VERSION = 0.11.0 +YACC = bison -y +YFLAGS = +ZLIB_CPPFLAGS = +ZLIB_LDFLAGS = +ZLIB_LIBS = -lz +abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/test/c_glib +abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/test/c_glib +abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift +abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift +ac_ct_AR = ar +ac_ct_CC = gcc +ac_ct_CXX = g++ +ac_ct_DUMPBIN = +am__include = include +am__leading_dot = . +am__quote = +am__tar = tar --format=ustar -chf - "$$tardir" +am__untar = tar -xf - +bindir = ${exec_prefix}/bin +build = x86_64-pc-linux-gnu +build_alias = +build_cpu = x86_64 +build_os = linux-gnu +build_vendor = pc +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +golang_version = 1.6.2 +have_prog_bison = yes +host = x86_64-pc-linux-gnu +host_alias = +host_cpu = x86_64 +host_os = linux-gnu +host_vendor = pc +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +luadir = ${prefix}/share/lua/5.3 +luaexecdir = ${exec_prefix}/lib/lua/5.3 +mandir = ${datarootdir}/man +mkdir_p = $(MKDIR_P) +oldincludedir = /usr/include +pdfdir = ${docdir} +pkgluadir = ${luadir}/thrift +pkgluaexecdir = ${luaexecdir}/thrift +pkgpyexecdir = ${pyexecdir}/thrift +pkgpythondir = ${pythondir}/thrift +prefix = /usr/local +program_transform_name = s,x,x, +psdir = ${docdir} +pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages +pythondir = ${prefix}/lib/python2.7/dist-packages +runstatedir = ${localstatedir}/run +rustc_version = rustc 1.17.0 +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +subdirs = lib/php/src/ext/thrift_protocol +sysconfdir = ${prefix}/etc +target_alias = +top_build_prefix = ../../ +top_builddir = ../.. +top_srcdir = ../.. + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +AUTOMAKE_OPTIONS = subdir-objects serial-tests +noinst_LTLIBRARIES = libtestcglib.la +nodist_libtestcglib_la_SOURCES = \ + gen-c_glib/t_test_second_service.c \ + gen-c_glib/t_test_second_service.h \ + gen-c_glib/t_test_thrift_test.c \ + gen-c_glib/t_test_thrift_test.h \ + gen-c_glib/t_test_thrift_test_types.c \ + gen-c_glib/t_test_thrift_test_types.h + +libtestcglib_la_LIBADD = $(top_builddir)/lib/c_glib/libthrift_c_glib.la +test_client_SOURCES = \ + src/test_client.c + +test_client_LDADD = \ + libtestcglib.la \ + $(top_builddir)/lib/c_glib/libthrift_c_glib.la + +test_server_SOURCES = \ + src/thrift_test_handler.c \ + src/thrift_test_handler.h \ + src/thrift_second_service_handler.c \ + src/thrift_second_service_handler.h \ + src/test_server.c + +test_server_LDADD = \ + libtestcglib.la \ + $(top_builddir)/lib/c_glib/libthrift_c_glib.la + +AM_CFLAGS = -g -Wall -Wextra $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) +AM_CXXFLAGS = $(AM_CFLAGS) +AM_CPPFLAGS = -I$(top_srcdir)/lib/c_glib/src -Igen-c_glib +AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) +EXTRA_DIST = \ + src/test_client.c \ + src/thrift_test_handler.c \ + src/thrift_test_handler.h \ + src/test_server.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/c_glib/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/c_glib/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } +gen-c_glib/$(am__dirstamp): + @$(MKDIR_P) gen-c_glib + @: > gen-c_glib/$(am__dirstamp) +gen-c_glib/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) gen-c_glib/$(DEPDIR) + @: > gen-c_glib/$(DEPDIR)/$(am__dirstamp) +gen-c_glib/t_test_second_service.lo: gen-c_glib/$(am__dirstamp) \ + gen-c_glib/$(DEPDIR)/$(am__dirstamp) +gen-c_glib/t_test_thrift_test.lo: gen-c_glib/$(am__dirstamp) \ + gen-c_glib/$(DEPDIR)/$(am__dirstamp) +gen-c_glib/t_test_thrift_test_types.lo: gen-c_glib/$(am__dirstamp) \ + gen-c_glib/$(DEPDIR)/$(am__dirstamp) + +libtestcglib.la: $(libtestcglib_la_OBJECTS) $(libtestcglib_la_DEPENDENCIES) $(EXTRA_libtestcglib_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libtestcglib_la_OBJECTS) $(libtestcglib_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +src/$(am__dirstamp): + @$(MKDIR_P) src + @: > src/$(am__dirstamp) +src/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/$(DEPDIR) + @: > src/$(DEPDIR)/$(am__dirstamp) +src/test_client.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +test_client$(EXEEXT): $(test_client_OBJECTS) $(test_client_DEPENDENCIES) $(EXTRA_test_client_DEPENDENCIES) + @rm -f test_client$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_client_OBJECTS) $(test_client_LDADD) $(LIBS) +src/thrift_test_handler.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/thrift_second_service_handler.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/test_server.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +test_server$(EXEEXT): $(test_server_OBJECTS) $(test_server_DEPENDENCIES) $(EXTRA_test_server_DEPENDENCIES) + @rm -f test_server$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_server_OBJECTS) $(test_server_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f gen-c_glib/*.$(OBJEXT) + -rm -f gen-c_glib/*.lo + -rm -f src/*.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +include gen-c_glib/$(DEPDIR)/t_test_second_service.Plo +include gen-c_glib/$(DEPDIR)/t_test_thrift_test.Plo +include gen-c_glib/$(DEPDIR)/t_test_thrift_test_types.Plo +include src/$(DEPDIR)/test_client.Po +include src/$(DEPDIR)/test_server.Po +include src/$(DEPDIR)/thrift_second_service_handler.Po +include src/$(DEPDIR)/thrift_test_handler.Po + +.c.o: + $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ + $(am__mv) $$depbase.Tpo $$depbase.Po +# $(AM_V_CC)source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(AM_V_CC_no)$(COMPILE) -c -o $@ $< + +.c.obj: + $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ + $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ + $(am__mv) $$depbase.Tpo $$depbase.Po +# $(AM_V_CC)source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(AM_V_CC_no)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: + $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ + $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ + $(am__mv) $$depbase.Tpo $$depbase.Plo +# $(AM_V_CC)source='$<' object='$@' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(AM_V_CC_no)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf gen-c_glib/.libs gen-c_glib/_libs +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f gen-c_glib/$(DEPDIR)/$(am__dirstamp) + -rm -f gen-c_glib/$(am__dirstamp) + -rm -f src/$(DEPDIR)/$(am__dirstamp) + -rm -f src/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool clean-local \ + clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf gen-c_glib/$(DEPDIR) src/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf gen-c_glib/$(DEPDIR) src/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool clean-local \ + clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am style-am style-local tags tags-am \ + uninstall uninstall-am + +.PRECIOUS: Makefile + + +precross: libtestcglib.la test_client test_server + +# +# Common thrift code generation rules +# +gen-c_glib/t_test_second_service.c gen-c_glib/t_test_second_service.h gen-c_glib/t_test_thrift_test.c gen-c_glib/t_test_thrift_test.h gen-c_glib/t_test_thrift_test_types.c gen-c_glib/t_test_thrift_test_types.h: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT) + $(THRIFT) --gen c_glib -r $< + +clean-local: + $(RM) gen-c_glib/* + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/c_glib/Makefile.am b/test/c_glib/Makefile.am new file mode 100755 index 0000000..4a03d29 --- /dev/null +++ b/test/c_glib/Makefile.am @@ -0,0 +1,74 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +AUTOMAKE_OPTIONS = subdir-objects serial-tests + +noinst_LTLIBRARIES = libtestcglib.la +nodist_libtestcglib_la_SOURCES = \ + gen-c_glib/t_test_second_service.c \ + gen-c_glib/t_test_second_service.h \ + gen-c_glib/t_test_thrift_test.c \ + gen-c_glib/t_test_thrift_test.h \ + gen-c_glib/t_test_thrift_test_types.c \ + gen-c_glib/t_test_thrift_test_types.h + +libtestcglib_la_LIBADD = $(top_builddir)/lib/c_glib/libthrift_c_glib.la + +precross: libtestcglib.la test_client test_server + +check_PROGRAMS = \ + test_client \ + test_server + +test_client_SOURCES = \ + src/test_client.c + +test_client_LDADD = \ + libtestcglib.la \ + $(top_builddir)/lib/c_glib/libthrift_c_glib.la + +test_server_SOURCES = \ + src/thrift_test_handler.c \ + src/thrift_test_handler.h \ + src/thrift_second_service_handler.c \ + src/thrift_second_service_handler.h \ + src/test_server.c + +test_server_LDADD = \ + libtestcglib.la \ + $(top_builddir)/lib/c_glib/libthrift_c_glib.la + +# +# Common thrift code generation rules +# +gen-c_glib/t_test_second_service.c gen-c_glib/t_test_second_service.h gen-c_glib/t_test_thrift_test.c gen-c_glib/t_test_thrift_test.h gen-c_glib/t_test_thrift_test_types.c gen-c_glib/t_test_thrift_test_types.h: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT) + $(THRIFT) --gen c_glib -r $< + +AM_CFLAGS = -g -Wall -Wextra $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) +AM_CXXFLAGS = $(AM_CFLAGS) +AM_CPPFLAGS = -I$(top_srcdir)/lib/c_glib/src -Igen-c_glib +AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) @GCOV_LDFLAGS@ + +clean-local: + $(RM) gen-c_glib/* + +EXTRA_DIST = \ + src/test_client.c \ + src/thrift_test_handler.c \ + src/thrift_test_handler.h \ + src/test_server.c diff --git a/test/c_glib/Makefile.in b/test/c_glib/Makefile.in new file mode 100644 index 0000000..08414ab --- /dev/null +++ b/test/c_glib/Makefile.in @@ -0,0 +1,896 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +check_PROGRAMS = test_client$(EXEEXT) test_server$(EXEEXT) +subdir = test/c_glib +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libtestcglib_la_DEPENDENCIES = \ + $(top_builddir)/lib/c_glib/libthrift_c_glib.la +am__dirstamp = $(am__leading_dot)dirstamp +nodist_libtestcglib_la_OBJECTS = gen-c_glib/t_test_second_service.lo \ + gen-c_glib/t_test_thrift_test.lo \ + gen-c_glib/t_test_thrift_test_types.lo +libtestcglib_la_OBJECTS = $(nodist_libtestcglib_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +am_test_client_OBJECTS = src/test_client.$(OBJEXT) +test_client_OBJECTS = $(am_test_client_OBJECTS) +test_client_DEPENDENCIES = libtestcglib.la \ + $(top_builddir)/lib/c_glib/libthrift_c_glib.la +am_test_server_OBJECTS = src/thrift_test_handler.$(OBJEXT) \ + src/thrift_second_service_handler.$(OBJEXT) \ + src/test_server.$(OBJEXT) +test_server_OBJECTS = $(am_test_server_OBJECTS) +test_server_DEPENDENCIES = libtestcglib.la \ + $(top_builddir)/lib/c_glib/libthrift_c_glib.la +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/lib/cpp/src/thrift -I$(top_builddir)/lib/c_glib/src/thrift +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(nodist_libtestcglib_la_SOURCES) $(test_client_SOURCES) \ + $(test_server_SOURCES) +DIST_SOURCES = $(test_client_SOURCES) $(test_server_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +AUTOMAKE_OPTIONS = subdir-objects serial-tests +noinst_LTLIBRARIES = libtestcglib.la +nodist_libtestcglib_la_SOURCES = \ + gen-c_glib/t_test_second_service.c \ + gen-c_glib/t_test_second_service.h \ + gen-c_glib/t_test_thrift_test.c \ + gen-c_glib/t_test_thrift_test.h \ + gen-c_glib/t_test_thrift_test_types.c \ + gen-c_glib/t_test_thrift_test_types.h + +libtestcglib_la_LIBADD = $(top_builddir)/lib/c_glib/libthrift_c_glib.la +test_client_SOURCES = \ + src/test_client.c + +test_client_LDADD = \ + libtestcglib.la \ + $(top_builddir)/lib/c_glib/libthrift_c_glib.la + +test_server_SOURCES = \ + src/thrift_test_handler.c \ + src/thrift_test_handler.h \ + src/thrift_second_service_handler.c \ + src/thrift_second_service_handler.h \ + src/test_server.c + +test_server_LDADD = \ + libtestcglib.la \ + $(top_builddir)/lib/c_glib/libthrift_c_glib.la + +AM_CFLAGS = -g -Wall -Wextra $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) +AM_CXXFLAGS = $(AM_CFLAGS) +AM_CPPFLAGS = -I$(top_srcdir)/lib/c_glib/src -Igen-c_glib +AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) @GCOV_LDFLAGS@ +EXTRA_DIST = \ + src/test_client.c \ + src/thrift_test_handler.c \ + src/thrift_test_handler.h \ + src/test_server.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/c_glib/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/c_glib/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } +gen-c_glib/$(am__dirstamp): + @$(MKDIR_P) gen-c_glib + @: > gen-c_glib/$(am__dirstamp) +gen-c_glib/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) gen-c_glib/$(DEPDIR) + @: > gen-c_glib/$(DEPDIR)/$(am__dirstamp) +gen-c_glib/t_test_second_service.lo: gen-c_glib/$(am__dirstamp) \ + gen-c_glib/$(DEPDIR)/$(am__dirstamp) +gen-c_glib/t_test_thrift_test.lo: gen-c_glib/$(am__dirstamp) \ + gen-c_glib/$(DEPDIR)/$(am__dirstamp) +gen-c_glib/t_test_thrift_test_types.lo: gen-c_glib/$(am__dirstamp) \ + gen-c_glib/$(DEPDIR)/$(am__dirstamp) + +libtestcglib.la: $(libtestcglib_la_OBJECTS) $(libtestcglib_la_DEPENDENCIES) $(EXTRA_libtestcglib_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libtestcglib_la_OBJECTS) $(libtestcglib_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +src/$(am__dirstamp): + @$(MKDIR_P) src + @: > src/$(am__dirstamp) +src/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/$(DEPDIR) + @: > src/$(DEPDIR)/$(am__dirstamp) +src/test_client.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +test_client$(EXEEXT): $(test_client_OBJECTS) $(test_client_DEPENDENCIES) $(EXTRA_test_client_DEPENDENCIES) + @rm -f test_client$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_client_OBJECTS) $(test_client_LDADD) $(LIBS) +src/thrift_test_handler.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/thrift_second_service_handler.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/test_server.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +test_server$(EXEEXT): $(test_server_OBJECTS) $(test_server_DEPENDENCIES) $(EXTRA_test_server_DEPENDENCIES) + @rm -f test_server$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_server_OBJECTS) $(test_server_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f gen-c_glib/*.$(OBJEXT) + -rm -f gen-c_glib/*.lo + -rm -f src/*.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@gen-c_glib/$(DEPDIR)/t_test_second_service.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gen-c_glib/$(DEPDIR)/t_test_thrift_test.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gen-c_glib/$(DEPDIR)/t_test_thrift_test_types.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/test_client.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/test_server.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/thrift_second_service_handler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/thrift_test_handler.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf gen-c_glib/.libs gen-c_glib/_libs +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f gen-c_glib/$(DEPDIR)/$(am__dirstamp) + -rm -f gen-c_glib/$(am__dirstamp) + -rm -f src/$(DEPDIR)/$(am__dirstamp) + -rm -f src/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool clean-local \ + clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf gen-c_glib/$(DEPDIR) src/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf gen-c_glib/$(DEPDIR) src/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool clean-local \ + clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am style-am style-local tags tags-am \ + uninstall uninstall-am + +.PRECIOUS: Makefile + + +precross: libtestcglib.la test_client test_server + +# +# Common thrift code generation rules +# +gen-c_glib/t_test_second_service.c gen-c_glib/t_test_second_service.h gen-c_glib/t_test_thrift_test.c gen-c_glib/t_test_thrift_test.h gen-c_glib/t_test_thrift_test_types.c gen-c_glib/t_test_thrift_test_types.h: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT) + $(THRIFT) --gen c_glib -r $< + +clean-local: + $(RM) gen-c_glib/* + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/c_glib/src/test_client.c b/test/c_glib/src/test_client.c new file mode 100644 index 0000000..ef24ab7 --- /dev/null +++ b/test/c_glib/src/test_client.c @@ -0,0 +1,1804 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../gen-c_glib/t_test_second_service.h" +#include "../gen-c_glib/t_test_thrift_test.h" + +/* Handle SIGPIPE signals (indicating the server has closed the + connection prematurely) by outputting an error message before + exiting. */ +static void +sigpipe_handler (int signal_number) +{ + THRIFT_UNUSED_VAR (signal_number); + + /* Flush standard output to make sure the test results so far are + logged */ + fflush (stdout); + + fputs ("Broken pipe (server closed connection prematurely)\n", stderr); + fflush (stderr); + + /* Re-raise the signal, this time invoking the default signal + handler, to terminate the program */ + raise (SIGPIPE); +} + +/* Compare two gint32 values. Used for sorting and finding integer + values within a GList. */ +static gint +gint32_compare (gconstpointer a, gconstpointer b) +{ + gint32 int32_a = *(gint32 *)a; + gint32 int32_b = *(gint32 *)b; + int result = 0; + + if (int32_a < int32_b) + result = -1; + else if (int32_a > int32_b) + result = 1; + + return result; +} + +/** + * It gets a multiplexed protocol which uses a concrete protocol underneath + * @param protocol_name the fully qualified protocol path (e.g. "binary:multi") + * @param transport the underlying transport + * @param service_name the single supported service name + * @todo need to allow multiple services to fully test multiplexed + * @return a multiplexed protocol wrapping the correct underlying protocol + */ +ThriftProtocol * +get_multiplexed_protocol(gchar *protocol_name, ThriftTransport *transport, gchar *service_name) +{ + ThriftProtocol * multiplexed_protocol = NULL; + + if ( strncmp(protocol_name, "binary:", 7) == 0) { + multiplexed_protocol = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, + "transport", transport, + NULL); + } else if ( strncmp(protocol_name, "compact:", 8) == 0) { + multiplexed_protocol = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, + "transport", transport, + NULL); + } else { + fprintf(stderr, "Unknown multiplex protocol name: %s\n", protocol_name); + return NULL; + } + + return g_object_new (THRIFT_TYPE_MULTIPLEXED_PROTOCOL, + "transport", transport, + "protocol", multiplexed_protocol, + "service-name", service_name, + NULL); +} + +int +main (int argc, char **argv) +{ + static gchar * host = NULL; + static gint port = 9090; + static gboolean ssl = FALSE; + static gchar * transport_option = NULL; + static gchar * protocol_option = NULL; + static gint num_tests = 1; + + static + GOptionEntry option_entries[] ={ + { "host", 'h', 0, G_OPTION_ARG_STRING, &host, + "Host to connect (=localhost)", NULL }, + { "port", 'p', 0, G_OPTION_ARG_INT, &port, + "Port number to connect (=9090)", NULL }, + { "ssl", 's', 0, G_OPTION_ARG_NONE, &ssl, + "Enable SSL", NULL }, + { "transport", 't', 0, G_OPTION_ARG_STRING, &transport_option, + "Transport: buffered, framed (=buffered)", NULL }, + { "protocol", 'r', 0, G_OPTION_ARG_STRING, &protocol_option, + "Protocol: binary, compact, multi, multic (=binary)", NULL }, + { "testloops", 'n', 0, G_OPTION_ARG_INT, &num_tests, + "Number of tests (=1)", NULL }, + { NULL } + }; + + struct sigaction sigpipe_action; + + GType socket_type = THRIFT_TYPE_SOCKET; + gchar *socket_name = "ip"; + GType transport_type = THRIFT_TYPE_BUFFERED_TRANSPORT; + gchar *transport_name = "buffered"; + GType protocol_type = THRIFT_TYPE_BINARY_PROTOCOL; + gchar *protocol_name = "binary"; + + ThriftSocket *socket = NULL; + ThriftTransport *transport = NULL; + ThriftProtocol *protocol = NULL; + ThriftProtocol *protocol2 = NULL; // for multiplexed tests + + TTestThriftTestIf *test_client = NULL; + TTestSecondServiceIf *second_service = NULL; // for multiplexed tests + + struct timeval time_start, time_stop, time_elapsed; + guint64 time_elapsed_usec, time_total_usec = 0; + guint64 time_min_usec = G_MAXUINT64, time_max_usec = 0, time_avg_usec; + + GOptionContext *option_context; + gboolean options_valid = TRUE; + int test_num = 0; + int fail_count = 0; + GError *error = NULL; + +#if (!GLIB_CHECK_VERSION (2, 36, 0)) + g_type_init (); +#endif + + /* Configure and parse our command-line options */ + option_context = g_option_context_new (NULL); + g_option_context_add_main_entries (option_context, + option_entries, + NULL); + if (!g_option_context_parse (option_context, + &argc, + &argv, + &error)) { + fprintf (stderr, "%s\n", error->message); + return 255; + } + g_option_context_free (option_context); + + /* Set remaining default values for unspecified options */ + if (host == NULL) + host = g_strdup ("localhost"); + + /* Validate the parsed options */ + if (protocol_option != NULL) { + if (strncmp (protocol_option, "compact", 8) == 0) { + protocol_type = THRIFT_TYPE_COMPACT_PROTOCOL; + protocol_name = "compact"; + } + else if (strncmp (protocol_option, "multi", 6) == 0) { + protocol_type = THRIFT_TYPE_MULTIPLEXED_PROTOCOL; + protocol_name = "binary:multi"; + } + else if (strncmp (protocol_option, "multic", 7) == 0) { + protocol_type = THRIFT_TYPE_MULTIPLEXED_PROTOCOL; + protocol_name = "compact:multic"; + } + else if (strncmp (protocol_option, "binary", 7) == 0) { + printf("We are going with default protocol\n"); + } + else { + fprintf (stderr, "Unknown protocol type %s\n", protocol_option); + options_valid = FALSE; + } + } + + if (transport_option != NULL) { + if (strncmp (transport_option, "framed", 7) == 0) { + transport_type = THRIFT_TYPE_FRAMED_TRANSPORT; + transport_name = "framed"; + } + else if (strncmp (transport_option, "buffered", 9) != 0) { + fprintf (stderr, "Unknown transport type %s\n", transport_option); + options_valid = FALSE; + } + } + + if (ssl) { + socket_type = THRIFT_TYPE_SSL_SOCKET; + socket_name = "ip-ssl"; + printf("Type name %s\n", g_type_name (socket_type)); + } + + if (!options_valid) + return 254; + + printf ("Connecting (%s/%s) to: %s/%s:%d\n", + transport_name, + protocol_name, + socket_name, + host, + port); + + /* Install our SIGPIPE handler, which outputs an error message to + standard error before exiting so testers can know what + happened */ + memset (&sigpipe_action, 0, sizeof (sigpipe_action)); + sigpipe_action.sa_handler = sigpipe_handler; + sigpipe_action.sa_flags = SA_RESETHAND; + sigaction (SIGPIPE, &sigpipe_action, NULL); + + if (ssl) { + thrift_ssl_socket_initialize_openssl(); + } + + /* Establish all our connection objects */ + socket = g_object_new (socket_type, + "hostname", host, + "port", port, + NULL); + + if (ssl && !thrift_ssl_load_cert_from_file(THRIFT_SSL_SOCKET(socket), "../keys/CA.pem")) { + fprintf(stderr, "Unable to load validation certificate ../keys/CA.pem - did you run in the test/c_glib directory?\n"); + g_clear_object (&socket); + return 253; + } + + transport = g_object_new (transport_type, + "transport", socket, + NULL); + + if(protocol_type==THRIFT_TYPE_MULTIPLEXED_PROTOCOL) { + // TODO: A multiplexed test should also test "Second" (see Java TestServer) + // The context comes from the name of the thrift file. If multiple thrift + // schemas are used we have to redo the way this is done. + protocol = get_multiplexed_protocol(protocol_name, transport, "ThriftTest"); + if (NULL == protocol) { + g_clear_object (&transport); + g_clear_object (&socket); + return 252; + } + + // Make a second protocol and client running on the same multiplexed transport + protocol2 = get_multiplexed_protocol(protocol_name, transport, "SecondService"); + second_service = g_object_new (T_TEST_TYPE_SECOND_SERVICE_CLIENT, + "input_protocol", protocol2, + "output_protocol", protocol2, + NULL); + + }else{ + protocol = g_object_new (protocol_type, + "transport", transport, + NULL); + } + + test_client = g_object_new (T_TEST_TYPE_THRIFT_TEST_CLIENT, + "input_protocol", protocol, + "output_protocol", protocol, + NULL); + + /* Execute the actual tests */ + for (test_num = 0; test_num < num_tests; ++test_num) { + if (thrift_transport_open (transport, &error)) { + gchar *string = NULL; + gboolean boolean = 0; + gint8 byte = 0; + gint32 int32 = 0; + gint64 int64 = 0; + gdouble dub = 0; + + gint byte_thing, i32_thing, inner_byte_thing, inner_i32_thing; + gint64 i64_thing, inner_i64_thing; + + TTestXtruct *xtruct_out, *xtruct_out2, *xtruct_in, *inner_xtruct_in; + TTestXtruct2 *xtruct2_out, *xtruct2_in; + + GHashTable *map_out, *map_in, *inner_map_in; + GHashTable *set_out, *set_in; + gpointer key, value; + gint32 *i32_key_ptr, *i32_value_ptr; + GHashTableIter hash_table_iter, inner_hash_table_iter; + GList *keys_out, *keys_in, *keys_elem; + + GArray *list_out, *list_in; + + TTestNumberz numberz; + TTestNumberz numberz2; + + TTestUserId user_id, *user_id_ptr, *user_id_ptr2; + + TTestInsanity *insanity_out, *insanity_in; + GHashTable *user_map; + GHashTableIter user_map_iter; + GPtrArray *xtructs; + + TTestXception *xception = NULL; + TTestXception2 *xception2 = NULL; + + gboolean oneway_result; + struct timeval oneway_start, oneway_end, oneway_elapsed; + gint oneway_elapsed_usec; + + gboolean first; + gint32 i, j; + + printf ("Test #%d, connect %s:%d\n", test_num + 1, host, port); + gettimeofday (&time_start, NULL); + + /* These test routines have been ported from the C++ test + client, care being taken to ensure their output remains as + close as possible to the original to facilitate diffs. + + For simplicity comments have been omitted, but every routine + has the same basic structure: + + - Create and populate data structures as necessary. + + - Format and output (to the console) a representation of the + outgoing data. + + - Issue the remote method call to the server. + + - Format and output a representation of the returned data. + + - Verify the returned data matches what was expected. + + - Deallocate any created data structures. + + Note the recognized values and expected behaviour of each + remote method are described in ThriftTest.thrift, which + you'll find in the top-level "test" folder. */ + + /** + * VOID TEST + */ + printf ("testVoid()"); + if (t_test_thrift_test_if_test_void (test_client, &error)) { + printf (" = void\n"); + } + else { + if(error!=NULL){ + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + } + fail_count++; + } + + /** + * STRING TEST + */ + printf ("testString(\"Test\")"); + if (t_test_thrift_test_if_test_string (test_client, + &string, + "Test", + &error)) { + printf (" = \"%s\"\n", string); + if (strncmp (string, "Test", 5) != 0) + fail_count++; + + g_free (string); + string = NULL; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + /** + * Multiplexed Test - do this right in the middle of the normal Test Client run + */ + if (second_service) { + printf ("testSecondServiceMultiplexSecondTestString(\"2nd\")"); + if (t_test_second_service_if_secondtest_string (second_service, + &string, + "2nd", + &error)) { + printf (" = \"%s\"\n", string); + if (strcmp (string, "testString(\"2nd\")") != 0) { + ++fail_count; + } + + g_free (string); + string = NULL; + } else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + ++fail_count; + } + } + + /** + * BOOL TEST + */ + printf ("testByte(true)"); + if (t_test_thrift_test_if_test_bool (test_client, + &boolean, + 1, + &error)) { + printf (" = %s\n", boolean ? "true" : "false"); + if (boolean != 1) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + printf ("testByte(false)"); + if (t_test_thrift_test_if_test_bool (test_client, + &boolean, + 0, + &error)) { + printf (" = %s\n", boolean ? "true" : "false"); + if (boolean != 0) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + /** + * BYTE TEST + */ + printf ("testByte(1)"); + if (t_test_thrift_test_if_test_byte (test_client, + &byte, + 1, + &error)) { + printf (" = %d\n", byte); + if (byte != 1) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + printf ("testByte(-1)"); + if (t_test_thrift_test_if_test_byte (test_client, + &byte, + -1, + &error)) { + printf (" = %d\n", byte); + if (byte != -1) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + /** + * I32 TEST + */ + printf ("testI32(-1)"); + if (t_test_thrift_test_if_test_i32 (test_client, + &int32, + -1, + &error)) { + printf (" = %d\n", int32); + if (int32 != -1) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + /** + * I64 TEST + */ + printf ("testI64(-34359738368)"); + if (t_test_thrift_test_if_test_i64 (test_client, + &int64, + (gint64)-34359738368, + &error)) { + printf (" = %" PRId64 "\n", int64); + if (int64 != (gint64)-34359738368) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + /** + * DOUBLE TEST + */ + printf("testDouble(-5.2098523)"); + if (t_test_thrift_test_if_test_double (test_client, + &dub, + -5.2098523, + &error)) { + printf (" = %f\n", dub); + if ((dub - (-5.2098523)) > 0.001) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + /** + * BINARY TEST + */ + printf ("testBinary(empty)"); + GByteArray *emptyArray = g_byte_array_new(); + GByteArray *result = NULL; + if (t_test_thrift_test_if_test_binary (test_client, + &result, + emptyArray, + &error)) { + GBytes *response = g_byte_array_free_to_bytes(result); // frees result + result = NULL; + gsize siz = g_bytes_get_size(response); + if (siz == 0) { + printf(" = empty\n"); + } else { + printf(" = not empty (%ld bytes)\n", (long)siz); + ++fail_count; + } + g_bytes_unref(response); + } else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + g_byte_array_unref(emptyArray); + emptyArray = NULL; + + // TODO: add testBinary() with data + printf ("testBinary([-128..127]) = {"); + const signed char bin_data[256] + = {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, + -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, + -98, -97, -96, -95, -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, + -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, + -68, -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, + -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, + -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, + -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, + -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127}; + GByteArray *fullArray = g_byte_array_new(); + g_byte_array_append(fullArray, (guint8 *)(&bin_data[0]), 256); + if (t_test_thrift_test_if_test_binary (test_client, + &result, + fullArray, + &error)) { + GBytes *response = g_byte_array_free_to_bytes(result); // frees result + result = NULL; + gsize siz = g_bytes_get_size(response); + gconstpointer ptr = g_bytes_get_data(response, &siz); + if (siz == 256) { + gboolean first = 1; + gboolean failed = 0; + int i; + + for (i = 0; i < 256; ++i) { + if (!first) + printf(","); + else + first = 0; + int val = ((signed char *)ptr)[i]; + printf("%d", val); + if (!failed && val != i - 128) { + failed = 1; + } + } + printf("} "); + if (failed) { + printf("FAIL (bad content) size %ld OK\n", (long)siz); + ++fail_count; + } else { + printf("OK size %ld OK\n", (long)siz); + } + } else { + printf(" = bad size %ld\n", (long)siz); + ++fail_count; + } + g_bytes_unref(response); + } else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + g_byte_array_unref(fullArray); + fullArray = NULL; + + /** + * STRUCT TEST + */ + printf ("testStruct({\"Zero\", 1, -3, -5})"); + xtruct_out = g_object_new (T_TEST_TYPE_XTRUCT, + "string_thing", "Zero", + "byte_thing", 1, + "i32_thing", -3, + "i64_thing", -5LL, + NULL); + xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL); + + if (t_test_thrift_test_if_test_struct (test_client, + &xtruct_in, + xtruct_out, + &error)) { + g_object_get (xtruct_in, + "string_thing", &string, + "byte_thing", &byte_thing, + "i32_thing", &i32_thing, + "i64_thing", &i64_thing, + NULL); + + printf (" = {\"%s\", %d, %d, %" PRId64 "}\n", + string, + byte_thing, + i32_thing, + i64_thing); + if ((string == NULL || strncmp (string, "Zero", 5) != 0) || + byte_thing != 1 || + i32_thing != -3 || + i64_thing != (gint64)-5) + fail_count++; + + if (string) { + g_free (string); + string = NULL; + } + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + // g_clear_object(&xtruct_out); used below + g_clear_object(&xtruct_in); + + /** + * NESTED STRUCT TEST + */ + printf ("testNest({1, {\"Zero\", 1, -3, -5}), 5}"); + xtruct2_out = g_object_new (T_TEST_TYPE_XTRUCT2, + "byte_thing", 1, + "struct_thing", xtruct_out, + "i32_thing", 5, + NULL); + xtruct2_in = g_object_new (T_TEST_TYPE_XTRUCT2, NULL); + + if (t_test_thrift_test_if_test_nest (test_client, + &xtruct2_in, + xtruct2_out, + &error)) { + g_object_get (xtruct2_in, + "byte_thing", &byte_thing, + "struct_thing", &xtruct_in, + "i32_thing", &i32_thing, + NULL); + g_object_get (xtruct_in, + "string_thing", &string, + "byte_thing", &inner_byte_thing, + "i32_thing", &inner_i32_thing, + "i64_thing", &inner_i64_thing, + NULL); + + printf (" = {%d, {\"%s\", %d, %d, %" PRId64 "}, %d}\n", + byte_thing, + string, + inner_byte_thing, + inner_i32_thing, + inner_i64_thing, + i32_thing); + if (byte_thing != 1 || + (string == NULL || strncmp (string, "Zero", 5) != 0) || + inner_byte_thing != 1 || + inner_i32_thing != -3 || + inner_i64_thing != (gint64)-5 || + i32_thing != 5) + fail_count++; + + if (string) { + g_free(string); + string = NULL; + } + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + g_clear_object(&xtruct_in); + g_clear_object(&xtruct2_in); + g_clear_object(&xtruct2_out); + g_clear_object(&xtruct_out); + + /** + * MAP TEST + */ + map_out = g_hash_table_new_full (g_int_hash, + g_int_equal, + g_free, + g_free); + for (i = 0; i < 5; ++i) { + i32_key_ptr = g_malloc (sizeof *i32_key_ptr); + i32_value_ptr = g_malloc (sizeof *i32_value_ptr); + + *i32_key_ptr = i; + *i32_value_ptr = i - 10; + + g_hash_table_insert (map_out, i32_key_ptr, i32_value_ptr); + } + printf ("testMap({"); + first = TRUE; + g_hash_table_iter_init (&hash_table_iter, map_out); + while (g_hash_table_iter_next (&hash_table_iter, + &key, + &value)) { + if (first) + first = FALSE; + else + printf (", "); + + printf ("%d => %d", *(gint32 *)key, *(gint32 *)value); + } + printf ("})"); + + map_in = g_hash_table_new_full (g_int_hash, + g_int_equal, + g_free, + g_free); + + if (t_test_thrift_test_if_test_map (test_client, + &map_in, + map_out, + &error)) { + printf (" = {"); + first = TRUE; + g_hash_table_iter_init (&hash_table_iter, map_in); + while (g_hash_table_iter_next (&hash_table_iter, + &key, + &value)) { + if (first) + first = FALSE; + else + printf (", "); + + printf ("%d => %d", *(gint32 *)key, *(gint32 *)value); + } + printf ("}\n"); + + if (g_hash_table_size (map_in) != g_hash_table_size (map_out)) + fail_count++; + else { + g_hash_table_iter_init (&hash_table_iter, map_out); + while (g_hash_table_iter_next (&hash_table_iter, + &key, + &value)) { + gpointer in_value = g_hash_table_lookup (map_in, key); + if (in_value == NULL || + *(gint32 *)in_value != *(gint32 *)value) { + fail_count++; + break; + } + } + } + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + g_hash_table_unref (map_in); + g_hash_table_unref (map_out); + + /** + * STRING MAP TEST + */ + map_out = g_hash_table_new_full (g_str_hash, + g_str_equal, + NULL, + NULL); + g_hash_table_insert (map_out, "a", "2"); + g_hash_table_insert (map_out, "b", "blah"); + g_hash_table_insert (map_out, "some", "thing"); + printf ("testStringMap({"); + first = TRUE; + g_hash_table_iter_init (&hash_table_iter, map_out); + while (g_hash_table_iter_next (&hash_table_iter, + &key, + &value)) { + if (first) + first = FALSE; + else + printf (", "); + + printf ("\"%s\" => \"%s\"", (gchar *)key, (gchar *)value); + } + printf (")}"); + + map_in = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); + + if (t_test_thrift_test_if_test_string_map (test_client, + &map_in, + map_out, + &error)) { + printf (" = {"); + first = TRUE; + g_hash_table_iter_init (&hash_table_iter, map_in); + while (g_hash_table_iter_next (&hash_table_iter, + &key, + &value)) { + if (first) + first = FALSE; + else + printf (", "); + + printf ("\"%s\" => \"%s\"", (gchar *)key, (gchar *)value); + } + printf ("}\n"); + + if (g_hash_table_size (map_in) != g_hash_table_size (map_out)) + fail_count++; + else { + g_hash_table_iter_init (&hash_table_iter, map_out); + while (g_hash_table_iter_next (&hash_table_iter, + &key, + &value)) { + gpointer in_value = g_hash_table_lookup (map_in, key); + if (in_value == NULL || + strcmp ((gchar *)in_value, (gchar *)value) != 0) { + fail_count++; + break; + } + } + } + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + g_hash_table_unref (map_in); + g_hash_table_unref (map_out); + + /** + * SET TEST + */ + set_out = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL); + for (i = -2; i < 3; ++i) { + i32_key_ptr = g_malloc (sizeof *i32_key_ptr); + *i32_key_ptr = i; + + g_hash_table_insert (set_out, i32_key_ptr, NULL); + } + printf ("testSet({"); + first = TRUE; + keys_out = g_hash_table_get_keys (set_out); + keys_elem = keys_out; + while (keys_elem != NULL) { + if (first) + first = FALSE; + else + printf (", "); + + printf ("%d", *(gint32 *)keys_elem->data); + + keys_elem = keys_elem->next; + } + printf ("})"); + + set_in = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL); + + if (t_test_thrift_test_if_test_set (test_client, + &set_in, + set_out, + &error)) { + printf(" = {"); + first = TRUE; + keys_in = g_hash_table_get_keys (set_in); + keys_elem = keys_in; + while (keys_elem != NULL) { + if (first) + first = FALSE; + else + printf (", "); + + printf ("%d", *(gint32 *)keys_elem->data); + + keys_elem = keys_elem->next; + } + printf ("}\n"); + + if (g_list_length (keys_in) != g_list_length (keys_out)) + fail_count++; + else { + keys_elem = keys_out; + while (keys_elem != NULL) { + if (g_list_find_custom (keys_in, + keys_elem->data, + gint32_compare) == NULL) { + fail_count++; + break; + } + + keys_elem = keys_elem->next; + } + } + + g_list_free (keys_in); + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + g_hash_table_unref (set_in); + g_list_free (keys_out); + g_hash_table_unref (set_out); + + /** + * LIST TEST + */ + list_out = g_array_new (FALSE, TRUE, sizeof (gint32)); + for (i = -2; i < 3; ++i) { + g_array_append_val (list_out, i); + } + printf ("testList({"); + first = TRUE; + for (i = 0; i < (gint32)list_out->len; ++i) { + if (first) + first = FALSE; + else + printf (", "); + + printf ("%d", g_array_index (list_out, gint32, i)); + } + printf ("})"); + + list_in = g_array_new (FALSE, TRUE, sizeof (gint32)); + + if (t_test_thrift_test_if_test_list (test_client, + &list_in, + list_out, + &error)) { + printf (" = {"); + first = TRUE; + for (i = 0; i < (gint32)list_in->len; ++i) { + if (first) + first = FALSE; + else + printf (", "); + + printf ("%d", g_array_index (list_in, gint32, i)); + } + printf ("}\n"); + + if (list_in->len != list_out->len || + memcmp (list_in->data, + list_out->data, + list_in->len * sizeof (gint32)) != 0) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + g_array_unref (list_in); + g_array_unref (list_out); + + /** + * ENUM TEST + */ + printf("testEnum(ONE)"); + if (t_test_thrift_test_if_test_enum (test_client, + &numberz, + T_TEST_NUMBERZ_ONE, + &error)) { + printf(" = %d\n", numberz); + if (numberz != T_TEST_NUMBERZ_ONE) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + printf("testEnum(TWO)"); + if (t_test_thrift_test_if_test_enum (test_client, + &numberz, + T_TEST_NUMBERZ_TWO, + &error)) { + printf(" = %d\n", numberz); + if (numberz != T_TEST_NUMBERZ_TWO) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + printf("testEnum(THREE)"); + if (t_test_thrift_test_if_test_enum (test_client, + &numberz, + T_TEST_NUMBERZ_THREE, + &error)) { + printf(" = %d\n", numberz); + if (numberz != T_TEST_NUMBERZ_THREE) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + printf("testEnum(FIVE)"); + if (t_test_thrift_test_if_test_enum (test_client, + &numberz, + T_TEST_NUMBERZ_FIVE, + &error)) { + printf(" = %d\n", numberz); + if (numberz != T_TEST_NUMBERZ_FIVE) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + printf("testEnum(EIGHT)"); + if (t_test_thrift_test_if_test_enum (test_client, + &numberz, + T_TEST_NUMBERZ_EIGHT, + &error)) { + printf(" = %d\n", numberz); + if (numberz != T_TEST_NUMBERZ_EIGHT) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + /** + * TYPEDEF TEST + */ + printf ("testTypedef(309858235082523)"); + if (t_test_thrift_test_if_test_typedef (test_client, + &user_id, + 309858235082523LL, + &error)) { + printf(" = %" PRId64 "\n", user_id); + if (user_id != 309858235082523LL) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + /** + * NESTED MAP TEST + */ + printf ("testMapMap(1)"); + map_in = g_hash_table_new_full (g_int_hash, + g_int_equal, + g_free, + (GDestroyNotify)g_hash_table_unref); + if (t_test_thrift_test_if_test_map_map (test_client, + &map_in, + 1, + &error)) { + g_hash_table_iter_init (&hash_table_iter, map_in); + + printf (" = {"); + while (g_hash_table_iter_next (&hash_table_iter, + &key, + &value)) { + printf ("%d => {", *(gint32 *)key); + + g_hash_table_iter_init (&inner_hash_table_iter, + (GHashTable *)value); + while (g_hash_table_iter_next (&inner_hash_table_iter, + &key, + &value)) { + printf ("%d => %d, ", *(gint32 *)key, *(gint32 *)value); + } + + printf ("}, "); + } + printf ("}\n"); + + if (g_hash_table_size (map_in) != 2) + fail_count++; + else { + gint32 inner_keys[] = {1, 2, 3, 4}; + gint32 i32_key; + + i32_key = -4; + inner_map_in = g_hash_table_lookup (map_in, &i32_key); + if (inner_map_in == NULL || + g_hash_table_size (inner_map_in) != 4) + fail_count++; + else { + keys_in = g_hash_table_get_keys (inner_map_in); + keys_in = g_list_sort (keys_in, gint32_compare); + + for (i = 0; i < 4; i++) { + keys_elem = g_list_nth (keys_in, 3 - i); + + if (*(gint32 *)keys_elem->data != (-1 * inner_keys[i]) || + *(gint32 *)g_hash_table_lookup (inner_map_in, + keys_elem->data) != + (-1 * inner_keys[i])) { + fail_count++; + break; + } + } + + g_list_free (keys_in); + } + + i32_key = 4; + inner_map_in = g_hash_table_lookup (map_in, &i32_key); + if (inner_map_in == NULL || + g_hash_table_size (inner_map_in) != 4) + fail_count++; + else { + keys_in = g_hash_table_get_keys (inner_map_in); + keys_in = g_list_sort (keys_in, gint32_compare); + + for (i = 0; i < 4; i++) { + keys_elem = g_list_nth (keys_in, i); + + if (*(gint32 *)keys_elem->data != inner_keys[i] || + *(gint32 *)g_hash_table_lookup (inner_map_in, + keys_elem->data) != + inner_keys[i]) { + fail_count++; + break; + } + } + + g_list_free (keys_in); + } + } + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + g_hash_table_unref (map_in); + + /** + * INSANITY TEST + */ + insanity_out = g_object_new (T_TEST_TYPE_INSANITY, NULL); + g_object_get (insanity_out, + "userMap", &user_map, + "xtructs", &xtructs, + NULL); + + numberz = T_TEST_NUMBERZ_FIVE; + numberz2 = T_TEST_NUMBERZ_EIGHT; + user_id_ptr = g_malloc (sizeof *user_id_ptr); + *user_id_ptr = 5; + user_id_ptr2 = g_malloc (sizeof *user_id_ptr); + *user_id_ptr2 = 8; + g_hash_table_insert (user_map, (gpointer)numberz, user_id_ptr); + g_hash_table_insert (user_map, (gpointer)numberz2, user_id_ptr2); + g_hash_table_unref (user_map); + + xtruct_out = g_object_new (T_TEST_TYPE_XTRUCT, + "string_thing", "Hello2", + "byte_thing", 2, + "i32_thing", 2, + "i64_thing", 2LL, + NULL); + xtruct_out2 = g_object_new (T_TEST_TYPE_XTRUCT, + "string_thing", "Goodbye4", + "byte_thing", 4, + "i32_thing", 4, + "i64_thing", 4LL, + NULL); + g_ptr_array_add (xtructs, xtruct_out2); + g_ptr_array_add (xtructs, xtruct_out); + g_ptr_array_unref (xtructs); + + map_in = g_hash_table_new_full (g_int64_hash, + g_int64_equal, + g_free, + (GDestroyNotify)g_hash_table_unref); + + printf("testInsanity()"); + if (t_test_thrift_test_if_test_insanity (test_client, + &map_in, + insanity_out, + &error)) { + printf (" = {"); + g_hash_table_iter_init (&hash_table_iter, map_in); + while (g_hash_table_iter_next (&hash_table_iter, + &key, + &value)) { + printf ("%" PRId64 " => {", *(TTestUserId *)key); + + g_hash_table_iter_init (&inner_hash_table_iter, + (GHashTable *)value); + while (g_hash_table_iter_next (&inner_hash_table_iter, + &key, + &value)) { + printf ("%d => {", (TTestNumberz)key); + + g_object_get ((TTestInsanity *)value, + "userMap", &user_map, + "xtructs", &xtructs, + NULL); + + printf ("{"); + g_hash_table_iter_init (&user_map_iter, user_map); + while (g_hash_table_iter_next (&user_map_iter, + &key, + &value)) { + printf ("%d => %" PRId64 ", ", + (TTestNumberz)key, + *(TTestUserId *)value); + } + printf ("}, "); + g_hash_table_unref (user_map); + + printf("{"); + for (i = 0; i < (gint32)xtructs->len; ++i) { + xtruct_in = g_ptr_array_index (xtructs, i); + g_object_get (xtruct_in, + "string_thing", &string, + "byte_thing", &byte_thing, + "i32_thing", &i32_thing, + "i64_thing", &i64_thing, + NULL); + + printf ("{\"%s\", %d, %d, %" PRId64 "}, ", + string, + byte_thing, + i32_thing, + i64_thing); + } + printf ("}"); + g_ptr_array_unref (xtructs); + + printf ("}, "); + } + printf("}, "); + } + printf("}\n"); + + if (g_hash_table_size (map_in) != 2) + fail_count++; + else { + TTestNumberz numberz_key_values[] = { + T_TEST_NUMBERZ_TWO, T_TEST_NUMBERZ_THREE + }; + gint user_map_values[] = { 5, 8 }; + TTestUserId user_id_key; + + user_id_key = 1; + inner_map_in = g_hash_table_lookup (map_in, &user_id_key); + if (inner_map_in == NULL || + g_hash_table_size (inner_map_in) != 2) + fail_count++; + else { + TTestNumberz numberz_key; + + for (i = 0; i < 2; ++i) { + numberz_key = numberz_key_values[i]; + insanity_in = + g_hash_table_lookup (inner_map_in, + (gconstpointer)numberz_key); + if (insanity_in == NULL) + fail_count++; + else { + g_object_get (insanity_in, + "userMap", &user_map, + "xtructs", &xtructs, + NULL); + + if (user_map == NULL) + fail_count++; + else { + if (g_hash_table_size (user_map) != 2) + fail_count++; + else { + for (j = 0; j < 2; ++j) { + numberz_key = (TTestNumberz)user_map_values[j]; + + value = + g_hash_table_lookup (user_map, + (gconstpointer)numberz_key); + if (value == NULL || + *(TTestUserId *)value != (TTestUserId)user_map_values[j]) + fail_count++; + } + } + + g_hash_table_unref (user_map); + } + + if (xtructs == NULL) + fail_count++; + else { + if (xtructs->len != 2) + fail_count++; + else { + xtruct_in = g_ptr_array_index (xtructs, 0); + g_object_get (xtruct_in, + "string_thing", &string, + "byte_thing", &byte_thing, + "i32_thing", &i32_thing, + "i64_thing", &i64_thing, + NULL); + if ((string == NULL || + strncmp (string, "Goodbye4", 9) != 0) || + byte_thing != 4 || + i32_thing != 4 || + i64_thing != 4) + fail_count++; + + if (string != NULL) + g_free (string); + + xtruct_in = g_ptr_array_index (xtructs, 1); + g_object_get (xtruct_in, + "string_thing", &string, + "byte_thing", &byte_thing, + "i32_thing", &i32_thing, + "i64_thing", &i64_thing, + NULL); + if ((string == NULL || + strncmp (string, "Hello2", 7) != 0) || + byte_thing != 2 || + i32_thing != 2 || + i64_thing != 2) + fail_count++; + + if (string != NULL) + g_free (string); + } + + g_ptr_array_unref (xtructs); + } + } + } + } + + user_id_key = 2; + inner_map_in = g_hash_table_lookup (map_in, &user_id_key); + if (inner_map_in == NULL || + g_hash_table_size (inner_map_in) != 1) + fail_count++; + else { + insanity_in = + g_hash_table_lookup (inner_map_in, + (gconstpointer)T_TEST_NUMBERZ_SIX); + if (insanity_in == NULL) + fail_count++; + else { + g_object_get (insanity_in, + "userMap", &user_map, + "xtructs", &xtructs, + NULL); + + if (user_map == NULL) + fail_count++; + else { + if (g_hash_table_size (user_map) != 0) + fail_count++; + + g_hash_table_unref (user_map); + } + + if (xtructs == NULL) + fail_count++; + else { + if (xtructs->len != 0) + fail_count++; + + g_ptr_array_unref (xtructs); + } + } + } + } + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + g_hash_table_unref (map_in); + g_clear_object (&insanity_out); + + /* test exception */ + printf ("testClient.testException(\"Xception\") =>"); + if (!t_test_thrift_test_if_test_exception (test_client, + "Xception", + &xception, + &error) && + xception != NULL) { + g_object_get (xception, + "errorCode", &int32, + "message", &string, + NULL); + printf (" {%u, \"%s\"}\n", int32, string); + g_free (string); + + g_clear_object (&xception); + + g_error_free (error); + error = NULL; + } + else { + printf (" void\nFAILURE\n"); + fail_count++; + + if (xception != NULL) { + g_object_unref (xception); + xception = NULL; + } + + if (error != NULL) { + g_error_free (error); + error = NULL; + } + } + + printf ("testClient.testException(\"TException\") =>"); + if (!t_test_thrift_test_if_test_exception (test_client, + "TException", + &xception, + &error) && + xception == NULL && + error != NULL) { + printf (" Caught TException\n"); + + g_error_free (error); + error = NULL; + } + else { + printf (" void\nFAILURE\n"); + fail_count++; + + g_clear_object (&xception); + + if (error != NULL) { + g_error_free (error); + error = NULL; + } + } + + printf ("testClient.testException(\"success\") =>"); + if (t_test_thrift_test_if_test_exception (test_client, + "success", + &xception, + &error)) + printf (" void\n"); + else { + printf (" void\nFAILURE\n"); + fail_count++; + + g_clear_object (&xception); + + g_error_free (error); + error = NULL; + } + + g_assert (error == NULL); + + /* test multi exception */ + printf ("testClient.testMultiException(\"Xception\", \"test 1\") =>"); + xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL); + if (!t_test_thrift_test_if_test_multi_exception (test_client, + &xtruct_in, + "Xception", + "test 1", + &xception, + &xception2, + &error) && + xception != NULL && + xception2 == NULL) { + g_object_get (xception, + "errorCode", &int32, + "message", &string, + NULL); + printf (" {%u, \"%s\"}\n", int32, string); + g_free (string); + + g_object_unref (xception); + xception = NULL; + + g_error_free (error); + error = NULL; + } + else { + printf (" result\nFAILURE\n"); + fail_count++; + + g_clear_object (&xception); + g_clear_object (&xception2); + + if (error != NULL) { + g_error_free (error); + error = NULL; + } + } + g_object_unref (xtruct_in); + + printf ("testClient.testMultiException(\"Xception2\", \"test 2\") =>"); + xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL); + if (!t_test_thrift_test_if_test_multi_exception (test_client, + &xtruct_in, + "Xception2", + "test 2", + &xception, + &xception2, + &error) && + xception == NULL && + xception2 != NULL) { + g_object_get (xception2, + "errorCode", &int32, + "struct_thing", &inner_xtruct_in, + NULL); + g_object_get (inner_xtruct_in, + "string_thing", &string, + NULL); + printf (" {%u, {\"%s\"}}\n", int32, string); + g_free (string); + + g_clear_object (&inner_xtruct_in); + g_clear_object (&xception2); + + g_error_free (error); + error = NULL; + } + else { + printf (" result\nFAILURE\n"); + fail_count++; + + g_clear_object (&xception); + g_clear_object (&xception2); + + if (error != NULL) { + g_error_free (error); + error = NULL; + } + } + g_clear_object (&xtruct_in); + + printf ("testClient.testMultiException(\"success\", \"test 3\") =>"); + xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL); + if (t_test_thrift_test_if_test_multi_exception (test_client, + &xtruct_in, + "success", + "test 3", + &xception, + &xception2, + &error) && + xception == NULL && + xception2 == NULL) { + g_object_get (xtruct_in, + "string_thing", &string, + NULL); + printf (" {{\"%s\"}}\n", string); + g_free (string); + } + else { + printf (" result\nFAILURE\n"); + fail_count++; + + g_clear_object (&xception); + g_clear_object (&xception2); + + if (error != NULL) { + g_error_free (error); + error = NULL; + } + } + g_clear_object (&xtruct_in); + + /* test oneway void */ + printf ("testClient.testOneway(1) =>"); + gettimeofday (&oneway_start, NULL); + oneway_result = t_test_thrift_test_if_test_oneway (test_client, + 1, + &error); + gettimeofday (&oneway_end, NULL); + timersub (&oneway_end, &oneway_start, &oneway_elapsed); + oneway_elapsed_usec = + oneway_elapsed.tv_sec * 1000 * 1000 + oneway_elapsed.tv_usec; + + if (oneway_result) { + if (oneway_elapsed_usec > 200 * 1000) { + printf (" FAILURE - took %.2f ms\n", + (double)oneway_elapsed_usec / 1000.0); + fail_count++; + } + else + printf (" success - took %.2f ms\n", + (double)oneway_elapsed_usec / 1000.0); + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + /** + * redo a simple test after the oneway to make sure we aren't "off by + * one" -- if the server treated oneway void like normal void, this next + * test will fail since it will get the void confirmation rather than + * the correct result. In this circumstance, the client will receive the + * error: + * + * application error: Wrong method name + */ + /** + * I32 TEST + */ + printf ("re-test testI32(-1)"); + if (t_test_thrift_test_if_test_i32 (test_client, + &int32, + -1, + &error)) { + printf (" = %d\n", int32); + if (int32 != -1) + fail_count++; + } + else { + printf ("%s\n", error->message); + g_error_free (error); + error = NULL; + + fail_count++; + } + + gettimeofday (&time_stop, NULL); + timersub (&time_stop, &time_start, &time_elapsed); + time_elapsed_usec = + time_elapsed.tv_sec * 1000 * 1000 + time_elapsed.tv_usec; + + printf("Total time: %" PRIu64 " us\n", time_elapsed_usec); + + time_total_usec += time_elapsed_usec; + if (time_elapsed_usec < time_min_usec) + time_min_usec = time_elapsed_usec; + if (time_elapsed_usec > time_max_usec) + time_max_usec = time_elapsed_usec; + + thrift_transport_close (transport, &error); + } + else { + printf ("Connect failed: %s\n", error->message); + g_error_free (error); + error = NULL; + + return 1; + } + } + + /* All done---output statistics */ + puts ("\nAll tests done."); + printf("Number of failures: %d\n", fail_count); + + time_avg_usec = time_total_usec / num_tests; + + printf ("Min time: %" PRIu64 " us\n", time_min_usec); + printf ("Max time: %" PRIu64 " us\n", time_max_usec); + printf ("Avg time: %" PRIu64 " us\n", time_avg_usec); + + g_clear_object(&second_service); + g_clear_object(&protocol2); + g_clear_object(&test_client); + g_clear_object(&protocol); + g_clear_object(&transport); + g_clear_object(&socket); + + if (ssl) { + thrift_ssl_socket_finalize_openssl(); + } + + return fail_count; +} diff --git a/test/c_glib/src/test_server.c b/test/c_glib/src/test_server.c new file mode 100644 index 0000000..2d716ec --- /dev/null +++ b/test/c_glib/src/test_server.c @@ -0,0 +1,290 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../gen-c_glib/t_test_thrift_test.h" +#include "../gen-c_glib/t_test_second_service.h" + +#include "thrift_test_handler.h" +#include "thrift_second_service_handler.h" + +/* Our server object, declared globally so it is accessible within the SIGINT + signal handler */ +ThriftServer *server = NULL; + +/* A flag that indicates whether the server was interrupted with SIGINT + (i.e. Ctrl-C) so we can tell whether its termination was abnormal */ +gboolean sigint_received = FALSE; + +/* Handle SIGINT ("Ctrl-C") signals by gracefully stopping the server */ +static void +sigint_handler (int signal_number) +{ + THRIFT_UNUSED_VAR (signal_number); + + /* Take note we were called */ + sigint_received = TRUE; + + /* Shut down the server gracefully */ + if (server != NULL) + thrift_server_stop (server); +} + +int +main (int argc, char **argv) +{ + static gint port = 9090; + static gchar *server_type_option = NULL; + static gchar *transport_option = NULL; + static gchar *protocol_option = NULL; + static gint string_limit = 0; + static gint container_limit = 0; + + static + GOptionEntry option_entries[] = { + { "port", 0, 0, G_OPTION_ARG_INT, &port, + "Port number to connect (=9090)", NULL }, + { "server-type", 0, 0, G_OPTION_ARG_STRING, &server_type_option, + "Type of server: simple (=simple)", NULL }, + { "transport", 0, 0, G_OPTION_ARG_STRING, &transport_option, + "Transport: buffered, framed (=buffered)", NULL }, + { "protocol", 0, 0, G_OPTION_ARG_STRING, &protocol_option, + "Protocol: binary, compact (=binary)", NULL }, + { "string-limit", 0, 0, G_OPTION_ARG_INT, &string_limit, + "Max string length (=none)", NULL }, + { "container-limit", 0, 0, G_OPTION_ARG_INT, &container_limit, + "Max container length (=none)", NULL }, + { NULL } + }; + + gchar *server_name = "simple"; + gchar *transport_name = "buffered"; + GType transport_factory_type = THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY; + gchar *protocol_name = "binary"; + GType protocol_factory_type = THRIFT_TYPE_BINARY_PROTOCOL_FACTORY; + + TTestThriftTestHandler *handler; + TTestThriftTestHandler *handler_second_service = NULL; + ThriftProcessor *processor; + ThriftProcessor *processor_test = NULL; + ThriftProcessor *processor_second_service = NULL; + ThriftServerTransport *server_transport; + ThriftTransportFactory *transport_factory; + ThriftProtocolFactory *protocol_factory; + + struct sigaction sigint_action; + + GOptionContext *option_context; + gboolean options_valid = TRUE; + + GError *error = NULL; + +#if (!GLIB_CHECK_VERSION (2, 36, 0)) + g_type_init (); +#endif + + /* Configure and parse our command-line options */ + option_context = g_option_context_new (NULL); + g_option_context_add_main_entries (option_context, + option_entries, + NULL); + if (g_option_context_parse (option_context, + &argc, + &argv, + &error) == FALSE) { + fprintf (stderr, "%s\n", error->message); + return 255; + } + g_option_context_free (option_context); + + /* Validate the parsed options */ + if (server_type_option != NULL && + strncmp (server_type_option, "simple", 7) != 0) { + fprintf (stderr, "Unknown server type %s\n", protocol_option); + options_valid = FALSE; + } + + if (protocol_option != NULL) { + if (strncmp (protocol_option, "compact", 8) == 0) { + protocol_factory_type = THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY; + protocol_name = "compact"; + } + else if (strncmp (protocol_option, "multi", 6) == 0) { + protocol_name = "binary:multi"; + } + else if (strncmp (protocol_option, "multic", 7) == 0) { + protocol_factory_type = THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY; + protocol_name = "compact:multic"; + } + else if (strncmp (protocol_option, "binary", 7) != 0) { + fprintf (stderr, "Unknown protocol type %s\n", protocol_option); + options_valid = FALSE; + } + } + + if (transport_option != NULL) { + if (strncmp (transport_option, "framed", 7) == 0) { + transport_factory_type = THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY; + transport_name = "framed"; + } + else if (strncmp (transport_option, "buffered", 9) != 0) { + fprintf (stderr, "Unknown transport type %s\n", transport_option); + options_valid = FALSE; + } + } + + if (!options_valid) + return 254; + + /* Establish all our connection objects */ + handler = g_object_new (TYPE_THRIFT_TEST_HANDLER, + NULL); + + + + if(strstr(protocol_name, ":multi")){ + /* When a multiplexed processor is involved the handler is not + registered as usual. We create the processor and the real + processor is registered. Multiple processors can be registered + at once. This is why we don't have a constructor property */ + processor = g_object_new (THRIFT_TYPE_MULTIPLEXED_PROCESSOR, + NULL); + + handler_second_service = g_object_new (TYPE_SECOND_SERVICE_HANDLER, + NULL); + + processor_test = g_object_new (T_TEST_TYPE_THRIFT_TEST_PROCESSOR, + "handler", handler, + NULL); + processor_second_service = g_object_new (T_TEST_TYPE_SECOND_SERVICE_PROCESSOR, + "handler", handler_second_service, + NULL); + + /* We register a test processor with Multiplexed name ThriftTest */ + if(!thrift_multiplexed_processor_register_processor(processor, + "ThriftTest", processor_test, + &error)){ + g_message ("thrift_server_serve: %s", + error != NULL ? error->message : "(null)"); + g_clear_error (&error); + } + /* We register a second test processor with Multiplexed name SecondService + * we are responsible of freeing the processor when it's not used anymore */ + if(!thrift_multiplexed_processor_register_processor(processor, + "SecondService", processor_second_service, + &error)){ + g_message ("thrift_server_serve: %s", + error != NULL ? error->message : "(null)"); + g_clear_error (&error); + } + + }else{ + processor = g_object_new (T_TEST_TYPE_THRIFT_TEST_PROCESSOR, + "handler", handler, + NULL); + } + server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET, + "port", port, + NULL); + transport_factory = g_object_new (transport_factory_type, + NULL); + + if (strstr (protocol_name, "compact") != NULL) { + protocol_factory = g_object_new (protocol_factory_type, + "string_limit", string_limit, + "container_limit", container_limit, + NULL); + } else { + protocol_factory = g_object_new (protocol_factory_type, + NULL); + } + + server = g_object_new (THRIFT_TYPE_SIMPLE_SERVER, + "processor", processor, + "server_transport", server_transport, + "input_transport_factory", transport_factory, + "output_transport_factory", transport_factory, + "input_protocol_factory", protocol_factory, + "output_protocol_factory", protocol_factory, + NULL); + + /* Install our SIGINT handler, which handles Ctrl-C being pressed by stopping + the server gracefully */ + memset (&sigint_action, 0, sizeof (sigint_action)); + sigint_action.sa_handler = sigint_handler; + sigint_action.sa_flags = SA_RESETHAND; + sigaction (SIGINT, &sigint_action, NULL); + + printf ("Starting \"%s\" server (%s/%s) listen on: %d\n", + server_name, + transport_name, + protocol_name, + port); + fflush (stdout); + + /* Serve clients until SIGINT is received (Ctrl-C is pressed) */ + thrift_server_serve (server, &error); + + /* If the server stopped for any reason other than being interrupted by the + user, report the error */ + if (!sigint_received) { + g_message ("thrift_server_serve: %s", + error != NULL ? error->message : "(null)"); + g_clear_error (&error); + } + + puts ("done."); + + g_object_unref (server); + g_object_unref (protocol_factory); + g_object_unref (transport_factory); + g_object_unref (server_transport); + g_object_unref (processor); + g_object_unref (handler); + if(handler_second_service){ + g_object_unref (handler_second_service); + } + if(processor_test){ + g_object_unref (processor_test); + } + if(processor_second_service){ + g_object_unref (processor_second_service); + } + + return 0; +} diff --git a/test/c_glib/src/thrift_second_service_handler.c b/test/c_glib/src/thrift_second_service_handler.c new file mode 100644 index 0000000..66ac7bc --- /dev/null +++ b/test/c_glib/src/thrift_second_service_handler.c @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +#include +#include + +#include "thrift_second_service_handler.h" + +/* A handler that implements the TTestSecondServiceIf interface */ + +G_DEFINE_TYPE (SecondServiceHandler, + second_service_handler, + T_TEST_TYPE_SECOND_SERVICE_HANDLER); + + +gboolean +second_service_handler_secondtest_string (TTestSecondServiceIf *iface, + gchar **_return, + const gchar *thing, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + gchar buffer[256]; + + printf ("testSecondServiceMultiplexSecondTestString(\"%s\")\n", thing); + snprintf(buffer, 255, "testString(\"%s\")", thing); + *_return = g_strdup (buffer); + + return TRUE; +} + +static void +second_service_handler_init (SecondServiceHandler *self) +{ + THRIFT_UNUSED_VAR (self); +} + +static void +second_service_handler_class_init (SecondServiceHandlerClass *klass) +{ + TTestSecondServiceHandlerClass *base_class = + T_TEST_SECOND_SERVICE_HANDLER_CLASS (klass); + + + base_class->secondtest_string = + second_service_handler_secondtest_string; + +} diff --git a/test/c_glib/src/thrift_second_service_handler.h b/test/c_glib/src/thrift_second_service_handler.h new file mode 100644 index 0000000..bbe048c --- /dev/null +++ b/test/c_glib/src/thrift_second_service_handler.h @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _SECOND_SERVICE_HANDLER_H +#define _SECOND_SERVICE_HANDLER_H + +#include +#include + +#include "../gen-c_glib/t_test_second_service.h" + +G_BEGIN_DECLS + +/* A handler that implements the TTestSecondServiceIf interface */ + +#define TYPE_SECOND_SERVICE_HANDLER (second_service_handler_get_type ()) + +#define SECOND_SERVICE_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + TYPE_SECOND_SERVICE_HANDLER, \ + SecondServiceHandler)) +#define IS_SECOND_SERVICE_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + TYPE_SECOND_SERVICE_HANDLER)) +#define SECOND_SERVICE_HANDLER_CLASS(c) \ + (G_TYPE_CHECK_CLASS_CAST ((c), \ + TYPE_SECOND_SERVICE_HANDLER, \ + SecondServiceHandlerClass)) +#define IS_SECOND_SERVICE_HANDLER_CLASS(c) \ + (G_TYPE_CHECK_CLASS_TYPE ((c), \ + TYPE_SECOND_SERVICE_HANDLER)) +#define SECOND_SERVICE_HANDLER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + TYPE_SECOND_SERVICE_HANDLER, \ + SecondServiceHandlerClass)) + +typedef struct _SecondServiceHandler SecondServiceHandler; +typedef struct _SecondServiceHandlerClass SecondServiceHandlerClass; + +struct _SecondServiceHandler { + TTestSecondServiceHandler parent; +}; + +struct _SecondServiceHandlerClass { + TTestSecondServiceHandlerClass parent; + +}; + +/* Used by SECOND_SERVICE_HANDLER_GET_TYPE */ +GType second_service_handler_get_type (void); + +gboolean second_service_handler_blah_blah (TTestSecondServiceIf *iface, GError **error); +gboolean second_service_handler_secondtest_string (TTestSecondServiceIf *iface, gchar ** _return, const gchar * thing, GError **error); + +G_END_DECLS + +#endif /* _SECOND_SERVICE_HANDLER_H */ diff --git a/test/c_glib/src/thrift_test_handler.c b/test/c_glib/src/thrift_test_handler.c new file mode 100644 index 0000000..1d8bcb2 --- /dev/null +++ b/test/c_glib/src/thrift_test_handler.c @@ -0,0 +1,837 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +#include +#include + +#include "thrift_test_handler.h" + +/* A handler that implements the TTestThriftTestIf interface */ + +G_DEFINE_TYPE (ThriftTestHandler, + thrift_test_handler, + T_TEST_TYPE_THRIFT_TEST_HANDLER); + +gboolean +thrift_test_handler_test_void (TTestThriftTestIf *iface, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testVoid()\n"); + + return TRUE; +} + +gboolean +thrift_test_handler_test_string (TTestThriftTestIf *iface, + gchar **_return, + const gchar *thing, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testString(\"%s\")\n", thing); + *_return = g_strdup (thing); + + return TRUE; +} + +gboolean +thrift_test_handler_test_bool (TTestThriftTestIf *iface, + gboolean *_return, + const gboolean thing, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testBool(%s)\n", thing ? "true" : "false"); + *_return = thing; + + return TRUE; +} + +gboolean +thrift_test_handler_test_byte (TTestThriftTestIf *iface, + gint8 *_return, + const gint8 thing, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testByte(%d)\n", (gint)thing); + *_return = thing; + + return TRUE; +} + +gboolean +thrift_test_handler_test_i32 (TTestThriftTestIf *iface, + gint32 *_return, + const gint32 thing, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testI32(%d)\n", thing); + *_return = thing; + + return TRUE; +} + +gboolean +thrift_test_handler_test_i64 (TTestThriftTestIf *iface, + gint64 *_return, + const gint64 thing, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testI64(%" PRId64 ")\n", thing); + *_return = thing; + + return TRUE; +} + +gboolean +thrift_test_handler_test_double (TTestThriftTestIf *iface, + gdouble *_return, + const gdouble thing, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testDouble(%f)\n", thing); + *_return = thing; + + return TRUE; +} + +gboolean +thrift_test_handler_test_binary (TTestThriftTestIf *iface, + GByteArray ** _return, + const GByteArray * thing, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testBinary()\n"); // TODO: hex output + g_byte_array_ref((GByteArray *)thing); + *_return = (GByteArray *)thing; + + return TRUE; +} + +gboolean +thrift_test_handler_test_struct (TTestThriftTestIf *iface, + TTestXtruct **_return, + const TTestXtruct *thing, + GError **error) +{ + gchar *string_thing = NULL; + gint byte_thing; + gint i32_thing; + gint64 i64_thing; + + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + g_object_get ((TTestXtruct *)thing, + "string_thing", &string_thing, + "byte_thing", &byte_thing, + "i32_thing", &i32_thing, + "i64_thing", &i64_thing, + NULL); + + printf ("testStruct({\"%s\", %d, %d, %" PRId64 "})\n", + string_thing, + (gint)byte_thing, + i32_thing, + i64_thing); + + g_object_set (*_return, + "string_thing", string_thing, + "byte_thing", byte_thing, + "i32_thing", i32_thing, + "i64_thing", i64_thing, + NULL); + + if (string_thing != NULL) + g_free (string_thing); + + return TRUE; +} + +gboolean +thrift_test_handler_test_nest (TTestThriftTestIf *iface, + TTestXtruct2 **_return, + const TTestXtruct2 *thing, + GError **error) +{ + gchar *inner_string_thing = NULL; + gint byte_thing, inner_byte_thing; + gint i32_thing, inner_i32_thing; + gint64 inner_i64_thing; + TTestXtruct *struct_thing; + + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + g_object_get ((TTestXtruct2 *)thing, + "byte_thing", &byte_thing, + "struct_thing", &struct_thing, + "i32_thing", &i32_thing, + NULL); + g_object_get (struct_thing, + "string_thing", &inner_string_thing, + "byte_thing", &inner_byte_thing, + "i32_thing", &inner_i32_thing, + "i64_thing", &inner_i64_thing, + NULL); + + printf ("testNest({%d, {\"%s\", %d, %d, %" PRId64 "}, %d})\n", + byte_thing, + inner_string_thing, + inner_byte_thing, + inner_i32_thing, + inner_i64_thing, + i32_thing); + + g_object_set (*_return, + "byte_thing", byte_thing, + "struct_thing", struct_thing, + "i32_thing", i32_thing, + NULL); + + if (inner_string_thing != NULL) + g_free (inner_string_thing); + g_object_unref (struct_thing); + + return TRUE; +} + +gboolean +thrift_test_handler_test_map (TTestThriftTestIf *iface, + GHashTable **_return, + const GHashTable *thing, + GError **error) +{ + GHashTableIter hash_table_iter; + gpointer key; + gpointer value; + gboolean first = TRUE; + + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testMap({"); + g_hash_table_iter_init (&hash_table_iter, (GHashTable *)thing); + while (g_hash_table_iter_next (&hash_table_iter, + &key, + &value)) { + gint32 *new_key; + gint32 *new_value; + + if (first) + first = FALSE; + else + printf (", "); + + printf ("%d => %d", *(gint32 *)key, *(gint32 *)value); + + new_key = g_malloc (sizeof *new_key); + *new_key = *(gint32 *)key; + new_value = g_malloc (sizeof *new_value); + *new_value = *(gint32 *)value; + g_hash_table_insert (*_return, new_key, new_value); + } + printf ("})\n"); + + return TRUE; +} + +gboolean +thrift_test_handler_test_string_map (TTestThriftTestIf *iface, + GHashTable **_return, + const GHashTable *thing, + GError **error) +{ + GHashTableIter hash_table_iter; + gpointer key; + gpointer value; + gboolean first = TRUE; + + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testStringMap({"); + g_hash_table_iter_init (&hash_table_iter, (GHashTable *)thing); + while (g_hash_table_iter_next (&hash_table_iter, + &key, + &value)) { + gchar *new_key; + gchar *new_value; + + if (first) + first = FALSE; + else + printf (", "); + + printf ("%s => %s", (gchar *)key, (gchar *)value); + + new_key = g_strdup ((gchar *)key); + new_value = g_strdup ((gchar *)value); + g_hash_table_insert (*_return, new_key, new_value); + } + printf ("})\n"); + + return TRUE; +} + +gboolean +thrift_test_handler_test_set (TTestThriftTestIf *iface, + GHashTable **_return, + const GHashTable *thing, + GError **error) +{ + GHashTableIter hash_table_iter; + gpointer key; + gboolean first = TRUE; + + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testSet({"); + g_hash_table_iter_init (&hash_table_iter, (GHashTable *)thing); + while (g_hash_table_iter_next (&hash_table_iter, + &key, + NULL)) { + gint32 *new_key; + + if (first) + first = FALSE; + else + printf (", "); + + printf ("%d", *(gint32 *)key); + + new_key = g_malloc (sizeof *new_key); + *new_key = *(gint32 *)key; + g_hash_table_insert (*_return, new_key, NULL); + } + printf ("})\n"); + + return TRUE; +} + +gboolean +thrift_test_handler_test_list (TTestThriftTestIf *iface, + GArray **_return, + const GArray *thing, + GError **error) +{ + guint i; + gboolean first = TRUE; + + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testList({"); + for (i = 0; i < thing->len; i += 1) { + gint32 value; + gint32 *new_value; + + if (first) + first = FALSE; + else + printf (", "); + + value = g_array_index (thing, gint32, i); + printf ("%d", value); + + new_value = g_malloc (sizeof *new_value); + *new_value = value; + g_array_append_val (*_return, *new_value); + } + printf ("})\n"); + + return TRUE; +} + +gboolean +thrift_test_handler_test_enum (TTestThriftTestIf *iface, + TTestNumberz *_return, + const TTestNumberz thing, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testEnum(%d)\n", thing); + *_return = thing; + + return TRUE; +} + +gboolean +thrift_test_handler_test_typedef (TTestThriftTestIf *iface, + TTestUserId *_return, + const TTestUserId thing, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testTypedef(%" PRId64 ")\n", thing); + *_return = thing; + + return TRUE; +} + +gboolean +thrift_test_handler_test_map_map (TTestThriftTestIf *iface, + GHashTable **_return, + const gint32 hello, + GError **error) +{ + GHashTable *positive; + GHashTable *negative; + gint32 *key; + gint32 *value; + guint i; + + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testMapMap(%d)\n", hello); + + positive = g_hash_table_new_full (g_int_hash, + g_int_equal, + g_free, + g_free); + negative = g_hash_table_new_full (g_int_hash, + g_int_equal, + g_free, + g_free); + + for (i = 1; i < 5; i += 1) { + key = g_malloc (sizeof *key); + value = g_malloc (sizeof *value); + *key = i; + *value = i; + g_hash_table_insert (positive, key, value); + + key = g_malloc (sizeof *key); + value = g_malloc (sizeof *value); + *key = -i; + *value = -i; + g_hash_table_insert (negative, key, value); + } + + key = g_malloc (sizeof *key); + *key = 4; + g_hash_table_insert (*_return, key, positive); + + key = g_malloc (sizeof *key); + *key = -4; + g_hash_table_insert (*_return, key, negative); + + return TRUE; +} + +gboolean +thrift_test_handler_test_insanity (TTestThriftTestIf *iface, + GHashTable **_return, + const TTestInsanity *argument, + GError **error) +{ + TTestXtruct *xtruct_in; + + gchar *string_thing = NULL; + gint byte_thing; + gint i32_thing; + gint64 i64_thing; + + GPtrArray *xtructs; + + TTestInsanity *looney; + + GHashTable *user_map; + GHashTable *first_map; + GHashTable *second_map; + + GHashTableIter hash_table_iter; + GHashTableIter inner_hash_table_iter; + GHashTableIter user_map_iter; + + gpointer key; + gpointer value; + + TTestUserId *user_id; + + guint i; + + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testInsanity()\n"); + + first_map = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + g_object_unref); + second_map = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + g_object_unref); + + g_hash_table_insert (first_map, + GINT_TO_POINTER (T_TEST_NUMBERZ_TWO), + (gpointer)argument); + g_hash_table_insert (first_map, + GINT_TO_POINTER (T_TEST_NUMBERZ_THREE), + (gpointer)argument); + + /* Increment argument's ref count by two because first_map now holds + two references to it and the caller is not aware we have made any + additional references to argument. (That is, caller owns argument + and will unref it explicitly in addition to unref-ing *_return.) + + We do this instead of creating a copy of argument in order to mimic + the C++ implementation (and since, frankly, the world needs less + argument, not more). */ + g_object_ref ((gpointer)argument); + g_object_ref ((gpointer)argument); + + looney = g_object_new (T_TEST_TYPE_INSANITY, NULL); + g_hash_table_insert (second_map, + GINT_TO_POINTER (T_TEST_NUMBERZ_SIX), + looney); + + user_id = g_malloc (sizeof *user_id); + *user_id = 1; + g_hash_table_insert (*_return, user_id, first_map); + + user_id = g_malloc (sizeof *user_id); + *user_id = 2; + g_hash_table_insert (*_return, user_id, second_map); + + printf ("return"); + printf (" = {"); + g_hash_table_iter_init (&hash_table_iter, *_return); + while (g_hash_table_iter_next (&hash_table_iter, + &key, + &value)) { + printf ("%" PRId64 " => {", *(TTestUserId *)key); + + g_hash_table_iter_init (&inner_hash_table_iter, + (GHashTable *)value); + while (g_hash_table_iter_next (&inner_hash_table_iter, + &key, + &value)) { + printf ("%d => {", (TTestNumberz)key); + + g_object_get ((TTestInsanity *)value, + "userMap", &user_map, + "xtructs", &xtructs, + NULL); + + printf ("{"); + g_hash_table_iter_init (&user_map_iter, user_map); + while (g_hash_table_iter_next (&user_map_iter, + &key, + &value)) { + printf ("%d => %" PRId64 ", ", + (TTestNumberz)key, + *(TTestUserId *)value); + } + printf ("}, "); + g_hash_table_unref (user_map); + + printf ("{"); + for (i = 0; i < xtructs->len; ++i) { + xtruct_in = g_ptr_array_index (xtructs, i); + g_object_get (xtruct_in, + "string_thing", &string_thing, + "byte_thing", &byte_thing, + "i32_thing", &i32_thing, + "i64_thing", &i64_thing, + NULL); + + printf ("{\"%s\", %d, %d, %" PRId64 "}, ", + string_thing, + byte_thing, + i32_thing, + i64_thing); + } + printf ("}"); + g_ptr_array_unref (xtructs); + + printf ("}, "); + } + printf ("}, "); + } + printf ("}\n"); + + return TRUE; +} + +gboolean +thrift_test_handler_test_multi (TTestThriftTestIf *iface, + TTestXtruct **_return, + const gint8 arg0, + const gint32 arg1, + const gint64 arg2, + const GHashTable *arg3, + const TTestNumberz arg4, + const TTestUserId arg5, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + THRIFT_UNUSED_VAR (arg3); + THRIFT_UNUSED_VAR (arg4); + THRIFT_UNUSED_VAR (arg5); + + printf ("testMulti()\n"); + + g_object_set (*_return, + "string_thing", g_strdup ("Hello2"), + "byte_thing", arg0, + "i32_thing", arg1, + "i64_thing", arg2, + NULL); + + return TRUE; +} + +gboolean +thrift_test_handler_test_exception (TTestThriftTestIf *iface, + const gchar *arg, + TTestXception **err1, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + + TTestXtruct *xtruct; + gboolean result; + + printf ("testException(%s)\n", arg); + + /* Unlike argument objects, exception objects are not pre-created */ + g_assert (*err1 == NULL); + + if (strncmp (arg, "Xception", 9) == 0) { + /* "Throw" a custom exception: Set the corresponding exception + argument, set *error to NULL and return FALSE */ + *err1 = g_object_new (T_TEST_TYPE_XCEPTION, + "errorCode", 1001, + "message", g_strdup (arg), + NULL); + *error = NULL; + result = FALSE; + } + else if (strncmp (arg, "TException", 11) == 0) { + /* "Throw" a generic TException (ThriftApplicationException): Set + all exception arguments to NULL, set *error and return FALSE */ + *err1 = NULL; + g_set_error (error, + thrift_application_exception_error_quark (), + THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN, + "Default TException."); + result = FALSE; + } + else { + *err1 = NULL; + *error = NULL; + + /* This code is duplicated from the C++ test suite, though it + appears to serve no purpose */ + xtruct = g_object_new (T_TEST_TYPE_XTRUCT, + "string_thing", g_strdup (arg), + NULL); + g_object_unref (xtruct); + + result = TRUE; + } + + return result; +} + +gboolean +thrift_test_handler_test_multi_exception (TTestThriftTestIf *iface, + TTestXtruct **_return, + const gchar *arg0, + const gchar *arg1, + TTestXception **err1, + TTestXception2 **err2, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + TTestXtruct *struct_thing; + gboolean result; + + printf ("testMultiException(%s, %s)\n", arg0, arg1); + + g_assert (*err1 == NULL); + g_assert (*err2 == NULL); + + if (strncmp (arg0, "Xception", 8) == 0 && strlen(arg0) == 8) { + *err1 = g_object_new (T_TEST_TYPE_XCEPTION, + "errorCode", 1001, + "message", g_strdup ("This is an Xception"), + NULL); + result = FALSE; + } + else if (strncmp (arg0, "Xception2", 9) == 0) { + *err2 = g_object_new (T_TEST_TYPE_XCEPTION2, + "errorCode", 2002, + NULL); + + g_object_get (*err2, + "struct_thing", &struct_thing, + NULL); + g_object_set (struct_thing, + "string_thing", g_strdup ("This is an Xception2"), + NULL); + g_object_set (*err2, + "struct_thing", struct_thing, + NULL); + g_object_unref (struct_thing); + + result = FALSE; + } + else { + g_object_set (*_return, + "string_thing", g_strdup (arg1), + NULL); + result = TRUE; + } + + return result; +} + +gboolean +thrift_test_handler_test_oneway (TTestThriftTestIf *iface, + const gint32 secondsToSleep, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("testOneway(%d): Sleeping...\n", secondsToSleep); + sleep (secondsToSleep); + printf ("testOneway(%d): done sleeping!\n", secondsToSleep); + + return TRUE; +} + +static void +thrift_test_handler_init (ThriftTestHandler *self) +{ + THRIFT_UNUSED_VAR (self); +} + +static void +thrift_test_handler_class_init (ThriftTestHandlerClass *klass) +{ + TTestThriftTestHandlerClass *base_class = + T_TEST_THRIFT_TEST_HANDLER_CLASS (klass); + + base_class->test_void = + klass->test_void = + thrift_test_handler_test_void; + base_class->test_string = + klass->test_string = + thrift_test_handler_test_string; + base_class->test_bool = + klass->test_bool = + thrift_test_handler_test_bool; + base_class->test_byte = + klass->test_byte = + thrift_test_handler_test_byte; + base_class->test_i32 = + klass->test_i32 = + thrift_test_handler_test_i32; + base_class->test_i64 = + klass->test_i64 = + thrift_test_handler_test_i64; + base_class->test_double = + klass->test_double = + thrift_test_handler_test_double; + base_class->test_binary = + klass->test_binary = + thrift_test_handler_test_binary; + base_class->test_struct = + klass->test_struct = + thrift_test_handler_test_struct; + base_class->test_nest = + klass->test_nest = + thrift_test_handler_test_nest; + base_class->test_map = + klass->test_map = + thrift_test_handler_test_map; + base_class->test_string_map = + klass->test_string_map = + thrift_test_handler_test_string_map; + base_class->test_set = + klass->test_set = + thrift_test_handler_test_set; + base_class->test_list = + klass->test_list = + thrift_test_handler_test_list; + base_class->test_enum = + klass->test_enum = + thrift_test_handler_test_enum; + base_class->test_typedef = + klass->test_typedef = + thrift_test_handler_test_typedef; + base_class->test_map_map = + klass->test_map_map = + thrift_test_handler_test_map_map; + base_class->test_insanity = + klass->test_insanity = + thrift_test_handler_test_insanity; + base_class->test_multi = + klass->test_multi = + thrift_test_handler_test_multi; + base_class->test_exception = + klass->test_exception = + thrift_test_handler_test_exception; + base_class->test_multi_exception = + klass->test_multi_exception = + thrift_test_handler_test_multi_exception; + base_class->test_oneway = + klass->test_oneway = + thrift_test_handler_test_oneway; +} diff --git a/test/c_glib/src/thrift_test_handler.h b/test/c_glib/src/thrift_test_handler.h new file mode 100644 index 0000000..b64cb16 --- /dev/null +++ b/test/c_glib/src/thrift_test_handler.h @@ -0,0 +1,245 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TEST_HANDLER_H +#define _THRIFT_TEST_HANDLER_H + +#include +#include + +#include "../gen-c_glib/t_test_thrift_test.h" + +G_BEGIN_DECLS + +/* A handler that implements the TTestThriftTestIf interface */ + +#define TYPE_THRIFT_TEST_HANDLER (thrift_test_handler_get_type ()) + +#define THRIFT_TEST_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + TYPE_THRIFT_TEST_HANDLER, \ + ThriftTestHandler)) +#define IS_THRIFT_TEST_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + TYPE_THRIFT_TEST_HANDLER)) +#define THRIFT_TEST_HANDLER_CLASS(c) \ + (G_TYPE_CHECK_CLASS_CAST ((c), \ + TYPE_THRIFT_TEST_HANDLER, \ + ThriftTestHandlerClass)) +#define IS_THRIFT_TEST_HANDLER_CLASS(c) \ + (G_TYPE_CHECK_CLASS_TYPE ((c), \ + TYPE_THRIFT_TEST_HANDLER)) +#define THRIFT_TEST_HANDLER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + TYPE_THRIFT_TEST_HANDLER, \ + ThriftTestHandlerClass)) + +typedef struct _ThriftTestHandler ThriftTestHandler; +typedef struct _ThriftTestHandlerClass ThriftTestHandlerClass; + +struct _ThriftTestHandler { + TTestThriftTestHandler parent; +}; + +struct _ThriftTestHandlerClass { + TTestThriftTestHandlerClass parent; + + gboolean (*test_void) (TTestThriftTestIf *iface, + GError **error); + gboolean (*test_string) (TTestThriftTestIf *iface, + gchar **_return, + const gchar *thing, + GError **error); + gboolean (*test_bool) (TTestThriftTestIf *iface, + gboolean*_return, + const gboolean thing, + GError **error); + gboolean (*test_byte) (TTestThriftTestIf *iface, + gint8*_return, + const gint8 thing, + GError **error); + gboolean (*test_i32) (TTestThriftTestIf *iface, + gint32*_return, + const gint32 thing, + GError **error); + gboolean (*test_i64) (TTestThriftTestIf *iface, + gint64*_return, + const gint64 thing, + GError **error); + gboolean (*test_double) (TTestThriftTestIf *iface, + gdouble*_return, + const gdouble thing, + GError **error); + gboolean (*test_binary) (TTestThriftTestIf *iface, + GByteArray **_return, + const GByteArray *thing, + GError **error); + gboolean (*test_struct) (TTestThriftTestIf *iface, + TTestXtruct **_return, + const TTestXtruct *thing, + GError **error); + gboolean (*test_nest) (TTestThriftTestIf *iface, + TTestXtruct2 **_return, + const TTestXtruct2 *thing, + GError **error); + gboolean (*test_map) (TTestThriftTestIf *iface, + GHashTable **_return, + const GHashTable *thing, + GError **error); + gboolean (*test_string_map) (TTestThriftTestIf *iface, + GHashTable **_return, + const GHashTable *thing, + GError **error); + gboolean (*test_set) (TTestThriftTestIf *iface, + GHashTable **_return, + const GHashTable *thing, + GError **error); + gboolean (*test_list) (TTestThriftTestIf *iface, + GArray **_return, + const GArray *thing, + GError **error); + gboolean (*test_enum) (TTestThriftTestIf *iface, + TTestNumberz*_return, + const TTestNumberz thing, + GError **error); + gboolean (*test_typedef) (TTestThriftTestIf *iface, + TTestUserId*_return, + const TTestUserId thing, + GError **error); + gboolean (*test_map_map) (TTestThriftTestIf *iface, + GHashTable **_return, + const gint32 hello, + GError **error); + gboolean (*test_insanity) (TTestThriftTestIf *iface, + GHashTable **_return, + const TTestInsanity *argument, + GError **error); + gboolean (*test_multi) (TTestThriftTestIf *iface, + TTestXtruct **_return, + const gint8 arg0, + const gint32 arg1, + const gint64 arg2, + const GHashTable *arg3, + const TTestNumberz arg4, + const TTestUserId arg5, + GError **error); + gboolean (*test_exception) (TTestThriftTestIf *iface, + const gchar *arg, + TTestXception **err1, + GError **error); + gboolean (*test_multi_exception) (TTestThriftTestIf *iface, + TTestXtruct **_return, + const gchar *arg0, + const gchar *arg1, + TTestXception **err1, + TTestXception2 **err2, + GError **error); + gboolean (*test_oneway) (TTestThriftTestIf *iface, + const gint32 secondsToSleep, + GError **error); +}; + +/* Used by THRIFT_TEST_HANDLER_GET_TYPE */ +GType thrift_test_handler_get_type (void); + +gboolean thrift_test_handler_test_void (TTestThriftTestIf *iface, + GError **error); +gboolean thrift_test_handler_test_string (TTestThriftTestIf *iface, + gchar **_return, + const gchar *thing, + GError **error); +gboolean thrift_test_handler_test_byte (TTestThriftTestIf *iface, + gint8*_return, + const gint8 thing, + GError **error); +gboolean t_test_thrift_test_if_test_i32 (TTestThriftTestIf *iface, + gint32*_return, + const gint32 thing, + GError **error); +gboolean thrift_test_handler_test_i64 (TTestThriftTestIf *iface, + gint64*_return, + const gint64 thing, + GError **error); +gboolean thrift_test_handler_test_double (TTestThriftTestIf *iface, + gdouble*_return, + const gdouble thing, + GError **error); +gboolean thrift_test_handler_test_struct (TTestThriftTestIf *iface, + TTestXtruct **_return, + const TTestXtruct *thing, + GError **error); +gboolean thrift_test_handler_test_nest (TTestThriftTestIf *iface, + TTestXtruct2 **_return, + const TTestXtruct2 *thing, + GError **error); +gboolean thrift_test_handler_test_map (TTestThriftTestIf *iface, + GHashTable **_return, + const GHashTable *thing, + GError **error); +gboolean thrift_test_handler_test_string_map (TTestThriftTestIf *iface, + GHashTable **_return, + const GHashTable *thing, + GError **error); +gboolean thrift_test_handler_test_set (TTestThriftTestIf *iface, + GHashTable **_return, + const GHashTable *thing, + GError **error); +gboolean thrift_test_handler_test_list (TTestThriftTestIf *iface, + GArray **_return, + const GArray *thing, + GError **error); +gboolean thrift_test_handler_test_typedef (TTestThriftTestIf *iface, + TTestUserId*_return, + const TTestUserId thing, + GError **error); +gboolean thrift_test_handler_test_map_map (TTestThriftTestIf *iface, + GHashTable **_return, + const gint32 hello, + GError **error); +gboolean thrift_test_handler_test_insanity (TTestThriftTestIf *iface, + GHashTable **_return, + const TTestInsanity *argument, + GError **error); +gboolean thrift_test_handler_test_multi (TTestThriftTestIf *iface, + TTestXtruct **_return, + const gint8 arg0, + const gint32 arg1, + const gint64 arg2, + const GHashTable *arg3, + const TTestNumberz arg4, + const TTestUserId arg5, + GError **error); +gboolean thrift_test_handler_test_exception (TTestThriftTestIf *iface, + const gchar *arg, + TTestXception **err1, + GError **error); +gboolean thrift_test_handler_test_multi_exception (TTestThriftTestIf *iface, + TTestXtruct **_return, + const gchar *arg0, + const gchar *arg1, + TTestXception **err1, + TTestXception2 **err2, + GError **error); +gboolean thrift_test_handler_test_oneway (TTestThriftTestIf *iface, + const gint32 secondsToSleep, + GError **error); + +G_END_DECLS + +#endif /* _THRIFT_TEST_HANDLER_H */ diff --git a/test/cpp/CMakeLists.txt b/test/cpp/CMakeLists.txt new file mode 100755 index 0000000..cdd63db --- /dev/null +++ b/test/cpp/CMakeLists.txt @@ -0,0 +1,89 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Contains the thrift specific LINK_AGAINST_THRIFT_LIBRARY +include(ThriftMacros) + +include_directories(SYSTEM "${Boost_INCLUDE_DIRS}") + +find_package(OpenSSL REQUIRED) +include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") + +find_package(Libevent REQUIRED) # Libevent comes with CMake support from upstream +include_directories(SYSTEM ${LIBEVENT_INCLUDE_DIRS}) + +#Make sure gen-cpp files can be included +include_directories("${CMAKE_CURRENT_BINARY_DIR}") +include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen-cpp") +include_directories("${PROJECT_SOURCE_DIR}/lib/cpp/src") + +set(crosstestgencpp_SOURCES + gen-cpp/SecondService.cpp + gen-cpp/ThriftTest.cpp + gen-cpp/ThriftTest_types.cpp + gen-cpp/ThriftTest_constants.cpp + src/ThriftTest_extras.cpp +) +add_library(crosstestgencpp STATIC ${crosstestgencpp_SOURCES}) +LINK_AGAINST_THRIFT_LIBRARY(crosstestgencpp thrift) + +set(crossstressgencpp_SOURCES + gen-cpp/Service.cpp + gen-cpp/StressTest_types.cpp + gen-cpp/StressTest_constants.cpp +) +add_library(crossstressgencpp STATIC ${crossstressgencpp_SOURCES}) +LINK_AGAINST_THRIFT_LIBRARY(crossstressgencpp thrift) + +add_executable(TestServer src/TestServer.cpp) +target_link_libraries(TestServer crosstestgencpp ${Boost_LIBRARIES} ${LIBEVENT_LIB}) +LINK_AGAINST_THRIFT_LIBRARY(TestServer thrift) +LINK_AGAINST_THRIFT_LIBRARY(TestServer thriftnb) +LINK_AGAINST_THRIFT_LIBRARY(TestServer thriftz) + +add_executable(TestClient src/TestClient.cpp) +target_link_libraries(TestClient crosstestgencpp ${Boost_LIBRARIES} ${LIBEVENT_LIB}) +LINK_AGAINST_THRIFT_LIBRARY(TestClient thrift) +LINK_AGAINST_THRIFT_LIBRARY(TestClient thriftnb) +LINK_AGAINST_THRIFT_LIBRARY(TestClient thriftz) + +add_executable(StressTest src/StressTest.cpp) +target_link_libraries(StressTest crossstressgencpp ${Boost_LIBRARIES} ${LIBEVENT_LIB}) +LINK_AGAINST_THRIFT_LIBRARY(StressTest thrift) +LINK_AGAINST_THRIFT_LIBRARY(StressTest thriftnb) +add_test(NAME StressTest COMMAND StressTest) + +add_executable(StressTestNonBlocking src/StressTestNonBlocking.cpp) +target_link_libraries(StressTestNonBlocking crossstressgencpp ${Boost_LIBRARIES} ${LIBEVENT_LIB}) +LINK_AGAINST_THRIFT_LIBRARY(StressTestNonBlocking thrift) +LINK_AGAINST_THRIFT_LIBRARY(StressTestNonBlocking thriftnb) +LINK_AGAINST_THRIFT_LIBRARY(StressTestNonBlocking thriftz) +add_test(NAME StressTestNonBlocking COMMAND StressTestNonBlocking) + +# +# Common thrift code generation rules +# + +add_custom_command(OUTPUT gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest.h gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp + COMMAND ${THRIFT_COMPILER} --gen cpp:templates,cob_style -r ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift +) + +add_custom_command(OUTPUT gen-cpp/StressTest_types.cpp gen-cpp/StressTest_constants.cpp gen-cpp/Service.cpp + COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/StressTest.thrift +) diff --git a/test/cpp/Makefile b/test/cpp/Makefile new file mode 100644 index 0000000..c0a8db4 --- /dev/null +++ b/test/cpp/Makefile @@ -0,0 +1,1016 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# test/cpp/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + + +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/thrift +pkgincludedir = $(includedir)/thrift +pkglibdir = $(libdir)/thrift +pkglibexecdir = $(libexecdir)/thrift +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-pc-linux-gnu +host_triplet = x86_64-pc-linux-gnu +check_PROGRAMS = TestServer$(EXEEXT) TestClient$(EXEEXT) \ + StressTest$(EXEEXT) StressTestNonBlocking$(EXEEXT) +subdir = test/cpp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libstresstestgencpp_la_DEPENDENCIES = \ + $(top_builddir)/lib/cpp/libthrift.la +am__dirstamp = $(am__leading_dot)dirstamp +nodist_libstresstestgencpp_la_OBJECTS = \ + gen-cpp/StressTest_constants.lo gen-cpp/StressTest_types.lo \ + gen-cpp/Service.lo +libstresstestgencpp_la_OBJECTS = \ + $(nodist_libstresstestgencpp_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am__v_lt_1 = +libtestgencpp_la_DEPENDENCIES = $(top_builddir)/lib/cpp/libthrift.la +nodist_libtestgencpp_la_OBJECTS = gen-cpp/SecondService.lo \ + gen-cpp/ThriftTest_constants.lo gen-cpp/ThriftTest_types.lo \ + gen-cpp/ThriftTest.lo src/ThriftTest_extras.lo +libtestgencpp_la_OBJECTS = $(nodist_libtestgencpp_la_OBJECTS) +am_StressTest_OBJECTS = src/StressTest.$(OBJEXT) +StressTest_OBJECTS = $(am_StressTest_OBJECTS) +StressTest_DEPENDENCIES = libstresstestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la +am_StressTestNonBlocking_OBJECTS = \ + src/StressTestNonBlocking.$(OBJEXT) +StressTestNonBlocking_OBJECTS = $(am_StressTestNonBlocking_OBJECTS) +StressTestNonBlocking_DEPENDENCIES = libstresstestgencpp.la \ + $(top_builddir)/lib/cpp/libthriftnb.la +am_TestClient_OBJECTS = src/TestClient.$(OBJEXT) +TestClient_OBJECTS = $(am_TestClient_OBJECTS) +am__DEPENDENCIES_1 = +TestClient_DEPENDENCIES = libtestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la \ + $(top_builddir)/lib/cpp/libthriftz.la \ + $(top_builddir)/lib/cpp/libthriftnb.la $(am__DEPENDENCIES_1) +am_TestServer_OBJECTS = src/TestServer.$(OBJEXT) +TestServer_OBJECTS = $(am_TestServer_OBJECTS) +TestServer_DEPENDENCIES = libtestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la \ + $(top_builddir)/lib/cpp/libthriftz.la \ + $(top_builddir)/lib/cpp/libthriftnb.la $(am__DEPENDENCIES_1) +AM_V_P = $(am__v_P_$(V)) +am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I. -I$(top_builddir) -I$(top_builddir)/lib/cpp/src/thrift -I$(top_builddir)/lib/c_glib/src/thrift +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_$(V)) +am__v_CXX_ = $(am__v_CXX_$(AM_DEFAULT_VERBOSITY)) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_$(V)) +am__v_CXXLD_ = $(am__v_CXXLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(nodist_libstresstestgencpp_la_SOURCES) \ + $(nodist_libtestgencpp_la_SOURCES) $(StressTest_SOURCES) \ + $(StressTestNonBlocking_SOURCES) $(TestClient_SOURCES) \ + $(TestServer_SOURCES) +DIST_SOURCES = $(StressTest_SOURCES) $(StressTestNonBlocking_SOURCES) \ + $(TestClient_SOURCES) $(TestServer_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15 +ALLOCA = +AMTAR = $${TAR-tar} +AM_DEFAULT_VERBOSITY = 1 +ANT = /usr/bin/ant +ANT_FLAGS = +AR = ar +AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf +AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader +AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15 +AWK = gawk +BISON = bison +BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a +BOOST_CPPFLAGS = -I/usr/include +BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a +BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu +BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu +BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a +BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a +BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a +BUNDLER = /usr/bin/bundle +CABAL = /usr/bin/cabal +CABAL_CONFIGURE_FLAGS = +CARGO = /usr/bin/cargo +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 +CLASSPATH = +CPP = gcc -E +CPPFLAGS = +CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \; +CXX = g++ -std=c++11 +CXXCPP = g++ -E -std=c++11 +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -g -O2 +CYGPATH_W = echo +DART = /usr/lib/dart/bin/dart +DARTPUB = /usr/lib/dart/bin/pub +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +DLLTOOL = false +DMD = dmd +DMD_LIBEVENT_FLAGS = +DMD_OF_DIRSEP = / +DMD_OPENSSL_FLAGS = +DOTNETCORE = /usr/bin/dotnet +DOTNETCORE_VERSION = 2.0.3 +DSYMUTIL = +DUMPBIN = +D_EVENT_LIB_NAME = libthriftd-event.a +D_IMPORT_PREFIX = ${prefix}/include/d2 +D_LIB_NAME = libthriftd.a +D_SSL_LIB_NAME = libthriftd-ssl.a +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +ENABLE_COVERAGE = 2 +ERL = /usr/bin/erl +ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib +ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0 +ERLANG_LIB_DIR = /usr/lib/erlang/lib +ERLC = /usr/bin/erlc +ERLCFLAGS = +EXEEXT = +FGREP = /bin/grep -F +GCOV_CFLAGS = +GCOV_CXXFLAGS = +GCOV_LDFLAGS = +GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GLIB_LIBS = -lglib-2.0 +GO = /usr/bin/go +GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0 +GREP = /bin/grep +HAVE_CXX11 = 1 +HAXE = /usr/bin/haxe +HAXE_VERSION = 3.2.1 +INSTALL = /usr/bin/install -c +INSTALLDIRS = vendor +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +JAVA_PREFIX = /usr/local/lib +LD = /usr/bin/ld -m elf_x86_64 +LDFLAGS = +LEX = flex +LEXLIB = -lfl +LEX_OUTPUT_ROOT = lex.yy +LIBEVENT_CPPFLAGS = +LIBEVENT_LDFLAGS = +LIBEVENT_LIBS = -levent +LIBOBJS = +LIBS = -lrt -lpthread +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LIPO = +LN_S = ln -s +LTLIBOBJS = +LT_SYS_LIBRARY_PATH = +LUA = /usr/bin/lua5.3 +LUA_EXEC_PREFIX = ${exec_prefix} +LUA_INCLUDE = -I/usr/include/lua5.3 +LUA_LIB = -llua5.3 -ldl +LUA_PLATFORM = unknown +LUA_PREFIX = ${prefix} +LUA_SHORT_VERSION = 53 +LUA_VERSION = 5.3 +MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo +MANIFEST_TOOL = : +MAYBE_CPP = cpp +MAYBE_CSHARP = csharp +MAYBE_C_GLIB = c_glib +MAYBE_D = +MAYBE_DART = dart +MAYBE_DOTNETCORE = netcore +MAYBE_ERLANG = erl +MAYBE_GO = go +MAYBE_HASKELL = hs +MAYBE_JAVA = java +MAYBE_LUA = lua +MAYBE_NODEJS = nodejs +MAYBE_PERL = perl +MAYBE_PHP = php +MAYBE_PY3 = py3 +MAYBE_PYTHON = py +MAYBE_RS = rs +MAYBE_RUBY = rb +MCS = /usr/bin/mcs +MKDIR_P = /bin/mkdir -p +MONO_CFLAGS = +MONO_LIBS = +NM = /usr/bin/nm -B +NMEDIT = +NODEJS = /usr/bin/nodejs +NPM = /usr/bin/npm +OBJDUMP = objdump +OBJEXT = o +OPENSSL_INCLUDES = +OPENSSL_LDFLAGS = +OPENSSL_LIBS = -lssl -lcrypto +OTOOL = +OTOOL64 = +PACKAGE = thrift +PACKAGE_BUGREPORT = +PACKAGE_NAME = thrift +PACKAGE_STRING = thrift 0.11.0 +PACKAGE_TARNAME = thrift +PACKAGE_URL = +PACKAGE_VERSION = 0.11.0 +PATH_SEPARATOR = : +PERL = /usr/bin/perl +PERL_PREFIX = /usr/local +PHP = /usr/bin/php +PHPUNIT = /usr/bin/phpunit +PHP_CONFIG = /usr/bin/php-config +PHP_CONFIG_PREFIX = /etc/php.d +PHP_PREFIX = /usr/lib/php +PKG_CONFIG = /usr/bin/pkg-config +PKG_CONFIG_LIBDIR = +PKG_CONFIG_PATH = +PYTHON = /usr/bin/python +PYTHON3 = /usr/bin/python3 +PYTHON_EXEC_PREFIX = ${exec_prefix} +PYTHON_PLATFORM = linux2 +PYTHON_PREFIX = ${prefix} +PYTHON_VERSION = 2.7 +PY_PREFIX = /usr +QT5_CFLAGS = +QT5_LIBS = +QT5_MOC = +QT_CFLAGS = +QT_LIBS = +QT_MOC = +RANLIB = ranlib +REBAR = /usr/bin/rebar +RUBY = /usr/bin/ruby +RUBY_PREFIX = +RUNHASKELL = /usr/bin/runhaskell +RUSTC = /usr/bin/rustc +SED = /bin/sed +SET_MAKE = +SHELL = /bin/bash +STRIP = strip +THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift +TRIAL = /usr/bin/trial +VERSION = 0.11.0 +YACC = bison -y +YFLAGS = +ZLIB_CPPFLAGS = +ZLIB_LDFLAGS = +ZLIB_LIBS = -lz +abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/test/cpp +abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/test/cpp +abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift +abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift +ac_ct_AR = ar +ac_ct_CC = gcc +ac_ct_CXX = g++ +ac_ct_DUMPBIN = +am__include = include +am__leading_dot = . +am__quote = +am__tar = tar --format=ustar -chf - "$$tardir" +am__untar = tar -xf - +bindir = ${exec_prefix}/bin +build = x86_64-pc-linux-gnu +build_alias = +build_cpu = x86_64 +build_os = linux-gnu +build_vendor = pc +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +golang_version = 1.6.2 +have_prog_bison = yes +host = x86_64-pc-linux-gnu +host_alias = +host_cpu = x86_64 +host_os = linux-gnu +host_vendor = pc +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +luadir = ${prefix}/share/lua/5.3 +luaexecdir = ${exec_prefix}/lib/lua/5.3 +mandir = ${datarootdir}/man +mkdir_p = $(MKDIR_P) +oldincludedir = /usr/include +pdfdir = ${docdir} +pkgluadir = ${luadir}/thrift +pkgluaexecdir = ${luaexecdir}/thrift +pkgpyexecdir = ${pyexecdir}/thrift +pkgpythondir = ${pythondir}/thrift +prefix = /usr/local +program_transform_name = s,x,x, +psdir = ${docdir} +pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages +pythondir = ${prefix}/lib/python2.7/dist-packages +runstatedir = ${localstatedir}/run +rustc_version = rustc 1.17.0 +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +subdirs = lib/php/src/ext/thrift_protocol +sysconfdir = ${prefix}/etc +target_alias = +top_build_prefix = ../../ +top_builddir = ../.. +top_srcdir = ../.. + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +AUTOMAKE_OPTIONS = subdir-objects serial-tests +BUILT_SOURCES = gen-cpp/ThriftTest.cpp \ + gen-cpp/ThriftTest_types.cpp \ + gen-cpp/ThriftTest_constants.cpp \ + gen-cpp/SecondService.cpp \ + gen-cpp/StressTest_types.cpp \ + gen-cpp/StressTest_constants.cpp \ + gen-cpp/Service.cpp + +noinst_LTLIBRARIES = libtestgencpp.la libstresstestgencpp.la +nodist_libtestgencpp_la_SOURCES = \ + gen-cpp/SecondService.cpp \ + gen-cpp/SecondService.h \ + gen-cpp/SecondService.tcc \ + gen-cpp/ThriftTest_constants.cpp \ + gen-cpp/ThriftTest_constants.h \ + gen-cpp/ThriftTest_types.cpp \ + gen-cpp/ThriftTest_types.h \ + gen-cpp/ThriftTest_types.tcc \ + gen-cpp/ThriftTest.cpp \ + gen-cpp/ThriftTest.h \ + gen-cpp/ThriftTest.tcc \ + src/ThriftTest_extras.cpp + +libtestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la +nodist_libstresstestgencpp_la_SOURCES = \ + gen-cpp/StressTest_constants.cpp \ + gen-cpp/StressTest_types.cpp \ + gen-cpp/StressTest_constants.h \ + gen-cpp/StressTest_types.h \ + gen-cpp/Service.cpp \ + gen-cpp/Service.h + +libstresstestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la + +# we currently do not run the testsuite, stop c++ server issue +# TESTS = \ +# $(check_PROGRAMS) +TestServer_SOURCES = \ + src/TestServer.cpp + +TestServer_LDADD = \ + libtestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la \ + $(top_builddir)/lib/cpp/libthriftz.la \ + $(top_builddir)/lib/cpp/libthriftnb.la \ + -levent -lboost_program_options -lboost_system -lboost_filesystem $(ZLIB_LIBS) + +TestClient_SOURCES = \ + src/TestClient.cpp + +TestClient_LDADD = \ + libtestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la \ + $(top_builddir)/lib/cpp/libthriftz.la \ + $(top_builddir)/lib/cpp/libthriftnb.la \ + -levent -lboost_program_options -lboost_system -lboost_filesystem $(ZLIB_LIBS) + +StressTest_SOURCES = \ + src/StressTest.cpp + +StressTest_LDADD = \ + libstresstestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la + +StressTestNonBlocking_SOURCES = \ + src/StressTestNonBlocking.cpp + +StressTestNonBlocking_LDADD = \ + libstresstestgencpp.la \ + $(top_builddir)/lib/cpp/libthriftnb.la \ + -levent + +AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -Igen-cpp +AM_CXXFLAGS = -Wall -Wextra -pedantic -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS) $(ZLIB_LIBS) +EXTRA_DIST = \ + src/TestClient.cpp \ + src/TestServer.cpp \ + src/StressTest.cpp \ + src/StressTestNonBlocking.cpp + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/cpp/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/cpp/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } +gen-cpp/$(am__dirstamp): + @$(MKDIR_P) gen-cpp + @: > gen-cpp/$(am__dirstamp) +gen-cpp/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) gen-cpp/$(DEPDIR) + @: > gen-cpp/$(DEPDIR)/$(am__dirstamp) +gen-cpp/StressTest_constants.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) +gen-cpp/StressTest_types.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) +gen-cpp/Service.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) + +libstresstestgencpp.la: $(libstresstestgencpp_la_OBJECTS) $(libstresstestgencpp_la_DEPENDENCIES) $(EXTRA_libstresstestgencpp_la_DEPENDENCIES) + $(AM_V_CXXLD)$(CXXLINK) $(libstresstestgencpp_la_OBJECTS) $(libstresstestgencpp_la_LIBADD) $(LIBS) +gen-cpp/SecondService.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) +gen-cpp/ThriftTest_constants.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) +gen-cpp/ThriftTest_types.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) +gen-cpp/ThriftTest.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) +src/$(am__dirstamp): + @$(MKDIR_P) src + @: > src/$(am__dirstamp) +src/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/$(DEPDIR) + @: > src/$(DEPDIR)/$(am__dirstamp) +src/ThriftTest_extras.lo: src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +libtestgencpp.la: $(libtestgencpp_la_OBJECTS) $(libtestgencpp_la_DEPENDENCIES) $(EXTRA_libtestgencpp_la_DEPENDENCIES) + $(AM_V_CXXLD)$(CXXLINK) $(libtestgencpp_la_OBJECTS) $(libtestgencpp_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +src/StressTest.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +StressTest$(EXEEXT): $(StressTest_OBJECTS) $(StressTest_DEPENDENCIES) $(EXTRA_StressTest_DEPENDENCIES) + @rm -f StressTest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(StressTest_OBJECTS) $(StressTest_LDADD) $(LIBS) +src/StressTestNonBlocking.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +StressTestNonBlocking$(EXEEXT): $(StressTestNonBlocking_OBJECTS) $(StressTestNonBlocking_DEPENDENCIES) $(EXTRA_StressTestNonBlocking_DEPENDENCIES) + @rm -f StressTestNonBlocking$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(StressTestNonBlocking_OBJECTS) $(StressTestNonBlocking_LDADD) $(LIBS) +src/TestClient.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +TestClient$(EXEEXT): $(TestClient_OBJECTS) $(TestClient_DEPENDENCIES) $(EXTRA_TestClient_DEPENDENCIES) + @rm -f TestClient$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(TestClient_OBJECTS) $(TestClient_LDADD) $(LIBS) +src/TestServer.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +TestServer$(EXEEXT): $(TestServer_OBJECTS) $(TestServer_DEPENDENCIES) $(EXTRA_TestServer_DEPENDENCIES) + @rm -f TestServer$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(TestServer_OBJECTS) $(TestServer_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f gen-cpp/*.$(OBJEXT) + -rm -f gen-cpp/*.lo + -rm -f src/*.$(OBJEXT) + -rm -f src/*.lo + +distclean-compile: + -rm -f *.tab.c + +include gen-cpp/$(DEPDIR)/SecondService.Plo +include gen-cpp/$(DEPDIR)/Service.Plo +include gen-cpp/$(DEPDIR)/StressTest_constants.Plo +include gen-cpp/$(DEPDIR)/StressTest_types.Plo +include gen-cpp/$(DEPDIR)/ThriftTest.Plo +include gen-cpp/$(DEPDIR)/ThriftTest_constants.Plo +include gen-cpp/$(DEPDIR)/ThriftTest_types.Plo +include src/$(DEPDIR)/StressTest.Po +include src/$(DEPDIR)/StressTestNonBlocking.Po +include src/$(DEPDIR)/TestClient.Po +include src/$(DEPDIR)/TestServer.Po +include src/$(DEPDIR)/ThriftTest_extras.Plo + +.cpp.o: + $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ + $(am__mv) $$depbase.Tpo $$depbase.Po +# $(AM_V_CXX)source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ +# $(AM_V_CXX_no)$(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: + $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ + $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ + $(am__mv) $$depbase.Tpo $$depbase.Po +# $(AM_V_CXX)source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ +# $(AM_V_CXX_no)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: + $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ + $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ + $(am__mv) $$depbase.Tpo $$depbase.Plo +# $(AM_V_CXX)source='$<' object='$@' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ +# $(AM_V_CXX_no)$(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf gen-cpp/.libs gen-cpp/_libs + -rm -rf src/.libs src/_libs +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f gen-cpp/$(DEPDIR)/$(am__dirstamp) + -rm -f gen-cpp/$(am__dirstamp) + -rm -f src/$(DEPDIR)/$(am__dirstamp) + -rm -f src/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool clean-local \ + clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf gen-cpp/$(DEPDIR) src/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf gen-cpp/$(DEPDIR) src/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: all check check-am install install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool clean-local \ + clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am style-am style-local tags tags-am \ + uninstall uninstall-am + +.PRECIOUS: Makefile + + +precross: TestServer TestClient +# +# Common thrift code generation rules +# +gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/SecondService.tcc: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT) + $(THRIFT) --gen cpp:templates,cob_style -r $< + +gen-cpp/StressTest_types.cpp gen-cpp/StressTest_constants.cpp gen-cpp/Service.cpp: $(top_srcdir)/test/StressTest.thrift $(THRIFT) + $(THRIFT) --gen cpp $< + +clean-local: + $(RM) gen-cpp/* + +style-local: + $(CPPSTYLE_CMD) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/cpp/Makefile.am b/test/cpp/Makefile.am new file mode 100755 index 0000000..e8be80a --- /dev/null +++ b/test/cpp/Makefile.am @@ -0,0 +1,125 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +AUTOMAKE_OPTIONS = subdir-objects serial-tests + +BUILT_SOURCES = gen-cpp/ThriftTest.cpp \ + gen-cpp/ThriftTest_types.cpp \ + gen-cpp/ThriftTest_constants.cpp \ + gen-cpp/SecondService.cpp \ + gen-cpp/StressTest_types.cpp \ + gen-cpp/StressTest_constants.cpp \ + gen-cpp/Service.cpp + +noinst_LTLIBRARIES = libtestgencpp.la libstresstestgencpp.la +nodist_libtestgencpp_la_SOURCES = \ + gen-cpp/SecondService.cpp \ + gen-cpp/SecondService.h \ + gen-cpp/SecondService.tcc \ + gen-cpp/ThriftTest_constants.cpp \ + gen-cpp/ThriftTest_constants.h \ + gen-cpp/ThriftTest_types.cpp \ + gen-cpp/ThriftTest_types.h \ + gen-cpp/ThriftTest_types.tcc \ + gen-cpp/ThriftTest.cpp \ + gen-cpp/ThriftTest.h \ + gen-cpp/ThriftTest.tcc \ + src/ThriftTest_extras.cpp + +libtestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la + +nodist_libstresstestgencpp_la_SOURCES = \ + gen-cpp/StressTest_constants.cpp \ + gen-cpp/StressTest_types.cpp \ + gen-cpp/StressTest_constants.h \ + gen-cpp/StressTest_types.h \ + gen-cpp/Service.cpp \ + gen-cpp/Service.h + +libstresstestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la + +precross: TestServer TestClient + +check_PROGRAMS = \ + TestServer \ + TestClient \ + StressTest \ + StressTestNonBlocking + +# we currently do not run the testsuite, stop c++ server issue +# TESTS = \ +# $(check_PROGRAMS) + +TestServer_SOURCES = \ + src/TestServer.cpp + +TestServer_LDADD = \ + libtestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la \ + $(top_builddir)/lib/cpp/libthriftz.la \ + $(top_builddir)/lib/cpp/libthriftnb.la \ + -levent -lboost_program_options -lboost_system -lboost_filesystem $(ZLIB_LIBS) + +TestClient_SOURCES = \ + src/TestClient.cpp + +TestClient_LDADD = \ + libtestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la \ + $(top_builddir)/lib/cpp/libthriftz.la \ + $(top_builddir)/lib/cpp/libthriftnb.la \ + -levent -lboost_program_options -lboost_system -lboost_filesystem $(ZLIB_LIBS) + +StressTest_SOURCES = \ + src/StressTest.cpp + +StressTest_LDADD = \ + libstresstestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la + +StressTestNonBlocking_SOURCES = \ + src/StressTestNonBlocking.cpp + +StressTestNonBlocking_LDADD = \ + libstresstestgencpp.la \ + $(top_builddir)/lib/cpp/libthriftnb.la \ + -levent +# +# Common thrift code generation rules +# +gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/SecondService.tcc: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT) + $(THRIFT) --gen cpp:templates,cob_style -r $< + +gen-cpp/StressTest_types.cpp gen-cpp/StressTest_constants.cpp gen-cpp/Service.cpp: $(top_srcdir)/test/StressTest.thrift $(THRIFT) + $(THRIFT) --gen cpp $< + +AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -Igen-cpp +AM_CXXFLAGS = -Wall -Wextra -pedantic -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS) $(ZLIB_LIBS) + +clean-local: + $(RM) gen-cpp/* + +style-local: + $(CPPSTYLE_CMD) + +EXTRA_DIST = \ + src/TestClient.cpp \ + src/TestServer.cpp \ + src/StressTest.cpp \ + src/StressTestNonBlocking.cpp diff --git a/test/cpp/Makefile.in b/test/cpp/Makefile.in new file mode 100644 index 0000000..edbb346 --- /dev/null +++ b/test/cpp/Makefile.in @@ -0,0 +1,1016 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +check_PROGRAMS = TestServer$(EXEEXT) TestClient$(EXEEXT) \ + StressTest$(EXEEXT) StressTestNonBlocking$(EXEEXT) +subdir = test/cpp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libstresstestgencpp_la_DEPENDENCIES = \ + $(top_builddir)/lib/cpp/libthrift.la +am__dirstamp = $(am__leading_dot)dirstamp +nodist_libstresstestgencpp_la_OBJECTS = \ + gen-cpp/StressTest_constants.lo gen-cpp/StressTest_types.lo \ + gen-cpp/Service.lo +libstresstestgencpp_la_OBJECTS = \ + $(nodist_libstresstestgencpp_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libtestgencpp_la_DEPENDENCIES = $(top_builddir)/lib/cpp/libthrift.la +nodist_libtestgencpp_la_OBJECTS = gen-cpp/SecondService.lo \ + gen-cpp/ThriftTest_constants.lo gen-cpp/ThriftTest_types.lo \ + gen-cpp/ThriftTest.lo src/ThriftTest_extras.lo +libtestgencpp_la_OBJECTS = $(nodist_libtestgencpp_la_OBJECTS) +am_StressTest_OBJECTS = src/StressTest.$(OBJEXT) +StressTest_OBJECTS = $(am_StressTest_OBJECTS) +StressTest_DEPENDENCIES = libstresstestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la +am_StressTestNonBlocking_OBJECTS = \ + src/StressTestNonBlocking.$(OBJEXT) +StressTestNonBlocking_OBJECTS = $(am_StressTestNonBlocking_OBJECTS) +StressTestNonBlocking_DEPENDENCIES = libstresstestgencpp.la \ + $(top_builddir)/lib/cpp/libthriftnb.la +am_TestClient_OBJECTS = src/TestClient.$(OBJEXT) +TestClient_OBJECTS = $(am_TestClient_OBJECTS) +am__DEPENDENCIES_1 = +TestClient_DEPENDENCIES = libtestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la \ + $(top_builddir)/lib/cpp/libthriftz.la \ + $(top_builddir)/lib/cpp/libthriftnb.la $(am__DEPENDENCIES_1) +am_TestServer_OBJECTS = src/TestServer.$(OBJEXT) +TestServer_OBJECTS = $(am_TestServer_OBJECTS) +TestServer_DEPENDENCIES = libtestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la \ + $(top_builddir)/lib/cpp/libthriftz.la \ + $(top_builddir)/lib/cpp/libthriftnb.la $(am__DEPENDENCIES_1) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/lib/cpp/src/thrift -I$(top_builddir)/lib/c_glib/src/thrift +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(nodist_libstresstestgencpp_la_SOURCES) \ + $(nodist_libtestgencpp_la_SOURCES) $(StressTest_SOURCES) \ + $(StressTestNonBlocking_SOURCES) $(TestClient_SOURCES) \ + $(TestServer_SOURCES) +DIST_SOURCES = $(StressTest_SOURCES) $(StressTestNonBlocking_SOURCES) \ + $(TestClient_SOURCES) $(TestServer_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +AUTOMAKE_OPTIONS = subdir-objects serial-tests +BUILT_SOURCES = gen-cpp/ThriftTest.cpp \ + gen-cpp/ThriftTest_types.cpp \ + gen-cpp/ThriftTest_constants.cpp \ + gen-cpp/SecondService.cpp \ + gen-cpp/StressTest_types.cpp \ + gen-cpp/StressTest_constants.cpp \ + gen-cpp/Service.cpp + +noinst_LTLIBRARIES = libtestgencpp.la libstresstestgencpp.la +nodist_libtestgencpp_la_SOURCES = \ + gen-cpp/SecondService.cpp \ + gen-cpp/SecondService.h \ + gen-cpp/SecondService.tcc \ + gen-cpp/ThriftTest_constants.cpp \ + gen-cpp/ThriftTest_constants.h \ + gen-cpp/ThriftTest_types.cpp \ + gen-cpp/ThriftTest_types.h \ + gen-cpp/ThriftTest_types.tcc \ + gen-cpp/ThriftTest.cpp \ + gen-cpp/ThriftTest.h \ + gen-cpp/ThriftTest.tcc \ + src/ThriftTest_extras.cpp + +libtestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la +nodist_libstresstestgencpp_la_SOURCES = \ + gen-cpp/StressTest_constants.cpp \ + gen-cpp/StressTest_types.cpp \ + gen-cpp/StressTest_constants.h \ + gen-cpp/StressTest_types.h \ + gen-cpp/Service.cpp \ + gen-cpp/Service.h + +libstresstestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la + +# we currently do not run the testsuite, stop c++ server issue +# TESTS = \ +# $(check_PROGRAMS) +TestServer_SOURCES = \ + src/TestServer.cpp + +TestServer_LDADD = \ + libtestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la \ + $(top_builddir)/lib/cpp/libthriftz.la \ + $(top_builddir)/lib/cpp/libthriftnb.la \ + -levent -lboost_program_options -lboost_system -lboost_filesystem $(ZLIB_LIBS) + +TestClient_SOURCES = \ + src/TestClient.cpp + +TestClient_LDADD = \ + libtestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la \ + $(top_builddir)/lib/cpp/libthriftz.la \ + $(top_builddir)/lib/cpp/libthriftnb.la \ + -levent -lboost_program_options -lboost_system -lboost_filesystem $(ZLIB_LIBS) + +StressTest_SOURCES = \ + src/StressTest.cpp + +StressTest_LDADD = \ + libstresstestgencpp.la \ + $(top_builddir)/lib/cpp/libthrift.la + +StressTestNonBlocking_SOURCES = \ + src/StressTestNonBlocking.cpp + +StressTestNonBlocking_LDADD = \ + libstresstestgencpp.la \ + $(top_builddir)/lib/cpp/libthriftnb.la \ + -levent + +AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -Igen-cpp +AM_CXXFLAGS = -Wall -Wextra -pedantic -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS) $(ZLIB_LIBS) +EXTRA_DIST = \ + src/TestClient.cpp \ + src/TestServer.cpp \ + src/StressTest.cpp \ + src/StressTestNonBlocking.cpp + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/cpp/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/cpp/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } +gen-cpp/$(am__dirstamp): + @$(MKDIR_P) gen-cpp + @: > gen-cpp/$(am__dirstamp) +gen-cpp/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) gen-cpp/$(DEPDIR) + @: > gen-cpp/$(DEPDIR)/$(am__dirstamp) +gen-cpp/StressTest_constants.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) +gen-cpp/StressTest_types.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) +gen-cpp/Service.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) + +libstresstestgencpp.la: $(libstresstestgencpp_la_OBJECTS) $(libstresstestgencpp_la_DEPENDENCIES) $(EXTRA_libstresstestgencpp_la_DEPENDENCIES) + $(AM_V_CXXLD)$(CXXLINK) $(libstresstestgencpp_la_OBJECTS) $(libstresstestgencpp_la_LIBADD) $(LIBS) +gen-cpp/SecondService.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) +gen-cpp/ThriftTest_constants.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) +gen-cpp/ThriftTest_types.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) +gen-cpp/ThriftTest.lo: gen-cpp/$(am__dirstamp) \ + gen-cpp/$(DEPDIR)/$(am__dirstamp) +src/$(am__dirstamp): + @$(MKDIR_P) src + @: > src/$(am__dirstamp) +src/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/$(DEPDIR) + @: > src/$(DEPDIR)/$(am__dirstamp) +src/ThriftTest_extras.lo: src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +libtestgencpp.la: $(libtestgencpp_la_OBJECTS) $(libtestgencpp_la_DEPENDENCIES) $(EXTRA_libtestgencpp_la_DEPENDENCIES) + $(AM_V_CXXLD)$(CXXLINK) $(libtestgencpp_la_OBJECTS) $(libtestgencpp_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +src/StressTest.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +StressTest$(EXEEXT): $(StressTest_OBJECTS) $(StressTest_DEPENDENCIES) $(EXTRA_StressTest_DEPENDENCIES) + @rm -f StressTest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(StressTest_OBJECTS) $(StressTest_LDADD) $(LIBS) +src/StressTestNonBlocking.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +StressTestNonBlocking$(EXEEXT): $(StressTestNonBlocking_OBJECTS) $(StressTestNonBlocking_DEPENDENCIES) $(EXTRA_StressTestNonBlocking_DEPENDENCIES) + @rm -f StressTestNonBlocking$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(StressTestNonBlocking_OBJECTS) $(StressTestNonBlocking_LDADD) $(LIBS) +src/TestClient.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +TestClient$(EXEEXT): $(TestClient_OBJECTS) $(TestClient_DEPENDENCIES) $(EXTRA_TestClient_DEPENDENCIES) + @rm -f TestClient$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(TestClient_OBJECTS) $(TestClient_LDADD) $(LIBS) +src/TestServer.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +TestServer$(EXEEXT): $(TestServer_OBJECTS) $(TestServer_DEPENDENCIES) $(EXTRA_TestServer_DEPENDENCIES) + @rm -f TestServer$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(TestServer_OBJECTS) $(TestServer_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f gen-cpp/*.$(OBJEXT) + -rm -f gen-cpp/*.lo + -rm -f src/*.$(OBJEXT) + -rm -f src/*.lo + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@gen-cpp/$(DEPDIR)/SecondService.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gen-cpp/$(DEPDIR)/Service.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gen-cpp/$(DEPDIR)/StressTest_constants.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gen-cpp/$(DEPDIR)/StressTest_types.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gen-cpp/$(DEPDIR)/ThriftTest.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gen-cpp/$(DEPDIR)/ThriftTest_constants.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gen-cpp/$(DEPDIR)/ThriftTest_types.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/StressTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/StressTestNonBlocking.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/TestClient.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/TestServer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/ThriftTest_extras.Plo@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf gen-cpp/.libs gen-cpp/_libs + -rm -rf src/.libs src/_libs +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f gen-cpp/$(DEPDIR)/$(am__dirstamp) + -rm -f gen-cpp/$(am__dirstamp) + -rm -f src/$(DEPDIR)/$(am__dirstamp) + -rm -f src/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool clean-local \ + clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf gen-cpp/$(DEPDIR) src/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf gen-cpp/$(DEPDIR) src/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: all check check-am install install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool clean-local \ + clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am style-am style-local tags tags-am \ + uninstall uninstall-am + +.PRECIOUS: Makefile + + +precross: TestServer TestClient +# +# Common thrift code generation rules +# +gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/SecondService.tcc: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT) + $(THRIFT) --gen cpp:templates,cob_style -r $< + +gen-cpp/StressTest_types.cpp gen-cpp/StressTest_constants.cpp gen-cpp/Service.cpp: $(top_srcdir)/test/StressTest.thrift $(THRIFT) + $(THRIFT) --gen cpp $< + +clean-local: + $(RM) gen-cpp/* + +style-local: + $(CPPSTYLE_CMD) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/cpp/src/StressTest.cpp b/test/cpp/src/StressTest.cpp new file mode 100644 index 0000000..5ff5e44 --- /dev/null +++ b/test/cpp/src/StressTest.cpp @@ -0,0 +1,606 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Service.h" +#include +#include +#include +#include +#include +#if _WIN32 +#include +#endif + +using namespace std; + +using namespace apache::thrift; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; +using namespace apache::thrift::server; +using namespace apache::thrift::concurrency; + +using namespace test::stress; + +struct eqstr { + bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) == 0; } +}; + +struct ltstr { + bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } +}; + +// typedef hash_map, eqstr> count_map; +typedef map count_map; + +class Server : public ServiceIf { +public: + Server() {} + + void count(const char* method) { + Guard m(lock_); + int ct = counts_[method]; + counts_[method] = ++ct; + } + + void echoVoid() { + count("echoVoid"); + return; + } + + count_map getCount() { + Guard m(lock_); + return counts_; + } + + int8_t echoByte(const int8_t arg) { return arg; } + int32_t echoI32(const int32_t arg) { return arg; } + int64_t echoI64(const int64_t arg) { return arg; } + void echoString(string& out, const string& arg) { + if (arg != "hello") { + T_ERROR_ABORT("WRONG STRING (%s)!!!!", arg.c_str()); + } + out = arg; + } + void echoList(vector& out, const vector& arg) { out = arg; } + void echoSet(set& out, const set& arg) { out = arg; } + void echoMap(map& out, const map& arg) { out = arg; } + +private: + count_map counts_; + Mutex lock_; +}; + +enum TransportOpenCloseBehavior { + OpenAndCloseTransportInThread, + DontOpenAndCloseTransportInThread +}; +class ClientThread : public Runnable { +public: + ClientThread(stdcxx::shared_ptr transport, + stdcxx::shared_ptr client, + Monitor& monitor, + size_t& workerCount, + size_t loopCount, + TType loopType, + TransportOpenCloseBehavior behavior) + : _transport(transport), + _client(client), + _monitor(monitor), + _workerCount(workerCount), + _loopCount(loopCount), + _loopType(loopType), + _behavior(behavior) {} + + void run() { + + // Wait for all worker threads to start + + { + Synchronized s(_monitor); + while (_workerCount == 0) { + _monitor.wait(); + } + } + + _startTime = Util::currentTime(); + if(_behavior == OpenAndCloseTransportInThread) { + _transport->open(); + } + + switch (_loopType) { + case T_VOID: + loopEchoVoid(); + break; + case T_BYTE: + loopEchoByte(); + break; + case T_I32: + loopEchoI32(); + break; + case T_I64: + loopEchoI64(); + break; + case T_STRING: + loopEchoString(); + break; + default: + cerr << "Unexpected loop type" << _loopType << endl; + break; + } + + _endTime = Util::currentTime(); + + if(_behavior == OpenAndCloseTransportInThread) { + _transport->close(); + } + + _done = true; + + { + Synchronized s(_monitor); + + _workerCount--; + + if (_workerCount == 0) { + + _monitor.notify(); + } + } + } + + void loopEchoVoid() { + for (size_t ix = 0; ix < _loopCount; ix++) { + _client->echoVoid(); + } + } + + void loopEchoByte() { + for (size_t ix = 0; ix < _loopCount; ix++) { + int8_t arg = 1; + int8_t result; + result = _client->echoByte(arg); + (void)result; + assert(result == arg); + } + } + + void loopEchoI32() { + for (size_t ix = 0; ix < _loopCount; ix++) { + int32_t arg = 1; + int32_t result; + result = _client->echoI32(arg); + (void)result; + assert(result == arg); + } + } + + void loopEchoI64() { + for (size_t ix = 0; ix < _loopCount; ix++) { + int64_t arg = 1; + int64_t result; + result = _client->echoI64(arg); + (void)result; + assert(result == arg); + } + } + + void loopEchoString() { + for (size_t ix = 0; ix < _loopCount; ix++) { + string arg = "hello"; + string result; + _client->echoString(result, arg); + assert(result == arg); + } + } + + stdcxx::shared_ptr _transport; + stdcxx::shared_ptr _client; + Monitor& _monitor; + size_t& _workerCount; + size_t _loopCount; + TType _loopType; + int64_t _startTime; + int64_t _endTime; + bool _done; + Monitor _sleep; + TransportOpenCloseBehavior _behavior; +}; + +class TStartObserver : public apache::thrift::server::TServerEventHandler { +public: + TStartObserver() : awake_(false) {} + virtual void preServe() { + apache::thrift::concurrency::Synchronized s(m_); + awake_ = true; + m_.notifyAll(); + } + void waitForService() { + apache::thrift::concurrency::Synchronized s(m_); + while (!awake_) + m_.waitForever(); + } + +private: + apache::thrift::concurrency::Monitor m_; + bool awake_; +}; + +int main(int argc, char** argv) { +#if _WIN32 + transport::TWinsockSingleton::create(); +#endif + + int port = 9091; + string clientType = "regular"; + string serverType = "thread-pool"; + string protocolType = "binary"; + size_t workerCount = 4; + size_t clientCount = 20; + size_t loopCount = 50000; + TType loopType = T_VOID; + string callName = "echoVoid"; + bool runServer = true; + bool logRequests = false; + string requestLogPath = "./requestlog.tlog"; + bool replayRequests = false; + + ostringstream usage; + + usage << argv[0] << " [--port=] [--server] [--server-type=] " + "[--protocol-type=] [--workers=] " + "[--clients=] [--loop=] " + "[--client-type=]" << endl + << "\tclients Number of client threads to create - 0 implies no clients, i.e. " + "server only. Default is " << clientCount << endl + << "\thelp Prints this help text." << endl + << "\tcall Service method to call. Default is " << callName << endl + << "\tloop The number of remote thrift calls each client makes. Default is " << loopCount << endl + << "\tport The port the server and clients should bind to " + "for thrift network connections. Default is " << port << endl + << "\tserver Run the Thrift server in this process. Default is " << runServer << endl + << "\tserver-type Type of server, \"simple\" or \"thread-pool\". Default is " << serverType << endl + << "\tprotocol-type Type of protocol, \"binary\", \"ascii\", or \"xml\". Default is " << protocolType << endl + << "\tlog-request Log all request to ./requestlog.tlog. Default is " << logRequests << endl + << "\treplay-request Replay requests from log file (./requestlog.tlog) Default is " << replayRequests << endl + << "\tworkers Number of thread pools workers. Only valid " + "for thread-pool server type. Default is " << workerCount << endl + << "\tclient-type Type of client, \"regular\" or \"concurrent\". Default is " << clientType << endl + << endl; + + map args; + + for (int ix = 1; ix < argc; ix++) { + + string arg(argv[ix]); + + if (arg.compare(0, 2, "--") == 0) { + + size_t end = arg.find_first_of("=", 2); + + string key = string(arg, 2, end - 2); + + if (end != string::npos) { + args[key] = string(arg, end + 1); + } else { + args[key] = "true"; + } + } else { + throw invalid_argument("Unexcepted command line token: " + arg); + } + } + + try { + + if (!args["clients"].empty()) { + clientCount = atoi(args["clients"].c_str()); + } + + if (!args["help"].empty()) { + cerr << usage.str(); + return 0; + } + + if (!args["loop"].empty()) { + loopCount = atoi(args["loop"].c_str()); + } + + if (!args["call"].empty()) { + callName = args["call"]; + } + + if (!args["port"].empty()) { + port = atoi(args["port"].c_str()); + } + + if (!args["server"].empty()) { + runServer = args["server"] == "true"; + } + + if (!args["log-request"].empty()) { + logRequests = args["log-request"] == "true"; + } + + if (!args["replay-request"].empty()) { + replayRequests = args["replay-request"] == "true"; + } + + if (!args["server-type"].empty()) { + serverType = args["server-type"]; + + if (serverType == "simple") { + + } else if (serverType == "thread-pool") { + + } else if (serverType == "threaded") { + + } else { + + throw invalid_argument("Unknown server type " + serverType); + } + } + if (!args["client-type"].empty()) { + clientType = args["client-type"]; + + if (clientType == "regular") { + + } else if (clientType == "concurrent") { + + } else { + + throw invalid_argument("Unknown client type " + clientType); + } + } + if (!args["workers"].empty()) { + workerCount = atoi(args["workers"].c_str()); + } + + } catch (std::exception& e) { + cerr << e.what() << endl; + cerr << usage.str(); + } + + stdcxx::shared_ptr threadFactory + = stdcxx::shared_ptr(new PlatformThreadFactory()); + + // Dispatcher + stdcxx::shared_ptr serviceHandler(new Server()); + + if (replayRequests) { + stdcxx::shared_ptr serviceHandler(new Server()); + stdcxx::shared_ptr serviceProcessor(new ServiceProcessor(serviceHandler)); + + // Transports + stdcxx::shared_ptr fileTransport(new TFileTransport(requestLogPath)); + fileTransport->setChunkSize(2 * 1024 * 1024); + fileTransport->setMaxEventSize(1024 * 16); + fileTransport->seekToEnd(); + + // Protocol Factory + stdcxx::shared_ptr protocolFactory(new TBinaryProtocolFactory()); + + TFileProcessor fileProcessor(serviceProcessor, protocolFactory, fileTransport); + + fileProcessor.process(0, true); + exit(0); + } + + if (runServer) { + + stdcxx::shared_ptr serviceProcessor(new ServiceProcessor(serviceHandler)); + + // Transport + stdcxx::shared_ptr serverSocket(new TServerSocket(port)); + + // Transport Factory + stdcxx::shared_ptr transportFactory(new TBufferedTransportFactory()); + + // Protocol Factory + stdcxx::shared_ptr protocolFactory(new TBinaryProtocolFactory()); + + if (logRequests) { + // initialize the log file + stdcxx::shared_ptr fileTransport(new TFileTransport(requestLogPath)); + fileTransport->setChunkSize(2 * 1024 * 1024); + fileTransport->setMaxEventSize(1024 * 16); + + transportFactory + = stdcxx::shared_ptr(new TPipedTransportFactory(fileTransport)); + } + + stdcxx::shared_ptr server; + + if (serverType == "simple") { + + server.reset( + new TSimpleServer(serviceProcessor, serverSocket, transportFactory, protocolFactory)); + + } else if (serverType == "threaded") { + + server.reset( + new TThreadedServer(serviceProcessor, serverSocket, transportFactory, protocolFactory)); + + } else if (serverType == "thread-pool") { + + stdcxx::shared_ptr threadManager + = ThreadManager::newSimpleThreadManager(workerCount); + + threadManager->threadFactory(threadFactory); + threadManager->start(); + server.reset(new TThreadPoolServer(serviceProcessor, + serverSocket, + transportFactory, + protocolFactory, + threadManager)); + } + + stdcxx::shared_ptr observer(new TStartObserver); + server->setServerEventHandler(observer); + stdcxx::shared_ptr serverThread = threadFactory->newThread(server); + + cerr << "Starting the server on port " << port << endl; + + serverThread->start(); + observer->waitForService(); + + // If we aren't running clients, just wait forever for external clients + if (clientCount == 0) { + serverThread->join(); + } + } + + if (clientCount > 0) { //FIXME: start here for client type? + + Monitor monitor; + + size_t threadCount = 0; + + set > clientThreads; + + if (callName == "echoVoid") { + loopType = T_VOID; + } else if (callName == "echoByte") { + loopType = T_BYTE; + } else if (callName == "echoI32") { + loopType = T_I32; + } else if (callName == "echoI64") { + loopType = T_I64; + } else if (callName == "echoString") { + loopType = T_STRING; + } else { + throw invalid_argument("Unknown service call " + callName); + } + + if(clientType == "regular") { + for (size_t ix = 0; ix < clientCount; ix++) { + + stdcxx::shared_ptr socket(new TSocket("127.0.0.1", port)); + stdcxx::shared_ptr bufferedSocket(new TBufferedTransport(socket, 2048)); + stdcxx::shared_ptr protocol(new TBinaryProtocol(bufferedSocket)); + stdcxx::shared_ptr serviceClient(new ServiceClient(protocol)); + + clientThreads.insert(threadFactory->newThread(stdcxx::shared_ptr( + new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType, OpenAndCloseTransportInThread)))); + } + } else if(clientType == "concurrent") { + stdcxx::shared_ptr socket(new TSocket("127.0.0.1", port)); + stdcxx::shared_ptr bufferedSocket(new TBufferedTransport(socket, 2048)); + stdcxx::shared_ptr protocol(new TBinaryProtocol(bufferedSocket)); + //stdcxx::shared_ptr serviceClient(new ServiceClient(protocol)); + stdcxx::shared_ptr serviceClient(new ServiceConcurrentClient(protocol)); + socket->open(); + for (size_t ix = 0; ix < clientCount; ix++) { + clientThreads.insert(threadFactory->newThread(stdcxx::shared_ptr( + new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType, DontOpenAndCloseTransportInThread)))); + } + } + + for (std::set >::const_iterator thread = clientThreads.begin(); + thread != clientThreads.end(); + thread++) { + (*thread)->start(); + } + + int64_t time00; + int64_t time01; + + { + Synchronized s(monitor); + threadCount = clientCount; + + cerr << "Launch " << clientCount << " " << clientType << " client threads" << endl; + + time00 = Util::currentTime(); + + monitor.notifyAll(); + + while (threadCount > 0) { + monitor.wait(); + } + + time01 = Util::currentTime(); + } + + int64_t firstTime = 9223372036854775807LL; + int64_t lastTime = 0; + + double averageTime = 0; + int64_t minTime = 9223372036854775807LL; + int64_t maxTime = 0; + + for (set >::iterator ix = clientThreads.begin(); + ix != clientThreads.end(); + ix++) { + + stdcxx::shared_ptr client + = stdcxx::dynamic_pointer_cast((*ix)->runnable()); + + int64_t delta = client->_endTime - client->_startTime; + + assert(delta > 0); + + if (client->_startTime < firstTime) { + firstTime = client->_startTime; + } + + if (client->_endTime > lastTime) { + lastTime = client->_endTime; + } + + if (delta < minTime) { + minTime = delta; + } + + if (delta > maxTime) { + maxTime = delta; + } + + averageTime += delta; + } + + averageTime /= clientCount; + + cout << "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount + << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl; + + count_map count = serviceHandler->getCount(); + count_map::iterator iter; + for (iter = count.begin(); iter != count.end(); ++iter) { + printf("%s => %d\n", iter->first, iter->second); + } + cerr << "done." << endl; + } + + return 0; +} diff --git a/test/cpp/src/StressTestNonBlocking.cpp b/test/cpp/src/StressTestNonBlocking.cpp new file mode 100644 index 0000000..e68988f --- /dev/null +++ b/test/cpp/src/StressTestNonBlocking.cpp @@ -0,0 +1,544 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Service.h" + +#include +#include +#include +#include +#include +#if _WIN32 +#include +#endif + +using namespace std; + +using namespace apache::thrift; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; +using namespace apache::thrift::server; +using namespace apache::thrift::concurrency; + +using namespace test::stress; + +struct eqstr { + bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) == 0; } +}; + +struct ltstr { + bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } +}; + +// typedef hash_map, eqstr> count_map; +typedef map count_map; + +class Server : public ServiceIf { +public: + Server() {} + + void count(const char* method) { + Guard m(lock_); + int ct = counts_[method]; + counts_[method] = ++ct; + } + + void echoVoid() { + count("echoVoid"); + // Sleep to simulate work + THRIFT_SLEEP_USEC(1); + return; + } + + count_map getCount() { + Guard m(lock_); + return counts_; + } + + int8_t echoByte(const int8_t arg) { return arg; } + int32_t echoI32(const int32_t arg) { return arg; } + int64_t echoI64(const int64_t arg) { return arg; } + void echoString(string& out, const string& arg) { + if (arg != "hello") { + T_ERROR_ABORT("WRONG STRING (%s)!!!!", arg.c_str()); + } + out = arg; + } + void echoList(vector& out, const vector& arg) { out = arg; } + void echoSet(set& out, const set& arg) { out = arg; } + void echoMap(map& out, const map& arg) { out = arg; } + +private: + count_map counts_; + Mutex lock_; +}; + +class ClientThread : public Runnable { +public: + ClientThread(stdcxx::shared_ptr transport, + stdcxx::shared_ptr client, + Monitor& monitor, + size_t& workerCount, + size_t loopCount, + TType loopType) + : _transport(transport), + _client(client), + _monitor(monitor), + _workerCount(workerCount), + _loopCount(loopCount), + _loopType(loopType) {} + + void run() { + + // Wait for all worker threads to start + + { + Synchronized s(_monitor); + while (_workerCount == 0) { + _monitor.wait(); + } + } + + _startTime = Util::currentTime(); + + _transport->open(); + + switch (_loopType) { + case T_VOID: + loopEchoVoid(); + break; + case T_BYTE: + loopEchoByte(); + break; + case T_I32: + loopEchoI32(); + break; + case T_I64: + loopEchoI64(); + break; + case T_STRING: + loopEchoString(); + break; + default: + cerr << "Unexpected loop type" << _loopType << endl; + break; + } + + _endTime = Util::currentTime(); + + _transport->close(); + + _done = true; + + { + Synchronized s(_monitor); + + _workerCount--; + + if (_workerCount == 0) { + + _monitor.notify(); + } + } + } + + void loopEchoVoid() { + for (size_t ix = 0; ix < _loopCount; ix++) { + _client->echoVoid(); + } + } + + void loopEchoByte() { + for (size_t ix = 0; ix < _loopCount; ix++) { + int8_t arg = 1; + int8_t result; + result = _client->echoByte(arg); + (void)result; + assert(result == arg); + } + } + + void loopEchoI32() { + for (size_t ix = 0; ix < _loopCount; ix++) { + int32_t arg = 1; + int32_t result; + result = _client->echoI32(arg); + (void)result; + assert(result == arg); + } + } + + void loopEchoI64() { + for (size_t ix = 0; ix < _loopCount; ix++) { + int64_t arg = 1; + int64_t result; + result = _client->echoI64(arg); + (void)result; + assert(result == arg); + } + } + + void loopEchoString() { + for (size_t ix = 0; ix < _loopCount; ix++) { + string arg = "hello"; + string result; + _client->echoString(result, arg); + assert(result == arg); + } + } + + stdcxx::shared_ptr _transport; + stdcxx::shared_ptr _client; + Monitor& _monitor; + size_t& _workerCount; + size_t _loopCount; + TType _loopType; + int64_t _startTime; + int64_t _endTime; + bool _done; + Monitor _sleep; +}; + +int main(int argc, char** argv) { +#if _WIN32 + transport::TWinsockSingleton::create(); +#endif + + int port = 9091; + string serverType = "simple"; + string protocolType = "binary"; + uint32_t workerCount = 4; + uint32_t clientCount = 20; + uint32_t loopCount = 1000; + TType loopType = T_VOID; + string callName = "echoVoid"; + bool runServer = true; + bool logRequests = false; + string requestLogPath = "./requestlog.tlog"; + bool replayRequests = false; + + ostringstream usage; + + usage << argv[0] << " [--port=] [--server] [--server-type=] " + "[--protocol-type=] [--workers=] " + "[--clients=] [--loop=]" << endl + << "\tclients Number of client threads to create - 0 implies no clients, i.e. " + "server only. Default is " << clientCount << endl + << "\thelp Prints this help text." << endl + << "\tcall Service method to call. Default is " << callName << endl + << "\tloop The number of remote thrift calls each client makes. Default is " + << loopCount << endl << "\tport The port the server and clients should bind to " + "for thrift network connections. Default is " << port << endl + << "\tserver Run the Thrift server in this process. Default is " << runServer + << endl << "\tserver-type Type of server, \"simple\" or \"thread-pool\". Default is " + << serverType << endl + << "\tprotocol-type Type of protocol, \"binary\", \"ascii\", or \"xml\". Default is " + << protocolType << endl + << "\tlog-request Log all request to ./requestlog.tlog. Default is " << logRequests + << endl << "\treplay-request Replay requests from log file (./requestlog.tlog) Default is " + << replayRequests << endl << "\tworkers Number of thread pools workers. Only valid " + "for thread-pool server type. Default is " << workerCount + << endl; + + map args; + + for (int ix = 1; ix < argc; ix++) { + + string arg(argv[ix]); + + if (arg.compare(0, 2, "--") == 0) { + + size_t end = arg.find_first_of("=", 2); + + string key = string(arg, 2, end - 2); + + if (end != string::npos) { + args[key] = string(arg, end + 1); + } else { + args[key] = "true"; + } + } else { + throw invalid_argument("Unexcepted command line token: " + arg); + } + } + + try { + + if (!args["clients"].empty()) { + clientCount = atoi(args["clients"].c_str()); + } + + if (!args["help"].empty()) { + cerr << usage.str(); + return 0; + } + + if (!args["loop"].empty()) { + loopCount = atoi(args["loop"].c_str()); + } + + if (!args["call"].empty()) { + callName = args["call"]; + } + + if (!args["port"].empty()) { + port = atoi(args["port"].c_str()); + } + + if (!args["server"].empty()) { + runServer = args["server"] == "true"; + } + + if (!args["log-request"].empty()) { + logRequests = args["log-request"] == "true"; + } + + if (!args["replay-request"].empty()) { + replayRequests = args["replay-request"] == "true"; + } + + if (!args["server-type"].empty()) { + serverType = args["server-type"]; + } + + if (!args["workers"].empty()) { + workerCount = atoi(args["workers"].c_str()); + } + + } catch (std::exception& e) { + cerr << e.what() << endl; + cerr << usage.str(); + } + + stdcxx::shared_ptr threadFactory + = stdcxx::shared_ptr(new PlatformThreadFactory()); + + // Dispatcher + stdcxx::shared_ptr serviceHandler(new Server()); + + if (replayRequests) { + stdcxx::shared_ptr serviceHandler(new Server()); + stdcxx::shared_ptr serviceProcessor(new ServiceProcessor(serviceHandler)); + + // Transports + stdcxx::shared_ptr fileTransport(new TFileTransport(requestLogPath)); + fileTransport->setChunkSize(2 * 1024 * 1024); + fileTransport->setMaxEventSize(1024 * 16); + fileTransport->seekToEnd(); + + // Protocol Factory + stdcxx::shared_ptr protocolFactory(new TBinaryProtocolFactory()); + + TFileProcessor fileProcessor(serviceProcessor, protocolFactory, fileTransport); + + fileProcessor.process(0, true); + exit(0); + } + + if (runServer) { + + stdcxx::shared_ptr serviceProcessor(new ServiceProcessor(serviceHandler)); + + // Protocol Factory + stdcxx::shared_ptr protocolFactory(new TBinaryProtocolFactory()); + + // Transport Factory + stdcxx::shared_ptr transportFactory; + + if (logRequests) { + // initialize the log file + stdcxx::shared_ptr fileTransport(new TFileTransport(requestLogPath)); + fileTransport->setChunkSize(2 * 1024 * 1024); + fileTransport->setMaxEventSize(1024 * 16); + + transportFactory + = stdcxx::shared_ptr(new TPipedTransportFactory(fileTransport)); + } + + stdcxx::shared_ptr serverThread; + stdcxx::shared_ptr serverThread2; + stdcxx::shared_ptr nbSocket1; + stdcxx::shared_ptr nbSocket2; + + if (serverType == "simple") { + + nbSocket1.reset(new transport::TNonblockingServerSocket(port)); + serverThread = threadFactory->newThread(stdcxx::shared_ptr( + new TNonblockingServer(serviceProcessor, protocolFactory, nbSocket1))); + nbSocket2.reset(new transport::TNonblockingServerSocket(port + 1)); + serverThread2 = threadFactory->newThread(stdcxx::shared_ptr( + new TNonblockingServer(serviceProcessor, protocolFactory, nbSocket2))); + + } else if (serverType == "thread-pool") { + + stdcxx::shared_ptr threadManager + = ThreadManager::newSimpleThreadManager(workerCount); + + threadManager->threadFactory(threadFactory); + threadManager->start(); + nbSocket1.reset(new transport::TNonblockingServerSocket(port)); + serverThread = threadFactory->newThread(stdcxx::shared_ptr( + new TNonblockingServer(serviceProcessor, protocolFactory, nbSocket1, threadManager))); + nbSocket2.reset(new transport::TNonblockingServerSocket(port + 1)); + serverThread2 = threadFactory->newThread(stdcxx::shared_ptr( + new TNonblockingServer(serviceProcessor, protocolFactory, nbSocket2, threadManager))); + } + + cerr << "Starting the server on port " << port << " and " << (port + 1) << endl; + serverThread->start(); + serverThread2->start(); + + // If we aren't running clients, just wait forever for external clients + + if (clientCount == 0) { + serverThread->join(); + serverThread2->join(); + } + } + THRIFT_SLEEP_SEC(1); + + if (clientCount > 0) { + + Monitor monitor; + + size_t threadCount = 0; + + set > clientThreads; + + if (callName == "echoVoid") { + loopType = T_VOID; + } else if (callName == "echoByte") { + loopType = T_BYTE; + } else if (callName == "echoI32") { + loopType = T_I32; + } else if (callName == "echoI64") { + loopType = T_I64; + } else if (callName == "echoString") { + loopType = T_STRING; + } else { + throw invalid_argument("Unknown service call " + callName); + } + + for (uint32_t ix = 0; ix < clientCount; ix++) { + + stdcxx::shared_ptr socket(new TSocket("127.0.0.1", port + (ix % 2))); + stdcxx::shared_ptr framedSocket(new TFramedTransport(socket)); + stdcxx::shared_ptr protocol(new TBinaryProtocol(framedSocket)); + stdcxx::shared_ptr serviceClient(new ServiceClient(protocol)); + + clientThreads.insert(threadFactory->newThread(stdcxx::shared_ptr( + new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType)))); + } + + for (std::set >::const_iterator thread = clientThreads.begin(); + thread != clientThreads.end(); + thread++) { + (*thread)->start(); + } + + int64_t time00; + int64_t time01; + + { + Synchronized s(monitor); + threadCount = clientCount; + + cerr << "Launch " << clientCount << " client threads" << endl; + + time00 = Util::currentTime(); + + monitor.notifyAll(); + + while (threadCount > 0) { + monitor.wait(); + } + + time01 = Util::currentTime(); + } + + int64_t firstTime = 9223372036854775807LL; + int64_t lastTime = 0; + + double averageTime = 0; + int64_t minTime = 9223372036854775807LL; + int64_t maxTime = 0; + + for (set >::iterator ix = clientThreads.begin(); + ix != clientThreads.end(); + ix++) { + + stdcxx::shared_ptr client + = stdcxx::dynamic_pointer_cast((*ix)->runnable()); + + int64_t delta = client->_endTime - client->_startTime; + + assert(delta > 0); + + if (client->_startTime < firstTime) { + firstTime = client->_startTime; + } + + if (client->_endTime > lastTime) { + lastTime = client->_endTime; + } + + if (delta < minTime) { + minTime = delta; + } + + if (delta > maxTime) { + maxTime = delta; + } + + averageTime += delta; + } + + averageTime /= clientCount; + + cout << "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount + << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl; + + count_map count = serviceHandler->getCount(); + count_map::iterator iter; + for (iter = count.begin(); iter != count.end(); ++iter) { + printf("%s => %d\n", iter->first, iter->second); + } + cerr << "done." << endl; + } + + return 0; +} diff --git a/test/cpp/src/TestClient.cpp b/test/cpp/src/TestClient.cpp new file mode 100644 index 0000000..9544a4a --- /dev/null +++ b/test/cpp/src/TestClient.cpp @@ -0,0 +1,1170 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // + +#ifdef HAVE_STDINT_H +#include +#endif +#ifdef HAVE_INTTYPES_H +#include +#endif + +#include +#include +#include +#include +#include +#if _WIN32 +#include +#endif + +#include "SecondService.h" +#include "ThriftTest.h" + +using namespace std; +using namespace apache::thrift; +using namespace apache::thrift::async; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; +using namespace thrift::test; + +// Current time, microseconds since the epoch +uint64_t now() { + int64_t ret; + struct timeval tv; + + THRIFT_GETTIMEOFDAY(&tv, NULL); + ret = tv.tv_sec; + ret = ret * 1000 * 1000 + tv.tv_usec; + return ret; +} + +static void testString_clientReturn(event_base* base, + int testNr, + ThriftTestCobClient* client) { + try { + string s; + client->recv_testString(s); + std::ostringstream os; + os << "test" << testNr; + const bool ok = (s == os.str()); + cout << "testString: " << s << " " << ((ok) ? "ok" : "failed") << endl; + } catch (TException& exn) { + cout << "Error: " << exn.what() << endl; + } + + if (testNr == 9) + event_base_loopbreak(base); // end test +} + +static void testVoid_clientReturn(event_base* base, ThriftTestCobClient* client) { + try { + client->recv_testVoid(); + cout << "testVoid" << endl; + + for (int testNr = 0; testNr < 10; ++testNr) { + std::ostringstream os; + os << "test" << testNr; + client->testString(stdcxx::bind(testString_clientReturn, + base, + testNr, + stdcxx::placeholders::_1), + os.str()); + } + } catch (TException& exn) { + cout << "Error: " << exn.what() << endl; + } +} + +// Workaround for absense of C++11 "auto" keyword. +template +bool print_eq(T expected, T actual) { + cout << "(" << actual << ")" << endl; + if (expected != actual) { + cout << "*** FAILED ***" << endl << "Expected: " << expected << " but got: " << actual << endl; + return false; + } + return true; +} + +#define BASETYPE_IDENTITY_TEST(func, value) \ + cout << #func "(" << value << ") = "; \ + try { \ + if (!print_eq(value, testClient.func(value))) \ + return_code |= ERR_BASETYPES; \ + } catch (TTransportException&) { \ + throw; \ + } catch (exception & ex) { \ + cout << "*** FAILED ***" << endl << ex.what() << endl; \ + return_code |= ERR_BASETYPES; \ + } + +int binary_test(ThriftTestClient& testClient, string::size_type siz); + +BOOST_CONSTEXPR_OR_CONST int ERR_BASETYPES = 1; +BOOST_CONSTEXPR_OR_CONST int ERR_STRUCTS = 2; +BOOST_CONSTEXPR_OR_CONST int ERR_CONTAINERS = 4; +BOOST_CONSTEXPR_OR_CONST int ERR_EXCEPTIONS = 8; +BOOST_CONSTEXPR_OR_CONST int ERR_UNKNOWN = 64; + +int main(int argc, char** argv) { + cout.precision(19); + + string testDir = boost::filesystem::system_complete(argv[0]).parent_path().parent_path().parent_path().string(); + string caPath = testDir + "/keys/CA.pem"; + string certPath = testDir + "/keys/client.crt"; + string keyPath = testDir + "/keys/client.key"; + +#if _WIN32 + transport::TWinsockSingleton::create(); +#endif + string host = "localhost"; + int port = 9090; + int numTests = 1; + bool ssl = false; + string transport_type = "buffered"; + string protocol_type = "binary"; + string domain_socket = ""; + bool abstract_namespace = false; + bool noinsane = false; + + int return_code = 0; + + boost::program_options::options_description desc("Allowed options"); + desc.add_options() + ("help,h", "produce help message") + ("host", + boost::program_options::value(&host)->default_value(host), + "Host to connect") + ("port", + boost::program_options::value(&port)->default_value(port), + "Port number to connect") + ("domain-socket", + boost::program_options::value(&domain_socket)->default_value(domain_socket), + "Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port") + ("abstract-namespace", + "Look for the domain socket in the Abstract Namespace" + " (no connection with filesystem pathnames)") + ("transport", + boost::program_options::value(&transport_type)->default_value(transport_type), + "Transport: buffered, framed, http, evhttp") + ("protocol", + boost::program_options::value(&protocol_type)->default_value(protocol_type), + "Protocol: binary, compact, header, json, multi, multic, multih, multij") + ("ssl", + "Encrypted Transport using SSL") + ("testloops,n", + boost::program_options::value(&numTests)->default_value(numTests), + "Number of Tests") + ("noinsane", + "Do not run insanity test"); + + boost::program_options::variables_map vm; + boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); + boost::program_options::notify(vm); + + if (vm.count("help")) { + cout << desc << endl; + return ERR_UNKNOWN; + } + + try { + if (!protocol_type.empty()) { + if (protocol_type == "binary") { + } else if (protocol_type == "compact") { + } else if (protocol_type == "header") { + } else if (protocol_type == "json") { + } else if (protocol_type == "multi") { + } else if (protocol_type == "multic") { + } else if (protocol_type == "multih") { + } else if (protocol_type == "multij") { + } else { + throw invalid_argument("Unknown protocol type " + protocol_type); + } + } + + if (!transport_type.empty()) { + if (transport_type == "buffered") { + } else if (transport_type == "framed") { + } else if (transport_type == "http") { + } else if (transport_type == "evhttp") { + } else { + throw invalid_argument("Unknown transport type " + transport_type); + } + } + + } catch (exception& e) { + cerr << e.what() << endl; + cout << desc << endl; + return ERR_UNKNOWN; + } + + if (vm.count("ssl")) { + ssl = true; + } + + if (vm.count("abstract-namespace")) { + abstract_namespace = true; + } + + if (vm.count("noinsane")) { + noinsane = true; + } + + // THRIFT-4164: The factory MUST outlive any sockets it creates for correct behavior! + stdcxx::shared_ptr factory; + stdcxx::shared_ptr socket; + stdcxx::shared_ptr transport; + stdcxx::shared_ptr protocol; + stdcxx::shared_ptr protocol2; // SecondService for multiplexed + + if (ssl) { + cout << "Client Certificate File: " << certPath << endl; + cout << "Client Key File: " << keyPath << endl; + cout << "CA File: " << caPath << endl; + + factory = stdcxx::shared_ptr(new TSSLSocketFactory()); + factory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); + factory->loadTrustedCertificates(caPath.c_str()); + factory->loadCertificate(certPath.c_str()); + factory->loadPrivateKey(keyPath.c_str()); + factory->authenticate(true); + socket = factory->createSocket(host, port); + } else { + if (domain_socket != "") { + if (abstract_namespace) { + std::string abstract_socket("\0", 1); + abstract_socket += domain_socket; + socket = stdcxx::shared_ptr(new TSocket(abstract_socket)); + } else { + socket = stdcxx::shared_ptr(new TSocket(domain_socket)); + } + port = 0; + } else { + socket = stdcxx::shared_ptr(new TSocket(host, port)); + } + } + + if (transport_type.compare("http") == 0) { + stdcxx::shared_ptr httpSocket(new THttpClient(socket, host, "/service")); + transport = httpSocket; + } else if (transport_type.compare("framed") == 0) { + stdcxx::shared_ptr framedSocket(new TFramedTransport(socket)); + transport = framedSocket; + } else { + stdcxx::shared_ptr bufferedSocket(new TBufferedTransport(socket)); + transport = bufferedSocket; + } + + if (protocol_type == "json" || protocol_type == "multij") { + protocol = stdcxx::make_shared(transport); + } else if (protocol_type == "compact" || protocol_type == "multic") { + protocol = stdcxx::make_shared(transport); + } else if (protocol_type == "header" || protocol_type == "multih") { + protocol = stdcxx::make_shared(transport); + } else { + protocol = stdcxx::make_shared(transport); + } + + if (boost::starts_with(protocol_type, "multi")) { + protocol2 = stdcxx::make_shared(protocol, "SecondService"); + // we don't need access to the original protocol any more, so... + protocol = stdcxx::make_shared(protocol, "ThriftTest"); + } + + // Connection info + cout << "Connecting (" << transport_type << "/" << protocol_type << ") to: "; + if (abstract_namespace) { + cout << '@'; + } + cout << domain_socket; + if (port != 0) { + cout << host << ":" << port; + } + cout << endl; + + if (transport_type.compare("evhttp") == 0) { + event_base* base = event_base_new(); + cout << "Libevent Version: " << event_get_version() << endl; + cout << "Libevent Method: " << event_base_get_method(base) << endl; +#if LIBEVENT_VERSION_NUMBER >= 0x02000000 + cout << "Libevent Features: 0x" << hex << event_base_get_features(base) << endl; +#endif + + stdcxx::shared_ptr protocolFactory(new TBinaryProtocolFactory()); + + stdcxx::shared_ptr channel( + new TEvhttpClientChannel(host.c_str(), "/", host.c_str(), port, base)); + ThriftTestCobClient* client = new ThriftTestCobClient(channel, protocolFactory.get()); + client->testVoid(stdcxx::bind(testVoid_clientReturn, + base, + stdcxx::placeholders::_1)); + + event_base_loop(base, 0); + return 0; + } + + ThriftTestClient testClient(protocol); + + uint64_t time_min = 0; + uint64_t time_max = 0; + uint64_t time_tot = 0; + + int test = 0; + for (test = 0; test < numTests; ++test) { + + try { + transport->open(); + } catch (TTransportException& ex) { + cout << "Connect failed: " << ex.what() << endl; + return ERR_UNKNOWN; + } + + /** + * CONNECT TEST + */ + printf("Test #%d, connect %s:%d\n", test + 1, host.c_str(), port); + + uint64_t start = now(); + + /** + * VOID TEST + */ + try { + cout << "testVoid()" << flush; + testClient.testVoid(); + cout << " = void" << endl; + } catch (TTransportException&) { + // Stop here if transport got broken + throw; + } catch (exception& ex) { + cout << "*** FAILED ***" << endl << ex.what() << endl; + return_code |= ERR_BASETYPES; + } + + /** + * STRING TEST + */ + cout << "testString(\"Test\")" << flush; + string s; + testClient.testString(s, "Test"); + cout << " = " << s << endl; + if (s != "Test") { + cout << "*** FAILED ***" << endl; + return_code |= ERR_BASETYPES; + } + + // + // Multiplexed protocol - call another service method + // in the middle of the ThriftTest + // + if (boost::starts_with(protocol_type, "multi")) { + SecondServiceClient ssc(protocol2); + // transport is already open... + + try { + cout << "secondService.secondTestString(\"foo\") => " << flush; + std::string result; + ssc.secondtestString(result, "foo"); + cout << "{" << result << "}" << endl; + } catch (std::exception& e) { + cout << " *** FAILED *** " << e.what() << endl; + return_code |= ERR_EXCEPTIONS; + } + } + + try { +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4566 ) +#endif + string str( + "}{Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " + "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " + "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, " + "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, " + "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, " + "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, " + "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, " + "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, " + "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, " + "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, " + "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, " + "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, " + "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, " + "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa " + "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa " + "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪" + "Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, " + "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, " + "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, " + "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple " + "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, " + "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, " + "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, " + "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, " + "Bân-lâm-gú, 粵語"); +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + cout << "testString(" << str << ") = " << flush; + testClient.testString(s, str); + cout << s << endl; + if (s != str) { + cout.imbue(locale("en_US.UTF8")); + cout << "*** FAILED ***" << endl << "Expected string: " << str << " but got: " << s << endl << "CLEAR"; + return_code |= ERR_BASETYPES; + } + } catch (TTransportException&) { + throw; + } catch (exception& ex) { + cout << "*** FAILED ***" << endl << ex.what() << endl; + return_code |= ERR_BASETYPES; + return return_code; + } + try { + string str( + "quote: \" backslash:" + " forwardslash-escaped: \\/ " + " backspace: \b formfeed: \f newline: \n return: \r tab: " + " now-all-of-them-together: \"\\\\/\b\n\r\t" + " now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><" + " char-to-test-json-parsing: ]] \"]] \\\" }}}{ [[[ "); + cout << "testString(" << str << ") = " << flush; + testClient.testString(s, str); + cout << s << endl; + if (s != str) { + cout.imbue(locale("en_US.UTF8")); + cout << "*** FAILED ***" << endl + << "Expected string: " << str << " but got: " << s << endl + << "CLEAR"; + ; + return_code |= ERR_BASETYPES; + } + } catch (TTransportException&) { + throw; + } catch (exception& ex) { + cout << "*** FAILED ***" << endl << ex.what() << endl; + return_code |= ERR_BASETYPES; + return return_code; + } + + /** + * BOOL TEST + */ + cout << boolalpha; + BASETYPE_IDENTITY_TEST(testBool, true); + BASETYPE_IDENTITY_TEST(testBool, false); + + /** + * BYTE TEST + */ + BASETYPE_IDENTITY_TEST(testByte, (int8_t)0); + BASETYPE_IDENTITY_TEST(testByte, (int8_t)-1); + BASETYPE_IDENTITY_TEST(testByte, (int8_t)42); + BASETYPE_IDENTITY_TEST(testByte, (int8_t)-42); + BASETYPE_IDENTITY_TEST(testByte, (int8_t)127); + BASETYPE_IDENTITY_TEST(testByte, (int8_t)-128); + + /** + * I32 TEST + */ + BASETYPE_IDENTITY_TEST(testI32, 0); + BASETYPE_IDENTITY_TEST(testI32, -1); + BASETYPE_IDENTITY_TEST(testI32, 190000013); + BASETYPE_IDENTITY_TEST(testI32, -190000013); + BASETYPE_IDENTITY_TEST(testI32, numeric_limits::max()); + BASETYPE_IDENTITY_TEST(testI32, numeric_limits::min()); + + /** + * I64 TEST + */ + BASETYPE_IDENTITY_TEST(testI64, (int64_t)0); + BASETYPE_IDENTITY_TEST(testI64, (int64_t)-1); + BASETYPE_IDENTITY_TEST(testI64, (int64_t)7000000000000000123LL); + BASETYPE_IDENTITY_TEST(testI64, (int64_t)-7000000000000000123LL); + BASETYPE_IDENTITY_TEST(testI64, (int64_t)pow(static_cast(2LL), 32)); + BASETYPE_IDENTITY_TEST(testI64, (int64_t)-pow(static_cast(2LL), 32)); + BASETYPE_IDENTITY_TEST(testI64, (int64_t)pow(static_cast(2LL), 32) + 1); + BASETYPE_IDENTITY_TEST(testI64, (int64_t)-pow(static_cast(2LL), 32) - 1); + BASETYPE_IDENTITY_TEST(testI64, numeric_limits::max()); + BASETYPE_IDENTITY_TEST(testI64, numeric_limits::min()); + + /** + * DOUBLE TEST + */ + // Comparing double values with plain equality because Thrift handles full precision of double + BASETYPE_IDENTITY_TEST(testDouble, 0.0); + BASETYPE_IDENTITY_TEST(testDouble, -1.0); + BASETYPE_IDENTITY_TEST(testDouble, -5.2098523); + BASETYPE_IDENTITY_TEST(testDouble, -0.000341012439638598279); + BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast(2), 32)); + BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast(2), 32) + 1); + BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast(2), 53) - 1); + BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast(2), 32)); + BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast(2), 32) - 1); + BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast(2), 53) + 1); + + try { + double expected = pow(static_cast(10), 307); + cout << "testDouble(" << expected << ") = " << flush; + double actual = testClient.testDouble(expected); + cout << "(" << actual << ")" << endl; + if (expected - actual > pow(static_cast(10), 292)) { + cout << "*** FAILED ***" << endl + << "Expected: " << expected << " but got: " << actual << endl; + } + } catch (TTransportException&) { + throw; + } catch (exception& ex) { + cout << "*** FAILED ***" << endl << ex.what() << endl; + return_code |= ERR_BASETYPES; + } + + try { + double expected = pow(static_cast(10), -292); + cout << "testDouble(" << expected << ") = " << flush; + double actual = testClient.testDouble(expected); + cout << "(" << actual << ")" << endl; + if (expected - actual > pow(static_cast(10), -307)) { + cout << "*** FAILED ***" << endl + << "Expected: " << expected << " but got: " << actual << endl; + } + } catch (TTransportException&) { + throw; + } catch (exception& ex) { + cout << "*** FAILED ***" << endl << ex.what() << endl; + return_code |= ERR_BASETYPES; + } + + /** + * BINARY TEST + */ + for (string::size_type i = 0; i < 131073 && !return_code; ) { + return_code |= binary_test(testClient, i); + if (i > 0) { i *= 2; } else { ++i; } + } + + + /** + * STRUCT TEST + */ + cout << "testStruct({\"Zero\", 1, -3, -5})" << flush; + Xtruct out; + out.string_thing = "Zero"; + out.byte_thing = 1; + out.i32_thing = -3; + out.i64_thing = -5; + Xtruct in; + testClient.testStruct(in, out); + printf(" = {\"%s\", %d, %d, %" PRId64 "}\n", + in.string_thing.c_str(), + (int)in.byte_thing, + in.i32_thing, + in.i64_thing); + if (in != out) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_STRUCTS; + } + + /** + * NESTED STRUCT TEST + */ + cout << "testNest({1, {\"Zero\", 1, -3, -5}), 5}" << flush; + Xtruct2 out2; + out2.byte_thing = 1; + out2.struct_thing = out; + out2.i32_thing = 5; + Xtruct2 in2; + testClient.testNest(in2, out2); + in = in2.struct_thing; + printf(" = {%d, {\"%s\", %d, %d, %" PRId64 "}, %d}\n", + in2.byte_thing, + in.string_thing.c_str(), + (int)in.byte_thing, + in.i32_thing, + in.i64_thing, + in2.i32_thing); + if (in2 != out2) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_STRUCTS; + } + + /** + * MAP TEST + */ + map mapout; + for (int32_t i = 0; i < 5; ++i) { + mapout.insert(make_pair(i, i - 10)); + } + cout << "testMap({" << flush; + map::const_iterator m_iter; + bool first = true; + for (m_iter = mapout.begin(); m_iter != mapout.end(); ++m_iter) { + if (first) { + first = false; + } else { + cout << ","; + } + cout << m_iter->first << " => " << m_iter->second; + } + cout << "})"; + map mapin; + testClient.testMap(mapin, mapout); + cout << " = {"; + first = true; + for (m_iter = mapin.begin(); m_iter != mapin.end(); ++m_iter) { + if (first) { + first = false; + } else { + cout << ","; + } + cout << m_iter->first << " => " << m_iter->second; + } + cout << "}" << endl; + if (mapin != mapout) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_CONTAINERS; + } + + /** + * STRING MAP TEST + */ + cout << "testStringMap({a => 2, b => blah, some => thing}) = {" << flush; + map smapin; + map smapout; + smapin["a"] = "2"; + smapin["b"] = "blah"; + smapin["some"] = "thing"; + try { + testClient.testStringMap(smapout, smapin); + first = true; + for (map::const_iterator it = smapout.begin(); it != smapout.end(); ++it) { + if (first) + cout << ","; + else + first = false; + cout << it->first << " => " << it->second; + } + cout << "}" << endl; + if (smapin != smapout) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_CONTAINERS; + } + } catch (TTransportException&) { + throw; + } catch (exception& ex) { + cout << "*** FAILED ***" << endl << ex.what() << endl; + return_code |= ERR_CONTAINERS; + } + + /** + * SET TEST + */ + set setout; + for (int32_t i = -2; i < 3; ++i) { + setout.insert(i); + } + cout << "testSet({" << flush; + set::const_iterator s_iter; + first = true; + for (s_iter = setout.begin(); s_iter != setout.end(); ++s_iter) { + if (first) { + first = false; + } else { + cout << ","; + } + cout << *s_iter; + } + cout << "})"; + set setin; + testClient.testSet(setin, setout); + cout << " = {"; + first = true; + for (s_iter = setin.begin(); s_iter != setin.end(); ++s_iter) { + if (first) { + first = false; + } else { + cout << ","; + } + cout << *s_iter; + } + cout << "}" << endl; + if (setin != setout) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_CONTAINERS; + } + + /** + * LIST TEST + */ + cout << "testList(empty)" << flush; + try { + vector listout; + testClient.testList(listout, vector()); + if (!listout.empty()) { + cout << "*** FAILED ***" << endl; + cout << "invalid length: " << listout.size() << endl; + return_code |= ERR_CONTAINERS; + } + } catch (TTransportException&) { + throw; + } catch (exception& ex) { + cout << "*** FAILED ***" << endl << ex.what() << endl; + return_code |= ERR_CONTAINERS; + } + try { + vector listout; + for (int32_t i = -2; i < 3; ++i) { + listout.push_back(i); + } + cout << "testList({" << flush; + vector::const_iterator l_iter; + first = true; + for (l_iter = listout.begin(); l_iter != listout.end(); ++l_iter) { + if (first) { + first = false; + } else { + cout << ","; + } + cout << *l_iter; + } + cout << "})"; + vector listin; + testClient.testList(listin, listout); + cout << " = {"; + first = true; + for (l_iter = listin.begin(); l_iter != listin.end(); ++l_iter) { + if (first) { + first = false; + } else { + cout << ","; + } + cout << *l_iter; + } + cout << "}" << endl; + if (listin != listout) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_CONTAINERS; + } + } catch (TTransportException&) { + throw; + } catch (exception& ex) { + cout << "*** FAILED ***" << endl << ex.what() << endl; + return_code |= ERR_CONTAINERS; + } + + /** + * ENUM TEST + */ + cout << "testEnum(ONE)" << flush; + Numberz::type ret = testClient.testEnum(Numberz::ONE); + cout << " = " << ret << endl; + if (ret != Numberz::ONE) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_STRUCTS; + } + + cout << "testEnum(TWO)" << flush; + ret = testClient.testEnum(Numberz::TWO); + cout << " = " << ret << endl; + if (ret != Numberz::TWO) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_STRUCTS; + } + + cout << "testEnum(THREE)" << flush; + ret = testClient.testEnum(Numberz::THREE); + cout << " = " << ret << endl; + if (ret != Numberz::THREE) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_STRUCTS; + } + + cout << "testEnum(FIVE)" << flush; + ret = testClient.testEnum(Numberz::FIVE); + cout << " = " << ret << endl; + if (ret != Numberz::FIVE) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_STRUCTS; + } + + cout << "testEnum(EIGHT)" << flush; + ret = testClient.testEnum(Numberz::EIGHT); + cout << " = " << ret << endl; + if (ret != Numberz::EIGHT) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_STRUCTS; + } + + /** + * TYPEDEF TEST + */ + cout << "testTypedef(309858235082523)" << flush; + UserId uid = testClient.testTypedef(309858235082523LL); + cout << " = " << uid << endl; + if (uid != 309858235082523LL) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_STRUCTS; + } + + /** + * NESTED MAP TEST + */ + cout << "testMapMap(1)" << flush; + map > mm; + testClient.testMapMap(mm, 1); + cout << " = {"; + map >::const_iterator mi; + for (mi = mm.begin(); mi != mm.end(); ++mi) { + printf("%d => {", mi->first); + map::const_iterator mi2; + for (mi2 = mi->second.begin(); mi2 != mi->second.end(); ++mi2) { + cout << mi2->first << " => " << mi2->second; + } + cout << "}, "; + } + cout << "}" << endl; + if (mm.size() != 2 || + mm[-4][-4] != -4 || + mm[-4][-3] != -3 || + mm[-4][-2] != -2 || + mm[-4][-1] != -1 || + mm[4][4] != 4 || + mm[4][3] != 3 || + mm[4][2] != 2 || + mm[4][1] != 1) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_CONTAINERS; + } + + /** + * INSANITY TEST + */ + if (!noinsane) { + Insanity insane; + insane.userMap.insert(make_pair(Numberz::FIVE, 5)); + insane.userMap.insert(make_pair(Numberz::EIGHT, 8)); + Xtruct truck; + truck.string_thing = "Goodbye4"; + truck.byte_thing = 4; + truck.i32_thing = 4; + truck.i64_thing = 4; + Xtruct truck2; + truck2.string_thing = "Hello2"; + truck2.byte_thing = 2; + truck2.i32_thing = 2; + truck2.i64_thing = 2; + insane.xtructs.push_back(truck); + insane.xtructs.push_back(truck2); + cout << "testInsanity()" << flush; + map > whoa; + testClient.testInsanity(whoa, insane); + cout << " = {"; + map >::const_iterator i_iter; + for (i_iter = whoa.begin(); i_iter != whoa.end(); ++i_iter) { + printf("%" PRId64 " => {", i_iter->first); + map::const_iterator i2_iter; + for (i2_iter = i_iter->second.begin(); i2_iter != i_iter->second.end(); ++i2_iter) { + printf("%d => {", i2_iter->first); + map userMap = i2_iter->second.userMap; + map::const_iterator um; + cout << "{"; + for (um = userMap.begin(); um != userMap.end(); ++um) { + cout << um->first << " => " << um->second; + } + cout << "}, "; + + vector xtructs = i2_iter->second.xtructs; + vector::const_iterator x; + cout << "{"; + for (x = xtructs.begin(); x != xtructs.end(); ++x) { + printf("{\"%s\", %d, %d, %" PRId64 "}, ", + x->string_thing.c_str(), + (int)x->byte_thing, + x->i32_thing, + x->i64_thing); + } + cout << "}"; + + cout << "}, "; + } + cout << "}, "; + } + cout << "}" << endl; + bool failed = false; + map >::const_iterator it1 = whoa.find(UserId(1)); + if (whoa.size() != 2) { + failed = true; + } + if (it1 == whoa.end()) { + failed = true; + } else { + map::const_iterator it12 = it1->second.find(Numberz::TWO); + if (it12 == it1->second.end() || it12->second != insane) { + failed = true; + } + map::const_iterator it13 = it1->second.find(Numberz::THREE); + if (it13 == it1->second.end() || it13->second != insane) { + failed = true; + } + } + map >::const_iterator it2 = whoa.find(UserId(2)); + if (it2 == whoa.end()) { + failed = true; + } else { + map::const_iterator it26 = it2->second.find(Numberz::SIX); + if (it26 == it1->second.end() || it26->second != Insanity()) { + failed = true; + } + } + if (failed) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_STRUCTS; + } + } + + /** + * MULTI TEST + */ + cout << "testMulti()" << endl; + try { + map mul_map; + Xtruct mul_result; + mul_map[1] = "blah"; + mul_map[2] = "thing"; + testClient.testMulti(mul_result, 42, 4242, 424242, mul_map, Numberz::EIGHT, UserId(24)); + Xtruct xxs; + xxs.string_thing = "Hello2"; + xxs.byte_thing = 42; + xxs.i32_thing = 4242; + xxs.i64_thing = 424242; + if (mul_result != xxs) { + cout << "*** FAILED ***" << endl; + return_code |= ERR_STRUCTS; + } + } catch (TTransportException&) { + throw; + } catch (exception& ex) { + cout << "*** FAILED ***" << endl << ex.what() << endl; + return_code |= ERR_STRUCTS; + } + + /* test exception */ + + try { + cout << "testClient.testException(\"Xception\") =>" << flush; + testClient.testException("Xception"); + cout << " void\n*** FAILED ***" << endl; + return_code |= ERR_EXCEPTIONS; + + } catch (Xception& e) { + printf(" {%u, \"%s\"}\n", e.errorCode, e.message.c_str()); + } + + try { + cout << "testClient.testException(\"TException\") =>" << flush; + testClient.testException("TException"); + cout << " void\n*** FAILED ***" << endl; + return_code |= ERR_EXCEPTIONS; + + } catch (const TException&) { + cout << " Caught TException" << endl; + } + + try { + cout << "testClient.testException(\"success\") =>" << flush; + testClient.testException("success"); + cout << " void" << endl; + } catch (exception & ex) { \ + cout << "*** FAILED ***" << endl << ex.what() << endl; + return_code |= ERR_EXCEPTIONS; + } + + /* test multi exception */ + + try { + cout << "testClient.testMultiException(\"Xception\", \"test 1\") =>" << flush; + Xtruct result; + testClient.testMultiException(result, "Xception", "test 1"); + cout << " result\n*** FAILED ***" << endl; + return_code |= ERR_EXCEPTIONS; + } catch (Xception& e) { + printf(" {%u, \"%s\"}\n", e.errorCode, e.message.c_str()); + } + + try { + cout << "testClient.testMultiException(\"Xception2\", \"test 2\") =>" << flush; + Xtruct result; + testClient.testMultiException(result, "Xception2", "test 2"); + cout << " result\n*** FAILED ***" << endl; + return_code |= ERR_EXCEPTIONS; + + } catch (Xception2& e) { + printf(" {%u, {\"%s\"}}\n", e.errorCode, e.struct_thing.string_thing.c_str()); + } + + try { + cout << "testClient.testMultiException(\"success\", \"test 3\") =>" << flush; + Xtruct result; + testClient.testMultiException(result, "success", "test 3"); + printf(" {{\"%s\"}}\n", result.string_thing.c_str()); + } catch (exception & ex) { \ + cout << "*** FAILED ***" << endl << ex.what() << endl; + return_code |= ERR_EXCEPTIONS; + } + + /* test oneway void */ + { + cout << "testClient.testOneway(1) =>" << flush; + uint64_t startOneway = now(); + testClient.testOneway(1); + uint64_t elapsed = now() - startOneway; + if (elapsed > 200 * 1000) { // 0.2 seconds + printf("*** FAILED *** - took %.2f ms\n", (double)elapsed / 1000.0); + return_code |= ERR_BASETYPES; + } else { + printf(" success - took %.2f ms\n", (double)elapsed / 1000.0); + } + } + + /** + * redo a simple test after the oneway to make sure we aren't "off by one" -- + * if the server treated oneway void like normal void, this next test will + * fail since it will get the void confirmation rather than the correct + * result. In this circumstance, the client will throw the exception: + * + * TApplicationException: Wrong method namea + */ + /** + * I32 TEST + */ + cout << "re-test testI32(-1)" << flush; + int i32 = testClient.testI32(-1); + cout << " = " << i32 << endl; + if (i32 != -1) + return_code |= ERR_BASETYPES; + + cout << endl << "All tests done." << endl << flush; + + uint64_t stop = now(); + uint64_t tot = stop - start; + + cout << "Total time: " << stop - start << " us" << endl; + + time_tot += tot; + if (time_min == 0 || tot < time_min) { + time_min = tot; + } + if (tot > time_max) { + time_max = tot; + } + + cout << flush; + transport->close(); + } + + + uint64_t time_avg = time_tot / numTests; + + cout << "Min time: " << time_min << " us" << endl; + cout << "Max time: " << time_max << " us" << endl; + cout << "Avg time: " << time_avg << " us" << endl; + + return return_code; +} + +void binary_fill(std::string& str, string::size_type siz) +{ + static const signed char bin_data[256] + = {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, + -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, + -98, -97, -96, -95, -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, + -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, + -68, -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, + -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, + -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, + -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, + -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127}; + + str.resize(siz); + char *ptr = &str[0]; + string::size_type pos = 0; + for (string::size_type i = 0; i < siz; ++i) + { + if (pos == 255) { pos = 0; } else { ++pos; } + *ptr++ = bin_data[pos]; + } +} + +int binary_test(ThriftTestClient& testClient, string::size_type siz) +{ + string bin_request; + string bin_result; + + cout << "testBinary(siz = " << siz << ")" << endl; + binary_fill(bin_request, siz); + try { + testClient.testBinary(bin_result, bin_request); + + if (bin_request.size() != bin_result.size()) { + cout << "*** FAILED: request size " << bin_request.size() << "; result size " << bin_result.size() << endl; + return ERR_BASETYPES; + } + + for (string::size_type i = 0; i < siz; ++i) { + if (bin_request.at(i) != bin_result.at(i)) { + cout << "*** FAILED: at position " << i << " request[i] is h" << hex << bin_request.at(i) << " result[i] is h" << hex << bin_result.at(i) << endl; + return ERR_BASETYPES; + } + } + } catch (TTransportException&) { + throw; + } catch (exception& ex) { + cout << "*** FAILED ***" << endl << ex.what() << endl; + return ERR_BASETYPES; + } + + return 0; +} diff --git a/test/cpp/src/TestServer.cpp b/test/cpp/src/TestServer.cpp new file mode 100644 index 0000000..78b0a74 --- /dev/null +++ b/test/cpp/src/TestServer.cpp @@ -0,0 +1,807 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SecondService.h" +#include "ThriftTest.h" + +#ifdef HAVE_STDINT_H +#include +#endif +#ifdef HAVE_INTTYPES_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#include +#if _WIN32 +#include +#endif + +using namespace std; + +using namespace apache::thrift; +using namespace apache::thrift::async; +using namespace apache::thrift::concurrency; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; +using namespace apache::thrift::server; + +using namespace thrift::test; + +class TestHandler : public ThriftTestIf { +public: + TestHandler() {} + + void testVoid() { printf("testVoid()\n"); } + + void testString(string& out, const string& thing) { + printf("testString(\"%s\")\n", thing.c_str()); + out = thing; + } + + bool testBool(const bool thing) { + printf("testBool(%s)\n", thing ? "true" : "false"); + return thing; + } + + int8_t testByte(const int8_t thing) { + printf("testByte(%d)\n", (int)thing); + return thing; + } + + int32_t testI32(const int32_t thing) { + printf("testI32(%d)\n", thing); + return thing; + } + + int64_t testI64(const int64_t thing) { + printf("testI64(%" PRId64 ")\n", thing); + return thing; + } + + double testDouble(const double thing) { + printf("testDouble(%f)\n", thing); + return thing; + } + + void testBinary(std::string& _return, const std::string& thing) { + std::ostringstream hexstr; + hexstr << std::hex << thing; + printf("testBinary(%lu: %s)\n", thing.size(), hexstr.str().c_str()); + _return = thing; + } + + void testStruct(Xtruct& out, const Xtruct& thing) { + printf("testStruct({\"%s\", %d, %d, %" PRId64 "})\n", + thing.string_thing.c_str(), + (int)thing.byte_thing, + thing.i32_thing, + thing.i64_thing); + out = thing; + } + + void testNest(Xtruct2& out, const Xtruct2& nest) { + const Xtruct& thing = nest.struct_thing; + printf("testNest({%d, {\"%s\", %d, %d, %" PRId64 "}, %d})\n", + (int)nest.byte_thing, + thing.string_thing.c_str(), + (int)thing.byte_thing, + thing.i32_thing, + thing.i64_thing, + nest.i32_thing); + out = nest; + } + + void testMap(map& out, const map& thing) { + printf("testMap({"); + map::const_iterator m_iter; + bool first = true; + for (m_iter = thing.begin(); m_iter != thing.end(); ++m_iter) { + if (first) { + first = false; + } else { + printf(", "); + } + printf("%d => %d", m_iter->first, m_iter->second); + } + printf("})\n"); + out = thing; + } + + void testStringMap(map& out, + const map& thing) { + printf("testMap({"); + map::const_iterator m_iter; + bool first = true; + for (m_iter = thing.begin(); m_iter != thing.end(); ++m_iter) { + if (first) { + first = false; + } else { + printf(", "); + } + printf("%s => %s", (m_iter->first).c_str(), (m_iter->second).c_str()); + } + printf("})\n"); + out = thing; + } + + void testSet(set& out, const set& thing) { + printf("testSet({"); + set::const_iterator s_iter; + bool first = true; + for (s_iter = thing.begin(); s_iter != thing.end(); ++s_iter) { + if (first) { + first = false; + } else { + printf(", "); + } + printf("%d", *s_iter); + } + printf("})\n"); + out = thing; + } + + void testList(vector& out, const vector& thing) { + printf("testList({"); + vector::const_iterator l_iter; + bool first = true; + for (l_iter = thing.begin(); l_iter != thing.end(); ++l_iter) { + if (first) { + first = false; + } else { + printf(", "); + } + printf("%d", *l_iter); + } + printf("})\n"); + out = thing; + } + + Numberz::type testEnum(const Numberz::type thing) { + printf("testEnum(%d)\n", thing); + return thing; + } + + UserId testTypedef(const UserId thing) { + printf("testTypedef(%" PRId64 ")\n", thing); + return thing; + } + + void testMapMap(map >& mapmap, const int32_t hello) { + printf("testMapMap(%d)\n", hello); + + map pos; + map neg; + for (int i = 1; i < 5; i++) { + pos.insert(make_pair(i, i)); + neg.insert(make_pair(-i, -i)); + } + + mapmap.insert(make_pair(4, pos)); + mapmap.insert(make_pair(-4, neg)); + } + + void testInsanity(map >& insane, const Insanity& argument) { + printf("testInsanity()\n"); + + Insanity looney; + map first_map; + map second_map; + + first_map.insert(make_pair(Numberz::TWO, argument)); + first_map.insert(make_pair(Numberz::THREE, argument)); + + second_map.insert(make_pair(Numberz::SIX, looney)); + + insane.insert(make_pair(1, first_map)); + insane.insert(make_pair(2, second_map)); + + printf("return"); + printf(" = {"); + map >::const_iterator i_iter; + for (i_iter = insane.begin(); i_iter != insane.end(); ++i_iter) { + printf("%" PRId64 " => {", i_iter->first); + map::const_iterator i2_iter; + for (i2_iter = i_iter->second.begin(); i2_iter != i_iter->second.end(); ++i2_iter) { + printf("%d => {", i2_iter->first); + map userMap = i2_iter->second.userMap; + map::const_iterator um; + printf("{"); + for (um = userMap.begin(); um != userMap.end(); ++um) { + printf("%d => %" PRId64 ", ", um->first, um->second); + } + printf("}, "); + + vector xtructs = i2_iter->second.xtructs; + vector::const_iterator x; + printf("{"); + for (x = xtructs.begin(); x != xtructs.end(); ++x) { + printf("{\"%s\", %d, %d, %" PRId64 "}, ", + x->string_thing.c_str(), + (int)x->byte_thing, + x->i32_thing, + x->i64_thing); + } + printf("}"); + + printf("}, "); + } + printf("}, "); + } + printf("}\n"); + } + + void testMulti(Xtruct& hello, + const int8_t arg0, + const int32_t arg1, + const int64_t arg2, + const std::map& arg3, + const Numberz::type arg4, + const UserId arg5) { + (void)arg3; + (void)arg4; + (void)arg5; + + printf("testMulti()\n"); + + hello.string_thing = "Hello2"; + hello.byte_thing = arg0; + hello.i32_thing = arg1; + hello.i64_thing = (int64_t)arg2; + } + + void testException(const std::string& arg) { + printf("testException(%s)\n", arg.c_str()); + if (arg.compare("Xception") == 0) { + Xception e; + e.errorCode = 1001; + e.message = arg; + throw e; + } else if (arg.compare("TException") == 0) { + apache::thrift::TException e; + throw e; + } else { + Xtruct result; + result.string_thing = arg; + return; + } + } + + void testMultiException(Xtruct& result, + const std::string& arg0, + const std::string& arg1) { + + printf("testMultiException(%s, %s)\n", arg0.c_str(), arg1.c_str()); + + if (arg0.compare("Xception") == 0) { + Xception e; + e.errorCode = 1001; + e.message = "This is an Xception"; + throw e; + } else if (arg0.compare("Xception2") == 0) { + Xception2 e; + e.errorCode = 2002; + e.struct_thing.string_thing = "This is an Xception2"; + throw e; + } else { + result.string_thing = arg1; + return; + } + } + + void testOneway(const int32_t aNum) { + printf("testOneway(%d): call received\n", aNum); + } +}; + +class SecondHandler : public SecondServiceIf +{ + public: + void secondtestString(std::string& result, const std::string& thing) + { result = "testString(\"" + thing + "\")"; } +}; + +class TestProcessorEventHandler : public TProcessorEventHandler { + virtual void* getContext(const char* fn_name, void* serverContext) { + (void)serverContext; + return new std::string(fn_name); + } + virtual void freeContext(void* ctx, const char* fn_name) { + (void)fn_name; + delete static_cast(ctx); + } + virtual void preRead(void* ctx, const char* fn_name) { communicate("preRead", ctx, fn_name); } + virtual void postRead(void* ctx, const char* fn_name, uint32_t bytes) { + (void)bytes; + communicate("postRead", ctx, fn_name); + } + virtual void preWrite(void* ctx, const char* fn_name) { communicate("preWrite", ctx, fn_name); } + virtual void postWrite(void* ctx, const char* fn_name, uint32_t bytes) { + (void)bytes; + communicate("postWrite", ctx, fn_name); + } + virtual void asyncComplete(void* ctx, const char* fn_name) { + communicate("asyncComplete", ctx, fn_name); + } + virtual void handlerError(void* ctx, const char* fn_name) { + communicate("handlerError", ctx, fn_name); + } + + void communicate(const char* event, void* ctx, const char* fn_name) { + std::cout << event << ": " << *static_cast(ctx) << " = " << fn_name << std::endl; + } +}; + +class TestHandlerAsync : public ThriftTestCobSvIf { +public: + TestHandlerAsync(stdcxx::shared_ptr& handler) : _delegate(handler) {} + virtual ~TestHandlerAsync() {} + + virtual void testVoid(stdcxx::function cob) { + _delegate->testVoid(); + cob(); + } + + virtual void testString(stdcxx::function cob, + const std::string& thing) { + std::string res; + _delegate->testString(res, thing); + cob(res); + } + + virtual void testBool(stdcxx::function cob, const bool thing) { + bool res = _delegate->testBool(thing); + cob(res); + } + + virtual void testByte(stdcxx::function cob, const int8_t thing) { + int8_t res = _delegate->testByte(thing); + cob(res); + } + + virtual void testI32(stdcxx::function cob, const int32_t thing) { + int32_t res = _delegate->testI32(thing); + cob(res); + } + + virtual void testI64(stdcxx::function cob, const int64_t thing) { + int64_t res = _delegate->testI64(thing); + cob(res); + } + + virtual void testDouble(stdcxx::function cob, const double thing) { + double res = _delegate->testDouble(thing); + cob(res); + } + + virtual void testBinary(stdcxx::function cob, + const std::string& thing) { + std::string res; + _delegate->testBinary(res, thing); + cob(res); + } + + virtual void testStruct(stdcxx::function cob, const Xtruct& thing) { + Xtruct res; + _delegate->testStruct(res, thing); + cob(res); + } + + virtual void testNest(stdcxx::function cob, const Xtruct2& thing) { + Xtruct2 res; + _delegate->testNest(res, thing); + cob(res); + } + + virtual void testMap(stdcxx::function const& _return)> cob, + const std::map& thing) { + std::map res; + _delegate->testMap(res, thing); + cob(res); + } + + virtual void testStringMap( + stdcxx::function const& _return)> cob, + const std::map& thing) { + std::map res; + _delegate->testStringMap(res, thing); + cob(res); + } + + virtual void testSet(stdcxx::function const& _return)> cob, + const std::set& thing) { + std::set res; + _delegate->testSet(res, thing); + cob(res); + } + + virtual void testList(stdcxx::function const& _return)> cob, + const std::vector& thing) { + std::vector res; + _delegate->testList(res, thing); + cob(res); + } + + virtual void testEnum(stdcxx::function cob, + const Numberz::type thing) { + Numberz::type res = _delegate->testEnum(thing); + cob(res); + } + + virtual void testTypedef(stdcxx::function cob, const UserId thing) { + UserId res = _delegate->testTypedef(thing); + cob(res); + } + + virtual void testMapMap( + stdcxx::function > const& _return)> cob, + const int32_t hello) { + std::map > res; + _delegate->testMapMap(res, hello); + cob(res); + } + + virtual void testInsanity( + stdcxx::function > const& _return)> cob, + const Insanity& argument) { + std::map > res; + _delegate->testInsanity(res, argument); + cob(res); + } + + virtual void testMulti(stdcxx::function cob, + const int8_t arg0, + const int32_t arg1, + const int64_t arg2, + const std::map& arg3, + const Numberz::type arg4, + const UserId arg5) { + Xtruct res; + _delegate->testMulti(res, arg0, arg1, arg2, arg3, arg4, arg5); + cob(res); + } + + virtual void testException( + stdcxx::function cob, + stdcxx::function exn_cob, + const std::string& arg) { + try { + _delegate->testException(arg); + } catch (const apache::thrift::TException& e) { + exn_cob(apache::thrift::TDelayedException::delayException(e)); + return; + } + cob(); + } + + virtual void testMultiException( + stdcxx::function cob, + stdcxx::function exn_cob, + const std::string& arg0, + const std::string& arg1) { + Xtruct res; + try { + _delegate->testMultiException(res, arg0, arg1); + } catch (const apache::thrift::TException& e) { + exn_cob(apache::thrift::TDelayedException::delayException(e)); + return; + } + cob(res); + } + + virtual void testOneway(stdcxx::function cob, const int32_t secondsToSleep) { + _delegate->testOneway(secondsToSleep); + cob(); + } + +protected: + stdcxx::shared_ptr _delegate; +}; + +namespace po = boost::program_options; + +int main(int argc, char** argv) { + + string testDir = boost::filesystem::system_complete(argv[0]).parent_path().parent_path().parent_path().string(); + string certPath = testDir + "/keys/server.crt"; + string keyPath = testDir + "/keys/server.key"; + +#if _WIN32 + transport::TWinsockSingleton::create(); +#endif + int port = 9090; + bool ssl = false; + string transport_type = "buffered"; + string protocol_type = "binary"; + string server_type = "simple"; + string domain_socket = ""; + bool abstract_namespace = false; + size_t workers = 4; + int string_limit = 0; + int container_limit = 0; + + po::options_description desc("Allowed options"); + desc.add_options() + ("help,h", "produce help message") + ("port", po::value(&port)->default_value(port), "Port number to listen") + ("domain-socket", po::value(&domain_socket) ->default_value(domain_socket), "Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)") + ("abstract-namespace", "Create the domain socket in the Abstract Namespace (no connection with filesystem pathnames)") + ("server-type", po::value(&server_type)->default_value(server_type), "type of server, \"simple\", \"thread-pool\", \"threaded\", or \"nonblocking\"") + ("transport", po::value(&transport_type)->default_value(transport_type), "transport: buffered, framed, http") + ("protocol", po::value(&protocol_type)->default_value(protocol_type), "protocol: binary, compact, header, json, multi, multic, multih, multij") + ("ssl", "Encrypted Transport using SSL") + ("processor-events", "processor-events") + ("workers,n", po::value(&workers)->default_value(workers), "Number of thread pools workers. Only valid for thread-pool server type") + ("string-limit", po::value(&string_limit)) + ("container-limit", po::value(&container_limit)); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + if (vm.count("help")) { + cout << desc << "\n"; + return 1; + } + + try { + if (!server_type.empty()) { + if (server_type == "simple") { + } else if (server_type == "thread-pool") { + } else if (server_type == "threaded") { + } else if (server_type == "nonblocking") { + } else { + throw invalid_argument("Unknown server type " + server_type); + } + } + + if (!protocol_type.empty()) { + if (protocol_type == "binary") { + } else if (protocol_type == "compact") { + } else if (protocol_type == "json") { + } else if (protocol_type == "header") { + } else if (protocol_type == "multi") { // multiplexed binary + } else if (protocol_type == "multic") { // multiplexed compact + } else if (protocol_type == "multih") { // multiplexed header + } else if (protocol_type == "multij") { // multiplexed json + } else { + throw invalid_argument("Unknown protocol type " + protocol_type); + } + } + + if (!transport_type.empty()) { + if (transport_type == "buffered") { + } else if (transport_type == "framed") { + } else if (transport_type == "http") { + } else { + throw invalid_argument("Unknown transport type " + transport_type); + } + } + + } catch (std::exception& e) { + cerr << e.what() << endl; + cout << desc << "\n"; + return 1; + } + + if (vm.count("ssl")) { + ssl = true; + } + + if (vm.count("abstract-namespace")) { + abstract_namespace = true; + } + + // Dispatcher + stdcxx::shared_ptr protocolFactory; + if (protocol_type == "json" || protocol_type == "multij") { + stdcxx::shared_ptr jsonProtocolFactory(new TJSONProtocolFactory()); + protocolFactory = jsonProtocolFactory; + } else if (protocol_type == "compact" || protocol_type == "multic") { + TCompactProtocolFactoryT *compactProtocolFactory = new TCompactProtocolFactoryT(); + compactProtocolFactory->setContainerSizeLimit(container_limit); + compactProtocolFactory->setStringSizeLimit(string_limit); + protocolFactory.reset(compactProtocolFactory); + } else if (protocol_type == "header" || protocol_type == "multih") { + stdcxx::shared_ptr headerProtocolFactory(new THeaderProtocolFactory()); + protocolFactory = headerProtocolFactory; + } else { + TBinaryProtocolFactoryT* binaryProtocolFactory = new TBinaryProtocolFactoryT(); + binaryProtocolFactory->setContainerSizeLimit(container_limit); + binaryProtocolFactory->setStringSizeLimit(string_limit); + protocolFactory.reset(binaryProtocolFactory); + } + + // Processors + stdcxx::shared_ptr testHandler(new TestHandler()); + stdcxx::shared_ptr testProcessor(new ThriftTestProcessor(testHandler)); + + if (vm.count("processor-events")) { + testProcessor->setEventHandler( + stdcxx::shared_ptr(new TestProcessorEventHandler())); + } + + // Transport + stdcxx::shared_ptr sslSocketFactory; + stdcxx::shared_ptr serverSocket; + + if (ssl) { + sslSocketFactory = stdcxx::shared_ptr(new TSSLSocketFactory()); + sslSocketFactory->loadCertificate(certPath.c_str()); + sslSocketFactory->loadPrivateKey(keyPath.c_str()); + sslSocketFactory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); + serverSocket = stdcxx::shared_ptr(new TSSLServerSocket(port, sslSocketFactory)); + } else { + if (domain_socket != "") { + if (abstract_namespace) { + std::string abstract_socket("\0", 1); + abstract_socket += domain_socket; + serverSocket = stdcxx::shared_ptr(new TServerSocket(abstract_socket)); + } else { + unlink(domain_socket.c_str()); + serverSocket = stdcxx::shared_ptr(new TServerSocket(domain_socket)); + } + port = 0; + } else { + serverSocket = stdcxx::shared_ptr(new TServerSocket(port)); + } + } + + // Factory + stdcxx::shared_ptr transportFactory; + + if (transport_type == "http" && server_type != "nonblocking") { + stdcxx::shared_ptr httpTransportFactory(new THttpServerTransportFactory()); + transportFactory = httpTransportFactory; + } else if (transport_type == "framed") { + stdcxx::shared_ptr framedTransportFactory(new TFramedTransportFactory()); + transportFactory = framedTransportFactory; + } else { + stdcxx::shared_ptr bufferedTransportFactory(new TBufferedTransportFactory()); + transportFactory = bufferedTransportFactory; + } + + // Server Info + cout << "Starting \"" << server_type << "\" server (" << transport_type << "/" << protocol_type + << ") listen on: "; + if (abstract_namespace) { + cout << '@'; + } + cout << domain_socket; + if (port != 0) { + cout << port; + } + cout << endl; + + // Multiplexed Processor if needed + if (boost::starts_with(protocol_type, "multi")) { + stdcxx::shared_ptr secondHandler(new SecondHandler()); + stdcxx::shared_ptr secondProcessor(new SecondServiceProcessor(secondHandler)); + + stdcxx::shared_ptr multiplexedProcessor(new TMultiplexedProcessor()); + multiplexedProcessor->registerDefault(testProcessor); // non-multi clients go to the default processor (multi:binary, multic:compact, ...) + multiplexedProcessor->registerProcessor("ThriftTest", testProcessor); + multiplexedProcessor->registerProcessor("SecondService", secondProcessor); + testProcessor = stdcxx::dynamic_pointer_cast(multiplexedProcessor); + } + + // Server + stdcxx::shared_ptr server; + + if (server_type == "simple") { + server.reset(new TSimpleServer(testProcessor, serverSocket, transportFactory, protocolFactory)); + } else if (server_type == "thread-pool") { + + stdcxx::shared_ptr threadManager = ThreadManager::newSimpleThreadManager(workers); + + stdcxx::shared_ptr threadFactory + = stdcxx::shared_ptr(new PlatformThreadFactory()); + + threadManager->threadFactory(threadFactory); + + threadManager->start(); + + server.reset(new TThreadPoolServer(testProcessor, + serverSocket, + transportFactory, + protocolFactory, + threadManager)); + } else if (server_type == "threaded") { + + server.reset( + new TThreadedServer(testProcessor, serverSocket, transportFactory, protocolFactory)); + } else if (server_type == "nonblocking") { + if (transport_type == "http") { + stdcxx::shared_ptr testHandlerAsync(new TestHandlerAsync(testHandler)); + stdcxx::shared_ptr testProcessorAsync( + new ThriftTestAsyncProcessor(testHandlerAsync)); + stdcxx::shared_ptr testBufferProcessor( + new TAsyncProtocolProcessor(testProcessorAsync, protocolFactory)); + + // not loading nonblockingServer into "server" because + // TEvhttpServer doesn't inherit from TServer, and doesn't + // provide a stop method. + TEvhttpServer nonblockingServer(testBufferProcessor, port); + nonblockingServer.serve(); + } else { + stdcxx::shared_ptr nbSocket; + nbSocket.reset(new transport::TNonblockingServerSocket(port)); + server.reset(new TNonblockingServer(testProcessor, protocolFactory, nbSocket)); + } + } + + if (server.get() != NULL) { + if (protocol_type == "header") { + // Tell the server to use the same protocol for input / output + // if using header + server->setOutputProtocolFactory(stdcxx::shared_ptr()); + } + apache::thrift::concurrency::PlatformThreadFactory factory; + factory.setDetached(false); + stdcxx::shared_ptr serverThreadRunner(server); + stdcxx::shared_ptr thread + = factory.newThread(serverThreadRunner); + thread->start(); + + // HACK: cross language test suite is unable to handle cin properly + // that's why we stay in a endless loop here + while (1) { + } + // FIXME: find another way to stop the server (e.g. a signal) + // cout<<"Press enter to stop the server."<stop(); + thread->join(); + server.reset(); + } + + cout << "done." << endl; + return 0; +} diff --git a/test/cpp/src/ThriftTest_extras.cpp b/test/cpp/src/ThriftTest_extras.cpp new file mode 100644 index 0000000..af5606e --- /dev/null +++ b/test/cpp/src/ThriftTest_extras.cpp @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// Extra functions required for ThriftTest_types to work + +#include +#include "gen-cpp/ThriftTest_types.h" + +namespace thrift { +namespace test { + +bool Insanity::operator<(thrift::test::Insanity const& other) const { + using apache::thrift::ThriftDebugString; + return ThriftDebugString(*this) < ThriftDebugString(other); +} +} +} diff --git a/test/crossrunner/__init__.py b/test/crossrunner/__init__.py new file mode 100644 index 0000000..9d0b83a --- /dev/null +++ b/test/crossrunner/__init__.py @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from .test import test_name # noqa +from .collect import collect_cross_tests, collect_feature_tests # noqa +from .run import TestDispatcher # noqa +from .report import generate_known_failures, load_known_failures # noqa diff --git a/test/crossrunner/collect.py b/test/crossrunner/collect.py new file mode 100644 index 0000000..03b0c36 --- /dev/null +++ b/test/crossrunner/collect.py @@ -0,0 +1,162 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import platform +import re +from itertools import product + +from .util import merge_dict +from .test import TestEntry + +# Those keys are passed to execution as is. +# Note that there are keys other than these, namely: +# delay: After server is started, client start is delayed for the value +# (seconds). +# timeout: Test timeout after client is started (seconds). +# platforms: Supported platforms. Should match platform.system() value. +# protocols: list of supported protocols +# transports: list of supported transports +# sockets: list of supported sockets +# +# protocols and transports entries can be colon separated "spec:impl" pair +# (e.g. binary:accel) where test is run for any matching "spec" while actual +# argument passed to test executable is "impl". +# Otherwise "spec" is equivalent to "spec:spec" pair. +# (e.g. "binary" is equivalent to "binary:binary" in tests.json) +# +VALID_JSON_KEYS = [ + 'name', # name of the library, typically a language name + 'workdir', # work directory where command is executed + 'command', # test command + 'extra_args', # args appended to command after other args are appended + 'remote_args', # args added to the other side of the program + 'join_args', # whether args should be passed as single concatenated string + 'env', # additional environmental variable +] + +DEFAULT_MAX_DELAY = 5 +DEFAULT_TIMEOUT = 5 + + +def _collect_testlibs(config, server_match, client_match=[None]): + """Collects server/client configurations from library configurations""" + def expand_libs(config): + for lib in config: + sv = lib.pop('server', None) + cl = lib.pop('client', None) + yield lib, sv, cl + + def yield_testlibs(base_configs, configs, match): + for base, conf in zip(base_configs, configs): + if conf: + if not match or base['name'] in match: + platforms = conf.get('platforms') or base.get('platforms') + if not platforms or platform.system() in platforms: + yield merge_dict(base, conf) + + libs, svs, cls = zip(*expand_libs(config)) + servers = list(yield_testlibs(libs, svs, server_match)) + clients = list(yield_testlibs(libs, cls, client_match)) + return servers, clients + + +def collect_features(config, match): + res = list(map(re.compile, match)) + return list(filter(lambda c: any(map(lambda r: r.search(c['name']), res)), config)) + + +def _do_collect_tests(servers, clients): + def intersection(key, o1, o2): + """intersection of two collections. + collections are replaced with sets the first time""" + def cached_set(o, key): + v = o[key] + if not isinstance(v, set): + v = set(v) + o[key] = v + return v + return cached_set(o1, key) & cached_set(o2, key) + + def intersect_with_spec(key, o1, o2): + # store as set of (spec, impl) tuple + def cached_set(o): + def to_spec_impl_tuples(values): + for v in values: + spec, _, impl = v.partition(':') + yield spec, impl or spec + v = o[key] + if not isinstance(v, set): + v = set(to_spec_impl_tuples(set(v))) + o[key] = v + return v + for spec1, impl1 in cached_set(o1): + for spec2, impl2 in cached_set(o2): + if spec1 == spec2: + name = impl1 if impl1 == impl2 else '%s-%s' % (impl1, impl2) + yield name, impl1, impl2 + + def maybe_max(key, o1, o2, default): + """maximum of two if present, otherwise defult value""" + v1 = o1.get(key) + v2 = o2.get(key) + return max(v1, v2) if v1 and v2 else v1 or v2 or default + + def filter_with_validkeys(o): + ret = {} + for key in VALID_JSON_KEYS: + if key in o: + ret[key] = o[key] + return ret + + def merge_metadata(o, **ret): + for key in VALID_JSON_KEYS: + if key in o: + ret[key] = o[key] + return ret + + for sv, cl in product(servers, clients): + for proto, proto1, proto2 in intersect_with_spec('protocols', sv, cl): + for trans, trans1, trans2 in intersect_with_spec('transports', sv, cl): + for sock in intersection('sockets', sv, cl): + yield { + 'server': merge_metadata(sv, **{'protocol': proto1, 'transport': trans1}), + 'client': merge_metadata(cl, **{'protocol': proto2, 'transport': trans2}), + 'delay': maybe_max('delay', sv, cl, DEFAULT_MAX_DELAY), + 'timeout': maybe_max('timeout', sv, cl, DEFAULT_TIMEOUT), + 'protocol': proto, + 'transport': trans, + 'socket': sock + } + + +def _filter_entries(tests, regex): + if regex: + return filter(lambda t: re.search(regex, TestEntry.get_name(**t)), tests) + return tests + + +def collect_cross_tests(tests_dict, server_match, client_match, regex): + sv, cl = _collect_testlibs(tests_dict, server_match, client_match) + return list(_filter_entries(_do_collect_tests(sv, cl), regex)) + + +def collect_feature_tests(tests_dict, features_dict, server_match, feature_match, regex): + sv, _ = _collect_testlibs(tests_dict, server_match) + ft = collect_features(features_dict, feature_match) + return list(_filter_entries(_do_collect_tests(sv, ft), regex)) diff --git a/test/crossrunner/compat.py b/test/crossrunner/compat.py new file mode 100644 index 0000000..f1ca91b --- /dev/null +++ b/test/crossrunner/compat.py @@ -0,0 +1,24 @@ +import os +import sys + +if sys.version_info[0] == 2: + _ENCODE = sys.getfilesystemencoding() + + def path_join(*args): + bin_args = map(lambda a: a.decode(_ENCODE), args) + return os.path.join(*bin_args).encode(_ENCODE) + + def str_join(s, l): + bin_args = map(lambda a: a.decode(_ENCODE), l) + b = s.decode(_ENCODE) + return b.join(bin_args).encode(_ENCODE) + + logfile_open = open + +else: + + path_join = os.path.join + str_join = str.join + + def logfile_open(*args): + return open(*args, errors='replace') diff --git a/test/crossrunner/report.py b/test/crossrunner/report.py new file mode 100644 index 0000000..76324ed --- /dev/null +++ b/test/crossrunner/report.py @@ -0,0 +1,434 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from __future__ import print_function +import datetime +import json +import multiprocessing +import os +import platform +import re +import subprocess +import sys +import time +import traceback + +from .compat import logfile_open, path_join, str_join +from .test import TestEntry + +LOG_DIR = 'log' +RESULT_HTML = 'index.html' +RESULT_JSON = 'results.json' +FAIL_JSON = 'known_failures_%s.json' + + +def generate_known_failures(testdir, overwrite, save, out): + def collect_failures(results): + success_index = 5 + for r in results: + if not r[success_index]: + yield TestEntry.get_name(*r) + try: + with logfile_open(path_join(testdir, RESULT_JSON), 'r') as fp: + results = json.load(fp) + except IOError: + sys.stderr.write('Unable to load last result. Did you run tests ?\n') + return False + fails = collect_failures(results['results']) + if not overwrite: + known = load_known_failures(testdir) + known.extend(fails) + fails = known + fails_json = json.dumps(sorted(set(fails)), indent=2, separators=(',', ': ')) + if save: + with logfile_open(os.path.join(testdir, FAIL_JSON % platform.system()), 'w+') as fp: + fp.write(fails_json) + sys.stdout.write('Successfully updated known failures.\n') + if out: + sys.stdout.write(fails_json) + sys.stdout.write('\n') + return True + + +def load_known_failures(testdir): + try: + with logfile_open(path_join(testdir, FAIL_JSON % platform.system()), 'r') as fp: + return json.load(fp) + except IOError: + return [] + + +class TestReporter(object): + # Unfortunately, standard library doesn't handle timezone well + # DATETIME_FORMAT = '%a %b %d %H:%M:%S %Z %Y' + DATETIME_FORMAT = '%a %b %d %H:%M:%S %Y' + + def __init__(self): + self._log = multiprocessing.get_logger() + self._lock = multiprocessing.Lock() + + @classmethod + def test_logfile(cls, test_name, prog_kind, dir=None): + relpath = path_join('log', '%s_%s.log' % (test_name, prog_kind)) + return relpath if not dir else os.path.realpath(path_join(dir, relpath)) + + def _start(self): + self._start_time = time.time() + + @property + def _elapsed(self): + return time.time() - self._start_time + + @classmethod + def _format_date(cls): + return '%s' % datetime.datetime.now().strftime(cls.DATETIME_FORMAT) + + def _print_date(self): + print(self._format_date(), file=self.out) + + def _print_bar(self, out=None): + print( + '===============================================================================', + file=(out or self.out)) + + def _print_exec_time(self): + print('Test execution took {:.1f} seconds.'.format(self._elapsed), file=self.out) + + +class ExecReporter(TestReporter): + def __init__(self, testdir, test, prog): + super(ExecReporter, self).__init__() + self._test = test + self._prog = prog + self.logpath = self.test_logfile(test.name, prog.kind, testdir) + self.out = None + + def begin(self): + self._start() + self._open() + if self.out and not self.out.closed: + self._print_header() + else: + self._log.debug('Output stream is not available.') + + def end(self, returncode): + self._lock.acquire() + try: + if self.out and not self.out.closed: + self._print_footer(returncode) + self._close() + self.out = None + else: + self._log.debug('Output stream is not available.') + finally: + self._lock.release() + + def killed(self): + print(file=self.out) + print('Server process is successfully killed.', file=self.out) + self.end(None) + + def died(self): + print(file=self.out) + print('*** Server process has died unexpectedly ***', file=self.out) + self.end(None) + + _init_failure_exprs = { + 'server': list(map(re.compile, [ + '[Aa]ddress already in use', + 'Could not bind', + 'EADDRINUSE', + ])), + 'client': list(map(re.compile, [ + '[Cc]onnection refused', + 'Could not connect to localhost', + 'ECONNREFUSED', + 'No such file or directory', # domain socket + ])), + } + + def maybe_false_positive(self): + """Searches through log file for socket bind error. + Returns True if suspicious expression is found, otherwise False""" + try: + if self.out and not self.out.closed: + self.out.flush() + exprs = self._init_failure_exprs[self._prog.kind] + + def match(line): + for expr in exprs: + if expr.search(line): + return True + + with logfile_open(self.logpath, 'r') as fp: + if any(map(match, fp)): + return True + except (KeyboardInterrupt, SystemExit): + raise + except Exception as ex: + self._log.warn('[%s]: Error while detecting false positive: %s' % (self._test.name, str(ex))) + self._log.info(traceback.print_exc()) + return False + + def _open(self): + self.out = logfile_open(self.logpath, 'w+') + + def _close(self): + self.out.close() + + def _print_header(self): + self._print_date() + print('Executing: %s' % str_join(' ', self._prog.command), file=self.out) + print('Directory: %s' % self._prog.workdir, file=self.out) + print('config:delay: %s' % self._test.delay, file=self.out) + print('config:timeout: %s' % self._test.timeout, file=self.out) + self._print_bar() + self.out.flush() + + def _print_footer(self, returncode=None): + self._print_bar() + if returncode is not None: + print('Return code: %d' % returncode, file=self.out) + else: + print('Process is killed.', file=self.out) + self._print_exec_time() + self._print_date() + + +class SummaryReporter(TestReporter): + def __init__(self, basedir, testdir_relative, concurrent=True): + super(SummaryReporter, self).__init__() + self._basedir = basedir + self._testdir_rel = testdir_relative + self.logdir = path_join(self.testdir, LOG_DIR) + self.out_path = path_join(self.testdir, RESULT_JSON) + self.concurrent = concurrent + self.out = sys.stdout + self._platform = platform.system() + self._revision = self._get_revision() + self._tests = [] + if not os.path.exists(self.logdir): + os.mkdir(self.logdir) + self._known_failures = load_known_failures(self.testdir) + self._unexpected_success = [] + self._flaky_success = [] + self._unexpected_failure = [] + self._expected_failure = [] + self._print_header() + + @property + def testdir(self): + return path_join(self._basedir, self._testdir_rel) + + def _result_string(self, test): + if test.success: + if test.retry_count == 0: + return 'success' + elif test.retry_count == 1: + return 'flaky(1 retry)' + else: + return 'flaky(%d retries)' % test.retry_count + elif test.expired: + return 'failure(timeout)' + else: + return 'failure(%d)' % test.returncode + + def _get_revision(self): + p = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'], + cwd=self.testdir, stdout=subprocess.PIPE) + out, _ = p.communicate() + return out.strip() + + def _format_test(self, test, with_result=True): + name = '%s-%s' % (test.server.name, test.client.name) + trans = '%s-%s' % (test.transport, test.socket) + if not with_result: + return '{:24s}{:18s}{:25s}'.format(name[:23], test.protocol[:17], trans[:24]) + else: + return '{:24s}{:18s}{:25s}{:s}\n'.format(name[:23], test.protocol[:17], trans[:24], self._result_string(test)) + + def _print_test_header(self): + self._print_bar() + print( + '{:24s}{:18s}{:25s}{:s}'.format('server-client:', 'protocol:', 'transport:', 'result:'), + file=self.out) + + def _print_header(self): + self._start() + print('Apache Thrift - Integration Test Suite', file=self.out) + self._print_date() + self._print_test_header() + + def _print_unexpected_failure(self): + if len(self._unexpected_failure) > 0: + self.out.writelines([ + '*** Following %d failures were unexpected ***:\n' % len(self._unexpected_failure), + 'If it is introduced by you, please fix it before submitting the code.\n', + # 'If not, please report at https://issues.apache.org/jira/browse/THRIFT\n', + ]) + self._print_test_header() + for i in self._unexpected_failure: + self.out.write(self._format_test(self._tests[i])) + self._print_bar() + else: + print('No unexpected failures.', file=self.out) + + def _print_flaky_success(self): + if len(self._flaky_success) > 0: + print( + 'Following %d tests were expected to cleanly succeed but needed retry:' % len(self._flaky_success), + file=self.out) + self._print_test_header() + for i in self._flaky_success: + self.out.write(self._format_test(self._tests[i])) + self._print_bar() + + def _print_unexpected_success(self): + if len(self._unexpected_success) > 0: + print( + 'Following %d tests were known to fail but succeeded (maybe flaky):' % len(self._unexpected_success), + file=self.out) + self._print_test_header() + for i in self._unexpected_success: + self.out.write(self._format_test(self._tests[i])) + self._print_bar() + + def _http_server_command(self, port): + if sys.version_info[0] < 3: + return 'python -m SimpleHTTPServer %d' % port + else: + return 'python -m http.server %d' % port + + def _print_footer(self): + fail_count = len(self._expected_failure) + len(self._unexpected_failure) + self._print_bar() + self._print_unexpected_success() + self._print_flaky_success() + self._print_unexpected_failure() + self._write_html_data() + self._assemble_log('unexpected failures', self._unexpected_failure) + self._assemble_log('known failures', self._expected_failure) + self.out.writelines([ + 'You can browse results at:\n', + '\tfile://%s/%s\n' % (self.testdir, RESULT_HTML), + '# If you use Chrome, run:\n', + '# \tcd %s\n#\t%s\n' % (self._basedir, self._http_server_command(8001)), + '# then browse:\n', + '# \thttp://localhost:%d/%s/\n' % (8001, self._testdir_rel), + 'Full log for each test is here:\n', + '\ttest/log/server_client_protocol_transport_client.log\n', + '\ttest/log/server_client_protocol_transport_server.log\n', + '%d failed of %d tests in total.\n' % (fail_count, len(self._tests)), + ]) + self._print_exec_time() + self._print_date() + + def _render_result(self, test): + return [ + test.server.name, + test.client.name, + test.protocol, + test.transport, + test.socket, + test.success, + test.as_expected, + test.returncode, + { + 'server': self.test_logfile(test.name, test.server.kind), + 'client': self.test_logfile(test.name, test.client.kind), + }, + ] + + def _write_html_data(self): + """Writes JSON data to be read by result html""" + results = [self._render_result(r) for r in self._tests] + with logfile_open(self.out_path, 'w+') as fp: + fp.write(json.dumps({ + 'date': self._format_date(), + 'revision': str(self._revision), + 'platform': self._platform, + 'duration': '{:.1f}'.format(self._elapsed), + 'results': results, + }, indent=2)) + + def _assemble_log(self, title, indexes): + if len(indexes) > 0: + def add_prog_log(fp, test, prog_kind): + print('*************************** %s message ***************************' % prog_kind, + file=fp) + path = self.test_logfile(test.name, prog_kind, self.testdir) + if os.path.exists(path): + with logfile_open(path, 'r') as prog_fp: + print(prog_fp.read(), file=fp) + filename = title.replace(' ', '_') + '.log' + with logfile_open(os.path.join(self.logdir, filename), 'w+') as fp: + for test in map(self._tests.__getitem__, indexes): + fp.write('TEST: [%s]\n' % test.name) + add_prog_log(fp, test, test.server.kind) + add_prog_log(fp, test, test.client.kind) + fp.write('**********************************************************************\n\n') + print('%s are logged to %s/%s/%s' % (title.capitalize(), self._testdir_rel, LOG_DIR, filename)) + + def end(self): + self._print_footer() + return len(self._unexpected_failure) == 0 + + def add_test(self, test_dict): + test = TestEntry(self.testdir, **test_dict) + self._lock.acquire() + try: + if not self.concurrent: + self.out.write(self._format_test(test, False)) + self.out.flush() + self._tests.append(test) + return len(self._tests) - 1 + finally: + self._lock.release() + + def add_result(self, index, returncode, expired, retry_count): + self._lock.acquire() + try: + failed = returncode is None or returncode != 0 + flaky = not failed and retry_count != 0 + test = self._tests[index] + known = test.name in self._known_failures + if failed: + if known: + self._log.debug('%s failed as expected' % test.name) + self._expected_failure.append(index) + else: + self._log.info('unexpected failure: %s' % test.name) + self._unexpected_failure.append(index) + elif flaky and not known: + self._log.info('unexpected flaky success: %s' % test.name) + self._flaky_success.append(index) + elif not flaky and known: + self._log.info('unexpected success: %s' % test.name) + self._unexpected_success.append(index) + test.success = not failed + test.returncode = returncode + test.retry_count = retry_count + test.expired = expired + test.as_expected = known == failed + if not self.concurrent: + self.out.write(self._result_string(test) + '\n') + else: + self.out.write(self._format_test(test)) + finally: + self._lock.release() diff --git a/test/crossrunner/run.py b/test/crossrunner/run.py new file mode 100644 index 0000000..f522bb1 --- /dev/null +++ b/test/crossrunner/run.py @@ -0,0 +1,389 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import contextlib +import multiprocessing +import multiprocessing.managers +import os +import platform +import random +import signal +import socket +import subprocess +import sys +import threading +import time + +from .compat import str_join +from .test import TestEntry, domain_socket_path +from .report import ExecReporter, SummaryReporter + +RESULT_TIMEOUT = 128 +RESULT_ERROR = 64 + +# globals +ports = None +stop = None + + +class ExecutionContext(object): + def __init__(self, cmd, cwd, env, report): + self._log = multiprocessing.get_logger() + self.report = report + self.cmd = cmd + self.cwd = cwd + self.env = env + self.timer = None + self.expired = False + self.killed = False + self.proc = None + + def _expire(self): + self._log.info('Timeout') + self.expired = True + self.kill() + + def kill(self): + self._log.debug('Killing process : %d' % self.proc.pid) + self.killed = True + if platform.system() != 'Windows': + try: + os.killpg(self.proc.pid, signal.SIGKILL) + except Exception: + self._log.info('Failed to kill process group', exc_info=sys.exc_info()) + try: + self.proc.kill() + except Exception: + self._log.info('Failed to kill process', exc_info=sys.exc_info()) + + def _popen_args(self): + args = { + 'cwd': self.cwd, + 'env': self.env, + 'stdout': self.report.out, + 'stderr': subprocess.STDOUT, + } + # make sure child processes doesn't remain after killing + if platform.system() == 'Windows': + DETACHED_PROCESS = 0x00000008 + args.update(creationflags=DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP) + else: + args.update(preexec_fn=os.setsid) + return args + + def start(self, timeout=0): + joined = str_join(' ', self.cmd) + self._log.debug('COMMAND: %s', joined) + self._log.debug('WORKDIR: %s', self.cwd) + self._log.debug('LOGFILE: %s', self.report.logpath) + self.report.begin() + self.proc = subprocess.Popen(self.cmd, **self._popen_args()) + if timeout > 0: + self.timer = threading.Timer(timeout, self._expire) + self.timer.start() + return self._scoped() + + @contextlib.contextmanager + def _scoped(self): + yield self + self._log.debug('Killing scoped process') + if self.proc.poll() is None: + self.kill() + self.report.killed() + else: + self._log.debug('Process died unexpectedly') + self.report.died() + + def wait(self): + self.proc.communicate() + if self.timer: + self.timer.cancel() + self.report.end(self.returncode) + + @property + def returncode(self): + return self.proc.returncode if self.proc else None + + +def exec_context(port, logdir, test, prog): + report = ExecReporter(logdir, test, prog) + prog.build_command(port) + return ExecutionContext(prog.command, prog.workdir, prog.env, report) + + +def run_test(testdir, logdir, test_dict, max_retry, async=True): + logger = multiprocessing.get_logger() + + def ensure_socket_open(proc, port, max_delay): + sleeped = 0.1 + time.sleep(sleeped) + sleep_step = 0.2 + while True: + # Create sockets every iteration because refused sockets cannot be + # reused on some systems. + sock4 = socket.socket() + sock6 = socket.socket(family=socket.AF_INET6) + try: + if sock4.connect_ex(('127.0.0.1', port)) == 0 \ + or sock6.connect_ex(('::1', port)) == 0: + return True + if proc.poll() is not None: + logger.warn('server process is exited') + return False + if sleeped > max_delay: + logger.warn('sleeped for %f seconds but server port is not open' % sleeped) + return False + time.sleep(sleep_step) + sleeped += sleep_step + finally: + sock4.close() + sock6.close() + logger.debug('waited %f sec for server port open' % sleeped) + return True + + try: + max_bind_retry = 3 + retry_count = 0 + bind_retry_count = 0 + test = TestEntry(testdir, **test_dict) + while True: + if stop.is_set(): + logger.debug('Skipping because shutting down') + return (retry_count, None) + logger.debug('Start') + with PortAllocator.alloc_port_scoped(ports, test.socket) as port: + logger.debug('Start with port %d' % port) + sv = exec_context(port, logdir, test, test.server) + cl = exec_context(port, logdir, test, test.client) + + logger.debug('Starting server') + with sv.start(): + if test.socket in ('domain', 'abstract'): + time.sleep(0.1) + port_ok = True + else: + port_ok = ensure_socket_open(sv.proc, port, test.delay) + if port_ok: + connect_retry_count = 0 + max_connect_retry = 3 + connect_retry_wait = 0.5 + while True: + if sv.proc.poll() is not None: + logger.info('not starting client because server process is absent') + break + logger.debug('Starting client') + cl.start(test.timeout) + logger.debug('Waiting client') + cl.wait() + if not cl.report.maybe_false_positive() or connect_retry_count >= max_connect_retry: + if connect_retry_count > 0 and connect_retry_count < max_connect_retry: + logger.warn('[%s]: Connected after %d retry (%.2f sec each)' % (test.server.name, connect_retry_count, connect_retry_wait)) + # Wait for 50ms to see if server does not die at the end. + time.sleep(0.05) + break + logger.debug('Server may not be ready, waiting %.2f second...' % connect_retry_wait) + time.sleep(connect_retry_wait) + connect_retry_count += 1 + + if sv.report.maybe_false_positive() and bind_retry_count < max_bind_retry: + logger.warn('[%s]: Detected socket bind failure, retrying...', test.server.name) + bind_retry_count += 1 + else: + if cl.expired: + result = RESULT_TIMEOUT + else: + result = cl.proc.returncode if cl.proc else RESULT_ERROR + if not sv.killed: + # Server died without being killed. + result |= RESULT_ERROR + + if result == 0 or retry_count >= max_retry: + return (retry_count, result) + else: + logger.info('[%s-%s]: test failed, retrying...', test.server.name, test.client.name) + retry_count += 1 + except Exception: + if not async: + raise + logger.warn('Error executing [%s]', test.name, exc_info=True) + return (retry_count, RESULT_ERROR) + except: + logger.info('Interrupted execution', exc_info=True) + if not async: + raise + stop.set() + return (retry_count, RESULT_ERROR) + + +class PortAllocator(object): + def __init__(self): + self._log = multiprocessing.get_logger() + self._lock = multiprocessing.Lock() + self._ports = set() + self._dom_ports = set() + self._last_alloc = 0 + + def _get_tcp_port(self): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.bind(('', 0)) + port = sock.getsockname()[1] + self._lock.acquire() + try: + ok = port not in self._ports + if ok: + self._ports.add(port) + self._last_alloc = time.time() + finally: + self._lock.release() + sock.close() + return port if ok else self._get_tcp_port() + + def _get_domain_port(self): + port = random.randint(1024, 65536) + self._lock.acquire() + try: + ok = port not in self._dom_ports + if ok: + self._dom_ports.add(port) + finally: + self._lock.release() + return port if ok else self._get_domain_port() + + def alloc_port(self, socket_type): + if socket_type in ('domain', 'abstract'): + return self._get_domain_port() + else: + return self._get_tcp_port() + + # static method for inter-process invokation + @staticmethod + @contextlib.contextmanager + def alloc_port_scoped(allocator, socket_type): + port = allocator.alloc_port(socket_type) + yield port + allocator.free_port(socket_type, port) + + def free_port(self, socket_type, port): + self._log.debug('free_port') + self._lock.acquire() + try: + if socket_type == 'domain': + self._dom_ports.remove(port) + path = domain_socket_path(port) + if os.path.exists(path): + os.remove(path) + elif socket_type == 'abstract': + self._dom_ports.remove(port) + else: + self._ports.remove(port) + except IOError: + self._log.info('Error while freeing port', exc_info=sys.exc_info()) + finally: + self._lock.release() + + +class NonAsyncResult(object): + def __init__(self, value): + self._value = value + + def get(self, timeout=None): + return self._value + + def wait(self, timeout=None): + pass + + def ready(self): + return True + + def successful(self): + return self._value == 0 + + +class TestDispatcher(object): + def __init__(self, testdir, basedir, logdir_rel, concurrency): + self._log = multiprocessing.get_logger() + self.testdir = testdir + self._report = SummaryReporter(basedir, logdir_rel, concurrency > 1) + self.logdir = self._report.testdir + # seems needed for python 2.x to handle keyboard interrupt + self._stop = multiprocessing.Event() + self._async = concurrency > 1 + if not self._async: + self._pool = None + global stop + global ports + stop = self._stop + ports = PortAllocator() + else: + self._m = multiprocessing.managers.BaseManager() + self._m.register('ports', PortAllocator) + self._m.start() + self._pool = multiprocessing.Pool(concurrency, self._pool_init, (self._m.address,)) + self._log.debug( + 'TestDispatcher started with %d concurrent jobs' % concurrency) + + def _pool_init(self, address): + global stop + global m + global ports + stop = self._stop + m = multiprocessing.managers.BaseManager(address) + m.connect() + ports = m.ports() + + def _dispatch_sync(self, test, cont, max_retry): + r = run_test(self.testdir, self.logdir, test, max_retry, False) + cont(r) + return NonAsyncResult(r) + + def _dispatch_async(self, test, cont, max_retry): + self._log.debug('_dispatch_async') + return self._pool.apply_async(func=run_test, args=(self.testdir, self.logdir, test, max_retry), callback=cont) + + def dispatch(self, test, max_retry): + index = self._report.add_test(test) + + def cont(result): + if not self._stop.is_set(): + if result and len(result) == 2: + retry_count, returncode = result + else: + retry_count = 0 + returncode = RESULT_ERROR + self._log.debug('freeing port') + self._log.debug('adding result') + self._report.add_result(index, returncode, returncode == RESULT_TIMEOUT, retry_count) + self._log.debug('finish continuation') + fn = self._dispatch_async if self._async else self._dispatch_sync + return fn(test, cont, max_retry) + + def wait(self): + if self._async: + self._pool.close() + self._pool.join() + self._m.shutdown() + return self._report.end() + + def terminate(self): + self._stop.set() + if self._async: + self._pool.terminate() + self._pool.join() + self._m.shutdown() diff --git a/test/crossrunner/setup.cfg b/test/crossrunner/setup.cfg new file mode 100644 index 0000000..7da1f96 --- /dev/null +++ b/test/crossrunner/setup.cfg @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 100 diff --git a/test/crossrunner/test.py b/test/crossrunner/test.py new file mode 100644 index 0000000..74fd916 --- /dev/null +++ b/test/crossrunner/test.py @@ -0,0 +1,143 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import copy +import multiprocessing +import os +import sys +from .compat import path_join +from .util import merge_dict + + +def domain_socket_path(port): + return '/tmp/ThriftTest.thrift.%d' % port + + +class TestProgram(object): + def __init__(self, kind, name, protocol, transport, socket, workdir, command, env=None, + extra_args=[], extra_args2=[], join_args=False, **kwargs): + self.kind = kind + self.name = name + self.protocol = protocol + self.transport = transport + self.socket = socket + self.workdir = workdir + self.command = None + self._base_command = self._fix_cmd_path(command) + if env: + self.env = copy.copy(os.environ) + self.env.update(env) + else: + self.env = os.environ + self._extra_args = extra_args + self._extra_args2 = extra_args2 + self._join_args = join_args + + def _fix_cmd_path(self, cmd): + # if the arg is a file in the current directory, make it path + def abs_if_exists(arg): + p = path_join(self.workdir, arg) + return p if os.path.exists(p) else arg + + if cmd[0] == 'python': + cmd[0] = sys.executable + else: + cmd[0] = abs_if_exists(cmd[0]) + return cmd + + def _socket_args(self, socket, port): + return { + 'ip-ssl': ['--ssl'], + 'domain': ['--domain-socket=%s' % domain_socket_path(port)], + 'abstract': ['--abstract-namespace', '--domain-socket=%s' % domain_socket_path(port)], + }.get(socket, None) + + def build_command(self, port): + cmd = copy.copy(self._base_command) + args = copy.copy(self._extra_args2) + args.append('--protocol=' + self.protocol) + args.append('--transport=' + self.transport) + socket_args = self._socket_args(self.socket, port) + if socket_args: + args += socket_args + args.append('--port=%d' % port) + if self._join_args: + cmd.append('%s' % " ".join(args)) + else: + cmd.extend(args) + if self._extra_args: + cmd.extend(self._extra_args) + self.command = cmd + return self.command + + +class TestEntry(object): + def __init__(self, testdir, server, client, delay, timeout, **kwargs): + self.testdir = testdir + self._log = multiprocessing.get_logger() + self._config = kwargs + self.protocol = kwargs['protocol'] + self.transport = kwargs['transport'] + self.socket = kwargs['socket'] + srv_dict = self._fix_workdir(merge_dict(self._config, server)) + cli_dict = self._fix_workdir(merge_dict(self._config, client)) + cli_dict['extra_args2'] = srv_dict.pop('remote_args', []) + srv_dict['extra_args2'] = cli_dict.pop('remote_args', []) + self.server = TestProgram('server', **srv_dict) + self.client = TestProgram('client', **cli_dict) + self.delay = delay + self.timeout = timeout + self._name = None + # results + self.success = None + self.as_expected = None + self.returncode = None + self.expired = False + self.retry_count = 0 + + def _fix_workdir(self, config): + key = 'workdir' + path = config.get(key, None) + if not path: + path = self.testdir + if os.path.isabs(path): + path = os.path.realpath(path) + else: + path = os.path.realpath(path_join(self.testdir, path)) + config.update({key: path}) + return config + + @classmethod + def get_name(cls, server, client, protocol, transport, socket, *args, **kwargs): + return '%s-%s_%s_%s-%s' % (server, client, protocol, transport, socket) + + @property + def name(self): + if not self._name: + self._name = self.get_name( + self.server.name, self.client.name, self.protocol, self.transport, self.socket) + return self._name + + @property + def transport_name(self): + return '%s-%s' % (self.transport, self.socket) + + +def test_name(server, client, protocol, transport, socket, **kwargs): + return TestEntry.get_name(server['name'], client['name'], protocol, transport, socket) diff --git a/test/crossrunner/util.py b/test/crossrunner/util.py new file mode 100644 index 0000000..e2d195a --- /dev/null +++ b/test/crossrunner/util.py @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import copy + + +def merge_dict(base, update): + """Update dict concatenating list values""" + res = copy.deepcopy(base) + for k, v in list(update.items()): + if k in list(res.keys()) and isinstance(v, list): + res[k].extend(v) + else: + res[k] = v + return res diff --git a/test/csharp/Makefile.am b/test/csharp/Makefile.am new file mode 100644 index 0000000..ad166e3 --- /dev/null +++ b/test/csharp/Makefile.am @@ -0,0 +1,95 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +GENERATED = \ + gen-csharp/Thrift/Test/Bonk.cs \ + gen-csharp/Thrift/Test/Bools.cs \ + gen-csharp/Thrift/Test/BoolTest.cs \ + gen-csharp/Thrift/Test/CrazyNesting.cs \ + gen-csharp/Thrift/Test/EmptyStruct.cs \ + gen-csharp/Thrift/Test/GuessProtocolStruct.cs \ + gen-csharp/Thrift/Test/Insanity.cs \ + gen-csharp/Thrift/Test/LargeDeltas.cs \ + gen-csharp/Thrift/Test/ListBonks.cs \ + gen-csharp/Thrift/Test/ListTypeVersioningV1.cs \ + gen-csharp/Thrift/Test/ListTypeVersioningV2.cs \ + gen-csharp/Thrift/Test/NestedListsBonk.cs \ + gen-csharp/Thrift/Test/NestedListsI32x2.cs \ + gen-csharp/Thrift/Test/NestedListsI32x3.cs \ + gen-csharp/Thrift/Test/NestedMixedx2.cs \ + gen-csharp/Thrift/Test/Numberz.cs \ + gen-csharp/Thrift/Test/OneField.cs \ + gen-csharp/Thrift/Test/SecondService.cs \ + gen-csharp/Thrift/Test/StructA.cs \ + gen-csharp/Thrift/Test/StructB.cs \ + gen-csharp/Thrift/Test/ThriftTest.Constants.cs \ + gen-csharp/Thrift/Test/ThriftTest.cs \ + gen-csharp/Thrift/Test/VersioningTestV1.cs \ + gen-csharp/Thrift/Test/VersioningTestV2.cs \ + gen-csharp/Thrift/Test/Xception.cs \ + gen-csharp/Thrift/Test/Xception2.cs \ + gen-csharp/Thrift/Test/Xtruct.cs \ + gen-csharp/Thrift/Test/Xtruct2.cs \ + gen-csharp/Thrift/Test/Xtruct3.cs + +BUILT_SOURCES = $(GENERATED) + +if MONO_MCS +CSC = mcs +else +CSC = gmcs +endif + +if NET_2_0 +CSC_DEFINES = -d:NET_2_0 +endif + +LIBDIR = $(top_builddir)/lib/csharp + +THRIFT = $(top_builddir)/compiler/cpp/thrift + +$(GENERATED): $(top_srcdir)/test/ThriftTest.thrift $(THRIFT) + $(THRIFT) --gen csharp -o . $< + +precross: TestClientServer.exe + +ThriftImpl.dll: $(GENERATED) $(LIBDIR)/Thrift.dll + $(CSC) $(CSC_DEFINES) -t:library -out:$@ -reference:$(LIBDIR)/Thrift.dll $(GENERATED) + +SRCS = TestClient.cs TestServer.cs Program.cs + +TestClientServer.exe: $(SRCS) ThriftImpl.dll + $(CSC) $(CSC_DEFINES) -out:$@ -reference:$(LIBDIR)/Thrift.dll -reference:ThriftImpl.dll $(SRCS) + +clean-local: + $(RM) -rf gen-csharp *.exe *.dll + +TESTPORT = 9500 +check-local: TestClientServer.exe + MONO_PATH=$(LIBDIR) timeout 10 mono TestClientServer.exe server --port=$(TESTPORT) & + sleep 1 + MONO_PATH=$(LIBDIR) mono TestClientServer.exe client --port=$(TESTPORT) + +EXTRA_DIST = \ + Properties/AssemblyInfo.cs \ + ThriftTest.csproj \ + ThriftTest.sln \ + Program.cs \ + TestServer.cs \ + TestClient.cs diff --git a/test/csharp/Makefile.in b/test/csharp/Makefile.in new file mode 100644 index 0000000..4055b65 --- /dev/null +++ b/test/csharp/Makefile.in @@ -0,0 +1,692 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = test/csharp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = $(top_builddir)/compiler/cpp/thrift +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +GENERATED = \ + gen-csharp/Thrift/Test/Bonk.cs \ + gen-csharp/Thrift/Test/Bools.cs \ + gen-csharp/Thrift/Test/BoolTest.cs \ + gen-csharp/Thrift/Test/CrazyNesting.cs \ + gen-csharp/Thrift/Test/EmptyStruct.cs \ + gen-csharp/Thrift/Test/GuessProtocolStruct.cs \ + gen-csharp/Thrift/Test/Insanity.cs \ + gen-csharp/Thrift/Test/LargeDeltas.cs \ + gen-csharp/Thrift/Test/ListBonks.cs \ + gen-csharp/Thrift/Test/ListTypeVersioningV1.cs \ + gen-csharp/Thrift/Test/ListTypeVersioningV2.cs \ + gen-csharp/Thrift/Test/NestedListsBonk.cs \ + gen-csharp/Thrift/Test/NestedListsI32x2.cs \ + gen-csharp/Thrift/Test/NestedListsI32x3.cs \ + gen-csharp/Thrift/Test/NestedMixedx2.cs \ + gen-csharp/Thrift/Test/Numberz.cs \ + gen-csharp/Thrift/Test/OneField.cs \ + gen-csharp/Thrift/Test/SecondService.cs \ + gen-csharp/Thrift/Test/StructA.cs \ + gen-csharp/Thrift/Test/StructB.cs \ + gen-csharp/Thrift/Test/ThriftTest.Constants.cs \ + gen-csharp/Thrift/Test/ThriftTest.cs \ + gen-csharp/Thrift/Test/VersioningTestV1.cs \ + gen-csharp/Thrift/Test/VersioningTestV2.cs \ + gen-csharp/Thrift/Test/Xception.cs \ + gen-csharp/Thrift/Test/Xception2.cs \ + gen-csharp/Thrift/Test/Xtruct.cs \ + gen-csharp/Thrift/Test/Xtruct2.cs \ + gen-csharp/Thrift/Test/Xtruct3.cs + +BUILT_SOURCES = $(GENERATED) +@MONO_MCS_FALSE@CSC = gmcs +@MONO_MCS_TRUE@CSC = mcs +@NET_2_0_TRUE@CSC_DEFINES = -d:NET_2_0 +LIBDIR = $(top_builddir)/lib/csharp +SRCS = TestClient.cs TestServer.cs Program.cs +TESTPORT = 9500 +EXTRA_DIST = \ + Properties/AssemblyInfo.cs \ + ThriftTest.csproj \ + ThriftTest.sln \ + Program.cs \ + TestServer.cs \ + TestClient.cs + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/csharp/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/csharp/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile +installdirs: +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: all check check-am install install-am install-strip + +.PHONY: all all-am check check-am check-local clean clean-generic \ + clean-libtool clean-local cscopelist-am ctags-am distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +$(GENERATED): $(top_srcdir)/test/ThriftTest.thrift $(THRIFT) + $(THRIFT) --gen csharp -o . $< + +precross: TestClientServer.exe + +ThriftImpl.dll: $(GENERATED) $(LIBDIR)/Thrift.dll + $(CSC) $(CSC_DEFINES) -t:library -out:$@ -reference:$(LIBDIR)/Thrift.dll $(GENERATED) + +TestClientServer.exe: $(SRCS) ThriftImpl.dll + $(CSC) $(CSC_DEFINES) -out:$@ -reference:$(LIBDIR)/Thrift.dll -reference:ThriftImpl.dll $(SRCS) + +clean-local: + $(RM) -rf gen-csharp *.exe *.dll +check-local: TestClientServer.exe + MONO_PATH=$(LIBDIR) timeout 10 mono TestClientServer.exe server --port=$(TESTPORT) & + sleep 1 + MONO_PATH=$(LIBDIR) mono TestClientServer.exe client --port=$(TESTPORT) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/csharp/Program.cs b/test/csharp/Program.cs new file mode 100644 index 0000000..8ec00e3 --- /dev/null +++ b/test/csharp/Program.cs @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// Distributed under the Thrift Software License +// +// See accompanying file LICENSE or visit the Thrift site at: +// http://developers.facebook.com/thrift/ + +using System; +using Thrift.Transport; +using Thrift.Protocol; +using Thrift.Test; //generated code + +namespace Test +{ + class Program + { + static int Main(string[] args) + { + if (args.Length == 0) + { + Console.WriteLine("must provide 'server' or 'client' arg"); + return -1; + } + + try + { + Console.SetBufferSize(Console.BufferWidth, 4096); + } + catch (Exception) + { + Console.WriteLine("Failed to grow scroll-back buffer"); + } + + string[] subArgs = new string[args.Length - 1]; + for(int i = 1; i < args.Length; i++) + { + subArgs[i-1] = args[i]; + } + if (args[0] == "client") + { + return TestClient.Execute(subArgs); + } + else if (args[0] == "server") + { + return TestServer.Execute(subArgs) ? 0 : 1; + } + else + { + Console.WriteLine("first argument must be 'server' or 'client'"); + } + return 0; + } + } +} diff --git a/test/csharp/Properties/AssemblyInfo.cs b/test/csharp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e2def42 --- /dev/null +++ b/test/csharp/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ThriftTest")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("The Apache Software Foundation")] +[assembly: AssemblyProduct("Thrift")] +[assembly: AssemblyCopyright("The Apache Software Foundation")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f41b193b-f1ab-48ee-8843-f88e43084e26")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.11.0.0")] +[assembly: AssemblyFileVersion("0.11.0.0")] diff --git a/test/csharp/TestClient.cs b/test/csharp/TestClient.cs new file mode 100644 index 0000000..17e5978 --- /dev/null +++ b/test/csharp/TestClient.cs @@ -0,0 +1,868 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +using System; +using System.Linq; +using System.Diagnostics; +using System.Collections.Generic; +using System.Threading; +using System.Security.Cryptography.X509Certificates; +using Thrift.Collections; +using Thrift.Protocol; +using Thrift.Transport; +using Thrift.Test; +using System.Security.Authentication; + +namespace Test +{ + public class TestClient + { + public class TestParams + { + public int numIterations = 1; + public string host = "localhost"; + public int port = 9090; + public string url; + public string pipe; + public bool buffered; + public bool framed; + public string protocol; + public bool encrypted = false; + public bool multiplexed = false; + protected bool _isFirstTransport = true; + + + public TTransport CreateTransport() + { + if (url == null) + { + // endpoint transport + TTransport trans = null; + if (pipe != null) + trans = new TNamedPipeClientTransport(pipe); + else + { + if (encrypted) + { + string certPath = "../keys/client.p12"; + X509Certificate cert = new X509Certificate2(certPath, "thrift"); + trans = new TTLSSocket(host, port, 0, cert, (o, c, chain, errors) => true, null, SslProtocols.Tls); + } + else + { + trans = new TSocket(host, port); + } + } + + // layered transport + if (buffered) + trans = new TBufferedTransport(trans); + if (framed) + trans = new TFramedTransport(trans); + + if (_isFirstTransport) + { + //ensure proper open/close of transport + trans.Open(); + trans.Close(); + _isFirstTransport = false; + } + return trans; + } + else + { + return new THttpClient(new Uri(url)); + } + } + + public TProtocol CreateProtocol(TTransport transport) + { + if (protocol == "compact") + return new TCompactProtocol(transport); + else if (protocol == "json") + return new TJSONProtocol(transport); + else + return new TBinaryProtocol(transport); + } + }; + + private const int ErrorBaseTypes = 1; + private const int ErrorStructs = 2; + private const int ErrorContainers = 4; + private const int ErrorExceptions = 8; + private const int ErrorProtocol = 16; + private const int ErrorUnknown = 64; + + private class ClientTest + { + private readonly TestParams param; + private readonly TTransport transport; + private readonly SecondService.Client second; + private readonly ThriftTest.Client client; + private readonly int numIterations; + private bool done; + + public int ReturnCode { get; set; } + + public ClientTest(TestParams paramin) + { + param = paramin; + transport = param.CreateTransport(); + TProtocol protocol = param.CreateProtocol(transport); + if (param.multiplexed) + { + second = new SecondService.Client(new TMultiplexedProtocol(protocol, "SecondService")); + } + client = new ThriftTest.Client(protocol); + numIterations = param.numIterations; + } + public void Execute() + { + if (done) + { + Console.WriteLine("Execute called more than once"); + throw new InvalidOperationException(); + } + + for (int i = 0; i < numIterations; i++) + { + try + { + if (!transport.IsOpen) + transport.Open(); + } + catch (TTransportException ex) + { + Console.WriteLine("*** FAILED ***"); + Console.WriteLine("Connect failed: " + ex.Message); + ReturnCode |= ErrorUnknown; + Console.WriteLine(ex.Message + " ST: " + ex.StackTrace); + continue; + } + + try + { + ReturnCode |= ExecuteClientTest(client, second, param); + } + catch (Exception ex) + { + Console.WriteLine("*** FAILED ***"); + Console.WriteLine(ex.Message + " ST: " + ex.StackTrace); + ReturnCode |= ErrorUnknown; + } + } + try + { + transport.Close(); + } + catch(Exception ex) + { + Console.WriteLine("Error while closing transport"); + Console.WriteLine(ex.Message + " ST: " + ex.StackTrace); + } + done = true; + } + } + + public static int Execute(string[] args) + { + try + { + TestParams param = new TestParams(); + int numThreads = 1; + try + { + for (int i = 0; i < args.Length; i++) + { + if (args[i] == "-u") + { + param.url = args[++i]; + } + else if (args[i] == "-n") + { + param.numIterations = Convert.ToInt32(args[++i]); + } + else if (args[i] == "-pipe") // -pipe + { + param.pipe = args[++i]; + Console.WriteLine("Using named pipes transport"); + } + else if (args[i].Contains("--host=")) + { + param.host = args[i].Substring(args[i].IndexOf("=") + 1); + } + else if (args[i].Contains("--port=")) + { + param.port = int.Parse(args[i].Substring(args[i].IndexOf("=")+1)); + } + else if (args[i] == "-b" || args[i] == "--buffered" || args[i] == "--transport=buffered") + { + param.buffered = true; + Console.WriteLine("Using buffered sockets"); + } + else if (args[i] == "-f" || args[i] == "--framed" || args[i] == "--transport=framed") + { + param.framed = true; + Console.WriteLine("Using framed transport"); + } + else if (args[i] == "-t") + { + numThreads = Convert.ToInt32(args[++i]); + } + else if (args[i] == "--compact" || args[i] == "--protocol=compact" || args[i] == "--protocol=multic") + { + param.protocol = "compact"; + Console.WriteLine("Using compact protocol"); + } + else if (args[i] == "--json" || args[i] == "--protocol=json" || args[i] == "--protocol=multij") + { + param.protocol = "json"; + Console.WriteLine("Using JSON protocol"); + } + else if (args[i] == "--ssl") + { + param.encrypted = true; + Console.WriteLine("Using encrypted transport"); + } + + if (args[i].StartsWith("--protocol=multi")) + { + param.multiplexed = true; + } + } + } + catch (Exception ex) + { + Console.WriteLine("*** FAILED ***"); + Console.WriteLine("Error while parsing arguments"); + Console.WriteLine(ex.Message + " ST: " + ex.StackTrace); + return ErrorUnknown; + } + + var tests = Enumerable.Range(0, numThreads).Select(_ => new ClientTest(param)).ToArray(); + //issue tests on separate threads simultaneously + var threads = tests.Select(test => new Thread(test.Execute)).ToArray(); + DateTime start = DateTime.Now; + foreach (var t in threads) + t.Start(); + foreach (var t in threads) + t.Join(); + Console.WriteLine("Total time: " + (DateTime.Now - start)); + Console.WriteLine(); + return tests.Select(t => t.ReturnCode).Aggregate((r1, r2) => r1 | r2); + } + catch (Exception outerEx) + { + Console.WriteLine("*** FAILED ***"); + Console.WriteLine("Unexpected error"); + Console.WriteLine(outerEx.Message + " ST: " + outerEx.StackTrace); + return ErrorUnknown; + } + } + + public static string BytesToHex(byte[] data) { + return BitConverter.ToString(data).Replace("-", string.Empty); + } + + public static byte[] PrepareTestData(bool randomDist, bool huge) + { + // huge = true tests for THRIFT-4372 + byte[] retval = new byte[huge ? 0x12345 : 0x100]; + int initLen = retval.Length; + + // linear distribution, unless random is requested + if (!randomDist) { + for (var i = 0; i < initLen; ++i) { + retval[i] = (byte)i; + } + return retval; + } + + // random distribution + for (var i = 0; i < initLen; ++i) { + retval[i] = (byte)0; + } + var rnd = new Random(); + for (var i = 1; i < initLen; ++i) { + while( true) { + int nextPos = rnd.Next() % initLen; + if (retval[nextPos] == 0) { + retval[nextPos] = (byte)i; + break; + } + } + } + return retval; + } + + public static int ExecuteClientTest(ThriftTest.Client client, SecondService.Client second, TestParams param) + { + int returnCode = 0; + + Console.Write("testVoid()"); + client.testVoid(); + Console.WriteLine(" = void"); + + Console.Write("testString(\"Test\")"); + string s = client.testString("Test"); + Console.WriteLine(" = \"" + s + "\""); + if ("Test" != s) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + } + + if (param.multiplexed) + { + Console.WriteLine("secondTestString(\"Test2\")"); + s = second.secondtestString("Test2"); + Console.WriteLine(" = \"" + s + "\""); + if ("testString(\"Test2\")" != s) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorProtocol; + } + } + + Console.Write("testBool(true)"); + bool t = client.testBool((bool)true); + Console.WriteLine(" = " + t); + if (!t) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + } + Console.Write("testBool(false)"); + bool f = client.testBool((bool)false); + Console.WriteLine(" = " + f); + if (f) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + } + + Console.Write("testByte(1)"); + sbyte i8 = client.testByte((sbyte)1); + Console.WriteLine(" = " + i8); + if (1 != i8) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + } + + Console.Write("testI32(-1)"); + int i32 = client.testI32(-1); + Console.WriteLine(" = " + i32); + if (-1 != i32) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + } + + Console.Write("testI64(-34359738368)"); + long i64 = client.testI64(-34359738368); + Console.WriteLine(" = " + i64); + if (-34359738368 != i64) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + } + + // TODO: Validate received message + Console.Write("testDouble(5.325098235)"); + double dub = client.testDouble(5.325098235); + Console.WriteLine(" = " + dub); + if (5.325098235 != dub) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + } + Console.Write("testDouble(-0.000341012439638598279)"); + dub = client.testDouble(-0.000341012439638598279); + Console.WriteLine(" = " + dub); + if (-0.000341012439638598279 != dub) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + } + + for (i32 = 0; i32 < 2; ++i32) + { + var huge = (i32 > 0); + byte[] binOut = PrepareTestData(false,huge); + Console.Write("testBinary(" + BytesToHex(binOut) + ")"); + try + { + byte[] binIn = client.testBinary(binOut); + Console.WriteLine(" = " + BytesToHex(binIn)); + if (binIn.Length != binOut.Length) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + } + for (int ofs = 0; ofs < Math.Min(binIn.Length, binOut.Length); ++ofs) + if (binIn[ofs] != binOut[ofs]) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + } + } + catch (Thrift.TApplicationException ex) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + Console.WriteLine(ex.Message + " ST: " + ex.StackTrace); + } + } + + // binary equals? only with hashcode option enabled ... + Console.WriteLine("Test CrazyNesting"); + if( typeof(CrazyNesting).GetMethod("Equals").DeclaringType == typeof(CrazyNesting)) + { + CrazyNesting one = new CrazyNesting(); + CrazyNesting two = new CrazyNesting(); + one.String_field = "crazy"; + two.String_field = "crazy"; + one.Binary_field = new byte[10] { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xFF }; + two.Binary_field = new byte[10] { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xFF }; + if (!one.Equals(two)) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorContainers; + throw new Exception("CrazyNesting.Equals failed"); + } + } + + // TODO: Validate received message + Console.Write("testStruct({\"Zero\", 1, -3, -5})"); + Xtruct o = new Xtruct(); + o.String_thing = "Zero"; + o.Byte_thing = (sbyte)1; + o.I32_thing = -3; + o.I64_thing = -5; + Xtruct i = client.testStruct(o); + Console.WriteLine(" = {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}"); + + // TODO: Validate received message + Console.Write("testNest({1, {\"Zero\", 1, -3, -5}, 5})"); + Xtruct2 o2 = new Xtruct2(); + o2.Byte_thing = (sbyte)1; + o2.Struct_thing = o; + o2.I32_thing = 5; + Xtruct2 i2 = client.testNest(o2); + i = i2.Struct_thing; + Console.WriteLine(" = {" + i2.Byte_thing + ", {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}, " + i2.I32_thing + "}"); + + Dictionary mapout = new Dictionary(); + for (int j = 0; j < 5; j++) + { + mapout[j] = j - 10; + } + Console.Write("testMap({"); + bool first = true; + foreach (int key in mapout.Keys) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(key + " => " + mapout[key]); + } + Console.Write("})"); + + Dictionary mapin = client.testMap(mapout); + + Console.Write(" = {"); + first = true; + foreach (int key in mapin.Keys) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(key + " => " + mapin[key]); + } + Console.WriteLine("}"); + + // TODO: Validate received message + List listout = new List(); + for (int j = -2; j < 3; j++) + { + listout.Add(j); + } + Console.Write("testList({"); + first = true; + foreach (int j in listout) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(j); + } + Console.Write("})"); + + List listin = client.testList(listout); + + Console.Write(" = {"); + first = true; + foreach (int j in listin) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(j); + } + Console.WriteLine("}"); + + //set + // TODO: Validate received message + THashSet setout = new THashSet(); + for (int j = -2; j < 3; j++) + { + setout.Add(j); + } + Console.Write("testSet({"); + first = true; + foreach (int j in setout) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(j); + } + Console.Write("})"); + + THashSet setin = client.testSet(setout); + + Console.Write(" = {"); + first = true; + foreach (int j in setin) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(j); + } + Console.WriteLine("}"); + + + Console.Write("testEnum(ONE)"); + Numberz ret = client.testEnum(Numberz.ONE); + Console.WriteLine(" = " + ret); + if (Numberz.ONE != ret) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorStructs; + } + + Console.Write("testEnum(TWO)"); + ret = client.testEnum(Numberz.TWO); + Console.WriteLine(" = " + ret); + if (Numberz.TWO != ret) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorStructs; + } + + Console.Write("testEnum(THREE)"); + ret = client.testEnum(Numberz.THREE); + Console.WriteLine(" = " + ret); + if (Numberz.THREE != ret) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorStructs; + } + + Console.Write("testEnum(FIVE)"); + ret = client.testEnum(Numberz.FIVE); + Console.WriteLine(" = " + ret); + if (Numberz.FIVE != ret) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorStructs; + } + + Console.Write("testEnum(EIGHT)"); + ret = client.testEnum(Numberz.EIGHT); + Console.WriteLine(" = " + ret); + if (Numberz.EIGHT != ret) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorStructs; + } + + Console.Write("testTypedef(309858235082523)"); + long uid = client.testTypedef(309858235082523L); + Console.WriteLine(" = " + uid); + if (309858235082523L != uid) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorStructs; + } + + // TODO: Validate received message + Console.Write("testMapMap(1)"); + Dictionary> mm = client.testMapMap(1); + Console.Write(" = {"); + foreach (int key in mm.Keys) + { + Console.Write(key + " => {"); + Dictionary m2 = mm[key]; + foreach (int k2 in m2.Keys) + { + Console.Write(k2 + " => " + m2[k2] + ", "); + } + Console.Write("}, "); + } + Console.WriteLine("}"); + + // TODO: Validate received message + Insanity insane = new Insanity(); + insane.UserMap = new Dictionary(); + insane.UserMap[Numberz.FIVE] = 5000L; + Xtruct truck = new Xtruct(); + truck.String_thing = "Truck"; + truck.Byte_thing = (sbyte)8; + truck.I32_thing = 8; + truck.I64_thing = 8; + insane.Xtructs = new List(); + insane.Xtructs.Add(truck); + Console.Write("testInsanity()"); + Dictionary> whoa = client.testInsanity(insane); + Console.Write(" = {"); + foreach (long key in whoa.Keys) + { + Dictionary val = whoa[key]; + Console.Write(key + " => {"); + + foreach (Numberz k2 in val.Keys) + { + Insanity v2 = val[k2]; + + Console.Write(k2 + " => {"); + Dictionary userMap = v2.UserMap; + + Console.Write("{"); + if (userMap != null) + { + foreach (Numberz k3 in userMap.Keys) + { + Console.Write(k3 + " => " + userMap[k3] + ", "); + } + } + else + { + Console.Write("null"); + } + Console.Write("}, "); + + List xtructs = v2.Xtructs; + + Console.Write("{"); + if (xtructs != null) + { + foreach (Xtruct x in xtructs) + { + Console.Write("{\"" + x.String_thing + "\", " + x.Byte_thing + ", " + x.I32_thing + ", " + x.I32_thing + "}, "); + } + } + else + { + Console.Write("null"); + } + Console.Write("}"); + + Console.Write("}, "); + } + Console.Write("}, "); + } + Console.WriteLine("}"); + + sbyte arg0 = 1; + int arg1 = 2; + long arg2 = long.MaxValue; + Dictionary multiDict = new Dictionary(); + multiDict[1] = "one"; + Numberz arg4 = Numberz.FIVE; + long arg5 = 5000000; + Console.Write("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")"); + Xtruct multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5); + Console.Write(" = Xtruct(byte_thing:" + multiResponse.Byte_thing + ",String_thing:" + multiResponse.String_thing + + ",i32_thing:" + multiResponse.I32_thing + ",i64_thing:" + multiResponse.I64_thing + ")\n"); + + try + { + Console.WriteLine("testException(\"Xception\")"); + client.testException("Xception"); + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + } + catch (Xception ex) + { + if (ex.ErrorCode != 1001 || ex.Message != "Xception") + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + } + } + catch (Exception ex) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + Console.WriteLine(ex.Message + " ST: " + ex.StackTrace); + } + try + { + Console.WriteLine("testException(\"TException\")"); + client.testException("TException"); + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + } + catch (Thrift.TException) + { + // OK + } + catch (Exception ex) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + Console.WriteLine(ex.Message + " ST: " + ex.StackTrace); + } + try + { + Console.WriteLine("testException(\"ok\")"); + client.testException("ok"); + // OK + } + catch (Exception ex) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + Console.WriteLine(ex.Message + " ST: " + ex.StackTrace); + } + + try + { + Console.WriteLine("testMultiException(\"Xception\", ...)"); + client.testMultiException("Xception", "ignore"); + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + } + catch (Xception ex) + { + if (ex.ErrorCode != 1001 || ex.Message != "This is an Xception") + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + } + } + catch (Exception ex) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + Console.WriteLine(ex.Message + " ST: " + ex.StackTrace); + } + try + { + Console.WriteLine("testMultiException(\"Xception2\", ...)"); + client.testMultiException("Xception2", "ignore"); + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + } + catch (Xception2 ex) + { + if (ex.ErrorCode != 2002 || ex.Struct_thing.String_thing != "This is an Xception2") + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + } + } + catch (Exception ex) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + Console.WriteLine(ex.Message + " ST: " + ex.StackTrace); + } + try + { + Console.WriteLine("testMultiException(\"success\", \"OK\")"); + if ("OK" != client.testMultiException("success", "OK").String_thing) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + } + } + catch (Exception ex) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorExceptions; + Console.WriteLine(ex.Message + " ST: " + ex.StackTrace); + } + + Stopwatch sw = new Stopwatch(); + sw.Start(); + Console.WriteLine("Test Oneway(1)"); + client.testOneway(1); + sw.Stop(); + if (sw.ElapsedMilliseconds > 1000) + { + Console.WriteLine("*** FAILED ***"); + returnCode |= ErrorBaseTypes; + } + + Console.Write("Test Calltime()"); + var times = 50; + sw.Reset(); + sw.Start(); + for (int k = 0; k < times; ++k) + client.testVoid(); + sw.Stop(); + Console.WriteLine(" = {0} ms a testVoid() call", sw.ElapsedMilliseconds / times); + return returnCode; + } + } +} diff --git a/test/csharp/TestServer.cs b/test/csharp/TestServer.cs new file mode 100644 index 0000000..e9c7168 --- /dev/null +++ b/test/csharp/TestServer.cs @@ -0,0 +1,533 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// Distributed under the Thrift Software License +// +// See accompanying file LICENSE or visit the Thrift site at: +// http://developers.facebook.com/thrift/ +using System; +using System.Collections.Generic; +using System.Security.Cryptography.X509Certificates; +using Thrift.Collections; +using Thrift.Test; //generated code +using Thrift.Transport; +using Thrift.Protocol; +using Thrift.Server; +using Thrift; +using System.Threading; +using System.Text; +using System.Security.Authentication; + +namespace Test +{ + public class TestServer + { + public static int _clientID = -1; + public delegate void TestLogDelegate(string msg, params object[] values); + + public class TradeServerEventHandler : TServerEventHandler + { + public int callCount = 0; + public void preServe() + { + callCount++; + } + public Object createContext(Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output) + { + callCount++; + return null; + } + public void deleteContext(Object serverContext, Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output) + { + callCount++; + } + public void processContext(Object serverContext, Thrift.Transport.TTransport transport) + { + callCount++; + } + }; + + + public class TestHandler : ThriftTest.Iface, Thrift.TControllingHandler + { + public TServer server { get; set; } + private int handlerID; + private StringBuilder reusableStringBuilder = new StringBuilder(); + private TestLogDelegate testLogDelegate; + + public TestHandler() + { + handlerID = Interlocked.Increment(ref _clientID); + testLogDelegate += testConsoleLogger; + testLogDelegate.Invoke("New TestHandler instance created"); + } + + public void testConsoleLogger(string msg, params object[] values) + { + reusableStringBuilder.Clear(); + reusableStringBuilder.AppendFormat("handler{0:D3}:",handlerID); + reusableStringBuilder.AppendFormat(msg, values); + reusableStringBuilder.AppendLine(); + Console.Write( reusableStringBuilder.ToString() ); + } + + public void testVoid() + { + testLogDelegate.Invoke("testVoid()"); + } + + public string testString(string thing) + { + testLogDelegate.Invoke("testString({0})", thing); + return thing; + } + + public bool testBool(bool thing) + { + testLogDelegate.Invoke("testBool({0})", thing); + return thing; + } + + public sbyte testByte(sbyte thing) + { + testLogDelegate.Invoke("testByte({0})", thing); + return thing; + } + + public int testI32(int thing) + { + testLogDelegate.Invoke("testI32({0})", thing); + return thing; + } + + public long testI64(long thing) + { + testLogDelegate.Invoke("testI64({0})", thing); + return thing; + } + + public double testDouble(double thing) + { + testLogDelegate.Invoke("testDouble({0})", thing); + return thing; + } + + public byte[] testBinary(byte[] thing) + { + string hex = BitConverter.ToString(thing).Replace("-", string.Empty); + testLogDelegate.Invoke("testBinary({0:X})", hex); + return thing; + } + + public Xtruct testStruct(Xtruct thing) + { + testLogDelegate.Invoke("testStruct({{\"{0}\", {1}, {2}, {3}}})", thing.String_thing, thing.Byte_thing, thing.I32_thing, thing.I64_thing); + return thing; + } + + public Xtruct2 testNest(Xtruct2 nest) + { + Xtruct thing = nest.Struct_thing; + testLogDelegate.Invoke("testNest({{{0}, {{\"{1}\", {2}, {3}, {4}, {5}}}}})", + nest.Byte_thing, + thing.String_thing, + thing.Byte_thing, + thing.I32_thing, + thing.I64_thing, + nest.I32_thing); + return nest; + } + + public Dictionary testMap(Dictionary thing) + { + reusableStringBuilder.Clear(); + reusableStringBuilder.Append("testMap({{"); + bool first = true; + foreach (int key in thing.Keys) + { + if (first) + { + first = false; + } + else + { + reusableStringBuilder.Append(", "); + } + reusableStringBuilder.AppendFormat("{0} => {1}", key, thing[key]); + } + reusableStringBuilder.Append("}})"); + testLogDelegate.Invoke(reusableStringBuilder.ToString()); + return thing; + } + + public Dictionary testStringMap(Dictionary thing) + { + reusableStringBuilder.Clear(); + reusableStringBuilder.Append("testStringMap({{"); + bool first = true; + foreach (string key in thing.Keys) + { + if (first) + { + first = false; + } + else + { + reusableStringBuilder.Append(", "); + } + reusableStringBuilder.AppendFormat("{0} => {1}", key, thing[key]); + } + reusableStringBuilder.Append("}})"); + testLogDelegate.Invoke(reusableStringBuilder.ToString()); + return thing; + } + + public THashSet testSet(THashSet thing) + { + reusableStringBuilder.Clear(); + reusableStringBuilder.Append("testSet({{"); + bool first = true; + foreach (int elem in thing) + { + if (first) + { + first = false; + } + else + { + reusableStringBuilder.Append(", "); + } + reusableStringBuilder.AppendFormat("{0}", elem); + } + reusableStringBuilder.Append("}})"); + testLogDelegate.Invoke(reusableStringBuilder.ToString()); + return thing; + } + + public List testList(List thing) + { + reusableStringBuilder.Clear(); + reusableStringBuilder.Append("testList({{"); + bool first = true; + foreach (int elem in thing) + { + if (first) + { + first = false; + } + else + { + reusableStringBuilder.Append(", "); + } + reusableStringBuilder.AppendFormat("{0}", elem); + } + reusableStringBuilder.Append("}})"); + testLogDelegate.Invoke(reusableStringBuilder.ToString()); + return thing; + } + + public Numberz testEnum(Numberz thing) + { + testLogDelegate.Invoke("testEnum({0})", thing); + return thing; + } + + public long testTypedef(long thing) + { + testLogDelegate.Invoke("testTypedef({0})", thing); + return thing; + } + + public Dictionary> testMapMap(int hello) + { + testLogDelegate.Invoke("testMapMap({0})", hello); + Dictionary> mapmap = + new Dictionary>(); + + Dictionary pos = new Dictionary(); + Dictionary neg = new Dictionary(); + for (int i = 1; i < 5; i++) + { + pos[i] = i; + neg[-i] = -i; + } + + mapmap[4] = pos; + mapmap[-4] = neg; + + return mapmap; + } + + // Insanity + // returns: + // { 1 => { 2 => argument, + // 3 => argument, + // }, + // 2 => { 6 => , }, + // } + public Dictionary> testInsanity(Insanity argument) + { + testLogDelegate.Invoke("testInsanity()"); + + Dictionary first_map = new Dictionary(); + Dictionary second_map = new Dictionary(); ; + + first_map[Numberz.TWO] = argument; + first_map[Numberz.THREE] = argument; + + second_map[Numberz.SIX] = new Insanity(); + + Dictionary> insane = + new Dictionary>(); + insane[(long)1] = first_map; + insane[(long)2] = second_map; + + return insane; + } + + public Xtruct testMulti(sbyte arg0, int arg1, long arg2, Dictionary arg3, Numberz arg4, long arg5) + { + testLogDelegate.Invoke("testMulti()"); + + Xtruct hello = new Xtruct(); ; + hello.String_thing = "Hello2"; + hello.Byte_thing = arg0; + hello.I32_thing = arg1; + hello.I64_thing = arg2; + return hello; + } + + /** + * Print 'testException(%s)' with arg as '%s' + * @param string arg - a string indication what type of exception to throw + * if arg == "Xception" throw Xception with errorCode = 1001 and message = arg + * elsen if arg == "TException" throw TException + * else do not throw anything + */ + public void testException(string arg) + { + testLogDelegate.Invoke("testException({0})", arg); + if (arg == "Xception") + { + Xception x = new Xception(); + x.ErrorCode = 1001; + x.Message = arg; + throw x; + } + if (arg == "TException") + { + throw new Thrift.TException(); + } + return; + } + + public Xtruct testMultiException(string arg0, string arg1) + { + testLogDelegate.Invoke("testMultiException({0}, {1})", arg0,arg1); + if (arg0 == "Xception") + { + Xception x = new Xception(); + x.ErrorCode = 1001; + x.Message = "This is an Xception"; + throw x; + } + else if (arg0 == "Xception2") + { + Xception2 x = new Xception2(); + x.ErrorCode = 2002; + x.Struct_thing = new Xtruct(); + x.Struct_thing.String_thing = "This is an Xception2"; + throw x; + } + + Xtruct result = new Xtruct(); + result.String_thing = arg1; + return result; + } + + public void testStop() + { + if (server != null) + { + server.Stop(); + } + } + + public void testOneway(int arg) + { + testLogDelegate.Invoke("testOneway({0}), sleeping...", arg); + System.Threading.Thread.Sleep(arg * 1000); + testLogDelegate.Invoke("testOneway finished"); + } + + } // class TestHandler + + private enum ServerType + { + TSimpleServer, + TThreadedServer, + TThreadPoolServer, + } + + private enum ProcessorFactoryType + { + TSingletonProcessorFactory, + TPrototypeProcessorFactory, + } + + public static bool Execute(string[] args) + { + try + { + bool useBufferedSockets = false, useFramed = false, useEncryption = false, compact = false, json = false; + ServerType serverType = ServerType.TSimpleServer; + ProcessorFactoryType processorFactoryType = ProcessorFactoryType.TSingletonProcessorFactory; + int port = 9090; + string pipe = null; + for (int i = 0; i < args.Length; i++) + { + if (args[i] == "-pipe") // -pipe name + { + pipe = args[++i]; + } + else if (args[i].Contains("--port=")) + { + port = int.Parse(args[i].Substring(args[i].IndexOf("=") + 1)); + } + else if (args[i] == "-b" || args[i] == "--buffered" || args[i] == "--transport=buffered") + { + useBufferedSockets = true; + } + else if (args[i] == "-f" || args[i] == "--framed" || args[i] == "--transport=framed") + { + useFramed = true; + } + else if (args[i] == "--compact" || args[i] == "--protocol=compact") + { + compact = true; + } + else if (args[i] == "--json" || args[i] == "--protocol=json") + { + json = true; + } + else if (args[i] == "--threaded" || args[i] == "--server-type=threaded") + { + serverType = ServerType.TThreadedServer; + } + else if (args[i] == "--threadpool" || args[i] == "--server-type=threadpool") + { + serverType = ServerType.TThreadPoolServer; + } + else if (args[i] == "--prototype" || args[i] == "--processor=prototype") + { + processorFactoryType = ProcessorFactoryType.TPrototypeProcessorFactory; + } + else if (args[i] == "--ssl") + { + useEncryption = true; + } + } + + // Transport + TServerTransport trans; + if (pipe != null) + { + trans = new TNamedPipeServerTransport(pipe); + } + else + { + if (useEncryption) + { + string certPath = "../keys/server.p12"; + trans = new TTLSServerSocket(port, 0, useBufferedSockets, new X509Certificate2(certPath, "thrift"), null, null, SslProtocols.Tls); + } + else + { + trans = new TServerSocket(port, 0, useBufferedSockets); + } + } + + TProtocolFactory proto; + if (compact) + proto = new TCompactProtocol.Factory(); + else if (json) + proto = new TJSONProtocol.Factory(); + else + proto = new TBinaryProtocol.Factory(); + + TProcessorFactory processorFactory; + if (processorFactoryType == ProcessorFactoryType.TPrototypeProcessorFactory) + { + processorFactory = new TPrototypeProcessorFactory(); + } + else + { + // Processor + TestHandler testHandler = new TestHandler(); + ThriftTest.Processor testProcessor = new ThriftTest.Processor(testHandler); + processorFactory = new TSingletonProcessorFactory(testProcessor); + } + + TTransportFactory transFactory; + if (useFramed) + transFactory = new TFramedTransport.Factory(); + else + transFactory = new TTransportFactory(); + + TServer serverEngine; + switch (serverType) + { + case ServerType.TThreadPoolServer: + serverEngine = new TThreadPoolServer(processorFactory, trans, transFactory, proto); + break; + case ServerType.TThreadedServer: + serverEngine = new TThreadedServer(processorFactory, trans, transFactory, proto); + break; + default: + serverEngine = new TSimpleServer(processorFactory, trans, transFactory, proto); + break; + } + + //Server event handler + TradeServerEventHandler serverEvents = new TradeServerEventHandler(); + serverEngine.setEventHandler(serverEvents); + + // Run it + string where = (pipe != null ? "on pipe " + pipe : "on port " + port); + Console.WriteLine("Starting the " + serverType.ToString() + " " + where + + (processorFactoryType == ProcessorFactoryType.TPrototypeProcessorFactory ? " with processor prototype factory " : "") + + (useBufferedSockets ? " with buffered socket" : "") + + (useFramed ? " with framed transport" : "") + + (useEncryption ? " with encryption" : "") + + (compact ? " with compact protocol" : "") + + (json ? " with json protocol" : "") + + "..."); + serverEngine.Serve(); + + } + catch (Exception x) + { + Console.Error.Write(x); + return false; + } + Console.WriteLine("done."); + return true; + } + } +} diff --git a/test/csharp/ThriftTest.csproj b/test/csharp/ThriftTest.csproj new file mode 100644 index 0000000..8fe40aa --- /dev/null +++ b/test/csharp/ThriftTest.csproj @@ -0,0 +1,141 @@ + + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {48DD757F-CA95-4DD7-BDA4-58DB6F108C2C} + Exe + Properties + ThriftTest + ThriftTest + v3.5 + 512 + false + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 0.11.0.%2a + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + + + False + .\ThriftImpl.dll + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 2.0 %28x86%29 + false + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + true + + + False + .NET Framework 3.5 SP1 + false + + + False + Windows Installer 3.1 + true + + + + + {499EB63C-D74C-47E8-AE48-A2FC94538E9D} + Thrift + + + + + + rmdir /s /q "$(ProjectDir)gen-csharp" +del /f /q "$(ProjectDir)ThriftImpl.dll" +SET OUTPUT_DIR=$(ProjectDir) +SET THRIFT_FILE=$(ProjectDir)\..\ThriftTest.thrift +for %25%25I in ("%25OUTPUT_DIR%25") do set SHORT_DIR=%25%25~fsI +for %25%25I in ("%25THRIFT_FILE%25") do set THRIFT_SHORT=%25%25~fsI +"$(ProjectDir)\..\..\compiler\cpp\thrift.exe" --gen csharp -o %25SHORT_DIR%25 %25THRIFT_SHORT%25 +$(MSBuildToolsPath)\Csc.exe /t:library /out:"$(ProjectDir)ThriftImpl.dll" /recurse:"$(ProjectDir)gen-csharp"\* /reference:"$(ProjectDir)..\..\lib\csharp\bin\Debug\Thrift.dll" + + \ No newline at end of file diff --git a/test/csharp/ThriftTest.sln b/test/csharp/ThriftTest.sln new file mode 100644 index 0000000..1765a03 --- /dev/null +++ b/test/csharp/ThriftTest.sln @@ -0,0 +1,17 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftTest", "ThriftTest.csproj", "{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/test/dart/Makefile b/test/dart/Makefile new file mode 100644 index 0000000..dd9b221 --- /dev/null +++ b/test/dart/Makefile @@ -0,0 +1,646 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# test/dart/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/thrift +pkgincludedir = $(includedir)/thrift +pkglibdir = $(libdir)/thrift +pkglibexecdir = $(libexecdir)/thrift +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-pc-linux-gnu +host_triplet = x86_64-pc-linux-gnu +subdir = test/dart +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_$(V)) +am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15 +ALLOCA = +AMTAR = $${TAR-tar} +AM_DEFAULT_VERBOSITY = 1 +ANT = /usr/bin/ant +ANT_FLAGS = +AR = ar +AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf +AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader +AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15 +AWK = gawk +BISON = bison +BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a +BOOST_CPPFLAGS = -I/usr/include +BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a +BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu +BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu +BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a +BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a +BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a +BUNDLER = /usr/bin/bundle +CABAL = /usr/bin/cabal +CABAL_CONFIGURE_FLAGS = +CARGO = /usr/bin/cargo +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 +CLASSPATH = +CPP = gcc -E +CPPFLAGS = +CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \; +CXX = g++ -std=c++11 +CXXCPP = g++ -E -std=c++11 +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -g -O2 +CYGPATH_W = echo +DART = /usr/lib/dart/bin/dart +DARTPUB = /usr/lib/dart/bin/pub +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +DLLTOOL = false +DMD = dmd +DMD_LIBEVENT_FLAGS = +DMD_OF_DIRSEP = / +DMD_OPENSSL_FLAGS = +DOTNETCORE = /usr/bin/dotnet +DOTNETCORE_VERSION = 2.0.3 +DSYMUTIL = +DUMPBIN = +D_EVENT_LIB_NAME = libthriftd-event.a +D_IMPORT_PREFIX = ${prefix}/include/d2 +D_LIB_NAME = libthriftd.a +D_SSL_LIB_NAME = libthriftd-ssl.a +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +ENABLE_COVERAGE = 2 +ERL = /usr/bin/erl +ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib +ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0 +ERLANG_LIB_DIR = /usr/lib/erlang/lib +ERLC = /usr/bin/erlc +ERLCFLAGS = +EXEEXT = +FGREP = /bin/grep -F +GCOV_CFLAGS = +GCOV_CXXFLAGS = +GCOV_LDFLAGS = +GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GLIB_LIBS = -lglib-2.0 +GO = /usr/bin/go +GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0 +GREP = /bin/grep +HAVE_CXX11 = 1 +HAXE = /usr/bin/haxe +HAXE_VERSION = 3.2.1 +INSTALL = /usr/bin/install -c +INSTALLDIRS = vendor +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +JAVA_PREFIX = /usr/local/lib +LD = /usr/bin/ld -m elf_x86_64 +LDFLAGS = +LEX = flex +LEXLIB = -lfl +LEX_OUTPUT_ROOT = lex.yy +LIBEVENT_CPPFLAGS = +LIBEVENT_LDFLAGS = +LIBEVENT_LIBS = -levent +LIBOBJS = +LIBS = -lrt -lpthread +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LIPO = +LN_S = ln -s +LTLIBOBJS = +LT_SYS_LIBRARY_PATH = +LUA = /usr/bin/lua5.3 +LUA_EXEC_PREFIX = ${exec_prefix} +LUA_INCLUDE = -I/usr/include/lua5.3 +LUA_LIB = -llua5.3 -ldl +LUA_PLATFORM = unknown +LUA_PREFIX = ${prefix} +LUA_SHORT_VERSION = 53 +LUA_VERSION = 5.3 +MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo +MANIFEST_TOOL = : +MAYBE_CPP = cpp +MAYBE_CSHARP = csharp +MAYBE_C_GLIB = c_glib +MAYBE_D = +MAYBE_DART = dart +MAYBE_DOTNETCORE = netcore +MAYBE_ERLANG = erl +MAYBE_GO = go +MAYBE_HASKELL = hs +MAYBE_JAVA = java +MAYBE_LUA = lua +MAYBE_NODEJS = nodejs +MAYBE_PERL = perl +MAYBE_PHP = php +MAYBE_PY3 = py3 +MAYBE_PYTHON = py +MAYBE_RS = rs +MAYBE_RUBY = rb +MCS = /usr/bin/mcs +MKDIR_P = /bin/mkdir -p +MONO_CFLAGS = +MONO_LIBS = +NM = /usr/bin/nm -B +NMEDIT = +NODEJS = /usr/bin/nodejs +NPM = /usr/bin/npm +OBJDUMP = objdump +OBJEXT = o +OPENSSL_INCLUDES = +OPENSSL_LDFLAGS = +OPENSSL_LIBS = -lssl -lcrypto +OTOOL = +OTOOL64 = +PACKAGE = thrift +PACKAGE_BUGREPORT = +PACKAGE_NAME = thrift +PACKAGE_STRING = thrift 0.11.0 +PACKAGE_TARNAME = thrift +PACKAGE_URL = +PACKAGE_VERSION = 0.11.0 +PATH_SEPARATOR = : +PERL = /usr/bin/perl +PERL_PREFIX = /usr/local +PHP = /usr/bin/php +PHPUNIT = /usr/bin/phpunit +PHP_CONFIG = /usr/bin/php-config +PHP_CONFIG_PREFIX = /etc/php.d +PHP_PREFIX = /usr/lib/php +PKG_CONFIG = /usr/bin/pkg-config +PKG_CONFIG_LIBDIR = +PKG_CONFIG_PATH = +PYTHON = /usr/bin/python +PYTHON3 = /usr/bin/python3 +PYTHON_EXEC_PREFIX = ${exec_prefix} +PYTHON_PLATFORM = linux2 +PYTHON_PREFIX = ${prefix} +PYTHON_VERSION = 2.7 +PY_PREFIX = /usr +QT5_CFLAGS = +QT5_LIBS = +QT5_MOC = +QT_CFLAGS = +QT_LIBS = +QT_MOC = +RANLIB = ranlib +REBAR = /usr/bin/rebar +RUBY = /usr/bin/ruby +RUBY_PREFIX = +RUNHASKELL = /usr/bin/runhaskell +RUSTC = /usr/bin/rustc +SED = /bin/sed +SET_MAKE = +SHELL = /bin/bash +STRIP = strip +THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift +TRIAL = /usr/bin/trial +VERSION = 0.11.0 +YACC = bison -y +YFLAGS = +ZLIB_CPPFLAGS = +ZLIB_LDFLAGS = +ZLIB_LIBS = -lz +abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/test/dart +abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/test/dart +abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift +abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift +ac_ct_AR = ar +ac_ct_CC = gcc +ac_ct_CXX = g++ +ac_ct_DUMPBIN = +am__include = include +am__leading_dot = . +am__quote = +am__tar = tar --format=ustar -chf - "$$tardir" +am__untar = tar -xf - +bindir = ${exec_prefix}/bin +build = x86_64-pc-linux-gnu +build_alias = +build_cpu = x86_64 +build_os = linux-gnu +build_vendor = pc +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +golang_version = 1.6.2 +have_prog_bison = yes +host = x86_64-pc-linux-gnu +host_alias = +host_cpu = x86_64 +host_os = linux-gnu +host_vendor = pc +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +luadir = ${prefix}/share/lua/5.3 +luaexecdir = ${exec_prefix}/lib/lua/5.3 +mandir = ${datarootdir}/man +mkdir_p = $(MKDIR_P) +oldincludedir = /usr/include +pdfdir = ${docdir} +pkgluadir = ${luadir}/thrift +pkgluaexecdir = ${luaexecdir}/thrift +pkgpyexecdir = ${pyexecdir}/thrift +pkgpythondir = ${pythondir}/thrift +prefix = /usr/local +program_transform_name = s,x,x, +psdir = ${docdir} +pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages +pythondir = ${prefix}/lib/python2.7/dist-packages +runstatedir = ${localstatedir}/run +rustc_version = rustc 1.17.0 +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +subdirs = lib/php/src/ext/thrift_protocol +sysconfdir = ${prefix}/etc +target_alias = +top_build_prefix = ../../ +top_builddir = ../.. +top_srcdir = ../.. +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/dart/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/dart/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +gen-dart/thrift_test/lib/thrift_test.dart: ../ThriftTest.thrift + $(THRIFT) --gen dart ../ThriftTest.thrift + +pub-get-gen: gen-dart/thrift_test/lib/thrift_test.dart + cd gen-dart/thrift_test; ${DARTPUB} get + +pub-get: pub-get-gen + cd test_client; ${DARTPUB} get + +stubs: gen-dart/thrift_test/lib/thrift_test.dart pub-get + +precross: stubs + +check: stubs + +clean-local: + $(RM) -r gen-dart test_client/.pub + find . -type d -name "packages" | xargs $(RM) -r + find . -type f -name ".packages" | xargs $(RM) + find . -type f -name "pubspec.lock" | xargs $(RM) + +client: stubs + ${DART} test_client/bin/main.dart + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/dart/Makefile.am b/test/dart/Makefile.am new file mode 100644 index 0000000..9750ec2 --- /dev/null +++ b/test/dart/Makefile.am @@ -0,0 +1,42 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +gen-dart/thrift_test/lib/thrift_test.dart: ../ThriftTest.thrift + $(THRIFT) --gen dart ../ThriftTest.thrift + +pub-get-gen: gen-dart/thrift_test/lib/thrift_test.dart + cd gen-dart/thrift_test; ${DARTPUB} get + +pub-get: pub-get-gen + cd test_client; ${DARTPUB} get + +stubs: gen-dart/thrift_test/lib/thrift_test.dart pub-get + +precross: stubs + +check: stubs + +clean-local: + $(RM) -r gen-dart test_client/.pub + find . -type d -name "packages" | xargs $(RM) -r + find . -type f -name ".packages" | xargs $(RM) + find . -type f -name "pubspec.lock" | xargs $(RM) + +client: stubs + ${DART} test_client/bin/main.dart diff --git a/test/dart/Makefile.in b/test/dart/Makefile.in new file mode 100644 index 0000000..298cfd9 --- /dev/null +++ b/test/dart/Makefile.in @@ -0,0 +1,646 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = test/dart +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/dart/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/dart/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +gen-dart/thrift_test/lib/thrift_test.dart: ../ThriftTest.thrift + $(THRIFT) --gen dart ../ThriftTest.thrift + +pub-get-gen: gen-dart/thrift_test/lib/thrift_test.dart + cd gen-dart/thrift_test; ${DARTPUB} get + +pub-get: pub-get-gen + cd test_client; ${DARTPUB} get + +stubs: gen-dart/thrift_test/lib/thrift_test.dart pub-get + +precross: stubs + +check: stubs + +clean-local: + $(RM) -r gen-dart test_client/.pub + find . -type d -name "packages" | xargs $(RM) -r + find . -type f -name ".packages" | xargs $(RM) + find . -type f -name "pubspec.lock" | xargs $(RM) + +client: stubs + ${DART} test_client/bin/main.dart + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/dart/test_client/.analysis_options b/test/dart/test_client/.analysis_options new file mode 100644 index 0000000..a10d4c5 --- /dev/null +++ b/test/dart/test_client/.analysis_options @@ -0,0 +1,2 @@ +analyzer: + strong-mode: true diff --git a/test/dart/test_client/bin/main.dart b/test/dart/test_client/bin/main.dart new file mode 100644 index 0000000..996844b --- /dev/null +++ b/test/dart/test_client/bin/main.dart @@ -0,0 +1,337 @@ +/// Licensed to the Apache Software Foundation (ASF) under one +/// or more contributor license agreements. See the NOTICE file +/// distributed with this work for additional information +/// regarding copyright ownership. The ASF licenses this file +/// to you under the Apache License, Version 2.0 (the +/// 'License'); you may not use this file except in compliance +/// with the License. You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, +/// software distributed under the License is distributed on an +/// 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +/// KIND, either express or implied. See the License for the +/// specific language governing permissions and limitations +/// under the License. + +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:collection/collection.dart'; +import 'package:http/http.dart' as http; +import 'package:thrift/thrift.dart'; +import 'package:thrift/thrift_console.dart'; +import 'package:thrift_test/thrift_test.dart'; + +const TEST_BASETYPES = 1; // 0000 0001 +const TEST_STRUCTS = 2; // 0000 0010 +const TEST_CONTAINERS = 4; // 0000 0100 +const TEST_EXCEPTIONS = 8; // 0000 1000 +const TEST_UNKNOWN = 64; // 0100 0000 (Failed to prepare environemt etc.) +const TEST_TIMEOUT = 128; // 1000 0000 +const TEST_NOTUSED = 48; // 0011 0000 (reserved bits) + +typedef Future FutureFunction(); + +class TTest { + final int errorCode; + final String name; + final FutureFunction func; + + TTest(this.errorCode, this.name, this.func); +} + +class TTestError extends Error { + final actual; + final expected; + + TTestError(this.actual, this.expected); + + String toString() => '$actual != $expected'; +} + +List _tests; +ThriftTestClient client; +bool verbose; + +/// Adapted from TestClient.php +main(List args) async { + ArgResults results = _parseArgs(args); + + if (results == null) { + exit(TEST_UNKNOWN); + } + + verbose = results['verbose'] == true; + + await _initTestClient( + host: results['host'], + port: int.parse(results['port']), + transportType: results['transport'], + protocolType: results['protocol']).catchError((e) { + stdout.writeln('Error:'); + stdout.writeln('$e'); + if (e is Error) { + stdout.writeln('${e.stackTrace}'); + } + exit(TEST_UNKNOWN); + }); + + // run tests + _tests = _createTests(); + + int result = 0; + + for (TTest test in _tests) { + if (verbose) stdout.write('${test.name}... '); + try { + await test.func(); + if (verbose) stdout.writeln('success!'); + } catch (e) { + if (verbose) stdout.writeln('$e'); + result = result | test.errorCode; + } + } + + exit(result); +} + +ArgResults _parseArgs(List args) { + var parser = new ArgParser(); + parser.addOption('host', defaultsTo: 'localhost', help: 'The server host'); + parser.addOption('port', defaultsTo: '9090', help: 'The port to connect to'); + parser.addOption('transport', + defaultsTo: 'buffered', + allowed: ['buffered', 'framed', 'http'], + help: 'The transport name', + allowedHelp: { + 'buffered': 'TBufferedTransport', + 'framed': 'TFramedTransport' + }); + parser.addOption('protocol', + defaultsTo: 'binary', + allowed: ['binary', 'compact', 'json'], + help: 'The protocol name', + allowedHelp: { + 'binary': 'TBinaryProtocol', + 'compact': 'TCompactProtocol', + 'json': 'TJsonProtocol' + }); + parser.addFlag('verbose', defaultsTo: false); + + ArgResults results; + try { + results = parser.parse(args); + } catch (e) { + stdout.writeln('$e\n'); + } + + if (results == null) stdout.write(parser.usage); + + return results; +} + +TProtocolFactory getProtocolFactory(String protocolType) { + if (protocolType == 'binary') { + return new TBinaryProtocolFactory(); + } else if (protocolType == 'compact') { + return new TCompactProtocolFactory(); + } else if (protocolType == 'json') { + return new TJsonProtocolFactory(); + } + + throw new ArgumentError.value(protocolType); +} + +Future _initTestClient( + {String host, int port, String transportType, String protocolType}) async { + TTransport transport; + var protocolFactory = getProtocolFactory(protocolType); + + if (transportType == 'http') { + var httpClient = new http.IOClient(); + var uri = Uri.parse('http://$host:$port'); + var config = new THttpConfig(uri, {}); + transport = new THttpClientTransport(httpClient, config); + } else { + var socket = await Socket.connect(host, port); + transport = new TClientSocketTransport(new TTcpSocket(socket)); + if (transportType == 'framed') { + transport = new TFramedTransport(transport); + } + } + + var protocol = protocolFactory.getProtocol(transport); + client = new ThriftTestClient(protocol); + + await transport.open(); +} + +List _createTests() { + List tests = []; + + var xtruct = new Xtruct() + ..string_thing = 'Zero' + ..byte_thing = 1 + ..i32_thing = -3 + ..i64_thing = -5; + + tests.add(new TTest(TEST_BASETYPES, 'testVoid', () async { + await client.testVoid(); + })); + + tests.add(new TTest(TEST_BASETYPES, 'testString', () async { + var input = 'Test'; + var result = await client.testString(input); + if (result != input) throw new TTestError(result, input); + })); + + tests.add(new TTest(TEST_BASETYPES, 'testBool', () async { + var input = true; + var result = await client.testBool(input); + if (result != input) throw new TTestError(result, input); + })); + + tests.add(new TTest(TEST_BASETYPES, 'testByte', () async { + var input = 64; + var result = await client.testByte(input); + if (result != input) throw new TTestError(result, input); + })); + + tests.add(new TTest(TEST_BASETYPES, 'testI32', () async { + var input = 2147483647; + var result = await client.testI32(input); + if (result != input) throw new TTestError(result, input); + })); + + tests.add(new TTest(TEST_BASETYPES, 'testI64', () async { + var input = 9223372036854775807; + var result = await client.testI64(input); + if (result != input) throw new TTestError(result, input); + })); + + tests.add(new TTest(TEST_BASETYPES, 'testDouble', () async { + var input = 3.1415926; + var result = await client.testDouble(input); + if (result != input) throw new TTestError(result, input); + })); + + tests.add(new TTest(TEST_BASETYPES, 'testBinary', () async { + var utf8Codec = const Utf8Codec(); + var input = utf8Codec.encode('foo'); + var result = await client.testBinary(input); + var equality = const ListEquality(); + if (!equality.equals(result, input)) throw new TTestError(result, input); + })); + + tests.add(new TTest(TEST_CONTAINERS, 'testStruct', () async { + var result = await client.testStruct(xtruct); + if ('$result' != '$xtruct') throw new TTestError(result, xtruct); + })); + + tests.add(new TTest(TEST_CONTAINERS, 'testNest', () async { + var input = new Xtruct2() + ..byte_thing = 1 + ..struct_thing = xtruct + ..i32_thing = -3; + + var result = await client.testNest(input); + if ('$result' != '$input') throw new TTestError(result, input); + })); + + tests.add(new TTest(TEST_CONTAINERS, 'testMap', () async { + Map input = {1: -10, 2: -9, 3: -8, 4: -7, 5: -6}; + + var result = await client.testMap(input); + var equality = const MapEquality(); + if (!equality.equals(result, input)) throw new TTestError(result, input); + })); + + tests.add(new TTest(TEST_CONTAINERS, 'testSet', () async { + var input = new Set.from([-2, -1, 0, 1, 2]); + var result = await client.testSet(input); + var equality = const SetEquality(); + if (!equality.equals(result, input)) throw new TTestError(result, input); + })); + + tests.add(new TTest(TEST_CONTAINERS, 'testList', () async { + var input = [-2, -1, 0, 1, 2]; + var result = await client.testList(input); + var equality = const ListEquality(); + if (!equality.equals(result, input)) throw new TTestError(result, input); + })); + + tests.add(new TTest(TEST_CONTAINERS, 'testEnum', () async { + await _testEnum(Numberz.ONE); + await _testEnum(Numberz.TWO); + await _testEnum(Numberz.THREE); + await _testEnum(Numberz.FIVE); + await _testEnum(Numberz.EIGHT); + })); + + tests.add(new TTest(TEST_BASETYPES, 'testTypedef', () async { + var input = 309858235082523; + var result = await client.testTypedef(input); + if (result != input) throw new TTestError(result, input); + })); + + tests.add(new TTest(TEST_CONTAINERS, 'testMapMap', () async { + Map> result = await client.testMapMap(1); + if (result.isEmpty || result[result.keys.first].isEmpty) { + throw new TTestError(result, 'Map>'); + } + })); + + tests.add(new TTest(TEST_CONTAINERS, 'testInsanity', () async { + var input = new Insanity(); + input.userMap = {Numberz.FIVE: 5000}; + input.xtructs = [xtruct]; + + Map> result = await client.testInsanity(input); + if (result.isEmpty || result[result.keys.first].isEmpty) { + throw new TTestError(result, 'Map>'); + } + })); + + tests.add(new TTest(TEST_CONTAINERS, 'testMulti', () async { + var input = new Xtruct() + ..string_thing = 'Hello2' + ..byte_thing = 123 + ..i32_thing = 456 + ..i64_thing = 789; + + var result = await client.testMulti(input.byte_thing, input.i32_thing, + input.i64_thing, {1: 'one'}, Numberz.EIGHT, 5678); + if ('$result' != '$input') throw new TTestError(result, input); + })); + + tests.add(new TTest(TEST_EXCEPTIONS, 'testException', () async { + try { + await client.testException('Xception'); + } on Xception catch (_) { + return; + } + + throw new TTestError(null, 'Xception'); + })); + + tests.add(new TTest(TEST_EXCEPTIONS, 'testMultiException', () async { + try { + await client.testMultiException('Xception2', 'foo'); + } on Xception2 catch (_) { + return; + } + + throw new TTestError(null, 'Xception2'); + })); + + return tests; +} + +Future _testEnum(int input) async { + var result = await client.testEnum(input); + if (result != input) throw new TTestError(result, input); +} diff --git a/test/dart/test_client/pubspec.yaml b/test/dart/test_client/pubspec.yaml new file mode 100644 index 0000000..e386c0e --- /dev/null +++ b/test/dart/test_client/pubspec.yaml @@ -0,0 +1,36 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# 'License'); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: thrift_test_client +version: 0.11.0 +description: A client integration test for the Dart Thrift library +author: Apache Thrift Developers +homepage: http://thrift.apache.org + +environment: + sdk: ">=1.13.0 <2.0.0" + +dependencies: + args: ^0.13.0 + http: ^0.11.0 + thrift: + path: ../../../lib/dart + thrift_test: + path: ../gen-dart/thrift_test + +dev_dependencies: + test: "^0.12.0" diff --git a/test/erl/Makefile b/test/erl/Makefile new file mode 100644 index 0000000..32ed61f --- /dev/null +++ b/test/erl/Makefile @@ -0,0 +1,638 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# test/erl/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/thrift +pkgincludedir = $(includedir)/thrift +pkglibdir = $(libdir)/thrift +pkglibexecdir = $(libexecdir)/thrift +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-pc-linux-gnu +host_triplet = x86_64-pc-linux-gnu +subdir = test/erl +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_$(V)) +am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15 +ALLOCA = +AMTAR = $${TAR-tar} +AM_DEFAULT_VERBOSITY = 1 +ANT = /usr/bin/ant +ANT_FLAGS = +AR = ar +AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf +AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader +AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15 +AWK = gawk +BISON = bison +BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a +BOOST_CPPFLAGS = -I/usr/include +BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a +BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu +BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu +BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a +BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a +BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a +BUNDLER = /usr/bin/bundle +CABAL = /usr/bin/cabal +CABAL_CONFIGURE_FLAGS = +CARGO = /usr/bin/cargo +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 +CLASSPATH = +CPP = gcc -E +CPPFLAGS = +CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \; +CXX = g++ -std=c++11 +CXXCPP = g++ -E -std=c++11 +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -g -O2 +CYGPATH_W = echo +DART = /usr/lib/dart/bin/dart +DARTPUB = /usr/lib/dart/bin/pub +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +DLLTOOL = false +DMD = dmd +DMD_LIBEVENT_FLAGS = +DMD_OF_DIRSEP = / +DMD_OPENSSL_FLAGS = +DOTNETCORE = /usr/bin/dotnet +DOTNETCORE_VERSION = 2.0.3 +DSYMUTIL = +DUMPBIN = +D_EVENT_LIB_NAME = libthriftd-event.a +D_IMPORT_PREFIX = ${prefix}/include/d2 +D_LIB_NAME = libthriftd.a +D_SSL_LIB_NAME = libthriftd-ssl.a +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +ENABLE_COVERAGE = 2 +ERL = /usr/bin/erl +ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib +ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0 +ERLANG_LIB_DIR = /usr/lib/erlang/lib +ERLC = /usr/bin/erlc +ERLCFLAGS = +EXEEXT = +FGREP = /bin/grep -F +GCOV_CFLAGS = +GCOV_CXXFLAGS = +GCOV_LDFLAGS = +GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GLIB_LIBS = -lglib-2.0 +GO = /usr/bin/go +GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0 +GREP = /bin/grep +HAVE_CXX11 = 1 +HAXE = /usr/bin/haxe +HAXE_VERSION = 3.2.1 +INSTALL = /usr/bin/install -c +INSTALLDIRS = vendor +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +JAVA_PREFIX = /usr/local/lib +LD = /usr/bin/ld -m elf_x86_64 +LDFLAGS = +LEX = flex +LEXLIB = -lfl +LEX_OUTPUT_ROOT = lex.yy +LIBEVENT_CPPFLAGS = +LIBEVENT_LDFLAGS = +LIBEVENT_LIBS = -levent +LIBOBJS = +LIBS = -lrt -lpthread +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LIPO = +LN_S = ln -s +LTLIBOBJS = +LT_SYS_LIBRARY_PATH = +LUA = /usr/bin/lua5.3 +LUA_EXEC_PREFIX = ${exec_prefix} +LUA_INCLUDE = -I/usr/include/lua5.3 +LUA_LIB = -llua5.3 -ldl +LUA_PLATFORM = unknown +LUA_PREFIX = ${prefix} +LUA_SHORT_VERSION = 53 +LUA_VERSION = 5.3 +MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo +MANIFEST_TOOL = : +MAYBE_CPP = cpp +MAYBE_CSHARP = csharp +MAYBE_C_GLIB = c_glib +MAYBE_D = +MAYBE_DART = dart +MAYBE_DOTNETCORE = netcore +MAYBE_ERLANG = erl +MAYBE_GO = go +MAYBE_HASKELL = hs +MAYBE_JAVA = java +MAYBE_LUA = lua +MAYBE_NODEJS = nodejs +MAYBE_PERL = perl +MAYBE_PHP = php +MAYBE_PY3 = py3 +MAYBE_PYTHON = py +MAYBE_RS = rs +MAYBE_RUBY = rb +MCS = /usr/bin/mcs +MKDIR_P = /bin/mkdir -p +MONO_CFLAGS = +MONO_LIBS = +NM = /usr/bin/nm -B +NMEDIT = +NODEJS = /usr/bin/nodejs +NPM = /usr/bin/npm +OBJDUMP = objdump +OBJEXT = o +OPENSSL_INCLUDES = +OPENSSL_LDFLAGS = +OPENSSL_LIBS = -lssl -lcrypto +OTOOL = +OTOOL64 = +PACKAGE = thrift +PACKAGE_BUGREPORT = +PACKAGE_NAME = thrift +PACKAGE_STRING = thrift 0.11.0 +PACKAGE_TARNAME = thrift +PACKAGE_URL = +PACKAGE_VERSION = 0.11.0 +PATH_SEPARATOR = : +PERL = /usr/bin/perl +PERL_PREFIX = /usr/local +PHP = /usr/bin/php +PHPUNIT = /usr/bin/phpunit +PHP_CONFIG = /usr/bin/php-config +PHP_CONFIG_PREFIX = /etc/php.d +PHP_PREFIX = /usr/lib/php +PKG_CONFIG = /usr/bin/pkg-config +PKG_CONFIG_LIBDIR = +PKG_CONFIG_PATH = +PYTHON = /usr/bin/python +PYTHON3 = /usr/bin/python3 +PYTHON_EXEC_PREFIX = ${exec_prefix} +PYTHON_PLATFORM = linux2 +PYTHON_PREFIX = ${prefix} +PYTHON_VERSION = 2.7 +PY_PREFIX = /usr +QT5_CFLAGS = +QT5_LIBS = +QT5_MOC = +QT_CFLAGS = +QT_LIBS = +QT_MOC = +RANLIB = ranlib +REBAR = /usr/bin/rebar +RUBY = /usr/bin/ruby +RUBY_PREFIX = +RUNHASKELL = /usr/bin/runhaskell +RUSTC = /usr/bin/rustc +SED = /bin/sed +SET_MAKE = +SHELL = /bin/bash +STRIP = strip +THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift +TRIAL = /usr/bin/trial +VERSION = 0.11.0 +YACC = bison -y +YFLAGS = +ZLIB_CPPFLAGS = +ZLIB_LDFLAGS = +ZLIB_LIBS = -lz +abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/test/erl +abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/test/erl +abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift +abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift +ac_ct_AR = ar +ac_ct_CC = gcc +ac_ct_CXX = g++ +ac_ct_DUMPBIN = +am__include = include +am__leading_dot = . +am__quote = +am__tar = tar --format=ustar -chf - "$$tardir" +am__untar = tar -xf - +bindir = ${exec_prefix}/bin +build = x86_64-pc-linux-gnu +build_alias = +build_cpu = x86_64 +build_os = linux-gnu +build_vendor = pc +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +golang_version = 1.6.2 +have_prog_bison = yes +host = x86_64-pc-linux-gnu +host_alias = +host_cpu = x86_64 +host_os = linux-gnu +host_vendor = pc +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +luadir = ${prefix}/share/lua/5.3 +luaexecdir = ${exec_prefix}/lib/lua/5.3 +mandir = ${datarootdir}/man +mkdir_p = $(MKDIR_P) +oldincludedir = /usr/include +pdfdir = ${docdir} +pkgluadir = ${luadir}/thrift +pkgluaexecdir = ${luaexecdir}/thrift +pkgpyexecdir = ${pyexecdir}/thrift +pkgpythondir = ${pythondir}/thrift +prefix = /usr/local +program_transform_name = s,x,x, +psdir = ${docdir} +pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages +pythondir = ${prefix}/lib/python2.7/dist-packages +runstatedir = ${localstatedir}/run +rustc_version = rustc 1.17.0 +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +subdirs = lib/php/src/ext/thrift_protocol +sysconfdir = ${prefix}/etc +target_alias = +top_build_prefix = ../../ +top_builddir = ../.. +top_srcdir = ../.. +THRIFT_FILES = $(wildcard ../*.thrift) +ERL_FLAG = erl +#ERL_FLAG = erl:otp16 +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/erl/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/erl/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + +# make sure ThriftTest.thrift is generated last to prevent conflicts with other *.thrift files +.generated: $(THRIFT_FILES) + for f in $(THRIFT_FILES) ; do \ + $(THRIFT) --gen $(ERL_FLAG) -o src $$f ; \ + done ; \ + $(THRIFT) --gen $(ERL_FLAG) -o src ../ThriftTest.thrift + touch .generated + +precross: .generated + $(REBAR) compile + +clean: + rm -f .generated + rm -rf src/gen-erl + $(REBAR) clean + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/erl/Makefile.am b/test/erl/Makefile.am new file mode 100644 index 0000000..ff25e89 --- /dev/null +++ b/test/erl/Makefile.am @@ -0,0 +1,41 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +THRIFT_FILES = $(wildcard ../*.thrift) + +if ERLANG_OTP16 +ERL_FLAG = erl:otp16 +else +ERL_FLAG = erl +endif +# make sure ThriftTest.thrift is generated last to prevent conflicts with other *.thrift files +.generated: $(THRIFT_FILES) + for f in $(THRIFT_FILES) ; do \ + $(THRIFT) --gen $(ERL_FLAG) -o src $$f ; \ + done ; \ + $(THRIFT) --gen $(ERL_FLAG) -o src ../ThriftTest.thrift + touch .generated + +precross: .generated + $(REBAR) compile + +clean: + rm -f .generated + rm -rf src/gen-erl + $(REBAR) clean diff --git a/test/erl/Makefile.in b/test/erl/Makefile.in new file mode 100644 index 0000000..15599e8 --- /dev/null +++ b/test/erl/Makefile.in @@ -0,0 +1,638 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = test/erl +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +THRIFT_FILES = $(wildcard ../*.thrift) +@ERLANG_OTP16_FALSE@ERL_FLAG = erl +@ERLANG_OTP16_TRUE@ERL_FLAG = erl:otp16 +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/erl/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/erl/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + +# make sure ThriftTest.thrift is generated last to prevent conflicts with other *.thrift files +.generated: $(THRIFT_FILES) + for f in $(THRIFT_FILES) ; do \ + $(THRIFT) --gen $(ERL_FLAG) -o src $$f ; \ + done ; \ + $(THRIFT) --gen $(ERL_FLAG) -o src ../ThriftTest.thrift + touch .generated + +precross: .generated + $(REBAR) compile + +clean: + rm -f .generated + rm -rf src/gen-erl + $(REBAR) clean + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/erl/rebar.config b/test/erl/rebar.config new file mode 100644 index 0000000..59a0788 --- /dev/null +++ b/test/erl/rebar.config @@ -0,0 +1,6 @@ +{sub_dirs, ["../../lib/erl"]}. + +{erl_opts, [ + debug_info, + {i, "../../lib/erl/include"} +]}. diff --git a/test/erl/src/test_client.erl b/test/erl/src/test_client.erl new file mode 100644 index 0000000..9bad592 --- /dev/null +++ b/test/erl/src/test_client.erl @@ -0,0 +1,174 @@ +%% +%% Licensed to the Apache Software Foundation (ASF) under one +%% or more contributor license agreements. See the NOTICE file +%% distributed with this work for additional information +%% regarding copyright ownership. The ASF licenses this file +%% to you under the Apache License, Version 2.0 (the +%% "License"); you may not use this file except in compliance +%% with the License. You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, +%% software distributed under the License is distributed on an +%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%% KIND, either express or implied. See the License for the +%% specific language governing permissions and limitations +%% under the License. +%% + +-module(test_client). + +-export([start/0, start/1]). + +-include("gen-erl/thrift_test_types.hrl"). + +-record(options, {port = 9090, + client_opts = []}). + +parse_args(Args) -> parse_args(Args, #options{}). +parse_args([], Opts) -> + Opts; +parse_args([Head | Rest], Opts) -> + NewOpts = + case Head of + "--port=" ++ Port -> + case string:to_integer(Port) of + {IntPort,_} when is_integer(IntPort) -> + Opts#options{port = IntPort}; + _Else -> + erlang:error({bad_arg, Head}) + end; + "--transport=" ++ Trans -> + % TODO: Enable Buffered and HTTP transport + case Trans of + "framed" -> + Opts#options{client_opts = [{framed, true} | Opts#options.client_opts]}; + _Else -> + Opts + end; + "--ssl" -> + ssl:start(), + SslOptions = + {ssloptions, [ + {cacertfile, "../keys/CA.pem"}, + {certfile, "../keys/client.pem"}, + {keyfile, "../keys/client.key"} + ]}, + Opts#options{client_opts = [{ssltransport, true} | [SslOptions | Opts#options.client_opts]]}; + "--protocol=" ++ Proto -> + Opts#options{client_opts = [{protocol, list_to_atom(Proto)}]}; + _Else -> + erlang:error({bad_arg, Head}) + end, + parse_args(Rest, NewOpts). + +start() -> start(init:get_plain_arguments()). +start(Args) -> + #options{port = Port, client_opts = ClientOpts} = parse_args(Args), + {ok, Client0} = thrift_client_util:new( + "127.0.0.1", Port, thrift_test_thrift, ClientOpts), + + DemoXtruct = #'thrift.test.Xtruct'{ + string_thing = <<"Zero">>, + byte_thing = 1, + i32_thing = 9128361, + i64_thing = 9223372036854775807}, + + DemoNest = #'thrift.test.Xtruct2'{ + byte_thing = 7, + struct_thing = DemoXtruct, + % Note that we don't set i32_thing, it will come back as undefined + % from the Python server, but 0 from the C++ server, since it is not + % optional + i32_thing = 2}, + + % Is it safe to match these things? + DemoDict = dict:from_list([ {Key, Key-10} || Key <- lists:seq(0,10) ]), + DemoSet = sets:from_list([ Key || Key <- lists:seq(-3,3) ]), + + DemoInsane = #'thrift.test.Insanity'{ + userMap = dict:from_list([{?THRIFT_TEST_NUMBERZ_FIVE, 5000}]), + xtructs = [#'thrift.test.Xtruct'{ string_thing = <<"Truck">>, byte_thing = 8, i32_thing = 8, i64_thing = 8}]}, + + error_logger:info_msg("testVoid"), + {Client01, {ok, ok}} = thrift_client:call(Client0, testVoid, []), + + error_logger:info_msg("testString"), + {Client02, {ok, <<"Test">>}} = thrift_client:call(Client01, testString, ["Test"]), + error_logger:info_msg("testString"), + {Client03, {ok, <<"Test">>}} = thrift_client:call(Client02, testString, [<<"Test">>]), + error_logger:info_msg("testByte"), + {Client04, {ok, 63}} = thrift_client:call(Client03, testByte, [63]), + error_logger:info_msg("testI32"), + {Client05, {ok, -1}} = thrift_client:call(Client04, testI32, [-1]), + error_logger:info_msg("testI32"), + {Client06, {ok, 0}} = thrift_client:call(Client05, testI32, [0]), + error_logger:info_msg("testI64"), + {Client07, {ok, -34359738368}} = thrift_client:call(Client06, testI64, [-34359738368]), + error_logger:info_msg("testDouble"), + {Client08, {ok, -5.2098523}} = thrift_client:call(Client07, testDouble, [-5.2098523]), + %% TODO: add testBinary() call + error_logger:info_msg("testStruct"), + {Client09, {ok, DemoXtruct}} = thrift_client:call(Client08, testStruct, [DemoXtruct]), + error_logger:info_msg("testNest"), + {Client10, {ok, DemoNest}} = thrift_client:call(Client09, testNest, [DemoNest]), + error_logger:info_msg("testMap"), + {Client11, {ok, DemoDict}} = thrift_client:call(Client10, testMap, [DemoDict]), + error_logger:info_msg("testSet"), + {Client12, {ok, DemoSet}} = thrift_client:call(Client11, testSet, [DemoSet]), + error_logger:info_msg("testList"), + {Client13, {ok, [-1,2,3]}} = thrift_client:call(Client12, testList, [[-1,2,3]]), + error_logger:info_msg("testEnum"), + {Client14, {ok, 1}} = thrift_client:call(Client13, testEnum, [?THRIFT_TEST_NUMBERZ_ONE]), + error_logger:info_msg("testTypedef"), + {Client15, {ok, 309858235082523}} = thrift_client:call(Client14, testTypedef, [309858235082523]), + error_logger:info_msg("testInsanity"), + {Client16, {ok, InsaneResult}} = thrift_client:call(Client15, testInsanity, [DemoInsane]), + io:format("~p~n", [InsaneResult]), + + {Client17, {ok, #'thrift.test.Xtruct'{string_thing = <<"Message">>}}} = + thrift_client:call(Client16, testMultiException, ["Safe", "Message"]), + + Client18 = + try + {ClientS1, Result1} = thrift_client:call(Client17, testMultiException, ["Xception", "Message"]), + io:format("Unexpected return! ~p~n", [Result1]), + ClientS1 + catch + throw:{ClientS2, {exception, ExnS1 = #'thrift.test.Xception'{}}} -> + #'thrift.test.Xception'{errorCode = 1001, message = <<"This is an Xception">>} = ExnS1, + ClientS2; + throw:{ClientS2, {exception, _ExnS1 = #'thrift.test.Xception2'{}}} -> + io:format("Wrong exception type!~n", []), + ClientS2 + end, + + Client19 = + try + {ClientS3, Result2} = thrift_client:call(Client18, testMultiException, ["Xception2", "Message"]), + io:format("Unexpected return! ~p~n", [Result2]), + ClientS3 + catch + throw:{ClientS4, {exception, _ExnS2 = #'thrift.test.Xception'{}}} -> + io:format("Wrong exception type!~n", []), + ClientS4; + throw:{ClientS4, {exception, ExnS2 = #'thrift.test.Xception2'{}}} -> + #'thrift.test.Xception2'{errorCode = 2002, + struct_thing = #'thrift.test.Xtruct'{ + string_thing = <<"This is an Xception2">>}} = ExnS2, + ClientS4 + end, + + %% Started = erlang:monotonic_time(milli_seconds), + {_, StartSec, StartUSec} = erlang:timestamp(), + error_logger:info_msg("testOneway"), + {Client20, {ok, ok}} = thrift_client:call(Client19, testOneway, [1]), + {_, EndSec, EndUSec} = erlang:timestamp(), + Elapsed = (EndSec - StartSec) * 1000 + (EndUSec - StartUSec) / 1000, + if + Elapsed > 1000 -> exit(1); + true -> true + end, + + thrift_client:close(Client20). diff --git a/test/erl/src/test_thrift_server.erl b/test/erl/src/test_thrift_server.erl new file mode 100644 index 0000000..dad8dec --- /dev/null +++ b/test/erl/src/test_thrift_server.erl @@ -0,0 +1,233 @@ +%% +%% Licensed to the Apache Software Foundation (ASF) under one +%% or more contributor license agreements. See the NOTICE file +%% distributed with this work for additional information +%% regarding copyright ownership. The ASF licenses this file +%% to you under the Apache License, Version 2.0 (the +%% "License"); you may not use this file except in compliance +%% with the License. You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, +%% software distributed under the License is distributed on an +%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%% KIND, either express or implied. See the License for the +%% specific language governing permissions and limitations +%% under the License. +%% + +-module(test_thrift_server). + +-export([start/0, start/1, start_link/2, handle_function/2]). + +-include("thrift_constants.hrl"). +-include("gen-erl/thrift_test_types.hrl"). + +-record(options, {port = 9090, + server_opts = []}). + +parse_args(Args) -> parse_args(Args, #options{}). +parse_args([], Opts) -> + Opts; +parse_args([Head | Rest], Opts) -> + NewOpts = + case Head of + "--port=" ++ Port -> + case string:to_integer(Port) of + {IntPort,_} when is_integer(IntPort) -> + Opts#options{port = IntPort}; + _Else -> + erlang:error({bad_arg, Head}) + end; + "--transport=" ++ Trans -> + case Trans of + "framed" -> + Opts#options{server_opts = [{framed, true} | Opts#options.server_opts]}; + _Else -> + Opts + end; + "--ssl" -> + ssl:start(), + SslOptions = + {ssloptions, [ + {certfile, "../keys/server.pem"} + ,{keyfile, "../keys/server.key"} + ]}, + Opts#options{server_opts = [{ssltransport, true} | [SslOptions | Opts#options.server_opts]]}; + "--protocol=" ++ Proto -> + Opts#options{server_opts = [{protocol, list_to_atom(Proto)} | Opts#options.server_opts]}; + _Else -> + erlang:error({bad_arg, Head}) + end, + parse_args(Rest, NewOpts). + +start() -> start(init:get_plain_arguments()). +start(Args) -> + #options{port = Port, server_opts = ServerOpts} = parse_args(Args), + spawn(fun() -> start_link(Port, ServerOpts), receive after infinity -> ok end end). + +start_link(Port, ServerOpts) -> + thrift_socket_server:start([{handler, ?MODULE}, + {service, thrift_test_thrift}, + {port, Port}] ++ + ServerOpts). + + +handle_function(testVoid, {}) -> + io:format("testVoid~n"), + ok; + +handle_function(testString, {S}) when is_binary(S) -> + io:format("testString: ~p~n", [S]), + {reply, S}; + +handle_function(testBool, {B}) when is_boolean(B) -> + io:format("testBool: ~p~n", [B]), + {reply, B}; + +handle_function(testByte, {I8}) when is_integer(I8) -> + io:format("testByte: ~p~n", [I8]), + {reply, I8}; + +handle_function(testI32, {I32}) when is_integer(I32) -> + io:format("testI32: ~p~n", [I32]), + {reply, I32}; + +handle_function(testI64, {I64}) when is_integer(I64) -> + io:format("testI64: ~p~n", [I64]), + {reply, I64}; + +handle_function(testDouble, {Double}) when is_float(Double) -> + io:format("testDouble: ~p~n", [Double]), + {reply, Double}; + +handle_function(testBinary, {S}) when is_binary(S) -> + io:format("testBinary: ~p~n", [S]), + {reply, S}; + +handle_function(testStruct, + {Struct = #'thrift.test.Xtruct'{string_thing = String, + byte_thing = Byte, + i32_thing = I32, + i64_thing = I64}}) +when is_binary(String), + is_integer(Byte), + is_integer(I32), + is_integer(I64) -> + io:format("testStruct: ~p~n", [Struct]), + {reply, Struct}; + +handle_function(testNest, + {Nest}) when is_record(Nest, 'thrift.test.Xtruct2'), + is_record(Nest#'thrift.test.Xtruct2'.struct_thing, 'thrift.test.Xtruct') -> + io:format("testNest: ~p~n", [Nest]), + {reply, Nest}; + +handle_function(testMap, {Map}) -> + io:format("testMap: ~p~n", [dict:to_list(Map)]), + {reply, Map}; + +handle_function(testStringMap, {Map}) -> + io:format("testStringMap: ~p~n", [dict:to_list(Map)]), + {reply, Map}; + +handle_function(testSet, {Set}) -> + true = sets:is_set(Set), + io:format("testSet: ~p~n", [sets:to_list(Set)]), + {reply, Set}; + +handle_function(testList, {List}) when is_list(List) -> + io:format("testList: ~p~n", [List]), + {reply, List}; + +handle_function(testEnum, {Enum}) when is_integer(Enum) -> + io:format("testEnum: ~p~n", [Enum]), + {reply, Enum}; + +handle_function(testTypedef, {UserID}) when is_integer(UserID) -> + io:format("testTypedef: ~p~n", [UserID]), + {reply, UserID}; + +handle_function(testMapMap, {Hello}) -> + io:format("testMapMap: ~p~n", [Hello]), + + PosList = [{I, I} || I <- lists:seq(1, 4)], + NegList = [{-I, -I} || I <- lists:seq(1, 4)], + + MapMap = dict:from_list([{4, dict:from_list(PosList)}, + {-4, dict:from_list(NegList)}]), + {reply, MapMap}; + +handle_function(testInsanity, {Insanity}) when is_record(Insanity, 'thrift.test.Insanity') -> + Hello = #'thrift.test.Xtruct'{string_thing = <<"Hello2">>, + byte_thing = 2, + i32_thing = 2, + i64_thing = 2}, + + Goodbye = #'thrift.test.Xtruct'{string_thing = <<"Goodbye4">>, + byte_thing = 4, + i32_thing = 4, + i64_thing = 4}, + Crazy = #'thrift.test.Insanity'{ + userMap = dict:from_list([{?THRIFT_TEST_NUMBERZ_EIGHT, 8}]), + xtructs = [Goodbye] + }, + + Looney = #'thrift.test.Insanity'{}, + + FirstMap = dict:from_list([{?THRIFT_TEST_NUMBERZ_TWO, Insanity}, + {?THRIFT_TEST_NUMBERZ_THREE, Insanity}]), + + SecondMap = dict:from_list([{?THRIFT_TEST_NUMBERZ_SIX, Looney}]), + + Insane = dict:from_list([{1, FirstMap}, + {2, SecondMap}]), + + io:format("Return = ~p~n", [Insane]), + + {reply, Insane}; + +handle_function(testMulti, Args = {Arg0, Arg1, Arg2, _Arg3, Arg4, Arg5}) + when is_integer(Arg0), + is_integer(Arg1), + is_integer(Arg2), + is_integer(Arg4), + is_integer(Arg5) -> + + io:format("testMulti(~p)~n", [Args]), + {reply, #'thrift.test.Xtruct'{string_thing = <<"Hello2">>, + byte_thing = Arg0, + i32_thing = Arg1, + i64_thing = Arg2}}; + +handle_function(testException, {String}) when is_binary(String) -> + io:format("testException(~p)~n", [String]), + case String of + <<"Xception">> -> + throw(#'thrift.test.Xception'{errorCode = 1001, + message = String}); + <<"TException">> -> + throw({?TApplicationException_Structure}); + _ -> + ok + end; + +handle_function(testMultiException, {Arg0, Arg1}) -> + io:format("testMultiException(~p, ~p)~n", [Arg0, Arg1]), + case Arg0 of + <<"Xception">> -> + throw(#'thrift.test.Xception'{errorCode = 1001, + message = <<"This is an Xception">>}); + <<"Xception2">> -> + throw(#'thrift.test.Xception2'{errorCode = 2002, + struct_thing = + #'thrift.test.Xtruct'{string_thing = <<"This is an Xception2">>}}); + _ -> + {reply, #'thrift.test.Xtruct'{string_thing = Arg1}} + end; + +handle_function(testOneway, {Seconds}) -> + io:format("testOneway: ~p~n", [Seconds]), + timer:sleep(1000 * Seconds), + ok. diff --git a/test/erl/src/thrift_test.app.src b/test/erl/src/thrift_test.app.src new file mode 100644 index 0000000..b552970 --- /dev/null +++ b/test/erl/src/thrift_test.app.src @@ -0,0 +1,54 @@ +%% +%% Licensed to the Apache Software Foundation (ASF) under one +%% or more contributor license agreements. See the NOTICE file +%% distributed with this work for additional information +%% regarding copyright ownership. The ASF licenses this file +%% to you under the Apache License, Version 2.0 (the +%% "License"); you may not use this file except in compliance +%% with the License. You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, +%% software distributed under the License is distributed on an +%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%% KIND, either express or implied. See the License for the +%% specific language governing permissions and limitations +%% under the License. +%% +%%% -*- mode:erlang -*- +{application, thrift_test, [ + % A quick description of the application. + {description, "Thrift cross language test"}, + + % The version of the applicaton + {vsn, "0.11.0"}, + + % All modules used by the application. + {modules, [ + test_client, + test_thrift_server + ]}, + + % All of the registered names the application uses. This can be ignored. + {registered, []}, + + % Applications that are to be started prior to this one. This can be ignored + % leave it alone unless you understand it well and let the .rel files in + % your release handle this. + {applications, [kernel, stdlib]}, + + % OTP application loader will load, but not start, included apps. Again + % this can be ignored as well. To load but not start an application it + % is easier to include it in the .rel file followed by the atom 'none' + {included_applications, []}, + + % configuration parameters similar to those in the config file specified + % on the command line. can be fetched with gas:get_env + {env, [ + % If an error/crash occurs during processing of a function, + % should the TApplicationException serialized back to the client + % include the erlang backtrace? + {exceptions_include_traces, true} + ]} +]}. diff --git a/test/features/Makefile.am b/test/features/Makefile.am new file mode 100644 index 0000000..337d789 --- /dev/null +++ b/test/features/Makefile.am @@ -0,0 +1,30 @@ +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +EXTRA_DIST = \ + local_thrift \ + index.html \ + container_limit.py \ + index.html \ + known_failures_Linux.json \ + Makefile.am \ + nosslv3.sh \ + string_limit.py \ + tests.json \ + theader_binary.py \ + setup.cfg \ + tls.sh \ + util.py diff --git a/test/features/Makefile.in b/test/features/Makefile.in new file mode 100644 index 0000000..959b99f --- /dev/null +++ b/test/features/Makefile.in @@ -0,0 +1,634 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = test/features +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + local_thrift \ + index.html \ + container_limit.py \ + index.html \ + known_failures_Linux.json \ + Makefile.am \ + nosslv3.sh \ + string_limit.py \ + tests.json \ + theader_binary.py \ + setup.cfg \ + tls.sh \ + util.py + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/features/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/features/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/features/container_limit.py b/test/features/container_limit.py new file mode 100644 index 0000000..88f8487 --- /dev/null +++ b/test/features/container_limit.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python + +import argparse +import sys + +from util import add_common_args, init_protocol +from local_thrift import thrift # noqa +from thrift.Thrift import TMessageType, TType + + +# TODO: generate from ThriftTest.thrift +def test_list(proto, value): + method_name = 'testList' + ttype = TType.LIST + etype = TType.I32 + proto.writeMessageBegin(method_name, TMessageType.CALL, 3) + proto.writeStructBegin(method_name + '_args') + proto.writeFieldBegin('thing', ttype, 1) + proto.writeListBegin(etype, len(value)) + for e in value: + proto.writeI32(e) + proto.writeListEnd() + proto.writeFieldEnd() + proto.writeFieldStop() + proto.writeStructEnd() + proto.writeMessageEnd() + proto.trans.flush() + + _, mtype, _ = proto.readMessageBegin() + assert mtype == TMessageType.REPLY + proto.readStructBegin() + _, ftype, fid = proto.readFieldBegin() + assert fid == 0 + assert ftype == ttype + etype2, len2 = proto.readListBegin() + assert etype == etype2 + assert len2 == len(value) + for i in range(len2): + v = proto.readI32() + assert v == value[i] + proto.readListEnd() + proto.readFieldEnd() + _, ftype, _ = proto.readFieldBegin() + assert ftype == TType.STOP + proto.readStructEnd() + proto.readMessageEnd() + + +def main(argv): + p = argparse.ArgumentParser() + add_common_args(p) + p.add_argument('--limit', type=int) + args = p.parse_args() + proto = init_protocol(args) + # TODO: test set and map + test_list(proto, list(range(args.limit - 1))) + test_list(proto, list(range(args.limit - 1))) + print('[OK]: limit - 1') + test_list(proto, list(range(args.limit))) + test_list(proto, list(range(args.limit))) + print('[OK]: just limit') + try: + test_list(proto, list(range(args.limit + 1))) + except Exception: + print('[OK]: limit + 1') + else: + print('[ERROR]: limit + 1') + assert False + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/test/features/index.html b/test/features/index.html new file mode 100644 index 0000000..34a0010 --- /dev/null +++ b/test/features/index.html @@ -0,0 +1,51 @@ + + + + + +Apache Thrift - integration test suite + + + + + + +

Apache Thrift - integration test suite: Results

+ + + + + + + + + + + +
ServerClientProtocolTransportResult (log)Expected
+

Test Information

+

+
+browse raw log files
+
+
+
diff --git a/test/features/known_failures_Linux.json b/test/features/known_failures_Linux.json
new file mode 100644
index 0000000..f96356d
--- /dev/null
+++ b/test/features/known_failures_Linux.json
@@ -0,0 +1,46 @@
+[
+  "c_glib-limit_container_length_binary_buffered-ip",
+  "c_glib-limit_string_length_binary_buffered-ip",
+  "cpp-theader_framed_binary_multih-header_buffered-ip",
+  "cpp-theader_framed_compact_multih-header_buffered-ip",
+  "cpp-theader_unframed_binary_multih-header_buffered-ip",
+  "cpp-theader_unframed_compact_multih-header_buffered-ip",
+  "csharp-limit_container_length_binary_buffered-ip",
+  "csharp-limit_container_length_compact_buffered-ip",
+  "csharp-limit_string_length_binary_buffered-ip",
+  "csharp-limit_string_length_compact_buffered-ip",
+  "d-limit_container_length_binary_buffered-ip",
+  "d-limit_container_length_compact_buffered-ip",
+  "d-limit_string_length_binary_buffered-ip",
+  "d-limit_string_length_compact_buffered-ip",
+  "erl-limit_container_length_binary_buffered-ip",
+  "erl-limit_container_length_compact_buffered-ip",
+  "erl-limit_string_length_binary_buffered-ip",
+  "erl-limit_string_length_compact_buffered-ip",
+  "go-limit_container_length_binary_buffered-ip",
+  "go-limit_container_length_compact_buffered-ip",
+  "go-limit_string_length_binary_buffered-ip",
+  "go-limit_string_length_compact_buffered-ip",
+  "hs-limit_container_length_binary_buffered-ip",
+  "hs-limit_container_length_compact_buffered-ip",
+  "hs-limit_string_length_binary_buffered-ip",
+  "hs-limit_string_length_compact_buffered-ip",
+  "nodejs-limit_container_length_binary_buffered-ip",
+  "nodejs-limit_container_length_compact_buffered-ip",
+  "nodejs-limit_string_length_binary_buffered-ip",
+  "nodejs-limit_string_length_compact_buffered-ip",
+  "perl-limit_container_length_binary_buffered-ip",
+  "perl-limit_string_length_binary_buffered-ip",
+  "rb-limit_container_length_accel-binary_buffered-ip",
+  "rb-limit_container_length_binary_buffered-ip",
+  "rb-limit_container_length_compact_buffered-ip",
+  "rb-limit_string_length_accel-binary_buffered-ip",
+  "rb-limit_string_length_binary_buffered-ip",
+  "rb-limit_string_length_compact_buffered-ip",
+  "rs-limit_container_length_binary_buffered-ip",
+  "rs-limit_container_length_compact_buffered-ip",
+  "rs-limit_container_length_multic-compact_buffered-ip",
+  "rs-limit_string_length_binary_buffered-ip",
+  "rs-limit_string_length_compact_buffered-ip",
+  "rs-limit_string_length_multic-compact_buffered-ip"
+]
\ No newline at end of file
diff --git a/test/features/local_thrift/__init__.py b/test/features/local_thrift/__init__.py
new file mode 100644
index 0000000..c85cebe
--- /dev/null
+++ b/test/features/local_thrift/__init__.py
@@ -0,0 +1,32 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import glob
+import os
+import sys
+
+_SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__))
+_ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(_SCRIPT_DIR)))
+_LIBDIR = os.path.join(_ROOT_DIR, 'lib', 'py', 'build', 'lib.*')
+
+for libpath in glob.glob(_LIBDIR):
+    if libpath.endswith('-%d.%d' % (sys.version_info[0], sys.version_info[1])):
+        sys.path.insert(0, libpath)
+        thrift = __import__('thrift')
+        break
diff --git a/test/features/nosslv3.sh b/test/features/nosslv3.sh
new file mode 100755
index 0000000..e550d51
--- /dev/null
+++ b/test/features/nosslv3.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+#
+# Checks to make sure SSLv3 is not allowed by a server.
+#
+
+THRIFTHOST=localhost
+THRIFTPORT=9090
+
+while [[ $# -ge 1 ]]; do
+  arg="$1"
+  argIN=(${arg//=/ })
+
+  case ${argIN[0]} in
+    -h|--host)
+    THRIFTHOST=${argIN[1]}
+    shift # past argument
+    ;;
+    -p|--port)
+    THRIFTPORT=${argIN[1]}
+    shift # past argument
+    ;;
+    *)
+          # unknown option ignored
+    ;;
+  esac
+
+  shift   # past argument or value
+done
+
+function nosslv3
+{
+  local nego
+  local negodenied
+
+  # echo "openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -ssl3 2>&1 < /dev/null"
+  nego=$(openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -ssl3 2>&1 < /dev/null)
+  negodenied=$?
+
+  if [[ $negodenied -ne 0 ]]; then
+    echo "[pass] SSLv3 negotiation disabled"
+    echo $nego
+    return 0
+  fi
+
+  echo "[fail] SSLv3 negotiation enabled!  stdout:"
+  echo $nego
+  return 1
+}
+
+nosslv3
+exit $?
diff --git a/test/features/setup.cfg b/test/features/setup.cfg
new file mode 100644
index 0000000..7da1f96
--- /dev/null
+++ b/test/features/setup.cfg
@@ -0,0 +1,2 @@
+[flake8]
+max-line-length = 100
diff --git a/test/features/string_limit.py b/test/features/string_limit.py
new file mode 100644
index 0000000..b8991d6
--- /dev/null
+++ b/test/features/string_limit.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+
+import argparse
+import sys
+
+from util import add_common_args, init_protocol
+from local_thrift import thrift  # noqa
+from thrift.Thrift import TMessageType, TType
+
+
+# TODO: generate from ThriftTest.thrift
+def test_string(proto, value):
+    method_name = 'testString'
+    ttype = TType.STRING
+    proto.writeMessageBegin(method_name, TMessageType.CALL, 3)
+    proto.writeStructBegin(method_name + '_args')
+    proto.writeFieldBegin('thing', ttype, 1)
+    proto.writeString(value)
+    proto.writeFieldEnd()
+    proto.writeFieldStop()
+    proto.writeStructEnd()
+    proto.writeMessageEnd()
+    proto.trans.flush()
+
+    _, mtype, _ = proto.readMessageBegin()
+    assert mtype == TMessageType.REPLY
+    proto.readStructBegin()
+    _, ftype, fid = proto.readFieldBegin()
+    assert fid == 0
+    assert ftype == ttype
+    result = proto.readString()
+    proto.readFieldEnd()
+    _, ftype, _ = proto.readFieldBegin()
+    assert ftype == TType.STOP
+    proto.readStructEnd()
+    proto.readMessageEnd()
+    assert value == result
+
+
+def main(argv):
+    p = argparse.ArgumentParser()
+    add_common_args(p)
+    p.add_argument('--limit', type=int)
+    args = p.parse_args()
+    proto = init_protocol(args)
+    test_string(proto, 'a' * (args.limit - 1))
+    test_string(proto, 'a' * (args.limit - 1))
+    print('[OK]: limit - 1')
+    test_string(proto, 'a' * args.limit)
+    test_string(proto, 'a' * args.limit)
+    print('[OK]: just limit')
+    try:
+        test_string(proto, 'a' * (args.limit + 1))
+    except Exception:
+        print('[OK]: limit + 1')
+    else:
+        print('[ERROR]: limit + 1')
+        assert False
+
+
+if __name__ == '__main__':
+    main(sys.argv[1:])
diff --git a/test/features/tests.json b/test/features/tests.json
new file mode 100644
index 0000000..41e07d7
--- /dev/null
+++ b/test/features/tests.json
@@ -0,0 +1,114 @@
+[
+  {
+    "description": "THeader detects unframed binary wire format",
+    "name": "theader_unframed_binary",
+    "command": [
+      "python",
+      "theader_binary.py",
+      "--override-protocol=binary",
+      "--override-transport=buffered"
+    ],
+    "protocols": ["header"],
+    "transports": ["buffered"],
+    "sockets": ["ip"],
+    "workdir": "features"
+  },
+  {
+    "description": "THeader detects framed binary wire format",
+    "name": "theader_framed_binary",
+    "command": [
+      "python",
+      "theader_binary.py",
+      "--override-protocol=binary",
+      "--override-transport=framed"
+    ],
+    "protocols": ["header"],
+    "transports": ["buffered"],
+    "sockets": ["ip"],
+    "workdir": "features"
+  },
+  {
+    "description": "THeader detects unframed compact wire format",
+    "name": "theader_unframed_compact",
+    "command": [
+      "python",
+      "theader_binary.py",
+      "--override-protocol=compact",
+      "--override-transport=buffered"
+    ],
+    "protocols": ["header"],
+    "transports": ["buffered"],
+    "sockets": ["ip"],
+    "workdir": "features"
+  },
+  {
+    "description": "THeader detects framed compact wire format",
+    "name": "theader_framed_compact",
+    "command": [
+      "python",
+      "theader_binary.py",
+      "--override-protocol=compact",
+      "--override-transport=framed"
+    ],
+    "protocols": ["header"],
+    "transports": ["buffered"],
+    "sockets": ["ip"],
+    "workdir": "features"
+  },
+  {
+    "name": "limit_string_length",
+    "command": [
+      "python",
+      "string_limit.py",
+      "--limit=50"
+    ],
+    "remote_args": [
+      "--string-limit=50"
+    ],
+    "protocols": [
+      "compact"
+    ],
+    "transports": ["buffered"],
+    "sockets": ["ip"],
+    "workdir": "features"
+  },
+  {
+    "name": "limit_container_length",
+    "command": [
+      "python",
+      "container_limit.py",
+      "--limit=50"
+    ],
+    "remote_args": [
+      "--container-limit=50"
+    ],
+    "protocols": [
+      "compact"
+    ],
+    "transports": ["buffered"],
+    "sockets": ["ip"],
+    "workdir": "features"
+  },
+  {
+    "name": "nosslv3",
+    "comment": "check to make sure SSLv3 is not supported",
+    "command": [
+      "nosslv3.sh"
+    ],
+    "protocols": ["binary"],
+    "transports": ["buffered"],
+    "sockets": ["ip-ssl"],
+    "workdir": "features"
+  },
+  {
+    "name": "tls",
+    "comment": "check to make sure TLSv1.0 or later is supported",
+    "command": [
+      "tls.sh"
+    ],
+    "protocols": ["binary"],
+    "transports": ["buffered"],
+    "sockets": ["ip-ssl"],
+    "workdir": "features"
+  }
+]
diff --git a/test/features/theader_binary.py b/test/features/theader_binary.py
new file mode 100644
index 0000000..451399a
--- /dev/null
+++ b/test/features/theader_binary.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+
+import argparse
+import socket
+import sys
+
+from util import add_common_args
+from local_thrift import thrift  # noqa
+from thrift.Thrift import TMessageType, TType
+from thrift.transport.TSocket import TSocket
+from thrift.transport.TTransport import TBufferedTransport, TFramedTransport
+from thrift.protocol.TBinaryProtocol import TBinaryProtocol
+from thrift.protocol.TCompactProtocol import TCompactProtocol
+
+
+def test_void(proto):
+    proto.writeMessageBegin('testVoid', TMessageType.CALL, 3)
+    proto.writeStructBegin('testVoid_args')
+    proto.writeFieldStop()
+    proto.writeStructEnd()
+    proto.writeMessageEnd()
+    proto.trans.flush()
+
+    _, mtype, _ = proto.readMessageBegin()
+    assert mtype == TMessageType.REPLY
+    proto.readStructBegin()
+    _, ftype, _ = proto.readFieldBegin()
+    assert ftype == TType.STOP
+    proto.readStructEnd()
+    proto.readMessageEnd()
+
+
+# THeader stack should accept binary protocol with optionally framed transport
+def main(argv):
+    p = argparse.ArgumentParser()
+    add_common_args(p)
+    # Since THeaderTransport acts as framed transport when detected frame, we
+    # cannot use --transport=framed as it would result in 2 layered frames.
+    p.add_argument('--override-transport')
+    p.add_argument('--override-protocol')
+    args = p.parse_args()
+    assert args.protocol == 'header'
+    assert args.transport == 'buffered'
+    assert not args.ssl
+
+    sock = TSocket(args.host, args.port, socket_family=socket.AF_INET)
+    if not args.override_transport or args.override_transport == 'buffered':
+        trans = TBufferedTransport(sock)
+    elif args.override_transport == 'framed':
+        print('TFRAMED')
+        trans = TFramedTransport(sock)
+    else:
+        raise ValueError('invalid transport')
+    trans.open()
+
+    if not args.override_protocol or args.override_protocol == 'binary':
+        proto = TBinaryProtocol(trans)
+    elif args.override_protocol == 'compact':
+        proto = TCompactProtocol(trans)
+    else:
+        raise ValueError('invalid transport')
+
+    test_void(proto)
+    test_void(proto)
+
+    trans.close()
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
diff --git a/test/features/tls.sh b/test/features/tls.sh
new file mode 100755
index 0000000..dada6ab
--- /dev/null
+++ b/test/features/tls.sh
@@ -0,0 +1,71 @@
+#!/bin/bash
+
+#
+# Checks to make sure TLSv1.0 or later is allowed by a server.
+#
+
+THRIFTHOST=localhost
+THRIFTPORT=9090
+
+while [[ $# -ge 1 ]]; do
+  arg="$1"
+  argIN=(${arg//=/ })
+
+  case ${argIN[0]} in
+    -h|--host)
+    THRIFTHOST=${argIN[1]}
+    shift # past argument
+    ;;
+    -p|--port)
+    THRIFTPORT=${argIN[1]}
+    shift # past argument
+    ;;
+    *)
+          # unknown option ignored
+    ;;
+  esac
+
+  shift   # past argument or value
+done
+
+declare -A EXPECT_NEGOTIATE
+EXPECT_NEGOTIATE[tls1]=1
+EXPECT_NEGOTIATE[tls1_1]=1
+EXPECT_NEGOTIATE[tls1_2]=1
+
+failures=0
+
+function tls
+{
+  for PROTO in "${!EXPECT_NEGOTIATE[@]}"; do
+
+    local nego
+    local negodenied
+    local res
+
+    echo "openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -$PROTO 2>&1 < /dev/null"
+    nego=$(openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -$PROTO 2>&1 < /dev/null)
+    negodenied=$?
+    echo "result of command: $negodenied"
+
+    res="enabled"; if [[ ${EXPECT_NEGOTIATE[$PROTO]} -eq 0 ]]; then res="disabled"; fi
+
+    if [[ $negodenied -ne ${EXPECT_NEGOTIATE[$PROTO]} ]]; then
+      echo "$PROTO negotiation allowed"
+    else
+      echo "[warn] $PROTO negotiation did not work"
+      echo $nego
+      ((failures++))
+    fi
+  done
+}
+
+tls
+
+if [[ $failures -eq 3 ]]; then
+  echo "[fail] At least one of TLSv1.0, TLSv1.1, or TLSv1.2 needs to work, but does not"
+  exit $failures
+fi
+
+echo "[pass] At least one of TLSv1.0, TLSv1.1, or TLSv1.2 worked"
+exit 0
diff --git a/test/features/util.py b/test/features/util.py
new file mode 100644
index 0000000..3abbbbd
--- /dev/null
+++ b/test/features/util.py
@@ -0,0 +1,40 @@
+import argparse
+import socket
+
+from local_thrift import thrift  # noqa
+from thrift.transport.TSocket import TSocket
+from thrift.transport.TTransport import TBufferedTransport, TFramedTransport
+from thrift.transport.THttpClient import THttpClient
+from thrift.protocol.TBinaryProtocol import TBinaryProtocol
+from thrift.protocol.TCompactProtocol import TCompactProtocol
+from thrift.protocol.TJSONProtocol import TJSONProtocol
+
+
+def add_common_args(p):
+    p.add_argument('--host', default='localhost')
+    p.add_argument('--port', type=int, default=9090)
+    p.add_argument('--protocol', default='binary')
+    p.add_argument('--transport', default='buffered')
+    p.add_argument('--ssl', action='store_true')
+
+
+def parse_common_args(argv):
+    p = argparse.ArgumentParser()
+    add_common_args(p)
+    return p.parse_args(argv)
+
+
+def init_protocol(args):
+    sock = TSocket(args.host, args.port, socket_family=socket.AF_INET)
+    sock.setTimeout(500)
+    trans = {
+        'buffered': TBufferedTransport,
+        'framed': TFramedTransport,
+        'http': THttpClient,
+    }[args.transport](sock)
+    trans.open()
+    return {
+        'binary': TBinaryProtocol,
+        'compact': TCompactProtocol,
+        'json': TJSONProtocol,
+    }[args.protocol](trans)
diff --git a/test/go/Makefile.am b/test/go/Makefile.am
new file mode 100644
index 0000000..6bc97f5
--- /dev/null
+++ b/test/go/Makefile.am
@@ -0,0 +1,70 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+BUILT_SOURCES = gopath
+if GOVERSION_LT_17
+COMPILER_EXTRAFLAG=",legacy_context"
+endif
+
+THRIFTCMD = $(THRIFT) -out src/gen --gen go:thrift_import=thrift$(COMPILER_EXTRAFLAG)
+THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift
+
+precross: bin/testclient bin/testserver
+
+ThriftTest.thrift: $(THRIFTTEST)
+	grep -v list.*map.*list.*map $(THRIFTTEST) > ThriftTest.thrift
+
+.PHONY: gopath
+
+# Thrift for GO has problems with complex map keys: THRIFT-2063
+gopath: $(THRIFT) ThriftTest.thrift
+	mkdir -p src/gen
+	$(THRIFTCMD) ThriftTest.thrift
+	$(THRIFTCMD) ../StressTest.thrift
+	GOPATH=`pwd` $(GO) get golang.org/x/net/context
+	GOPATH=`pwd` $(GO) get github.com/golang/mock/gomock || true
+	sed -i 's/\"context\"/\"golang.org\/x\/net\/context\"/g' src/github.com/golang/mock/gomock/controller.go || true
+	GOPATH=`pwd` $(GO) get github.com/golang/mock/gomock
+	ln -nfs ../../../lib/go/thrift src/thrift
+	touch gopath
+
+bin/testclient: gopath
+	GOPATH=`pwd` $(GO) install bin/testclient
+
+bin/testserver: gopath
+	GOPATH=`pwd` $(GO) install bin/testserver
+
+bin/stress: gopath
+	GOPATH=`pwd` $(GO) install bin/stress
+
+clean-local:
+	$(RM) -r src/gen src/github.com/golang src/thrift bin pkg gopath ThriftTest.thrift
+
+check_PROGRAMS: bin/testclient bin/testserver bin/stress
+
+check: gopath genmock
+	GOPATH=`pwd` $(GO) test -v common/...
+
+genmock: gopath
+	GOPATH=`pwd` $(GO) install github.com/golang/mock/mockgen
+	GOPATH=`pwd` bin/mockgen -destination=src/common/mock_handler.go -package=common gen/thrifttest ThriftTest
+
+EXTRA_DIST = \
+	src/bin \
+	src/common
diff --git a/test/go/Makefile.in b/test/go/Makefile.in
new file mode 100644
index 0000000..6e990e2
--- /dev/null
+++ b/test/go/Makefile.in
@@ -0,0 +1,674 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/go
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+BUILT_SOURCES = gopath
+@GOVERSION_LT_17_TRUE@COMPILER_EXTRAFLAG = ",legacy_context"
+THRIFTCMD = $(THRIFT) -out src/gen --gen go:thrift_import=thrift$(COMPILER_EXTRAFLAG)
+THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift
+EXTRA_DIST = \
+	src/bin \
+	src/common
+
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/go/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/go/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile
+installdirs:
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	clean-local cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+precross: bin/testclient bin/testserver
+
+ThriftTest.thrift: $(THRIFTTEST)
+	grep -v list.*map.*list.*map $(THRIFTTEST) > ThriftTest.thrift
+
+.PHONY: gopath
+
+# Thrift for GO has problems with complex map keys: THRIFT-2063
+gopath: $(THRIFT) ThriftTest.thrift
+	mkdir -p src/gen
+	$(THRIFTCMD) ThriftTest.thrift
+	$(THRIFTCMD) ../StressTest.thrift
+	GOPATH=`pwd` $(GO) get golang.org/x/net/context
+	GOPATH=`pwd` $(GO) get github.com/golang/mock/gomock || true
+	sed -i 's/\"context\"/\"golang.org\/x\/net\/context\"/g' src/github.com/golang/mock/gomock/controller.go || true
+	GOPATH=`pwd` $(GO) get github.com/golang/mock/gomock
+	ln -nfs ../../../lib/go/thrift src/thrift
+	touch gopath
+
+bin/testclient: gopath
+	GOPATH=`pwd` $(GO) install bin/testclient
+
+bin/testserver: gopath
+	GOPATH=`pwd` $(GO) install bin/testserver
+
+bin/stress: gopath
+	GOPATH=`pwd` $(GO) install bin/stress
+
+clean-local:
+	$(RM) -r src/gen src/github.com/golang src/thrift bin pkg gopath ThriftTest.thrift
+
+check_PROGRAMS: bin/testclient bin/testserver bin/stress
+
+check: gopath genmock
+	GOPATH=`pwd` $(GO) test -v common/...
+
+genmock: gopath
+	GOPATH=`pwd` $(GO) install github.com/golang/mock/mockgen
+	GOPATH=`pwd` bin/mockgen -destination=src/common/mock_handler.go -package=common gen/thrifttest ThriftTest
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/go/src/bin/stress/go17.go b/test/go/src/bin/stress/go17.go
new file mode 100644
index 0000000..81f1ad8
--- /dev/null
+++ b/test/go/src/bin/stress/go17.go
@@ -0,0 +1,62 @@
+// +build go1.7
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package main
+
+import (
+	"context"
+	"sync/atomic"
+)
+
+type handler struct{}
+
+func (h *handler) EchoVoid(ctx context.Context) (err error) {
+	atomic.AddInt64(&counter, 1)
+	return nil
+}
+func (h *handler) EchoByte(ctx context.Context, arg int8) (r int8, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoI32(ctx context.Context, arg int32) (r int32, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoI64(ctx context.Context, arg int64) (r int64, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoString(ctx context.Context, arg string) (r string, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoList(ctx context.Context, arg []int8) (r []int8, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoSet(ctx context.Context, arg map[int8]struct{}) (r map[int8]struct{}, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoMap(ctx context.Context, arg map[int8]int8) (r map[int8]int8, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
diff --git a/test/go/src/bin/stress/main.go b/test/go/src/bin/stress/main.go
new file mode 100644
index 0000000..e8e6b2a
--- /dev/null
+++ b/test/go/src/bin/stress/main.go
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"gen/stress"
+	"log"
+	_ "net/http/pprof"
+	"os"
+	"runtime"
+	"runtime/pprof"
+	"sync"
+	"sync/atomic"
+	"thrift"
+	"time"
+)
+
+var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
+var memprofile = flag.String("memprofile", "", "write memory profile to this file")
+
+var (
+	host      = flag.String("host", "localhost", "Host to connect")
+	port      = flag.Int64("port", 9091, "Port number to connect")
+	loop      = flag.Int("loops", 50000, "The number of remote thrift calls each client makes")
+	runserver = flag.Int("server", 1, "Run the Thrift server in this process")
+	clients   = flag.Int("clients", 20, "Number of client threads to create - 0 implies no clients, i.e. server only")
+	callName  = flag.String("call", "echoVoid", "Service method to call, one of echoVoid, echoByte, echoI32, echoI64, echoString, echiList, echoSet, echoMap")
+	compact   = flag.Bool("compact", false, "Use compact protocol instead of binary.")
+	framed    = flag.Bool("framed", false, "Use framed transport instead of buffered.")
+)
+var hostPort string
+
+type callT int64
+
+const (
+	echoVoid callT = iota
+	echoByte
+	echoI32
+	echoI64
+	echoString
+	echiList
+	echoSet
+	echoMap
+)
+
+var callTMap = map[string]callT{
+	"echoVoid":   echoVoid,
+	"echoByte":   echoByte,
+	"echoI32":    echoI32,
+	"echoI64":    echoI64,
+	"echoString": echoString,
+	"echiList":   echiList,
+	"echoSet":    echoSet,
+	"echoMap":    echoMap,
+}
+var callType callT
+
+var ready, done sync.WaitGroup
+
+var clicounter int64 = 0
+var counter int64 = 0
+
+func main() {
+	flag.Parse()
+	if *memprofile != "" {
+		runtime.MemProfileRate = 100
+	}
+	var ok bool
+	if callType, ok = callTMap[*callName]; !ok {
+		log.Fatal("Unknown service call", *callName)
+	}
+	if *cpuprofile != "" {
+		f, err := os.Create(*cpuprofile)
+		if err != nil {
+			log.Fatal(err)
+		}
+		pprof.StartCPUProfile(f)
+		defer pprof.StopCPUProfile()
+	}
+	hostPort = fmt.Sprintf("%s:%d", *host, *port)
+	var protocolFactory thrift.TProtocolFactory
+	var transportFactory thrift.TTransportFactory
+
+	if *compact {
+		protocolFactory = thrift.NewTCompactProtocolFactory()
+	} else {
+		protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
+	}
+
+	if *framed {
+		transportFactory = thrift.NewTTransportFactory()
+		transportFactory = thrift.NewTFramedTransportFactory(transportFactory)
+	} else {
+		transportFactory = thrift.NewTBufferedTransportFactory(8192)
+	}
+
+	if *runserver > 0 {
+		serverTransport, err := thrift.NewTServerSocket(hostPort)
+		if err != nil {
+			log.Fatalf("Unable to create server socket: %s", err)
+		}
+
+		processor := stress.NewServiceProcessor(&handler{})
+		server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
+		if *clients == 0 {
+			server.Serve()
+		} else {
+			go server.Serve()
+		}
+	}
+	//start clients
+	if *clients != 0 {
+		ready.Add(*clients + 1)
+		done.Add(*clients)
+		for i := 0; i < *clients; i++ {
+			go client(protocolFactory)
+		}
+		ready.Done()
+		ready.Wait()
+		//run!
+		startTime := time.Now()
+		//wait for completion
+		done.Wait()
+		endTime := time.Now()
+		duration := endTime.Sub(startTime)
+		log.Printf("%d calls in %v (%f calls per second)\n", clicounter, duration, float64(clicounter)/duration.Seconds())
+	}
+	if *memprofile != "" {
+		f, err := os.Create(*memprofile)
+		if err != nil {
+			log.Fatal(err)
+		}
+		pprof.WriteHeapProfile(f)
+		f.Close()
+		return
+	}
+}
+
+func client(protocolFactory thrift.TProtocolFactory) {
+	trans, err := thrift.NewTSocket(hostPort)
+	if err != nil {
+		log.Fatalf("Unable to create server socket: %s", err)
+	}
+	btrans := thrift.NewTBufferedTransport(trans, 2048)
+	client := stress.NewServiceClientFactory(btrans, protocolFactory)
+	err = trans.Open()
+	if err != nil {
+		log.Fatalf("Unable to open connection: %s", err)
+	}
+	ready.Done()
+	ready.Wait()
+	switch callType {
+	case echoVoid:
+		for i := 0; i < *loop; i++ {
+			client.EchoVoid()
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echoByte:
+		for i := 0; i < *loop; i++ {
+			client.EchoByte(42)
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echoI32:
+		for i := 0; i < *loop; i++ {
+			client.EchoI32(4242)
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echoI64:
+		for i := 0; i < *loop; i++ {
+			client.EchoI64(424242)
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echoString:
+		for i := 0; i < *loop; i++ {
+			client.EchoString("TestString")
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echiList:
+		l := []int8{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8}
+		for i := 0; i < *loop; i++ {
+			client.EchoList(l)
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echoSet:
+		s := map[int8]struct{}{-10: {}, -9: {}, -8: {}, -7: {}, -6: {}, -5: {}, -4: {}, -3: {}, -2: {}, -1: {}, 0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {}, 8: {}}
+		for i := 0; i < *loop; i++ {
+			client.EchoSet(s)
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echoMap:
+		m := map[int8]int8{-10: 10, -9: 9, -8: 8, -7: 7, -6: 6, -5: 5, -4: 4, -3: 3, -2: 2, -1: 1, 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8}
+		for i := 0; i < *loop; i++ {
+			client.EchoMap(m)
+			atomic.AddInt64(&clicounter, 1)
+		}
+	}
+
+	done.Done()
+}
diff --git a/test/go/src/bin/stress/pre_go17.go b/test/go/src/bin/stress/pre_go17.go
new file mode 100644
index 0000000..07ae5c6
--- /dev/null
+++ b/test/go/src/bin/stress/pre_go17.go
@@ -0,0 +1,63 @@
+// +build !go1.7
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package main
+
+import (
+	"sync/atomic"
+
+	"golang.org/x/net/context"
+)
+
+type handler struct{}
+
+func (h *handler) EchoVoid(ctx context.Context) (err error) {
+	atomic.AddInt64(&counter, 1)
+	return nil
+}
+func (h *handler) EchoByte(ctx context.Context, arg int8) (r int8, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoI32(ctx context.Context, arg int32) (r int32, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoI64(ctx context.Context, arg int64) (r int64, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoString(ctx context.Context, arg string) (r string, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoList(ctx context.Context, arg []int8) (r []int8, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoSet(ctx context.Context, arg map[int8]struct{}) (r map[int8]struct{}, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoMap(ctx context.Context, arg map[int8]int8) (r map[int8]int8, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
diff --git a/test/go/src/bin/testclient/go17.go b/test/go/src/bin/testclient/go17.go
new file mode 100644
index 0000000..a6003a9
--- /dev/null
+++ b/test/go/src/bin/testclient/go17.go
@@ -0,0 +1,26 @@
+// +build go1.7
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package main
+
+import "context"
+
+var defaultCtx = context.Background()
diff --git a/test/go/src/bin/testclient/main.go b/test/go/src/bin/testclient/main.go
new file mode 100644
index 0000000..ab24cbf
--- /dev/null
+++ b/test/go/src/bin/testclient/main.go
@@ -0,0 +1,313 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package main
+
+import (
+	"common"
+	"flag"
+	"gen/thrifttest"
+	t "log"
+	"reflect"
+	"thrift"
+)
+
+var host = flag.String("host", "localhost", "Host to connect")
+var port = flag.Int64("port", 9090, "Port number to connect")
+var domain_socket = flag.String("domain-socket", "", "Domain Socket (e.g. /tmp/thrifttest.thrift), instead of host and port")
+var transport = flag.String("transport", "buffered", "Transport: buffered, framed, http, zlib")
+var protocol = flag.String("protocol", "binary", "Protocol: binary, compact, json")
+var ssl = flag.Bool("ssl", false, "Encrypted Transport using SSL")
+var testloops = flag.Int("testloops", 1, "Number of Tests")
+
+func main() {
+	flag.Parse()
+	client, _, err := common.StartClient(*host, *port, *domain_socket, *transport, *protocol, *ssl)
+	if err != nil {
+		t.Fatalf("Unable to start client: ", err)
+	}
+	for i := 0; i < *testloops; i++ {
+		callEverything(client)
+	}
+}
+
+var rmapmap = map[int32]map[int32]int32{
+	-4: map[int32]int32{-4: -4, -3: -3, -2: -2, -1: -1},
+	4:  map[int32]int32{4: 4, 3: 3, 2: 2, 1: 1},
+}
+
+var xxs = &thrifttest.Xtruct{
+	StringThing: "Hello2",
+	ByteThing:   42,
+	I32Thing:    4242,
+	I64Thing:    424242,
+}
+
+var xcept = &thrifttest.Xception{ErrorCode: 1001, Message: "Xception"}
+
+func callEverything(client *thrifttest.ThriftTestClient) {
+	var err error
+	if err = client.TestVoid(defaultCtx); err != nil {
+		t.Fatalf("Unexpected error in TestVoid() call: ", err)
+	}
+
+	thing, err := client.TestString(defaultCtx, "thing")
+	if err != nil {
+		t.Fatalf("Unexpected error in TestString() call: ", err)
+	}
+	if thing != "thing" {
+		t.Fatalf("Unexpected TestString() result, expected 'thing' got '%s' ", thing)
+	}
+
+	bl, err := client.TestBool(defaultCtx, true)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestBool() call: ", err)
+	}
+	if !bl {
+		t.Fatalf("Unexpected TestBool() result expected true, got %f ", bl)
+	}
+	bl, err = client.TestBool(defaultCtx, false)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestBool() call: ", err)
+	}
+	if bl {
+		t.Fatalf("Unexpected TestBool() result expected false, got %f ", bl)
+	}
+
+	b, err := client.TestByte(defaultCtx, 42)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestByte() call: ", err)
+	}
+	if b != 42 {
+		t.Fatalf("Unexpected TestByte() result expected 42, got %d ", b)
+	}
+
+	i32, err := client.TestI32(defaultCtx, 4242)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestI32() call: ", err)
+	}
+	if i32 != 4242 {
+		t.Fatalf("Unexpected TestI32() result expected 4242, got %d ", i32)
+	}
+
+	i64, err := client.TestI64(defaultCtx, 424242)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestI64() call: ", err)
+	}
+	if i64 != 424242 {
+		t.Fatalf("Unexpected TestI64() result expected 424242, got %d ", i64)
+	}
+
+	d, err := client.TestDouble(defaultCtx, 42.42)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestDouble() call: ", err)
+	}
+	if d != 42.42 {
+		t.Fatalf("Unexpected TestDouble() result expected 42.42, got %f ", d)
+	}
+
+	binout := make([]byte, 256)
+	for i := 0; i < 256; i++ {
+		binout[i] = byte(i)
+	}
+	bin, err := client.TestBinary(defaultCtx, binout)
+	for i := 0; i < 256; i++ {
+		if binout[i] != bin[i] {
+			t.Fatalf("Unexpected TestBinary() result expected %d, got %d ", binout[i], bin[i])
+		}
+	}
+
+	xs := thrifttest.NewXtruct()
+	xs.StringThing = "thing"
+	xs.ByteThing = 42
+	xs.I32Thing = 4242
+	xs.I64Thing = 424242
+	xsret, err := client.TestStruct(defaultCtx, xs)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestStruct() call: ", err)
+	}
+	if *xs != *xsret {
+		t.Fatalf("Unexpected TestStruct() result expected %#v, got %#v ", xs, xsret)
+	}
+
+	x2 := thrifttest.NewXtruct2()
+	x2.StructThing = xs
+	x2ret, err := client.TestNest(defaultCtx, x2)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestNest() call: ", err)
+	}
+	if !reflect.DeepEqual(x2, x2ret) {
+		t.Fatalf("Unexpected TestNest() result expected %#v, got %#v ", x2, x2ret)
+	}
+
+	m := map[int32]int32{1: 2, 3: 4, 5: 42}
+	mret, err := client.TestMap(defaultCtx, m)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestMap() call: ", err)
+	}
+	if !reflect.DeepEqual(m, mret) {
+		t.Fatalf("Unexpected TestMap() result expected %#v, got %#v ", m, mret)
+	}
+
+	sm := map[string]string{"a": "2", "b": "blah", "some": "thing"}
+	smret, err := client.TestStringMap(defaultCtx, sm)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestStringMap() call: ", err)
+	}
+	if !reflect.DeepEqual(sm, smret) {
+		t.Fatalf("Unexpected TestStringMap() result expected %#v, got %#v ", sm, smret)
+	}
+
+	s := []int32{1, 2, 42}
+	sret, err := client.TestSet(defaultCtx, s)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestSet() call: ", err)
+	}
+	// Sets can be in any order, but Go slices are ordered, so reflect.DeepEqual won't work.
+	stemp := map[int32]struct{}{}
+	for _, val := range s {
+		stemp[val] = struct{}{}
+	}
+	for _, val := range sret {
+		if _, ok := stemp[val]; !ok {
+			t.Fatalf("Unexpected TestSet() result expected %#v, got %#v ", s, sret)
+		}
+	}
+
+	l := []int32{1, 2, 42}
+	lret, err := client.TestList(defaultCtx, l)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestList() call: ", err)
+	}
+	if !reflect.DeepEqual(l, lret) {
+		t.Fatalf("Unexpected TestList() result expected %#v, got %#v ", l, lret)
+	}
+
+	eret, err := client.TestEnum(defaultCtx, thrifttest.Numberz_TWO)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestEnum() call: ", err)
+	}
+	if eret != thrifttest.Numberz_TWO {
+		t.Fatalf("Unexpected TestEnum() result expected %#v, got %#v ", thrifttest.Numberz_TWO, eret)
+	}
+
+	tret, err := client.TestTypedef(defaultCtx, thrifttest.UserId(42))
+	if err != nil {
+		t.Fatalf("Unexpected error in TestTypedef() call: ", err)
+	}
+	if tret != thrifttest.UserId(42) {
+		t.Fatalf("Unexpected TestTypedef() result expected %#v, got %#v ", thrifttest.UserId(42), tret)
+	}
+
+	mapmap, err := client.TestMapMap(defaultCtx, 42)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestMapMap() call: ", err)
+	}
+	if !reflect.DeepEqual(mapmap, rmapmap) {
+		t.Fatalf("Unexpected TestMapMap() result expected %#v, got %#v ", rmapmap, mapmap)
+	}
+
+	crazy := thrifttest.NewInsanity()
+	crazy.UserMap = map[thrifttest.Numberz]thrifttest.UserId{
+		thrifttest.Numberz_FIVE:  5,
+		thrifttest.Numberz_EIGHT: 8,
+	}
+	truck1 := thrifttest.NewXtruct()
+	truck1.StringThing = "Goodbye4"
+	truck1.ByteThing = 4
+	truck1.I32Thing = 4
+	truck1.I64Thing = 4
+	truck2 := thrifttest.NewXtruct()
+	truck2.StringThing = "Hello2"
+	truck2.ByteThing = 2
+	truck2.I32Thing = 2
+	truck2.I64Thing = 2
+	crazy.Xtructs = []*thrifttest.Xtruct{
+		truck1,
+		truck2,
+	}
+	insanity, err := client.TestInsanity(defaultCtx, crazy)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestInsanity() call: ", err)
+	}
+	if !reflect.DeepEqual(crazy, insanity[1][2]) {
+		t.Fatalf("Unexpected TestInsanity() first result expected %#v, got %#v ",
+			crazy,
+			insanity[1][2])
+	}
+	if !reflect.DeepEqual(crazy, insanity[1][3]) {
+		t.Fatalf("Unexpected TestInsanity() second result expected %#v, got %#v ",
+			crazy,
+			insanity[1][3])
+	}
+	if len(insanity[2][6].UserMap) > 0 || len(insanity[2][6].Xtructs) > 0 {
+		t.Fatalf("Unexpected TestInsanity() non-empty result got %#v ",
+			insanity[2][6])
+	}
+
+	xxsret, err := client.TestMulti(defaultCtx, 42, 4242, 424242, map[int16]string{1: "blah", 2: "thing"}, thrifttest.Numberz_EIGHT, thrifttest.UserId(24))
+	if err != nil {
+		t.Fatalf("Unexpected error in TestMulti() call: ", err)
+	}
+	if !reflect.DeepEqual(xxs, xxsret) {
+		t.Fatalf("Unexpected TestMulti() result expected %#v, got %#v ", xxs, xxsret)
+	}
+
+	err = client.TestException(defaultCtx, "Xception")
+	if err == nil {
+		t.Fatalf("Expecting exception in TestException() call")
+	}
+	if !reflect.DeepEqual(err, xcept) {
+		t.Fatalf("Unexpected TestException() result expected %#v, got %#v ", xcept, err)
+	}
+
+	err = client.TestException(defaultCtx, "TException")
+	_, ok := err.(thrift.TApplicationException)
+	if err == nil || !ok {
+		t.Fatalf("Unexpected TestException() result expected ApplicationError, got %#v ", err)
+	}
+
+	ign, err := client.TestMultiException(defaultCtx, "Xception", "ignoreme")
+	if ign != nil || err == nil {
+		t.Fatalf("Expecting exception in TestMultiException() call")
+	}
+	if !reflect.DeepEqual(err, &thrifttest.Xception{ErrorCode: 1001, Message: "This is an Xception"}) {
+		t.Fatalf("Unexpected TestMultiException() %#v ", err)
+	}
+
+	ign, err = client.TestMultiException(defaultCtx, "Xception2", "ignoreme")
+	if ign != nil || err == nil {
+		t.Fatalf("Expecting exception in TestMultiException() call")
+	}
+	expecting := &thrifttest.Xception2{ErrorCode: 2002, StructThing: &thrifttest.Xtruct{StringThing: "This is an Xception2"}}
+
+	if !reflect.DeepEqual(err, expecting) {
+		t.Fatalf("Unexpected TestMultiException() %#v ", err)
+	}
+
+	err = client.TestOneway(defaultCtx, 2)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestOneway() call: ", err)
+	}
+
+	//Make sure the connection still alive
+	if err = client.TestVoid(defaultCtx); err != nil {
+		t.Fatalf("Unexpected error in TestVoid() call: ", err)
+	}
+}
diff --git a/test/go/src/bin/testclient/pre_go17.go b/test/go/src/bin/testclient/pre_go17.go
new file mode 100644
index 0000000..10a6fb8
--- /dev/null
+++ b/test/go/src/bin/testclient/pre_go17.go
@@ -0,0 +1,26 @@
+// +build !go1.7
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package main
+
+import "golang.org/x/net/context"
+
+var defaultCtx = context.Background()
diff --git a/test/go/src/bin/testserver/main.go b/test/go/src/bin/testserver/main.go
new file mode 100644
index 0000000..0bf833d
--- /dev/null
+++ b/test/go/src/bin/testserver/main.go
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package main
+
+import (
+	"common"
+	"flag"
+	"fmt"
+	"log"
+	"net/http"
+	"thrift"
+)
+
+var host = flag.String("host", "localhost", "Host to connect")
+var port = flag.Int64("port", 9090, "Port number to connect")
+var domain_socket = flag.String("domain-socket", "", "Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port")
+var transport = flag.String("transport", "buffered", "Transport: buffered, framed, http, zlib")
+var protocol = flag.String("protocol", "binary", "Protocol: binary, compact, json")
+var ssl = flag.Bool("ssl", false, "Encrypted Transport using SSL")
+var certPath = flag.String("certPath", "keys", "Directory that contains SSL certificates")
+
+func main() {
+	flag.Parse()
+
+	processor, serverTransport, transportFactory, protocolFactory, err := common.GetServerParams(*host, *port, *domain_socket, *transport, *protocol, *ssl, *certPath, common.PrintingHandler)
+
+	if err != nil {
+		log.Fatalf("Unable to process server params: ", err)
+	}
+
+	if *transport == "http" {
+		http.HandleFunc("/", thrift.NewThriftHandlerFunc(processor, protocolFactory, protocolFactory))
+
+		if *ssl {
+			err := http.ListenAndServeTLS(fmt.Sprintf(":%d", *port),
+				*certPath+"/server.pem", *certPath+"/server.key", nil)
+
+			if err != nil {
+				fmt.Println(err)
+				return
+			}
+		} else {
+			http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)
+		}
+	} else {
+		server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
+		if err = server.Listen(); err != nil {
+			return
+		}
+		go server.AcceptLoop()
+		server.Serve()
+	}
+}
diff --git a/test/go/src/common/client.go b/test/go/src/common/client.go
new file mode 100644
index 0000000..236ce43
--- /dev/null
+++ b/test/go/src/common/client.go
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package common
+
+import (
+	"compress/zlib"
+	"crypto/tls"
+	"flag"
+	"fmt"
+	"gen/thrifttest"
+	"net/http"
+	"thrift"
+)
+
+var debugClientProtocol bool
+
+func init() {
+	flag.BoolVar(&debugClientProtocol, "debug_client_protocol", false, "turn client protocol trace on")
+}
+
+func StartClient(
+	host string,
+	port int64,
+	domain_socket string,
+	transport string,
+	protocol string,
+	ssl bool) (client *thrifttest.ThriftTestClient, trans thrift.TTransport, err error) {
+
+	hostPort := fmt.Sprintf("%s:%d", host, port)
+
+	var protocolFactory thrift.TProtocolFactory
+	switch protocol {
+	case "compact":
+		protocolFactory = thrift.NewTCompactProtocolFactory()
+	case "simplejson":
+		protocolFactory = thrift.NewTSimpleJSONProtocolFactory()
+	case "json":
+		protocolFactory = thrift.NewTJSONProtocolFactory()
+	case "binary":
+		protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
+	default:
+		return nil, nil, fmt.Errorf("Invalid protocol specified %s", protocol)
+	}
+	if debugClientProtocol {
+		protocolFactory = thrift.NewTDebugProtocolFactory(protocolFactory, "client:")
+	}
+	if ssl {
+		trans, err = thrift.NewTSSLSocket(hostPort, &tls.Config{InsecureSkipVerify: true})
+	} else {
+		if domain_socket != "" {
+			trans, err = thrift.NewTSocket(domain_socket)
+		} else {
+			trans, err = thrift.NewTSocket(hostPort)
+		}
+	}
+	if err != nil {
+		return nil, nil, err
+	}
+	switch transport {
+	case "http":
+		if ssl {
+			tr := &http.Transport{
+				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+			}
+			client := &http.Client{Transport: tr}
+			trans, err = thrift.NewTHttpPostClientWithOptions(fmt.Sprintf("https://%s/", hostPort), thrift.THttpClientOptions{Client: client})
+			fmt.Println(hostPort)
+		} else {
+			trans, err = thrift.NewTHttpPostClient(fmt.Sprintf("http://%s/", hostPort))
+		}
+	case "framed":
+		trans = thrift.NewTFramedTransport(trans)
+	case "buffered":
+		trans = thrift.NewTBufferedTransport(trans, 8192)
+	case "zlib":
+		trans, err = thrift.NewTZlibTransport(trans, zlib.BestCompression)
+	case "":
+		trans = trans
+	default:
+		return nil, nil, fmt.Errorf("Invalid transport specified %s", transport)
+	}
+	if err != nil {
+		return nil, nil, err
+	}
+	if err = trans.Open(); err != nil {
+		return nil, nil, err
+	}
+	iprot := protocolFactory.GetProtocol(trans)
+	oprot := protocolFactory.GetProtocol(trans)
+	client = thrifttest.NewThriftTestClient(thrift.NewTStandardClient(iprot, oprot))
+	return
+}
diff --git a/test/go/src/common/clientserver_test.go b/test/go/src/common/clientserver_test.go
new file mode 100644
index 0000000..c4cfd44
--- /dev/null
+++ b/test/go/src/common/clientserver_test.go
@@ -0,0 +1,333 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package common
+
+import (
+	"errors"
+	"gen/thrifttest"
+	"reflect"
+	"sync"
+	"testing"
+	"thrift"
+
+	"github.com/golang/mock/gomock"
+)
+
+type test_unit struct {
+	host          string
+	port          int64
+	domain_socket string
+	transport     string
+	protocol      string
+	ssl           bool
+}
+
+var units = []test_unit{
+	{"127.0.0.1", 9095, "", "", "binary", false},
+	{"127.0.0.1", 9091, "", "", "compact", false},
+	{"127.0.0.1", 9092, "", "", "binary", true},
+	{"127.0.0.1", 9093, "", "", "compact", true},
+}
+
+func TestAllConnection(t *testing.T) {
+	certPath = "../../../keys"
+	wg := &sync.WaitGroup{}
+	wg.Add(len(units))
+	for _, unit := range units {
+		go func(u test_unit) {
+			defer wg.Done()
+			doUnit(t, &u)
+		}(unit)
+	}
+	wg.Wait()
+}
+
+func doUnit(t *testing.T, unit *test_unit) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+	handler := NewMockThriftTest(ctrl)
+
+	processor, serverTransport, transportFactory, protocolFactory, err := GetServerParams(unit.host, unit.port, unit.domain_socket, unit.transport, unit.protocol, unit.ssl, "../../../keys", handler)
+
+	server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
+	if err = server.Listen(); err != nil {
+		t.Errorf("Unable to start server: %v", err)
+		return
+	}
+	go server.AcceptLoop()
+	defer server.Stop()
+	client, trans, err := StartClient(unit.host, unit.port, unit.domain_socket, unit.transport, unit.protocol, unit.ssl)
+	if err != nil {
+		t.Errorf("Unable to start client: %v", err)
+		return
+	}
+	defer trans.Close()
+	callEverythingWithMock(t, client, handler)
+}
+
+var rmapmap = map[int32]map[int32]int32{
+	-4: map[int32]int32{-4: -4, -3: -3, -2: -2, -1: -1},
+	4:  map[int32]int32{4: 4, 3: 3, 2: 2, 1: 1},
+}
+
+var xxs = &thrifttest.Xtruct{
+	StringThing: "Hello2",
+	ByteThing:   42,
+	I32Thing:    4242,
+	I64Thing:    424242,
+}
+
+var xcept = &thrifttest.Xception{ErrorCode: 1001, Message: "some"}
+
+func callEverythingWithMock(t *testing.T, client *thrifttest.ThriftTestClient, handler *MockThriftTest) {
+	gomock.InOrder(
+		handler.EXPECT().TestVoid(gomock.Any()),
+		handler.EXPECT().TestString(gomock.Any(), "thing").Return("thing", nil),
+		handler.EXPECT().TestBool(gomock.Any(), true).Return(true, nil),
+		handler.EXPECT().TestBool(gomock.Any(), false).Return(false, nil),
+		handler.EXPECT().TestByte(gomock.Any(), int8(42)).Return(int8(42), nil),
+		handler.EXPECT().TestI32(gomock.Any(), int32(4242)).Return(int32(4242), nil),
+		handler.EXPECT().TestI64(gomock.Any(), int64(424242)).Return(int64(424242), nil),
+		// TODO: add TestBinary()
+		handler.EXPECT().TestDouble(gomock.Any(), float64(42.42)).Return(float64(42.42), nil),
+		handler.EXPECT().TestStruct(gomock.Any(), &thrifttest.Xtruct{StringThing: "thing", ByteThing: 42, I32Thing: 4242, I64Thing: 424242}).Return(&thrifttest.Xtruct{StringThing: "thing", ByteThing: 42, I32Thing: 4242, I64Thing: 424242}, nil),
+		handler.EXPECT().TestNest(gomock.Any(), &thrifttest.Xtruct2{StructThing: &thrifttest.Xtruct{StringThing: "thing", ByteThing: 42, I32Thing: 4242, I64Thing: 424242}}).Return(&thrifttest.Xtruct2{StructThing: &thrifttest.Xtruct{StringThing: "thing", ByteThing: 42, I32Thing: 4242, I64Thing: 424242}}, nil),
+		handler.EXPECT().TestMap(gomock.Any(), map[int32]int32{1: 2, 3: 4, 5: 42}).Return(map[int32]int32{1: 2, 3: 4, 5: 42}, nil),
+		handler.EXPECT().TestStringMap(gomock.Any(), map[string]string{"a": "2", "b": "blah", "some": "thing"}).Return(map[string]string{"a": "2", "b": "blah", "some": "thing"}, nil),
+		handler.EXPECT().TestSet(gomock.Any(), []int32{1, 2, 42}).Return([]int32{1, 2, 42}, nil),
+		handler.EXPECT().TestList(gomock.Any(), []int32{1, 2, 42}).Return([]int32{1, 2, 42}, nil),
+		handler.EXPECT().TestEnum(gomock.Any(), thrifttest.Numberz_TWO).Return(thrifttest.Numberz_TWO, nil),
+		handler.EXPECT().TestTypedef(gomock.Any(), thrifttest.UserId(42)).Return(thrifttest.UserId(42), nil),
+		handler.EXPECT().TestMapMap(gomock.Any(), int32(42)).Return(rmapmap, nil),
+		// TODO: not testing insanity
+		handler.EXPECT().TestMulti(gomock.Any(), int8(42), int32(4242), int64(424242), map[int16]string{1: "blah", 2: "thing"}, thrifttest.Numberz_EIGHT, thrifttest.UserId(24)).Return(xxs, nil),
+		handler.EXPECT().TestException(gomock.Any(), "some").Return(xcept),
+		handler.EXPECT().TestException(gomock.Any(), "TException").Return(errors.New("Just random exception")),
+		handler.EXPECT().TestMultiException(gomock.Any(), "Xception", "ignoreme").Return(nil, &thrifttest.Xception{ErrorCode: 1001, Message: "This is an Xception"}),
+		handler.EXPECT().TestMultiException(gomock.Any(), "Xception2", "ignoreme").Return(nil, &thrifttest.Xception2{ErrorCode: 2002, StructThing: &thrifttest.Xtruct{StringThing: "This is an Xception2"}}),
+		handler.EXPECT().TestOneway(gomock.Any(), int32(2)).Return(nil),
+		handler.EXPECT().TestVoid(gomock.Any()),
+	)
+	var err error
+	if err = client.TestVoid(defaultCtx); err != nil {
+		t.Errorf("Unexpected error in TestVoid() call: ", err)
+	}
+
+	thing, err := client.TestString(defaultCtx, "thing")
+	if err != nil {
+		t.Errorf("Unexpected error in TestString() call: ", err)
+	}
+	if thing != "thing" {
+		t.Errorf("Unexpected TestString() result, expected 'thing' got '%s' ", thing)
+	}
+
+	bl, err := client.TestBool(defaultCtx, true)
+	if err != nil {
+		t.Errorf("Unexpected error in TestBool() call: ", err)
+	}
+	if !bl {
+		t.Errorf("Unexpected TestBool() result expected true, got %f ", bl)
+	}
+	bl, err = client.TestBool(defaultCtx, false)
+	if err != nil {
+		t.Errorf("Unexpected error in TestBool() call: ", err)
+	}
+	if bl {
+		t.Errorf("Unexpected TestBool() result expected false, got %f ", bl)
+	}
+
+	b, err := client.TestByte(defaultCtx, 42)
+	if err != nil {
+		t.Errorf("Unexpected error in TestByte() call: ", err)
+	}
+	if b != 42 {
+		t.Errorf("Unexpected TestByte() result expected 42, got %d ", b)
+	}
+
+	i32, err := client.TestI32(defaultCtx, 4242)
+	if err != nil {
+		t.Errorf("Unexpected error in TestI32() call: ", err)
+	}
+	if i32 != 4242 {
+		t.Errorf("Unexpected TestI32() result expected 4242, got %d ", i32)
+	}
+
+	i64, err := client.TestI64(defaultCtx, 424242)
+	if err != nil {
+		t.Errorf("Unexpected error in TestI64() call: ", err)
+	}
+	if i64 != 424242 {
+		t.Errorf("Unexpected TestI64() result expected 424242, got %d ", i64)
+	}
+
+	d, err := client.TestDouble(defaultCtx, 42.42)
+	if err != nil {
+		t.Errorf("Unexpected error in TestDouble() call: ", err)
+	}
+	if d != 42.42 {
+		t.Errorf("Unexpected TestDouble() result expected 42.42, got %f ", d)
+	}
+
+	// TODO: add TestBinary() call
+
+	xs := thrifttest.NewXtruct()
+	xs.StringThing = "thing"
+	xs.ByteThing = 42
+	xs.I32Thing = 4242
+	xs.I64Thing = 424242
+	xsret, err := client.TestStruct(defaultCtx, xs)
+	if err != nil {
+		t.Errorf("Unexpected error in TestStruct() call: ", err)
+	}
+	if *xs != *xsret {
+		t.Errorf("Unexpected TestStruct() result expected %#v, got %#v ", xs, xsret)
+	}
+
+	x2 := thrifttest.NewXtruct2()
+	x2.StructThing = xs
+	x2ret, err := client.TestNest(defaultCtx, x2)
+	if err != nil {
+		t.Errorf("Unexpected error in TestNest() call: ", err)
+	}
+	if !reflect.DeepEqual(x2, x2ret) {
+		t.Errorf("Unexpected TestNest() result expected %#v, got %#v ", x2, x2ret)
+	}
+
+	m := map[int32]int32{1: 2, 3: 4, 5: 42}
+	mret, err := client.TestMap(defaultCtx, m)
+	if err != nil {
+		t.Errorf("Unexpected error in TestMap() call: ", err)
+	}
+	if !reflect.DeepEqual(m, mret) {
+		t.Errorf("Unexpected TestMap() result expected %#v, got %#v ", m, mret)
+	}
+
+	sm := map[string]string{"a": "2", "b": "blah", "some": "thing"}
+	smret, err := client.TestStringMap(defaultCtx, sm)
+	if err != nil {
+		t.Errorf("Unexpected error in TestStringMap() call: ", err)
+	}
+	if !reflect.DeepEqual(sm, smret) {
+		t.Errorf("Unexpected TestStringMap() result expected %#v, got %#v ", sm, smret)
+	}
+
+	s := []int32{1, 2, 42}
+	sret, err := client.TestSet(defaultCtx, s)
+	if err != nil {
+		t.Errorf("Unexpected error in TestSet() call: ", err)
+	}
+	// Sets can be in any order, but Go slices are ordered, so reflect.DeepEqual won't work.
+	stemp := map[int32]struct{}{}
+	for _, val := range s {
+		stemp[val] = struct{}{}
+	}
+	for _, val := range sret {
+		if _, ok := stemp[val]; !ok {
+			t.Fatalf("Unexpected TestSet() result expected %#v, got %#v ", s, sret)
+		}
+	}
+
+	l := []int32{1, 2, 42}
+	lret, err := client.TestList(defaultCtx, l)
+	if err != nil {
+		t.Errorf("Unexpected error in TestList() call: ", err)
+	}
+	if !reflect.DeepEqual(l, lret) {
+		t.Errorf("Unexpected TestList() result expected %#v, got %#v ", l, lret)
+	}
+
+	eret, err := client.TestEnum(defaultCtx, thrifttest.Numberz_TWO)
+	if err != nil {
+		t.Errorf("Unexpected error in TestEnum() call: ", err)
+	}
+	if eret != thrifttest.Numberz_TWO {
+		t.Errorf("Unexpected TestEnum() result expected %#v, got %#v ", thrifttest.Numberz_TWO, eret)
+	}
+
+	tret, err := client.TestTypedef(defaultCtx, thrifttest.UserId(42))
+	if err != nil {
+		t.Errorf("Unexpected error in TestTypedef() call: ", err)
+	}
+	if tret != thrifttest.UserId(42) {
+		t.Errorf("Unexpected TestTypedef() result expected %#v, got %#v ", thrifttest.UserId(42), tret)
+	}
+
+	mapmap, err := client.TestMapMap(defaultCtx, 42)
+	if err != nil {
+		t.Errorf("Unexpected error in TestMapmap() call: ", err)
+	}
+	if !reflect.DeepEqual(mapmap, rmapmap) {
+		t.Errorf("Unexpected TestMapmap() result expected %#v, got %#v ", rmapmap, mapmap)
+	}
+
+	xxsret, err := client.TestMulti(defaultCtx, 42, 4242, 424242, map[int16]string{1: "blah", 2: "thing"}, thrifttest.Numberz_EIGHT, thrifttest.UserId(24))
+	if err != nil {
+		t.Errorf("Unexpected error in TestMulti() call: %v", err)
+	}
+	if !reflect.DeepEqual(xxs, xxsret) {
+		t.Errorf("Unexpected TestMulti() result expected %#v, got %#v ", xxs, xxsret)
+	}
+
+	err = client.TestException(defaultCtx, "some")
+	if err == nil {
+		t.Errorf("Expecting exception in TestException() call")
+	}
+	if !reflect.DeepEqual(err, xcept) {
+		t.Errorf("Unexpected TestException() result expected %#v, got %#v ", xcept, err)
+	}
+
+	// TODO: connection is being closed on this
+	err = client.TestException(defaultCtx, "TException")
+	if err == nil {
+		t.Error("expected exception got nil")
+	} else if tex, ok := err.(thrift.TApplicationException); !ok {
+		t.Errorf("Unexpected TestException() result expected ApplicationError, got %T ", err)
+	} else if tex.TypeId() != thrift.INTERNAL_ERROR {
+		t.Errorf("expected internal_error got %v", tex.TypeId())
+	}
+
+	ign, err := client.TestMultiException(defaultCtx, "Xception", "ignoreme")
+	if ign != nil || err == nil {
+		t.Errorf("Expecting exception in TestMultiException() call")
+	}
+	if !reflect.DeepEqual(err, &thrifttest.Xception{ErrorCode: 1001, Message: "This is an Xception"}) {
+		t.Errorf("Unexpected TestMultiException() %#v ", err)
+	}
+
+	ign, err = client.TestMultiException(defaultCtx, "Xception2", "ignoreme")
+	if ign != nil || err == nil {
+		t.Errorf("Expecting exception in TestMultiException() call")
+	}
+	expecting := &thrifttest.Xception2{ErrorCode: 2002, StructThing: &thrifttest.Xtruct{StringThing: "This is an Xception2"}}
+
+	if !reflect.DeepEqual(err, expecting) {
+		t.Errorf("Unexpected TestMultiException() %#v ", err)
+	}
+
+	err = client.TestOneway(defaultCtx, 2)
+	if err != nil {
+		t.Errorf("Unexpected error in TestOneway() call: ", err)
+	}
+
+	//Make sure the connection still alive
+	if err = client.TestVoid(defaultCtx); err != nil {
+		t.Errorf("Unexpected error in TestVoid() call: ", err)
+	}
+}
diff --git a/test/go/src/common/go17.go b/test/go/src/common/go17.go
new file mode 100644
index 0000000..9aca407
--- /dev/null
+++ b/test/go/src/common/go17.go
@@ -0,0 +1,26 @@
+// +build go1.7
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package common
+
+import "context"
+
+var defaultCtx = context.Background()
diff --git a/test/go/src/common/pre_go17.go b/test/go/src/common/pre_go17.go
new file mode 100644
index 0000000..6c14579
--- /dev/null
+++ b/test/go/src/common/pre_go17.go
@@ -0,0 +1,26 @@
+// +build !go1.7
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package common
+
+import "golang.org/x/net/context"
+
+var defaultCtx = context.Background()
diff --git a/test/go/src/common/printing_handler.go b/test/go/src/common/printing_handler.go
new file mode 100644
index 0000000..c0a2862
--- /dev/null
+++ b/test/go/src/common/printing_handler.go
@@ -0,0 +1,387 @@
+// +build !go1.7
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package common
+
+import (
+	"errors"
+	"fmt"
+	"encoding/hex"
+	. "gen/thrifttest"
+	"time"
+
+	"golang.org/x/net/context"
+)
+
+var PrintingHandler = &printingHandler{}
+
+type printingHandler struct{}
+
+// Prints "testVoid()" and returns nothing.
+func (p *printingHandler) TestVoid(ctx context.Context) (err error) {
+	fmt.Println("testVoid()")
+	return nil
+}
+
+// Prints 'testString("%s")' with thing as '%s'
+// @param string thing - the string to print
+// @return string - returns the string 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestString(ctx context.Context, thing string) (r string, err error) {
+	fmt.Printf("testString(\"%s\")\n", thing)
+	return thing, nil
+}
+
+// Prints 'testBool("%t")' with thing as 'true' or 'false'
+// @param bool thing - the bool to print
+// @return bool - returns the bool 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestBool(ctx context.Context, thing bool) (r bool, err error) {
+	fmt.Printf("testBool(%t)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testByte("%d")' with thing as '%d'
+// @param byte thing - the byte to print
+// @return byte - returns the byte 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestByte(ctx context.Context, thing int8) (r int8, err error) {
+	fmt.Printf("testByte(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testI32("%d")' with thing as '%d'
+// @param i32 thing - the i32 to print
+// @return i32 - returns the i32 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestI32(ctx context.Context, thing int32) (r int32, err error) {
+	fmt.Printf("testI32(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testI64("%d")' with thing as '%d'
+// @param i64 thing - the i64 to print
+// @return i64 - returns the i64 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestI64(ctx context.Context, thing int64) (r int64, err error) {
+	fmt.Printf("testI64(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testDouble("%f")' with thing as '%f'
+// @param double thing - the double to print
+// @return double - returns the double 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestDouble(ctx context.Context, thing float64) (r float64, err error) {
+	fmt.Printf("testDouble(%f)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testBinary("%s")' where '%s' is a hex-formatted string of thing's data
+// @param []byte thing - the binary to print
+// @return []byte - returns the binary 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestBinary(ctx context.Context, thing []byte) (r []byte, err error) {
+	fmt.Printf("testBinary(%s)\n", hex.EncodeToString(thing))
+	return thing, nil
+}
+
+// Prints 'testStruct("{%s}")' where thing has been formatted into a string of comma separated values
+// @param Xtruct thing - the Xtruct to print
+// @return Xtruct - returns the Xtruct 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestStruct(ctx context.Context, thing *Xtruct) (r *Xtruct, err error) {
+	fmt.Printf("testStruct({\"%s\", %d, %d, %d})\n", thing.StringThing, thing.ByteThing, thing.I32Thing, thing.I64Thing)
+	return thing, err
+}
+
+// Prints 'testNest("{%s}")' where thing has been formatted into a string of the nested struct
+// @param Xtruct2 thing - the Xtruct2 to print
+// @return Xtruct2 - returns the Xtruct2 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestNest(ctx context.Context, nest *Xtruct2) (r *Xtruct2, err error) {
+	thing := nest.StructThing
+	fmt.Printf("testNest({%d, {\"%s\", %d, %d, %d}, %d})\n", nest.ByteThing, thing.StringThing, thing.ByteThing, thing.I32Thing, thing.I64Thing, nest.I32Thing)
+	return nest, nil
+}
+
+// Prints 'testMap("{%s")' where thing has been formatted into a string of  'key => value' pairs
+//  separated by commas and new lines
+// @param map thing - the map to print
+// @return map - returns the map 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestMap(ctx context.Context, thing map[int32]int32) (r map[int32]int32, err error) {
+	fmt.Printf("testMap({")
+	first := true
+	for k, v := range thing {
+		if first {
+			first = false
+		} else {
+			fmt.Printf(", ")
+		}
+		fmt.Printf("%d => %d", k, v)
+	}
+	fmt.Printf("})\n")
+	return thing, nil
+}
+
+// Prints 'testStringMap("{%s}")' where thing has been formatted into a string of  'key => value' pairs
+//  separated by commas and new lines
+// @param map thing - the map to print
+// @return map - returns the map 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestStringMap(ctx context.Context, thing map[string]string) (r map[string]string, err error) {
+	fmt.Printf("testStringMap({")
+	first := true
+	for k, v := range thing {
+		if first {
+			first = false
+		} else {
+			fmt.Printf(", ")
+		}
+		fmt.Printf("%s => %s", k, v)
+	}
+	fmt.Printf("})\n")
+	return thing, nil
+}
+
+// Prints 'testSet("{%s}")' where thing has been formatted into a string of  values
+//  separated by commas and new lines
+// @param set thing - the set to print
+// @return set - returns the set 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestSet(ctx context.Context, thing []int32) (r []int32, err error) {
+	fmt.Printf("testSet({")
+	first := true
+	for k, _ := range thing {
+		if first {
+			first = false
+		} else {
+			fmt.Printf(", ")
+		}
+		fmt.Printf("%d", k)
+	}
+	fmt.Printf("})\n")
+	return thing, nil
+}
+
+// Prints 'testList("{%s}")' where thing has been formatted into a string of  values
+//  separated by commas and new lines
+// @param list thing - the list to print
+// @return list - returns the list 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestList(ctx context.Context, thing []int32) (r []int32, err error) {
+	fmt.Printf("testList({")
+	for i, v := range thing {
+		if i != 0 {
+			fmt.Printf(", ")
+		}
+		fmt.Printf("%d", v)
+	}
+	fmt.Printf("})\n")
+	return thing, nil
+}
+
+// Prints 'testEnum("%d")' where thing has been formatted into it's numeric value
+// @param Numberz thing - the Numberz to print
+// @return Numberz - returns the Numberz 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestEnum(ctx context.Context, thing Numberz) (r Numberz, err error) {
+	fmt.Printf("testEnum(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testTypedef("%d")' with thing as '%d'
+// @param UserId thing - the UserId to print
+// @return UserId - returns the UserId 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestTypedef(ctx context.Context, thing UserId) (r UserId, err error) {
+	fmt.Printf("testTypedef(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testMapMap("%d")' with hello as '%d'
+// @param i32 hello - the i32 to print
+// @return map> - returns a dictionary with these values:
+//   {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2 => 2, 3 => 3, 4 => 4, }, }
+//
+// Parameters:
+//  - Hello
+func (p *printingHandler) TestMapMap(ctx context.Context, hello int32) (r map[int32]map[int32]int32, err error) {
+	fmt.Printf("testMapMap(%d)\n", hello)
+
+	r = map[int32]map[int32]int32{
+		-4: map[int32]int32{-4: -4, -3: -3, -2: -2, -1: -1},
+		4:  map[int32]int32{4: 4, 3: 3, 2: 2, 1: 1},
+	}
+	return
+}
+
+// So you think you've got this all worked, out eh?
+//
+// Creates a the returned map with these values and prints it out:
+//   { 1 => { 2 => argument,
+//            3 => argument,
+//          },
+//     2 => { 6 => , },
+//   }
+// @return map> - a map with the above values
+//
+// Parameters:
+//  - Argument
+func (p *printingHandler) TestInsanity(ctx context.Context, argument *Insanity) (r map[UserId]map[Numberz]*Insanity, err error) {
+	fmt.Printf("testInsanity()\n")
+	r = make(map[UserId]map[Numberz]*Insanity)
+	r[1] = map[Numberz]*Insanity {
+		2: argument,
+		3: argument,
+	}
+	r[2] = map[Numberz]*Insanity {
+		6: NewInsanity(),
+	}
+	return
+}
+
+// Prints 'testMulti()'
+// @param byte arg0 -
+// @param i32 arg1 -
+// @param i64 arg2 -
+// @param map arg3 -
+// @param Numberz arg4 -
+// @param UserId arg5 -
+// @return Xtruct - returns an Xtruct with StringThing = "Hello2, ByteThing = arg0, I32Thing = arg1
+//    and I64Thing = arg2
+//
+// Parameters:
+//  - Arg0
+//  - Arg1
+//  - Arg2
+//  - Arg3
+//  - Arg4
+//  - Arg5
+func (p *printingHandler) TestMulti(ctx context.Context, arg0 int8, arg1 int32, arg2 int64, arg3 map[int16]string, arg4 Numberz, arg5 UserId) (r *Xtruct, err error) {
+	fmt.Printf("testMulti()\n")
+	r = NewXtruct()
+
+	r.StringThing = "Hello2"
+	r.ByteThing = arg0
+	r.I32Thing = arg1
+	r.I64Thing = arg2
+	return
+}
+
+// Print 'testException(%s)' with arg as '%s'
+// @param string arg - a string indication what type of exception to throw
+// if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
+// elsen if arg == "TException" throw TException
+// else do not throw anything
+//
+// Parameters:
+//  - Arg
+func (p *printingHandler) TestException(ctx context.Context, arg string) (err error) {
+	fmt.Printf("testException(%s)\n", arg)
+	switch arg {
+	case "Xception":
+		e := NewXception()
+		e.ErrorCode = 1001
+		e.Message = arg
+		return e
+	case "TException":
+		return errors.New("Just TException")
+	}
+	return
+}
+
+// Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s'
+// @param string arg - a string indication what type of exception to throw
+// if arg0 == "Xception" throw Xception with errorCode = 1001 and message = "This is an Xception"
+// elsen if arg0 == "Xception2" throw Xception2 with errorCode = 2002 and message = "This is an Xception2"
+// else do not throw anything
+// @return Xtruct - an Xtruct with StringThing = arg1
+//
+// Parameters:
+//  - Arg0
+//  - Arg1
+func (p *printingHandler) TestMultiException(ctx context.Context, arg0 string, arg1 string) (r *Xtruct, err error) {
+	fmt.Printf("testMultiException(%s, %s)\n", arg0, arg1)
+	switch arg0 {
+
+	case "Xception":
+		e := NewXception()
+		e.ErrorCode = 1001
+		e.Message = "This is an Xception"
+		return nil, e
+	case "Xception2":
+		e := NewXception2()
+		e.ErrorCode = 2002
+		e.StructThing = NewXtruct()
+		e.StructThing.StringThing = "This is an Xception2"
+		return nil, e
+	default:
+		r = NewXtruct()
+		r.StringThing = arg1
+		return
+	}
+}
+
+// Print 'testOneway(%d): Sleeping...' with secondsToSleep as '%d'
+// sleep 'secondsToSleep'
+// Print 'testOneway(%d): done sleeping!' with secondsToSleep as '%d'
+// @param i32 secondsToSleep - the number of seconds to sleep
+//
+// Parameters:
+//  - SecondsToSleep
+func (p *printingHandler) TestOneway(ctx context.Context, secondsToSleep int32) (err error) {
+	fmt.Printf("testOneway(%d): Sleeping...\n", secondsToSleep)
+	time.Sleep(time.Second * time.Duration(secondsToSleep))
+	fmt.Printf("testOneway(%d): done sleeping!\n", secondsToSleep)
+	return
+}
diff --git a/test/go/src/common/printing_handler_go17.go b/test/go/src/common/printing_handler_go17.go
new file mode 100644
index 0000000..1efae86
--- /dev/null
+++ b/test/go/src/common/printing_handler_go17.go
@@ -0,0 +1,386 @@
+// +build go1.7
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package common
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"encoding/hex"
+	. "gen/thrifttest"
+	"time"
+)
+
+var PrintingHandler = &printingHandler{}
+
+type printingHandler struct{}
+
+// Prints "testVoid()" and returns nothing.
+func (p *printingHandler) TestVoid(ctx context.Context) (err error) {
+	fmt.Println("testVoid()")
+	return nil
+}
+
+// Prints 'testString("%s")' with thing as '%s'
+// @param string thing - the string to print
+// @return string - returns the string 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestString(ctx context.Context, thing string) (r string, err error) {
+	fmt.Printf("testString(\"%s\")\n", thing)
+	return thing, nil
+}
+
+// Prints 'testBool("%t")' with thing as 'true' or 'false'
+// @param bool thing - the bool to print
+// @return bool - returns the bool 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestBool(ctx context.Context, thing bool) (r bool, err error) {
+	fmt.Printf("testBool(%t)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testByte("%d")' with thing as '%d'
+// @param byte thing - the byte to print
+// @return byte - returns the byte 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestByte(ctx context.Context, thing int8) (r int8, err error) {
+	fmt.Printf("testByte(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testI32("%d")' with thing as '%d'
+// @param i32 thing - the i32 to print
+// @return i32 - returns the i32 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestI32(ctx context.Context, thing int32) (r int32, err error) {
+	fmt.Printf("testI32(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testI64("%d")' with thing as '%d'
+// @param i64 thing - the i64 to print
+// @return i64 - returns the i64 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestI64(ctx context.Context, thing int64) (r int64, err error) {
+	fmt.Printf("testI64(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testDouble("%f")' with thing as '%f'
+// @param double thing - the double to print
+// @return double - returns the double 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestDouble(ctx context.Context, thing float64) (r float64, err error) {
+	fmt.Printf("testDouble(%f)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testBinary("%s")' where '%s' is a hex-formatted string of thing's data
+// @param []byte thing - the binary to print
+// @return []byte - returns the binary 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestBinary(ctx context.Context, thing []byte) (r []byte, err error) {
+	fmt.Printf("testBinary(%s)\n", hex.EncodeToString(thing))
+	return thing, nil
+}
+
+// Prints 'testStruct("{%s}")' where thing has been formatted into a string of comma separated values
+// @param Xtruct thing - the Xtruct to print
+// @return Xtruct - returns the Xtruct 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestStruct(ctx context.Context, thing *Xtruct) (r *Xtruct, err error) {
+	fmt.Printf("testStruct({\"%s\", %d, %d, %d})\n", thing.StringThing, thing.ByteThing, thing.I32Thing, thing.I64Thing)
+	return thing, err
+}
+
+// Prints 'testNest("{%s}")' where thing has been formatted into a string of the nested struct
+// @param Xtruct2 thing - the Xtruct2 to print
+// @return Xtruct2 - returns the Xtruct2 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestNest(ctx context.Context, nest *Xtruct2) (r *Xtruct2, err error) {
+	thing := nest.StructThing
+	fmt.Printf("testNest({%d, {\"%s\", %d, %d, %d}, %d})\n", nest.ByteThing, thing.StringThing, thing.ByteThing, thing.I32Thing, thing.I64Thing, nest.I32Thing)
+	return nest, nil
+}
+
+// Prints 'testMap("{%s")' where thing has been formatted into a string of  'key => value' pairs
+//  separated by commas and new lines
+// @param map thing - the map to print
+// @return map - returns the map 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestMap(ctx context.Context, thing map[int32]int32) (r map[int32]int32, err error) {
+	fmt.Printf("testMap({")
+	first := true
+	for k, v := range thing {
+		if first {
+			first = false
+		} else {
+			fmt.Printf(", ")
+		}
+		fmt.Printf("%d => %d", k, v)
+	}
+	fmt.Printf("})\n")
+	return thing, nil
+}
+
+// Prints 'testStringMap("{%s}")' where thing has been formatted into a string of  'key => value' pairs
+//  separated by commas and new lines
+// @param map thing - the map to print
+// @return map - returns the map 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestStringMap(ctx context.Context, thing map[string]string) (r map[string]string, err error) {
+	fmt.Printf("testStringMap({")
+	first := true
+	for k, v := range thing {
+		if first {
+			first = false
+		} else {
+			fmt.Printf(", ")
+		}
+		fmt.Printf("%s => %s", k, v)
+	}
+	fmt.Printf("})\n")
+	return thing, nil
+}
+
+// Prints 'testSet("{%s}")' where thing has been formatted into a string of  values
+//  separated by commas and new lines
+// @param set thing - the set to print
+// @return set - returns the set 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestSet(ctx context.Context, thing []int32) (r []int32, err error) {
+	fmt.Printf("testSet({")
+	first := true
+	for k, _ := range thing {
+		if first {
+			first = false
+		} else {
+			fmt.Printf(", ")
+		}
+		fmt.Printf("%d", k)
+	}
+	fmt.Printf("})\n")
+	return thing, nil
+}
+
+// Prints 'testList("{%s}")' where thing has been formatted into a string of  values
+//  separated by commas and new lines
+// @param list thing - the list to print
+// @return list - returns the list 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestList(ctx context.Context, thing []int32) (r []int32, err error) {
+	fmt.Printf("testList({")
+	for i, v := range thing {
+		if i != 0 {
+			fmt.Printf(", ")
+		}
+		fmt.Printf("%d", v)
+	}
+	fmt.Printf("})\n")
+	return thing, nil
+}
+
+// Prints 'testEnum("%d")' where thing has been formatted into it's numeric value
+// @param Numberz thing - the Numberz to print
+// @return Numberz - returns the Numberz 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestEnum(ctx context.Context, thing Numberz) (r Numberz, err error) {
+	fmt.Printf("testEnum(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testTypedef("%d")' with thing as '%d'
+// @param UserId thing - the UserId to print
+// @return UserId - returns the UserId 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestTypedef(ctx context.Context, thing UserId) (r UserId, err error) {
+	fmt.Printf("testTypedef(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testMapMap("%d")' with hello as '%d'
+// @param i32 hello - the i32 to print
+// @return map> - returns a dictionary with these values:
+//   {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2 => 2, 3 => 3, 4 => 4, }, }
+//
+// Parameters:
+//  - Hello
+func (p *printingHandler) TestMapMap(ctx context.Context, hello int32) (r map[int32]map[int32]int32, err error) {
+	fmt.Printf("testMapMap(%d)\n", hello)
+
+	r = map[int32]map[int32]int32{
+		-4: map[int32]int32{-4: -4, -3: -3, -2: -2, -1: -1},
+		4:  map[int32]int32{4: 4, 3: 3, 2: 2, 1: 1},
+	}
+	return
+}
+
+// So you think you've got this all worked, out eh?
+//
+// Creates a the returned map with these values and prints it out:
+//   { 1 => { 2 => argument,
+//            3 => argument,
+//          },
+//     2 => { 6 => , },
+//   }
+// @return map> - a map with the above values
+//
+// Parameters:
+//  - Argument
+func (p *printingHandler) TestInsanity(ctx context.Context, argument *Insanity) (r map[UserId]map[Numberz]*Insanity, err error) {
+	fmt.Printf("testInsanity()\n")
+	r = make(map[UserId]map[Numberz]*Insanity)
+	r[1] = map[Numberz]*Insanity {
+		2: argument,
+		3: argument,
+	}
+	r[2] = map[Numberz]*Insanity {
+		6: NewInsanity(),
+	}
+	return
+}
+
+// Prints 'testMulti()'
+// @param byte arg0 -
+// @param i32 arg1 -
+// @param i64 arg2 -
+// @param map arg3 -
+// @param Numberz arg4 -
+// @param UserId arg5 -
+// @return Xtruct - returns an Xtruct with StringThing = "Hello2, ByteThing = arg0, I32Thing = arg1
+//    and I64Thing = arg2
+//
+// Parameters:
+//  - Arg0
+//  - Arg1
+//  - Arg2
+//  - Arg3
+//  - Arg4
+//  - Arg5
+func (p *printingHandler) TestMulti(ctx context.Context, arg0 int8, arg1 int32, arg2 int64, arg3 map[int16]string, arg4 Numberz, arg5 UserId) (r *Xtruct, err error) {
+	fmt.Printf("testMulti()\n")
+	r = NewXtruct()
+
+	r.StringThing = "Hello2"
+	r.ByteThing = arg0
+	r.I32Thing = arg1
+	r.I64Thing = arg2
+	return
+}
+
+// Print 'testException(%s)' with arg as '%s'
+// @param string arg - a string indication what type of exception to throw
+// if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
+// elsen if arg == "TException" throw TException
+// else do not throw anything
+//
+// Parameters:
+//  - Arg
+func (p *printingHandler) TestException(ctx context.Context, arg string) (err error) {
+	fmt.Printf("testException(%s)\n", arg)
+	switch arg {
+	case "Xception":
+		e := NewXception()
+		e.ErrorCode = 1001
+		e.Message = arg
+		return e
+	case "TException":
+		return errors.New("Just TException")
+	}
+	return
+}
+
+// Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s'
+// @param string arg - a string indication what type of exception to throw
+// if arg0 == "Xception" throw Xception with errorCode = 1001 and message = "This is an Xception"
+// elsen if arg0 == "Xception2" throw Xception2 with errorCode = 2002 and message = "This is an Xception2"
+// else do not throw anything
+// @return Xtruct - an Xtruct with StringThing = arg1
+//
+// Parameters:
+//  - Arg0
+//  - Arg1
+func (p *printingHandler) TestMultiException(ctx context.Context, arg0 string, arg1 string) (r *Xtruct, err error) {
+	fmt.Printf("testMultiException(%s, %s)\n", arg0, arg1)
+	switch arg0 {
+
+	case "Xception":
+		e := NewXception()
+		e.ErrorCode = 1001
+		e.Message = "This is an Xception"
+		return nil, e
+	case "Xception2":
+		e := NewXception2()
+		e.ErrorCode = 2002
+		e.StructThing = NewXtruct()
+		e.StructThing.StringThing = "This is an Xception2"
+		return nil, e
+	default:
+		r = NewXtruct()
+		r.StringThing = arg1
+		return
+	}
+}
+
+// Print 'testOneway(%d): Sleeping...' with secondsToSleep as '%d'
+// sleep 'secondsToSleep'
+// Print 'testOneway(%d): done sleeping!' with secondsToSleep as '%d'
+// @param i32 secondsToSleep - the number of seconds to sleep
+//
+// Parameters:
+//  - SecondsToSleep
+func (p *printingHandler) TestOneway(ctx context.Context, secondsToSleep int32) (err error) {
+	fmt.Printf("testOneway(%d): Sleeping...\n", secondsToSleep)
+	time.Sleep(time.Second * time.Duration(secondsToSleep))
+	fmt.Printf("testOneway(%d): done sleeping!\n", secondsToSleep)
+	return
+}
diff --git a/test/go/src/common/server.go b/test/go/src/common/server.go
new file mode 100644
index 0000000..5ac4400
--- /dev/null
+++ b/test/go/src/common/server.go
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package common
+
+import (
+	"compress/zlib"
+	"crypto/tls"
+	"flag"
+	"fmt"
+	"gen/thrifttest"
+	"thrift"
+)
+
+var (
+	debugServerProtocol bool
+	certPath            string
+)
+
+func init() {
+	flag.BoolVar(&debugServerProtocol, "debug_server_protocol", false, "turn server protocol trace on")
+}
+
+func GetServerParams(
+	host string,
+	port int64,
+	domain_socket string,
+	transport string,
+	protocol string,
+	ssl bool,
+	certPath string,
+	handler thrifttest.ThriftTest) (thrift.TProcessor, thrift.TServerTransport, thrift.TTransportFactory, thrift.TProtocolFactory, error) {
+
+	var err error
+	hostPort := fmt.Sprintf("%s:%d", host, port)
+
+	var protocolFactory thrift.TProtocolFactory
+	switch protocol {
+	case "compact":
+		protocolFactory = thrift.NewTCompactProtocolFactory()
+	case "simplejson":
+		protocolFactory = thrift.NewTSimpleJSONProtocolFactory()
+	case "json":
+		protocolFactory = thrift.NewTJSONProtocolFactory()
+	case "binary":
+		protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
+	default:
+		return nil, nil, nil, nil, fmt.Errorf("Invalid protocol specified %s", protocol)
+	}
+	if debugServerProtocol {
+		protocolFactory = thrift.NewTDebugProtocolFactory(protocolFactory, "server:")
+	}
+
+	var serverTransport thrift.TServerTransport
+	if ssl {
+		cfg := new(tls.Config)
+		if cert, err := tls.LoadX509KeyPair(certPath+"/server.crt", certPath+"/server.key"); err != nil {
+			return nil, nil, nil, nil, err
+		} else {
+			cfg.Certificates = append(cfg.Certificates, cert)
+		}
+		serverTransport, err = thrift.NewTSSLServerSocket(hostPort, cfg)
+	} else {
+		if domain_socket != "" {
+			serverTransport, err = thrift.NewTServerSocket(domain_socket)
+		} else {
+			serverTransport, err = thrift.NewTServerSocket(hostPort)
+		}
+	}
+	if err != nil {
+		return nil, nil, nil, nil, err
+	}
+
+	var transportFactory thrift.TTransportFactory
+
+	switch transport {
+	case "http":
+		// there is no such factory, and we don't need any
+		transportFactory = nil
+	case "framed":
+		transportFactory = thrift.NewTTransportFactory()
+		transportFactory = thrift.NewTFramedTransportFactory(transportFactory)
+	case "buffered":
+		transportFactory = thrift.NewTBufferedTransportFactory(8192)
+	case "zlib":
+		transportFactory = thrift.NewTZlibTransportFactory(zlib.BestCompression)
+	case "":
+		transportFactory = thrift.NewTTransportFactory()
+	default:
+		return nil, nil, nil, nil, fmt.Errorf("Invalid transport specified %s", transport)
+	}
+	processor := thrifttest.NewThriftTestProcessor(handler)
+
+	return processor, serverTransport, transportFactory, protocolFactory, nil
+}
diff --git a/test/go/src/common/simple_handler.go b/test/go/src/common/simple_handler.go
new file mode 100644
index 0000000..0c9463d
--- /dev/null
+++ b/test/go/src/common/simple_handler.go
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package common
+
+import (
+	"errors"
+	. "gen/thrifttest"
+	"time"
+)
+
+var SimpleHandler = &simpleHandler{}
+
+type simpleHandler struct{}
+
+func (p *simpleHandler) TestVoid() (err error) {
+	return nil
+}
+
+func (p *simpleHandler) TestString(thing string) (r string, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestBool(thing []byte) (r []byte, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestByte(thing int8) (r int8, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestI32(thing int32) (r int32, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestI64(thing int64) (r int64, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestDouble(thing float64) (r float64, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestBinary(thing []byte) (r []byte, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestStruct(thing *Xtruct) (r *Xtruct, err error) {
+	return r, err
+}
+
+func (p *simpleHandler) TestNest(nest *Xtruct2) (r *Xtruct2, err error) {
+	return nest, nil
+}
+
+func (p *simpleHandler) TestMap(thing map[int32]int32) (r map[int32]int32, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestStringMap(thing map[string]string) (r map[string]string, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestSet(thing []int32) (r []int32, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestList(thing []int32) (r []int32, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestEnum(thing Numberz) (r Numberz, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestTypedef(thing UserId) (r UserId, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestMapMap(hello int32) (r map[int32]map[int32]int32, err error) {
+
+	r = map[int32]map[int32]int32{
+		-4: map[int32]int32{-4: -4, -3: -3, -2: -2, -1: -1},
+		4:  map[int32]int32{4: 4, 3: 3, 2: 2, 1: 1},
+	}
+	return
+}
+
+func (p *simpleHandler) TestInsanity(argument *Insanity) (r map[UserId]map[Numberz]*Insanity, err error) {
+	return nil, errors.New("No Insanity")
+}
+
+func (p *simpleHandler) TestMulti(arg0 int8, arg1 int32, arg2 int64, arg3 map[int16]string, arg4 Numberz, arg5 UserId) (r *Xtruct, err error) {
+	r = NewXtruct()
+
+	r.StringThing = "Hello2"
+	r.ByteThing = arg0
+	r.I32Thing = arg1
+	r.I64Thing = arg2
+	return
+}
+
+func (p *simpleHandler) TestException(arg string) (err error) {
+	switch arg {
+	case "Xception":
+		e := NewXception()
+		e.ErrorCode = 1001
+		e.Message = arg
+		return e
+	case "TException":
+		return errors.New("Just TException")
+	}
+	return
+}
+
+func (p *simpleHandler) TestMultiException(arg0 string, arg1 string) (r *Xtruct, err error) {
+	switch arg0 {
+
+	case "Xception":
+		e := NewXception()
+		e.ErrorCode = 1001
+		e.Message = "This is an Xception"
+		return nil, e
+	case "Xception2":
+		e := NewXception2()
+		e.ErrorCode = 2002
+		e.StructThing.StringThing = "This is an Xception2"
+		return nil, e
+	default:
+		r = NewXtruct()
+		r.StringThing = arg1
+		return
+	}
+}
+
+func (p *simpleHandler) TestOneway(secondsToSleep int32) (err error) {
+	time.Sleep(time.Second * time.Duration(secondsToSleep))
+	return
+}
diff --git a/test/haxe/Makefile.am b/test/haxe/Makefile.am
new file mode 100644
index 0000000..6c0483e
--- /dev/null
+++ b/test/haxe/Makefile.am
@@ -0,0 +1,104 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+THRIFTCMD = $(THRIFT) --gen haxe -r
+THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift
+
+BIN_CPP = bin/Main-debug
+BIN_PHP = bin/php/Main-debug.php
+BIN_PHP_WEB = bin/php-web-server/Main-debug.php
+
+gen-haxe/thrift/test/ThriftTest.hx: $(THRIFTTEST)
+	$(THRIFTCMD) $(THRIFTTEST)
+
+all-local: $(BIN_CPP) $(BIN_PHP) $(BIN_PHP_WEB)
+
+$(BIN_CPP): \
+		src/*.hx \
+		../../lib/haxe/src/org/apache/thrift/**/*.hx \
+		gen-haxe/thrift/test/ThriftTest.hx
+	$(HAXE) --cwd .  cpp.hxml
+
+$(BIN_PHP): \
+		src/*.hx \
+		../../lib/haxe/src/org/apache/thrift/**/*.hx \
+		gen-haxe/thrift/test/ThriftTest.hx
+	$(HAXE) --cwd .  php.hxml
+
+$(BIN_PHP_WEB): \
+		src/*.hx \
+		../../lib/haxe/src/org/apache/thrift/**/*.hx \
+		gen-haxe/thrift/test/ThriftTest.hx
+	$(HAXE) --cwd .  php-web-server.hxml
+
+
+
+#TODO: other haxe targets
+#    $(HAXE)  --cwd .  csharp
+#    $(HAXE)  --cwd .  flash
+#    $(HAXE)  --cwd .  java
+#    $(HAXE)  --cwd .  javascript
+#    $(HAXE)  --cwd .  neko
+#    $(HAXE)  --cwd .  python  # needs Haxe 3.2.0
+
+
+clean-local:
+	$(RM) -r gen-haxe bin
+
+.NOTPARALLEL:
+
+check: check_cpp \
+	check_php \
+	check_php_web 
+
+check_cpp: $(BIN_CPP) 
+	timeout 20 $(BIN_CPP) server &
+	sleep 1
+	$(BIN_CPP) client
+	sleep 10
+
+check_php: $(BIN_PHP) 
+	timeout 20 php -f $(BIN_PHP) server &
+	sleep 1
+	php -f $(BIN_PHP) client
+	sleep 10
+
+check_php_web: $(BIN_PHP_WEB) $(BIN_CPP)
+	timeout 20 php -S 127.0.0.1:9090 router.php &
+	sleep 1
+	$(BIN_CPP) client --transport http
+	sleep 10
+
+
+EXTRA_DIST = \
+	src \
+	cpp.hxml \
+	csharp.hxml \
+	flash.hxml \
+	java.hxml \
+	javascript.hxml \
+	neko.hxml \
+	php.hxml \
+	python.hxml \
+	router.php \
+	project.hide \
+	php-web-server.hxml \
+	TestClientServer.hxproj \
+	make_all.bat \
+	make_all.sh
diff --git a/test/haxe/Makefile.in b/test/haxe/Makefile.in
new file mode 100644
index 0000000..5c8c4bf
--- /dev/null
+++ b/test/haxe/Makefile.in
@@ -0,0 +1,703 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/haxe
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+THRIFTCMD = $(THRIFT) --gen haxe -r
+THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift
+BIN_CPP = bin/Main-debug
+BIN_PHP = bin/php/Main-debug.php
+BIN_PHP_WEB = bin/php-web-server/Main-debug.php
+EXTRA_DIST = \
+	src \
+	cpp.hxml \
+	csharp.hxml \
+	flash.hxml \
+	java.hxml \
+	javascript.hxml \
+	neko.hxml \
+	php.hxml \
+	python.hxml \
+	router.php \
+	project.hide \
+	php-web-server.hxml \
+	TestClientServer.hxproj \
+	make_all.bat \
+	make_all.sh
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/haxe/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/haxe/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile all-local
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am all-local check check-am clean clean-generic \
+	clean-libtool clean-local cscopelist-am ctags-am distclean \
+	distclean-generic distclean-libtool distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \
+	tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+gen-haxe/thrift/test/ThriftTest.hx: $(THRIFTTEST)
+	$(THRIFTCMD) $(THRIFTTEST)
+
+all-local: $(BIN_CPP) $(BIN_PHP) $(BIN_PHP_WEB)
+
+$(BIN_CPP): \
+		src/*.hx \
+		../../lib/haxe/src/org/apache/thrift/**/*.hx \
+		gen-haxe/thrift/test/ThriftTest.hx
+	$(HAXE) --cwd .  cpp.hxml
+
+$(BIN_PHP): \
+		src/*.hx \
+		../../lib/haxe/src/org/apache/thrift/**/*.hx \
+		gen-haxe/thrift/test/ThriftTest.hx
+	$(HAXE) --cwd .  php.hxml
+
+$(BIN_PHP_WEB): \
+		src/*.hx \
+		../../lib/haxe/src/org/apache/thrift/**/*.hx \
+		gen-haxe/thrift/test/ThriftTest.hx
+	$(HAXE) --cwd .  php-web-server.hxml
+
+#TODO: other haxe targets
+#    $(HAXE)  --cwd .  csharp
+#    $(HAXE)  --cwd .  flash
+#    $(HAXE)  --cwd .  java
+#    $(HAXE)  --cwd .  javascript
+#    $(HAXE)  --cwd .  neko
+#    $(HAXE)  --cwd .  python  # needs Haxe 3.2.0
+
+clean-local:
+	$(RM) -r gen-haxe bin
+
+.NOTPARALLEL:
+
+check: check_cpp \
+	check_php \
+	check_php_web 
+
+check_cpp: $(BIN_CPP) 
+	timeout 20 $(BIN_CPP) server &
+	sleep 1
+	$(BIN_CPP) client
+	sleep 10
+
+check_php: $(BIN_PHP) 
+	timeout 20 php -f $(BIN_PHP) server &
+	sleep 1
+	php -f $(BIN_PHP) client
+	sleep 10
+
+check_php_web: $(BIN_PHP_WEB) $(BIN_CPP)
+	timeout 20 php -S 127.0.0.1:9090 router.php &
+	sleep 1
+	$(BIN_CPP) client --transport http
+	sleep 10
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/haxe/TestClientServer.hxproj b/test/haxe/TestClientServer.hxproj
new file mode 100644
index 0000000..6696d80
--- /dev/null
+++ b/test/haxe/TestClientServer.hxproj
@@ -0,0 +1,67 @@
+
+
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  
+  
+  
+    
+    
+    
+  
+  
+  
+    
+  
+  
+    
+  
+  
+  
+    
+  
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  
+  
+  thrift -r -gen haxe  ../ThriftTest.thrift
+  
+  
+  
+  
+    
+  
+  
+
\ No newline at end of file
diff --git a/test/haxe/cpp.hxml b/test/haxe/cpp.hxml
new file mode 100644
index 0000000..6adb52d
--- /dev/null
+++ b/test/haxe/cpp.hxml
@@ -0,0 +1,41 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#CPP target
+-cpp bin
+
+#To produce 64 bit binaries the file should define the HXCPP_M64 compile variable:
+#-D HXCPP_M64
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/csharp.hxml b/test/haxe/csharp.hxml
new file mode 100644
index 0000000..295c017
--- /dev/null
+++ b/test/haxe/csharp.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#CSHARP target
+-cs bin/Tutorial.exe
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/flash.hxml b/test/haxe/flash.hxml
new file mode 100644
index 0000000..a1f0568
--- /dev/null
+++ b/test/haxe/flash.hxml
@@ -0,0 +1,41 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Flash target
+-swf bin/Tutorial.swf
+
+#Add debug information
+-debug
+
+# we need some goodies from sys.net
+# --macro allowPackage("sys")
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/java.hxml b/test/haxe/java.hxml
new file mode 100644
index 0000000..c615565
--- /dev/null
+++ b/test/haxe/java.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src 
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Java target
+-java bin/Tutorial.jar
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/javascript.hxml b/test/haxe/javascript.hxml
new file mode 100644
index 0000000..b2b3876
--- /dev/null
+++ b/test/haxe/javascript.hxml
@@ -0,0 +1,44 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#JavaScript target
+-js bin/Tutorial.js
+
+#You can use -D source-map-content (requires Haxe 3.1+) to have the .hx 
+#files directly embedded into the map file, this way you only have to 
+#upload it, and it will be always in sync with the compiled .js even if 
+#you modify your .hx files.
+-D source-map-content
+
+#Generate source map and add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/make_all.bat b/test/haxe/make_all.bat
new file mode 100644
index 0000000..eaeba89
--- /dev/null
+++ b/test/haxe/make_all.bat
@@ -0,0 +1,68 @@
+@echo off
+rem /*
+rem  * Licensed to the Apache Software Foundation (ASF) under one
+rem  * or more contributor license agreements. See the NOTICE file
+rem  * distributed with this work for additional information
+rem  * regarding copyright ownership. The ASF licenses this file
+rem  * to you under the Apache License, Version 2.0 (the
+rem  * "License"); you may not use this file except in compliance
+rem  * with the License. You may obtain a copy of the License at
+rem  *
+rem  *   http://www.apache.org/licenses/LICENSE-2.0
+rem  *
+rem  * Unless required by applicable law or agreed to in writing,
+rem  * software distributed under the License is distributed on an
+rem  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem  * KIND, either express or implied. See the License for the
+rem  * specific language governing permissions and limitations
+rem  * under the License.
+rem  */
+
+setlocal
+if "%HOMEDRIVE%"=="" goto MISSINGVARS
+if "%HOMEPATH%"=="" goto MISSINGVARS
+if "%HAXEPATH%"=="" goto NOTINSTALLED
+
+set path=%HAXEPATH%;%HAXEPATH%\..\neko;%path%
+
+rem # invoke Thrift comnpiler
+thrift -r -gen haxe   ..\ThriftTest.thrift
+if errorlevel 1 goto STOP
+
+rem # invoke Haxe compiler for all targets
+for %%a in (*.hxml) do (
+	rem * filter Python, as it is not supported by Haxe 3.1.3 (but will be in 3.1.4)
+	if not "%%a"=="python.hxml" (
+		echo --------------------------
+		echo Building %%a ...
+		echo --------------------------
+		haxe  --cwd .  %%a
+	)
+)
+
+
+echo.
+echo done.
+pause
+goto eof
+
+:NOTINSTALLED
+echo FATAL: Either Haxe is not installed, or the HAXEPATH variable is not set.
+pause
+goto eof
+
+:MISSINGVARS
+echo FATAL: Unable to locate home folder.
+echo.
+echo Both HOMEDRIVE and HOMEPATH need to be set to point to your Home folder.
+echo The current values are:
+echo HOMEDRIVE=%HOMEDRIVE%
+echo HOMEPATH=%HOMEPATH%
+pause
+goto eof
+
+:STOP
+pause
+goto eof
+
+:eof
diff --git a/test/haxe/make_all.sh b/test/haxe/make_all.sh
new file mode 100644
index 0000000..2621258
--- /dev/null
+++ b/test/haxe/make_all.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# invoke Thrift comnpiler
+thrift -r -gen haxe  ../ThriftTest.thrift
+
+# output folder
+if [ ! -d bin ]; then
+  mkdir  bin
+fi
+
+# invoke Haxe compiler
+for target in *.hxml; do 
+  echo --------------------------
+  echo Building ${target} ...
+  echo --------------------------
+  if [ ! -d bin/${target} ]; then
+    mkdir  bin/${target}
+  fi
+  haxe  --cwd .  ${target} 
+done
+
+
+#eof
diff --git a/test/haxe/neko.hxml b/test/haxe/neko.hxml
new file mode 100644
index 0000000..6161f69
--- /dev/null
+++ b/test/haxe/neko.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#neko target
+-neko bin/Tutorial.n
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/php-web-server.hxml b/test/haxe/php-web-server.hxml
new file mode 100644
index 0000000..395a852
--- /dev/null
+++ b/test/haxe/php-web-server.hxml
@@ -0,0 +1,43 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#PHP target
+-php bin/php-web-server/
+--php-front Main-debug.php
+
+#defines
+-D phpwebserver
+
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
diff --git a/test/haxe/php.hxml b/test/haxe/php.hxml
new file mode 100644
index 0000000..9651898
--- /dev/null
+++ b/test/haxe/php.hxml
@@ -0,0 +1,40 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#PHP target
+-php bin/php/
+--php-front Main-debug.php
+
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
diff --git a/test/haxe/project.hide b/test/haxe/project.hide
new file mode 100644
index 0000000..a1c09ba
--- /dev/null
+++ b/test/haxe/project.hide
@@ -0,0 +1,76 @@
+{
+     "type" : 0
+    ,"target" : 4
+    ,"name" : "Apache Thrift cross-platform test client/server"
+    ,"main" : null
+    ,"projectPackage" : ""
+    ,"company" : "Apache Software Foundation (ASF)"
+    ,"license" : "Apache License, Version 2.0"
+    ,"url" : "http://www.apache.org/licenses/LICENSE-2.0"
+    ,"targetData" : [
+         {
+             "pathToHxml" : "flash.hxml"
+            ,"runActionType" : 1
+            ,"runActionText" : "bin/Tutorial.swf"
+        }
+        ,{
+             "pathToHxml" : "javascript.hxml"
+            ,"runActionType" : 1
+            ,"runActionText" : "bin\\index.html"
+        }
+        ,{
+             "pathToHxml" : "neko.hxml"
+            ,"runActionType" : 2
+            ,"runActionText" : "neko bin/Tutorial.n"
+        }
+        ,{
+             "pathToHxml" : "php.hxml"
+        }
+        ,{
+             "pathToHxml" : "cpp.hxml"
+            ,"runActionType" : 2
+            ,"runActionText" : "bin/Main-debug.exe  client --protocol json"
+        }
+        ,{
+             "pathToHxml" : "java.hxml"
+        }
+        ,{
+             "pathToHxml" : "csharp.hxml"
+        }
+        ,{
+             "pathToHxml" : "python.hxml"
+            ,"runActionType" : 2
+            ,"runActionText" : "python bin/Tutorial.py"
+        }
+    ]
+    ,"files" : [
+         {
+             "path" : "src\\TestClient.hx"
+            ,"useTabs" : true
+            ,"indentSize" : 4
+            ,"foldedRegions" : [
+
+            ]
+            ,"activeLine" : 188
+        }
+        ,{
+             "path" : "src\\TestServer.hx"
+            ,"useTabs" : true
+            ,"indentSize" : 4
+            ,"foldedRegions" : [
+
+            ]
+            ,"activeLine" : 88
+        }
+    ]
+    ,"activeFile" : "src\\TestClient.hx"
+    ,"openFLTarget" : null
+    ,"openFLBuildMode" : "Debug"
+    ,"runActionType" : null
+    ,"runActionText" : null
+    ,"buildActionCommand" : null
+    ,"hiddenItems" : [
+
+    ]
+    ,"showHiddenItems" : false
+}
\ No newline at end of file
diff --git a/test/haxe/python.hxml b/test/haxe/python.hxml
new file mode 100644
index 0000000..f2c19fa
--- /dev/null
+++ b/test/haxe/python.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Python target
+-python bin/Tutorial.py
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/router.php b/test/haxe/router.php
new file mode 100644
index 0000000..e34135c
--- /dev/null
+++ b/test/haxe/router.php
@@ -0,0 +1,31 @@
+ 0) {
+            arg = args.shift();
+
+            if ( (arg == "-h") || (arg == "--help")) {
+                // -h [ --help ]               produce help message
+                Sys.println( GetHelp());
+                printHelpOnly = true;
+                return;
+            }
+            else if (arg == "--port") {
+                // --port arg (=9090)          Port number to listen
+                arg = args.shift();
+                var tmp = Std.parseInt(arg);
+                if( tmp != null) {
+                    port = tmp;
+                } else {
+                    throw "Invalid port number "+arg;
+                }
+            }
+            else if (arg == "--domain-socket") {
+                //   --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)
+                throw "domain sockets not supported yet";
+            }
+            else if (arg == "--named-pipe") {
+                //   --named-pipe arg            Windows Named Pipe (e.g. MyThriftPipe)
+                throw "named pipes not supported yet";
+            }
+            else if (arg == "--protocol") {
+                // --protocol arg (=binary)    protocol: binary, compact, json
+                arg = args.shift();
+                if( arg == "binary") {
+                    protocol = binary;
+                } else if( arg == "compact") {
+                    protocol = compact;
+                } else if( arg == "json") {
+                    protocol = json;
+                } else {
+                    InvalidArg(arg);
+                }
+            }
+            else if (arg == "--ssl") {
+                // --ssl                       Encrypted Transport using SSL
+                throw "SSL not supported yet";
+            }
+            else {
+                //Server only options:
+                if( server) {
+                    ParseServerArgument( arg, args);
+                } else {
+                    ParseClientArgument( arg, args);
+                }
+            }
+        }
+    }
+
+
+    private function ParseServerArgument( arg : String, args : Array) : Void {
+        if (arg == "--transport") {
+            //  --transport arg (=sockets)  Transport: buffered, framed, http, anonpipe
+            arg = args.shift();
+            if( arg == "buffered") {
+                buffered = true;
+            } else if( arg == "framed") {
+                framed = true;
+            } else if( arg == "http") {
+                transport = http;
+            } else if( arg == "anonpipe") {
+                throw "Anon pipes transport not supported yet";
+            } else {
+                InvalidArg(arg);
+            }
+        }
+        else if (arg == "--processor-events") {
+            throw "Processor events not supported yet";
+        }
+        else if (arg == "--server-type") {
+            //  --server-type arg (=simple) type of server,
+            // one of "simple", "thread-pool", "threaded", "nonblocking"
+            arg = args.shift();
+            if( arg == "simple") {
+                servertype = simple;
+            } else if( arg == "thread-pool") {
+                throw arg+" server not supported yet";
+            } else if( arg == "threaded") {
+                throw arg+" server not supported yet";
+            } else if( arg == "nonblocking") {
+                throw arg+" server not supported yet";
+            } else {
+                InvalidArg(arg);
+            }
+        }
+        else if ((arg == "-n") || (arg == "--workers")) {
+            //  -n [ --workers ] arg (=4)   Number of thread pools workers. Only valid for
+            //                              thread-pool server type
+            arg = args.shift();
+            var tmp = Std.parseInt(arg);
+            if( tmp != null) {
+                numThreads = tmp;
+            } else{
+                throw "Invalid number "+arg;
+            }
+        }
+        else {
+            InvalidArg(arg);
+        }
+    }
+
+
+    private function ParseClientArgument( arg : String, args : Array) : Void {
+        if (arg == "--host") {
+            //  --host arg (=localhost)     Host to connect
+            host = args.shift();
+        }
+        else if (arg == "--transport") {
+            //  --transport arg (=sockets)  Transport: buffered, framed, http, evhttp
+            arg = args.shift();
+            if( arg == "buffered") {
+                buffered = true;
+            } else if( arg == "framed") {
+                framed = true;
+            } else if( arg == "http") {
+                transport = http;
+            } else if( arg == "evhttp") {
+                throw "evhttp transport not supported yet";
+            } else {
+                InvalidArg(arg);
+            }
+        }
+        else if (arg == "--anon-pipes") {
+            //  --anon-pipes hRead hWrite   Windows Anonymous Pipes pair (handles)
+            throw "Anon pipes transport not supported yet";
+        }
+        else if ((arg == "-n") || (arg == "--testloops")) {
+            //  -n [ --testloops ] arg (=1) Number of Tests
+            arg = args.shift();
+            var tmp = Std.parseInt(arg);
+            if( tmp != null) {
+                numIterations = tmp;
+            } else {
+                throw "Invalid number "+arg;
+            }
+        }
+        else if ((arg == "-t") || (arg == "--threads")) {
+            //  -t [ --threads ] arg (=1)   Number of Test threads
+            arg = args.shift();
+            var tmp = Std.parseInt(arg);
+            if( tmp != null) {
+                numThreads = tmp;
+            } else {
+                throw "Invalid number "+arg;
+            }
+        }
+        else if (arg == "--skip-speed-test") {
+            //  --skip-speed-test              Skip the speed test
+            skipSpeedTest = true;
+        }
+        else {
+            InvalidArg(arg);
+        }
+    }
+
+
+    #end
+
+
+    private function InvalidArg( arg : String) : Void {
+        throw 'Invalid argument $arg';
+    }
+}
diff --git a/test/haxe/src/Main.hx b/test/haxe/src/Main.hx
new file mode 100644
index 0000000..9eb828f
--- /dev/null
+++ b/test/haxe/src/Main.hx
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import thrift.test.*;  // generated code
+
+class Main
+{
+    static function main() {
+        #if phpwebserver
+        initPhpWebServer();
+        //check method
+        if(php.Web.getMethod() != 'POST') {
+          Sys.println('http endpoint for thrift test server');
+          return;
+        }
+        #end
+
+        try {
+            var args = new Arguments();
+
+            if( args.printHelpOnly)
+                return;
+
+            if (args.server)
+                TestServer.Execute(args);
+            else
+                TestClient.Execute(args);
+
+            trace("Completed.");
+        } catch (e : String) {
+            trace(e);
+        }
+    }
+
+    #if phpwebserver
+    private static function initPhpWebServer()
+    {
+        //remap trace to error log
+        haxe.Log.trace = function(v:Dynamic, ?infos:haxe.PosInfos)
+        {
+          // handle trace
+          var newValue : Dynamic;
+          if (infos != null && infos.customParams!=null) {
+            var extra:String = "";
+            for( v in infos.customParams )
+              extra += "," + v;
+            newValue = v + extra;
+          }
+          else {
+            newValue = v;
+          }
+          var msg = infos != null ? infos.fileName + ':' + infos.lineNumber + ': ' : '';
+          Sys.stderr().writeString('${msg}${newValue}\n');
+        }
+    }
+    #end
+
+}
diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx
new file mode 100644
index 0000000..853319e
--- /dev/null
+++ b/test/haxe/src/TestClient.hx
@@ -0,0 +1,937 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package;
+
+import haxe.Int32;
+import haxe.Int64;
+import haxe.io.Bytes;
+import haxe.Timer;
+import haxe.ds.IntMap;
+import haxe.ds.StringMap;
+import haxe.ds.ObjectMap;
+
+import org.apache.thrift.*;
+import org.apache.thrift.helper.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+#if cpp
+import cpp.vm.Thread;
+#else
+// no thread support (yet)
+#end
+
+import thrift.test.*;  // generated code
+
+
+using StringTools;
+
+class TestResults {
+    private var successCnt : Int = 0;
+    private var errorCnt : Int = 0;
+    private var failedTests : String = "";
+    private var print_direct : Bool = false;
+
+    public static var EXITCODE_SUCCESS            = 0x00;  // no errors bits set
+    //
+    public static var EXITCODE_FAILBIT_BASETYPES  = 0x01;
+    public static var EXITCODE_FAILBIT_STRUCTS    = 0x02;
+    public static var EXITCODE_FAILBIT_CONTAINERS = 0x04;
+    public static var EXITCODE_FAILBIT_EXCEPTIONS = 0x08;
+    //
+    public static var EXITCODE_ALL_FAILBITS       = 0x0F;
+    //
+    private var testsExecuted : Int = 0;
+    private var testsFailed : Int = 0;
+    private var currentTest : Int = 0;
+
+
+    public function new(direct : Bool) {
+        print_direct = direct;
+    }
+
+    public function StartTestGroup( groupBit : Int) : Void {
+        currentTest = groupBit;
+        testsExecuted |= groupBit;
+    }
+
+    public function Expect( expr : Bool, msg : String) : Void {
+        if ( expr) {
+            ++successCnt;
+        } else {
+            ++errorCnt;
+            testsFailed |= currentTest;
+            failedTests += "\n  " + msg;
+            if( print_direct) {
+                trace('FAIL: $msg');
+            }
+        }
+    }
+
+    public function CalculateExitCode() : Int {
+        var notExecuted : Int = EXITCODE_ALL_FAILBITS & (~testsExecuted);
+        return testsFailed | notExecuted;
+    }
+
+    public function PrintSummary() : Void {
+        var total = successCnt + errorCnt;
+        var sp = Math.round((1000 * successCnt) / total) / 10;
+        var ep = Math.round((1000 * errorCnt) / total) / 10;
+
+        trace('===========================');
+        trace('Tests executed    $total');
+        trace('Tests succeeded   $successCnt ($sp%)');
+        trace('Tests failed      $errorCnt ($ep%)');
+        if ( errorCnt > 0)
+        {
+            trace('===========================');
+            trace('FAILED TESTS: $failedTests');
+        }
+        trace('===========================');
+    }
+}
+
+
+class TestClient {
+
+    public static function Execute(args : Arguments) :  Void
+    {
+        var exitCode = 0xFF;
+        try
+        {
+            var difft = Timer.stamp();
+
+            if ( args.numThreads > 1) {
+                #if cpp
+                exitCode = MultiThreadClient(args);
+                #else
+                trace('Threads not supported/implemented for this platform.');
+                exitCode = SingleThreadClient(args);
+                #end
+            } else {
+                exitCode = SingleThreadClient(args);
+            }
+
+            difft = Math.round( 1000 * (Timer.stamp() - difft)) / 1000;
+            trace('total test time: $difft seconds');
+        }
+        catch (e : TException)
+        {
+            trace('TException: $e');
+            exitCode = 0xFF;
+        }
+        catch (e : Dynamic)
+        {
+            trace('Exception: $e');
+            exitCode = 0xFF;
+        }
+
+        #if sys
+        Sys.exit( exitCode);
+        #end
+    }
+
+
+    public static function SingleThreadClient(args : Arguments) :  Int
+    {
+        var rslt = new TestResults(true);
+        RunClient(args,rslt);
+        rslt.PrintSummary();
+        return rslt.CalculateExitCode();
+    }
+
+
+    #if cpp
+    public static function MultiThreadClient(args : Arguments) :  Int
+    {
+        var threads = new List();
+        for( test in 0 ... args.numThreads) {
+            threads.add( StartThread( args));
+        }
+        var exitCode : Int = 0;
+        for( thread in threads) {
+            exitCode |= Thread.readMessage(true);
+        }
+        return exitCode;
+    }
+    #end
+
+    #if cpp
+    private static function StartThread(args : Arguments) : Thread {
+        var thread = Thread.create(
+            function() : Void {
+                var rslt = new TestResults(false);
+                var main : Thread = Thread.readMessage(true);
+                try
+                {
+                    RunClient(args,rslt);
+                }
+                catch (e : TException)
+                {
+                    rslt.Expect( false, '$e');
+                    trace('$e');
+                }
+                catch (e : Dynamic)
+                {
+                    rslt.Expect( false, '$e');
+                    trace('$e');
+                }
+                main.sendMessage( rslt.CalculateExitCode());
+            });
+
+        thread.sendMessage(Thread.current());
+        return thread;
+    }
+    #end
+
+
+    public static function RunClient(args : Arguments, rslt : TestResults)
+    {
+        var transport : TTransport = null;
+        switch (args.transport)
+        {
+            case socket:
+                transport = new TSocket(args.host, args.port);
+            case http:
+                var uri = 'http://${args.host}:${args.port}';
+                trace('- http client : ${uri}');
+                transport = new THttpClient(uri);
+            default:
+                throw "Unhandled transport";
+        }
+
+        // optional: layered transport
+        if ( args.framed) {
+            trace("- framed transport");
+            transport = new TFramedTransport(transport);
+        }
+        if ( args.buffered) {
+            trace("- buffered transport");
+            transport = new TBufferedTransport(transport);
+        }
+
+        // protocol
+        var protocol : TProtocol = null;
+        switch( args.protocol)
+        {
+        case binary:
+            trace("- binary protocol");
+            protocol = new TBinaryProtocol(transport);
+        case json:
+            trace("- json protocol");
+            protocol = new TJSONProtocol(transport);
+        case compact:
+            trace("- compact protocol");
+            protocol = new TCompactProtocol(transport);
+        }
+
+        // some quick and basic unit tests
+        HaxeBasicsTest( args, rslt);
+        ModuleUnitTests( args, rslt);
+
+        // now run the test code
+        trace('- ${args.numIterations} iterations');
+        for( i in 0 ... args.numIterations) {
+            ClientTest( transport, protocol, args, rslt);
+        }
+    }
+
+
+    public static function HaxeBasicsTest( args : Arguments, rslt : TestResults) : Void
+    {
+        // We need to test a few basic things used in the ClientTest
+        // Anything else beyond this scope should go into /lib/haxe/ instead
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);
+
+        var map32 = new IntMap();
+        var map64 = new Int64Map();
+
+        rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map Test #1");
+        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #2");
+        rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map Test #3");
+        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #4");
+
+        map32.set( 42, 815);
+        map64.set( Int64.make(0,42), 815);
+        map32.set( -517, 23);
+        map64.set( Int64.neg(Int64.make(0,517)), 23);
+        map32.set( 0, -123);
+        map64.set( Int64.make(0,0), -123);
+
+        //trace('map32 = $map32');
+        //trace('map64 = $map64');
+
+        rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map Test #10");
+        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #11");
+        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map Test #12");
+        rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map Test #13");
+        rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map Test #14");
+        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #15");
+        rslt.Expect( map32.get( -517) == map64.get( Int64.neg(Int64.make(0,517))), "Int64Map Test #16");
+        rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map Test #Int64.make(-5,17)");
+        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map Test #18");
+        rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map Test #19");
+        rslt.Expect( map32.remove( -517) == map64.remove( Int64.neg(Int64.make(0,517))), "Int64Map Test #20");
+        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #21");
+        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map Test #22");
+        rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map Test #23");
+        rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map Test #24");
+        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #25");
+        rslt.Expect( map32.get( -517) == map64.get( Int64.neg(Int64.make(0,517))), "Int64Map Test #26");
+        rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map Test #27");
+        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map Test #28");
+
+        map32.set( 42, 1);
+        map64.set( Int64.make(0,42), 1);
+        map32.set( -517, -2);
+        map64.set( Int64.neg(Int64.make(0,517)), -2);
+        map32.set( 0, 3);
+        map64.set( Int64.make(0,0), 3);
+
+        var c32 = 0;
+        var ksum32 = 0;
+        for (key in map32.keys()) {
+            ++c32;
+            ksum32 += key;
+        }
+        var c64 = 0;
+        var ksum64 = Int64.make(0,0);
+        for (key in map64.keys()) {
+            ++c64;
+            ksum64 = Int64.add( ksum64, key);
+        }
+        rslt.Expect( c32 == c64, "Int64Map Test #30");
+        rslt.Expect( '$ksum64' == '$ksum32', '$ksum64 == $ksum32   Test #31');
+
+        //compare without spaces because differ in php and cpp
+        var s32 = map32.toString().replace(' ', '');
+        var s64 = map64.toString().replace(' ', '');
+        rslt.Expect( s32 == s64, "Int64Map.toString(): " + ' ("$s32" == "$s64") Test #32');
+
+        map32.remove( 42);
+        map64.remove( Int64.make(0,42));
+        map32.remove( -517);
+        map64.remove( Int64.neg(Int64.make(0,517)));
+        map32.remove( 0);
+        map64.remove( Int64.make(0,0));
+
+        rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map Test #90");
+        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #91");
+        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map Test #92");
+        rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map Test #93");
+        rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map Test #94");
+        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #95");
+        rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map Test #96");
+        rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map Test #97");
+        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0, 0)), "Int64Map Test #98");
+    }
+
+
+    // core module unit tests
+    public static function ModuleUnitTests( args : Arguments, rslt : TestResults) : Void {
+        #if debug
+
+        try {
+            BitConverter.UnitTest();
+            rslt.Expect( true, 'BitConverter.UnitTest  Test #100');
+        }
+        catch( e : Dynamic) {
+            rslt.Expect( false, 'BitConverter.UnitTest: $e  Test #100');
+        }
+
+        try {
+            ZigZag.UnitTest();
+            rslt.Expect( true, 'ZigZag.UnitTest  Test #101');
+        }
+        catch( e : Dynamic) {
+            rslt.Expect( false, 'ZigZag.UnitTest: $e  Test #101');
+        }
+
+        #end
+    }
+
+
+    public static function BytesToHex(data : Bytes) : String {
+        var hex = "";
+        for ( i in 0 ... data.length) {
+            hex += StringTools.hex( data.get(i), 2);
+        }
+        return hex;
+    }
+
+    public static function PrepareTestData(randomDist : Bool) : Bytes    {
+        var retval = Bytes.alloc(0x100);
+        var initLen : Int = (retval.length > 0x100 ? 0x100 : retval.length);
+
+        // linear distribution, unless random is requested
+        if (!randomDist) {
+            for (i in 0 ... initLen) {
+                retval.set(i, i % 0x100);
+            }
+            return retval;
+        }
+
+        // random distribution
+        for (i in 0 ... initLen) {
+            retval.set(i, 0);
+        }
+        for (i in 1 ... initLen) {
+            while( true) {
+                var nextPos = Std.random(initLen);
+                if (retval.get(nextPos) == 0) {
+                    retval.set( nextPos, i % 0x100);
+                    break;
+                }
+            }
+        }
+        return retval;
+    }
+
+
+    public static function ClientTest( transport : TTransport, protocol : TProtocol,
+                                       args : Arguments, rslt : TestResults) : Void
+    {
+        var client = new ThriftTestImpl(protocol,protocol);
+        try
+        {
+            if (!transport.isOpen())
+            {
+                transport.open();
+            }
+        }
+        catch (e : TException)
+        {
+            rslt.Expect( false, 'unable to open transport: $e');
+            return;
+        }
+        catch (e : Dynamic)
+        {
+            rslt.Expect( false, 'unable to open transport: $e');
+            return;
+        }
+
+        var start = Date.now();
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_EXCEPTIONS);
+
+        // if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
+        trace('testException("Xception")');
+        try {
+            client.testException("Xception");
+            rslt.Expect( false, 'testException("Xception") should throw');
+        }
+        catch (e : Xception)
+        {
+            rslt.Expect( e.message == "Xception", 'testException("Xception")  -  e.message == "Xception"');
+            rslt.Expect( e.errorCode == 1001, 'testException("Xception")  -  e.errorCode == 1001');
+        }
+        catch (e : TException)
+        {
+            rslt.Expect( false, 'testException("Xception")  -  ${e} : ${e.errorMsg}');
+        }
+        catch (e : Dynamic)
+        {
+            rslt.Expect( false, 'testException("Xception")  -  $e');
+        }
+
+        // if arg == "TException" throw TException
+        trace('testException("TException")');
+        try {
+            client.testException("TException");
+            rslt.Expect( false, 'testException("TException") should throw');
+        }
+        catch (e : TException)
+        {
+            rslt.Expect( true, 'testException("TException")  -  $e : ${e.errorMsg}');
+        }
+        catch (e : Dynamic)
+        {
+            rslt.Expect( false, 'testException("TException")  -  $e');
+        }
+
+        // reopen the transport, just in case the server closed his end
+        if (transport.isOpen())
+            transport.close();
+        transport.open();
+
+        // else do not throw anything
+        trace('testException("bla")');
+        try {
+            client.testException("bla");
+            rslt.Expect( true, 'testException("bla") should not throw');
+        }
+        catch (e : TException)
+        {
+            rslt.Expect( false, 'testException("bla")  -  ${e} : ${e.errorMsg}');
+        }
+        catch (e : Dynamic)
+        {
+            rslt.Expect( false, 'testException("bla")  -  $e');
+        }
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);
+
+        trace('testVoid()');
+        client.testVoid();
+        trace(' = void');
+        rslt.Expect(true,"testVoid()");  // bump counter
+
+        trace('testBool(${true})');
+        var b = client.testBool(true);
+        trace(' = $b');
+        rslt.Expect(b, '$b == "${true}"');
+        trace('testBool(${false})');
+        b = client.testBool(false);
+        trace(' = $b');
+        rslt.Expect( ! b, '$b == "${false}"');
+
+        trace('testString("Test")');
+        var s = client.testString("Test");
+        trace(' = "$s"');
+        rslt.Expect(s == "Test", '$s == "Test"');
+
+        trace('testByte(1)');
+        var i8 = client.testByte(1);
+        trace(' = $i8');
+        rslt.Expect(i8 == 1, '$i8 == 1');
+
+        trace('testI32(-1)');
+        var i32 = client.testI32(-1);
+        trace(' = $i32');
+        rslt.Expect(i32 == -1, '$i32 == -1');
+
+        trace('testI64(-34359738368)');
+        var i64 = client.testI64( Int64.make( 0xFFFFFFF8, 0x00000000)); // -34359738368
+        trace(' = $i64');
+        rslt.Expect( Int64.compare( i64, Int64.make( 0xFFFFFFF8, 0x00000000)) == 0,
+                     Int64.toStr(i64) +" == "+Int64.toStr(Int64.make( 0xFFFFFFF8, 0x00000000)));
+
+        // edge case: the largest negative Int64 has no positive Int64 equivalent
+        trace('testI64(-9223372036854775808)');
+        i64 = client.testI64( Int64.make( 0x80000000, 0x00000000)); // -9223372036854775808
+        trace(' = $i64');
+        rslt.Expect( Int64.compare( i64, Int64.make( 0x80000000, 0x00000000)) == 0,
+                     Int64.toStr(i64) +" == "+Int64.toStr(Int64.make( 0x80000000, 0x00000000)));
+
+        trace('testDouble(5.325098235)');
+        var dub = client.testDouble(5.325098235);
+        trace(' = $dub');
+        rslt.Expect(dub == 5.325098235, '$dub == 5.325098235');
+
+        var binOut = PrepareTestData(true);
+        trace('testBinary('+BytesToHex(binOut)+')');
+        try {
+            var binIn = client.testBinary(binOut);
+            trace('testBinary() = '+BytesToHex(binIn));
+            rslt.Expect( binIn.length == binOut.length, '${binIn.length} == ${binOut.length}');
+            var len = ((binIn.length < binOut.length)  ?  binIn.length  : binOut.length);
+            for (ofs in 0 ... len) {
+                if (binIn.get(ofs) != binOut.get(ofs)) {
+                    rslt.Expect( false, 'testBinary('+BytesToHex(binOut)+'): content mismatch at offset $ofs');
+                }
+            }
+        }
+        catch (e : TApplicationException) {
+            trace('testBinary('+BytesToHex(binOut)+'): '+e.errorMsg);  // may not be supported by the server
+        }
+
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_STRUCTS);
+
+        trace('testStruct({"Zero", 1, -3, -5})');
+        var o = new Xtruct();
+        o.string_thing = "Zero";
+        o.byte_thing = 1;
+        o.i32_thing = -3;
+        o.i64_thing = Int64.make(0,-5);
+        var i = client.testStruct(o);
+        trace(' = {"' + i.string_thing + '", ' + i.byte_thing +', '
+                      + i.i32_thing +', '+ Int64.toStr(i.i64_thing) + '}');
+        rslt.Expect( i.string_thing == o.string_thing, "i.string_thing == o.string_thing");
+        rslt.Expect( i.byte_thing == o.byte_thing, "i.byte_thing == o.byte_thing");
+        rslt.Expect( i.i32_thing == o.i32_thing, "i.i64_thing == o.i64_thing");
+        rslt.Expect( i.i32_thing == o.i32_thing, "i.i64_thing == o.i64_thing");
+
+        trace('testNest({1, {\"Zero\", 1, -3, -5}, 5})');
+        var o2 = new Xtruct2();
+        o2.byte_thing = 1;
+        o2.struct_thing = o;
+        o2.i32_thing = 5;
+        var i2 = client.testNest(o2);
+        i = i2.struct_thing;
+        trace(" = {" + i2.byte_thing + ", {\"" + i.string_thing + "\", "
+              + i.byte_thing + ", " + i.i32_thing + ", " + Int64.toStr(i.i64_thing) + "}, "
+              + i2.i32_thing + "}");
+        rslt.Expect( i2.byte_thing == o2.byte_thing, "i2.byte_thing == o2.byte_thing");
+        rslt.Expect( i2.i32_thing == o2.i32_thing, "i2.i32_thing == o2.i32_thing");
+        rslt.Expect( i.string_thing == o.string_thing, "i.string_thing == o.string_thing");
+        rslt.Expect( i.byte_thing == o.byte_thing, "i.byte_thing == o.byte_thing");
+        rslt.Expect( i.i32_thing == o.i32_thing, "i.i32_thing == o.i32_thing");
+        rslt.Expect( Int64.compare( i.i64_thing, o.i64_thing) == 0, "i.i64_thing == o.i64_thing");
+
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_CONTAINERS);
+
+        var mapout = new IntMap< haxe.Int32>();
+        for ( j in 0 ... 5)
+        {
+            mapout.set(j, j - 10);
+        }
+        trace("testMap({");
+        var first : Bool = true;
+        for( key in mapout.keys())
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                trace(", ");
+            }
+            trace(key + " => " + mapout.get(key));
+        }
+        trace("})");
+
+        var mapin = client.testMap(mapout);
+
+        trace(" = {");
+        first = true;
+        for( key in mapin.keys())
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                trace(", ");
+            }
+            trace(key + " => " + mapin.get(key));
+            rslt.Expect( mapin.get(key) == mapout.get(key), ' mapin.get($key) == mapout.get($key)');
+        }
+        trace("}");
+        for( key in mapout.keys())
+        {
+            rslt.Expect(mapin.exists(key), 'mapin.exists($key)');
+        }
+
+        var listout = new List();
+        for (j in -2 ... 3)
+        {
+            listout.add(j);
+        }
+        trace("testList({");
+        first = true;
+        for( j in listout)
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                trace(", ");
+            }
+            trace(j);
+        }
+        trace("})");
+
+        var listin = client.testList(listout);
+
+        trace(" = {");
+        first = true;
+        for( j in listin)
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                trace(", ");
+            }
+            trace(j);
+        }
+        trace("}");
+
+        rslt.Expect(listin.length == listout.length, "listin.length == listout.length");
+        var literout = listout.iterator();
+        var literin = listin.iterator();
+        while( literin.hasNext()) {
+            rslt.Expect(literin.next() == literout.next(), "literin[i] == literout[i]");
+        }
+
+        //set
+        var setout = new IntSet();
+        for (j in -2 ... 3)
+        {
+            setout.add(j);
+        }
+        trace("testSet({");
+        first = true;
+        for( j in setout)
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                trace(", ");
+            }
+            trace(j);
+        }
+        trace("})");
+
+        var setin = client.testSet(setout);
+
+        trace(" = {");
+        first = true;
+        for( j in setin)
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                trace(", ");
+            }
+            trace(j);
+            rslt.Expect(setout.contains(j), 'setout.contains($j)');
+        }
+        trace("}");
+        rslt.Expect(setin.size == setout.size, "setin.length == setout.length");
+
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);
+
+        trace("testEnum(ONE)");
+        var ret = client.testEnum(Numberz.ONE);
+        trace(" = " + ret);
+        rslt.Expect(ret == Numberz.ONE, '$ret == Numberz.ONE');
+
+        trace("testEnum(TWO)");
+        ret = client.testEnum(Numberz.TWO);
+        trace(" = " + ret);
+        rslt.Expect(ret == Numberz.TWO, '$ret == Numberz.TWO');
+
+        trace("testEnum(THREE)");
+        ret = client.testEnum(Numberz.THREE);
+        trace(" = " + ret);
+        rslt.Expect(ret == Numberz.THREE, '$ret == Numberz.THREE');
+
+        trace("testEnum(FIVE)");
+        ret = client.testEnum(Numberz.FIVE);
+        trace(" = " + ret);
+        rslt.Expect(ret == Numberz.FIVE, '$ret == Numberz.FIVE');
+
+        trace("testEnum(EIGHT)");
+        ret = client.testEnum(Numberz.EIGHT);
+        trace(" = " + ret);
+        rslt.Expect(ret == Numberz.EIGHT, '$ret == Numberz.EIGHT');
+
+        trace("testTypedef(309858235082523)");
+        var uid = client.testTypedef( Int64.make( 0x119D0, 0x7E08671B));  // 309858235082523
+        trace(" = " + uid);
+        rslt.Expect( Int64.compare( uid, Int64.make( 0x119D0, 0x7E08671B)) == 0,
+                     Int64.toStr(uid)+" == "+Int64.toStr(Int64.make( 0x119D0, 0x7E08671B)));
+
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_CONTAINERS);
+
+        trace("testMapMap(1)");
+        var mm = client.testMapMap(1);
+        trace(" = {");
+        for( key in mm.keys())
+        {
+            trace(key + " => {");
+            var m2 = mm.get(key);
+            for( k2 in m2.keys())
+            {
+                trace(k2 + " => " + m2.get(k2) + ", ");
+            }
+            trace("}, ");
+        }
+        trace("}");
+
+        var pos = mm.get(4);
+        var neg = mm.get(-4);
+        rslt.Expect( (pos != null) && (neg != null), "(pos != null) && (neg != null)");
+        for (i in 1 ... 5) {
+            rslt.Expect( pos.get(i) == i, 'pos.get($i) == $i');
+            rslt.Expect( neg.get(-i) == -i, 'neg.get(-$i) == -$i');
+        }
+        rslt.Expect( ! pos.exists(0), '!pos.exists(0)');
+        rslt.Expect( ! neg.exists(-0), '!neg.exists(-0)');
+        rslt.Expect( ! pos.exists(42), '!pos.exists(42)');
+        rslt.Expect( ! neg.exists(-42), '!neg.exists(-42)');
+
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_STRUCTS);
+
+        var insane = new Insanity();
+        insane.userMap = new IntMap< Int64>();
+        insane.userMap.set( Numberz.FIVE, Int64.make(0,5000));
+        var truck = new Xtruct();
+        truck.string_thing = "Truck";
+        truck.byte_thing = 8;
+        truck.i32_thing = 8;
+        truck.i64_thing = Int64.make(0,8);
+        insane.xtructs = new List();
+        insane.xtructs.add(truck);
+        trace("testInsanity()");
+        var whoa = client.testInsanity(insane);
+        trace(" = {");
+        for( key in whoa.keys())
+        {
+            var val = whoa.get(key);
+            trace(key + " => {");
+
+            for( k2 in val.keys())
+            {
+                var v2 = val.get(k2);
+
+                trace(k2 + " => {");
+                var userMap = v2.userMap;
+
+                trace("{");
+                if (userMap != null)
+                {
+                    for( k3 in userMap.keys())
+                    {
+                        trace(k3 + " => " + userMap.get(k3) + ", ");
+                    }
+                }
+                else
+                {
+                    trace("null");
+                }
+                trace("}, ");
+
+                var xtructs = v2.xtructs;
+
+                trace("{");
+                if (xtructs != null)
+                {
+                    for( x in xtructs)
+                    {
+                        trace("{\"" + x.string_thing + "\", "
+                              + x.byte_thing + ", " + x.i32_thing + ", "
+                              + x.i32_thing + "}, ");
+                    }
+                }
+                else
+                {
+                    trace("null");
+                }
+                trace("}");
+
+                trace("}, ");
+            }
+            trace("}, ");
+        }
+        trace("}");
+
+
+		/**
+		* So you think you've got this all worked, out eh?
+		*
+		* Creates a the returned map with these values and prints it out:
+		*   { 1 => { 2 => argument,
+		*            3 => argument,
+		*          },
+		*     2 => { 6 => , },
+		*   }
+		* @return map> - a map with the above values
+		*/
+		
+        var first_map = whoa.get(Int64.make(0,1));
+        var second_map = whoa.get(Int64.make(0,2));
+        rslt.Expect( (first_map != null) && (second_map != null), "(first_map != null) && (second_map != null)");
+        if ((first_map != null) && (second_map != null))
+        {
+            var crazy2 = first_map.get(Numberz.TWO);
+            var crazy3 = first_map.get(Numberz.THREE);
+            var looney = second_map.get(Numberz.SIX);
+            rslt.Expect( (crazy2 != null) && (crazy3 != null) && (looney != null),
+                        "(crazy2 != null) && (crazy3 != null) && (looney != null)");
+
+            var crz2iter = crazy2.xtructs.iterator();
+            var crz3iter = crazy3.xtructs.iterator();
+            rslt.Expect( crz2iter.hasNext() && crz3iter.hasNext(), "crz2iter.hasNext() && crz3iter.hasNext()");
+            var goodbye2 = crz2iter.next();
+            var goodbye3 = crz3iter.next();
+            rslt.Expect( ! (crz2iter.hasNext() || crz3iter.hasNext()), "! (crz2iter.hasNext() || crz3iter.hasNext())");
+
+			rslt.Expect( Int64.compare( crazy2.userMap.get(Numberz.FIVE), insane.userMap.get(Numberz.FIVE)) == 0, "crazy2.userMap[5] == insane.userMap[5]");
+			rslt.Expect( truck.string_thing == goodbye2.string_thing, "truck.string_thing == goodbye2.string_thing");
+			rslt.Expect( truck.byte_thing  == goodbye2.byte_thing, "truck.byte_thing  == goodbye2.byte_thing");
+			rslt.Expect( truck.i32_thing  == goodbye2.i32_thing, "truck.i32_thing  == goodbye2.i32_thing");
+			rslt.Expect( Int64.compare( truck.i64_thing, goodbye2.i64_thing) == 0, "truck.i64_thing  == goodbye2.i64_thing");
+
+			rslt.Expect( Int64.compare( crazy3.userMap.get(Numberz.FIVE), insane.userMap.get(Numberz.FIVE)) == 0, "crazy3.userMap[5] == insane.userMap[5]");
+			rslt.Expect( truck.string_thing == goodbye3.string_thing, "truck.string_thing == goodbye3.string_thing");
+			rslt.Expect( truck.byte_thing  == goodbye3.byte_thing, "truck.byte_thing  == goodbye3.byte_thing");
+			rslt.Expect( truck.i32_thing  == goodbye3.i32_thing, "truck.i32_thing  == goodbye3.i32_thing");
+			rslt.Expect( Int64.compare( truck.i64_thing, goodbye3.i64_thing) == 0, "truck.i64_thing  == goodbye3.i64_thing");
+			
+			rslt.Expect( ! looney.isSet(1), "! looney.isSet(1)");
+			rslt.Expect( ! looney.isSet(2), "! looney.isSet(2)");
+        }
+
+        var arg0 = 1;
+        var arg1 = 2;
+        var arg2 = Int64.make( 0x7FFFFFFF,0xFFFFFFFF);
+        var multiDict = new IntMap< String>();
+        multiDict.set(1, "one");
+        var arg4 = Numberz.FIVE;
+        var arg5 = Int64.make(0,5000000);
+        trace("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")");
+        var multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5);
+        trace(" = Xtruct(byte_thing:" + multiResponse.byte_thing + ",string_thing:" + multiResponse.string_thing
+                    + ",i32_thing:" + multiResponse.i32_thing
+                    + ",i64_thing:" + Int64.toStr(multiResponse.i64_thing) + ")");
+
+        rslt.Expect( multiResponse.string_thing == "Hello2", 'multiResponse.String_thing == "Hello2"');
+        rslt.Expect( multiResponse.byte_thing == arg0, 'multiResponse.Byte_thing == arg0');
+        rslt.Expect( multiResponse.i32_thing == arg1, 'multiResponse.I32_thing == arg1');
+        rslt.Expect( Int64.compare( multiResponse.i64_thing, arg2) == 0, 'multiResponse.I64_thing == arg2');
+
+
+        rslt.StartTestGroup( 0);
+
+        trace("Test Oneway(1)");
+        client.testOneway(1);
+
+        if( ! args.skipSpeedTest) {
+            trace("Test Calltime()");
+            var difft = Timer.stamp();
+            for ( k in 0 ... 1000) {
+                client.testVoid();
+            }
+            difft = Math.round( 1000 * (Timer.stamp() - difft)) / 1000;
+            trace('$difft ms per testVoid() call');
+        }
+    }
+}
diff --git a/test/haxe/src/TestMacro.hx b/test/haxe/src/TestMacro.hx
new file mode 100644
index 0000000..a620760
--- /dev/null
+++ b/test/haxe/src/TestMacro.hx
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package ;
+
+import haxe.macro.Context;
+import haxe.macro.Expr;
+
+/****
+ * If you call the Thrift compiler this way (e.g. by changing the prebuild command)
+ *
+ *     thrift -r -gen haxe:buildmacro=TestMacro.handle()   ../ThriftTest.thrift
+ *
+ * the TestMacro.handle() function implemented below is called for each generated class
+ * and interface. Use "thrift --help" to get more info about other available options.
+ */
+class TestMacro
+{
+  public static function handle( ) : Array< Field> {
+    trace('TestMacro called for ' + Context.getLocalType());
+    return Context.getBuildFields();
+  }
+
+}
diff --git a/test/haxe/src/TestServer.hx b/test/haxe/src/TestServer.hx
new file mode 100644
index 0000000..450c8f2
--- /dev/null
+++ b/test/haxe/src/TestServer.hx
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import thrift.test.*;  // generated code
+
+
+class TestServer
+{
+    public static function Execute(args : Arguments) :  Void
+    {
+        try
+        {
+            // Transport
+            var transport : TServerTransport = null;
+            switch( args.transport) {
+            case socket:
+                trace("- socket port "+args.port);
+                transport = new TServerSocket( args.port);
+            case http:
+                trace("- http");
+                #if !phpwebserver
+                  throw "HTTP server not implemented yet";
+                 //transport = new THttpServer( targetHost);
+                #else
+                transport =    new TWrappingServerTransport(
+                        new TStreamTransport(
+                          new TFileStream("php://input", Read),
+                          new TFileStream("php://output", Append)
+                          )
+                        );
+
+                #end
+            default:
+                throw "Unhandled transport";
+            }
+
+            // optional: layered transport
+            var transfactory : TTransportFactory = null;
+            if ( args.framed) {
+                trace("- framed transport");
+                transfactory = new TFramedTransportFactory();
+            }
+            if ( args.buffered) {
+                trace("- buffered transport");
+                transfactory = new TBufferedTransportFactory();
+            }
+
+            // protocol
+            var protfactory : TProtocolFactory = null;
+            switch( args.protocol)
+            {
+            case binary:
+                trace("- binary protocol");
+                protfactory = new TBinaryProtocolFactory();
+            case json:
+                trace("- json protocol");
+                protfactory = new TJSONProtocolFactory();
+            case compact:
+                trace("- compact protocol");
+                protfactory = new TCompactProtocolFactory();
+            }
+
+
+            // Processor
+            var handler = new TestServerHandler();
+            var processor = new ThriftTestProcessor(handler);
+
+            // Simple Server
+            var server : TServer = null;
+            switch( args.servertype)
+            {
+            case simple:
+                var simpleServer = new TSimpleServer( processor, transport, transfactory, protfactory);
+                #if phpwebserver
+                simpleServer.runOnce = true;
+                #end
+                server = simpleServer;
+
+            default:
+                throw "Unhandled server type";
+            }
+
+
+            /*
+            // Server event handler
+            if( args.serverEvents) {
+                var events = new TestServerEventHandler();
+                server.setEventHandler(serverEvents);
+                handler.server = serverEngine;
+            }
+            */
+
+            // Run it
+            server.Serve();
+            trace("done.");
+
+        }
+        catch (x : TException)
+        {
+            trace('$x ${x.errorID} ${x.errorMsg}');
+        }
+        catch (x : Dynamic)
+        {
+            trace('$x');
+        }
+    }
+}
diff --git a/test/haxe/src/TestServerEventHandler.hx b/test/haxe/src/TestServerEventHandler.hx
new file mode 100644
index 0000000..d17567c
--- /dev/null
+++ b/test/haxe/src/TestServerEventHandler.hx
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import thrift.test.*;  // generated code
+
+
+class TestServerEventHandler : TServerEventHandler
+{
+    public int callCount = 0;
+    public void preServe()
+    {
+        callCount++;
+    }
+    public Object createContext(Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output)
+    {
+        callCount++;
+        return null;
+    }
+    public void deleteContext(Object serverContext, Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output)
+    {
+        callCount++;
+    }
+    public void processContext(Object serverContext, Thrift.Transport.TTransport transport)
+    {
+        callCount++;
+    }
+}
+
+    
\ No newline at end of file
diff --git a/test/haxe/src/TestServerHandler.hx b/test/haxe/src/TestServerHandler.hx
new file mode 100644
index 0000000..b8a2590
--- /dev/null
+++ b/test/haxe/src/TestServerHandler.hx
@@ -0,0 +1,479 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+import org.apache.thrift.helper.*;
+
+import haxe.Int32;
+import haxe.Int64;
+import haxe.io.Bytes;
+import haxe.ds.IntMap;
+import haxe.ds.StringMap;
+import haxe.ds.ObjectMap;
+
+import thrift.test.*;  // generated code
+
+
+class TestServerHandler implements ThriftTest {
+
+    public var server:TServer;
+
+    public function new() {
+    }
+
+    /**
+    * Prints "testVoid()" and returns nothing.
+    */
+    public function testVoid():Void
+    {
+        trace("testVoid()");
+    }
+
+    /**
+    * Prints 'testBool("%s")' where '%s' with thing as 'true' or 'false'
+    * @param bool  thing - the bool data to print
+    * @return bool  - returns the bool 'thing'
+    *
+    * @param thing
+    */
+    public function testBool(thing : Bool) : Bool
+    {
+        trace('testBool($thing)');
+        return thing;
+    }
+
+    /**
+    * Prints 'testString("%s")' with thing as '%s'
+    * @param string thing - the string to print
+    * @return string - returns the string 'thing'
+    *
+    * @param thing
+    */
+    public function testString(thing:String):String
+    {
+        trace("teststring(\"" + thing + "\")");
+        return thing;
+    }
+
+    /**
+    * Prints 'testByte("%d")' with thing as '%d'
+    * @param byte thing - the byte to print
+    * @return byte - returns the byte 'thing'
+    *
+    * @param thing
+    */
+    public function testByte(thing:haxe.Int32):haxe.Int32
+    {
+        trace("testByte(" + thing + ")");
+        return thing;
+    }
+
+    /**
+    * Prints 'testI32("%d")' with thing as '%d'
+    * @param i32 thing - the i32 to print
+    * @return i32 - returns the i32 'thing'
+    *
+    * @param thing
+    */
+    public function testI32(thing:haxe.Int32):haxe.Int32
+    {
+        trace("testI32(" + thing + ")");
+        return thing;
+    }
+
+    /**
+    * Prints 'testI64("%d")' with thing as '%d'
+    * @param i64 thing - the i64 to print
+    * @return i64 - returns the i64 'thing'
+    *
+    * @param thing
+    */
+    public function testI64(thing:haxe.Int64):haxe.Int64
+    {
+        trace("testI64(" + thing + ")");
+        return thing;
+    }
+
+    /**
+    * Prints 'testDouble("%f")' with thing as '%f'
+    * @param double thing - the double to print
+    * @return double - returns the double 'thing'
+    *
+    * @param thing
+    */
+    public function testDouble(thing:Float):Float
+    {
+        trace("testDouble(" + thing + ")");
+        return thing;
+    }
+
+    /**
+     * Prints 'testBinary("%s")' where '%s' is a hex-formatted string of thing's data
+     * @param binary  thing - the binary data to print
+     * @return binary  - returns the binary 'thing'
+     *
+     * @param thing
+     */
+    public function testBinary(thing : haxe.io.Bytes) : haxe.io.Bytes
+    {
+        var hex = "";
+        for ( i in 0 ... thing.length) {
+            hex += StringTools.hex( thing.get(i), 2);
+        }
+        trace('testBinary($hex)');
+        return thing;
+    }
+
+    /**
+    * Prints 'testStruct("{%s}")' where thing has been formatted
+    *  into a string of comma separated values
+    * @param Xtruct thing - the Xtruct to print
+    * @return Xtruct - returns the Xtruct 'thing'
+    *
+    * @param thing
+    */
+    public function testStruct(thing:Xtruct):Xtruct
+    {
+        trace("testStruct({" +
+                          "\"" + thing.string_thing + "\", " +
+                          thing.byte_thing + ", " +
+                          thing.i32_thing + ", " +
+                          Int64.toStr(thing.i64_thing) + "})");
+        return thing;
+    }
+
+    /**
+    * Prints 'testNest("{%s}")' where thing has been formatted
+    *  into a string of the nested struct
+    * @param Xtruct2 thing - the Xtruct2 to print
+    * @return Xtruct2 - returns the Xtruct2 'thing'
+    *
+    * @param thing
+    */
+    public function testNest(nest:Xtruct2):Xtruct2
+    {
+        var thing:Xtruct = nest.struct_thing;
+        trace("testNest({" +
+                          nest.byte_thing + ", {" +
+                          "\"" + thing.string_thing + "\", " +
+                          thing.byte_thing + ", " +
+                          thing.i32_thing + ", " +
+                          Int64.toStr(thing.i64_thing) + "}, " +
+                          nest.i32_thing + "})");
+        return nest;
+    }
+
+    /**
+    * Prints 'testMap("{%s")' where thing has been formatted
+    *  into a string of  'key => value' pairs
+    *  separated by commas and new lines
+    * @param map thing - the map to print
+    * @return map - returns the map 'thing'
+    *
+    * @param thing
+    */
+    public function testMap(thing:IntMap):IntMap
+    {
+        trace("testMap({");
+        var first:Bool = true;
+        for (key in thing.keys()) {
+            if (first) {
+                first = false;
+            } else {
+                trace(", ");
+            };
+            trace(key + " => " + thing.get(key));
+        };
+        trace("})");
+        return thing;
+    }
+
+    /**
+    * Prints 'testStringMap("{%s}")' where thing has been formatted
+    *  into a string of  'key => value' pairs
+    *  separated by commas and new lines
+    * @param map thing - the map to print
+    * @return map - returns the map 'thing'
+    *
+    * @param thing
+    */
+    public function testStringMap(thing:StringMap):StringMap
+    {
+        trace("testStringMap({");
+        var first:Bool = true;
+        for (key in thing.keys()) {
+            if (first) {
+                first = false;
+            } else {
+                trace(", ");
+            };
+            trace(key + " => " + thing.get(key));
+        };
+        trace("})");
+        return thing;
+    }
+
+    /**
+    * Prints 'testSet("{%s}")' where thing has been formatted
+    *  into a string of  values
+    *  separated by commas and new lines
+    * @param set thing - the set to print
+    * @return set - returns the set 'thing'
+    *
+    * @param thing
+    */
+    public function testSet(thing:IntSet):IntSet
+    {
+        trace("testSet({");
+        var first:Bool = true;
+        for (elem in thing) {
+            if (first) {
+                first = false;
+            } else {
+                trace(", ");
+            };
+            trace(elem);
+        };
+        trace("})");
+        return thing;
+    }
+
+    /**
+    * Prints 'testList("{%s}")' where thing has been formatted
+    *  into a string of  values
+    *  separated by commas and new lines
+    * @param list thing - the list to print
+    * @return list - returns the list 'thing'
+    *
+    * @param thing
+    */
+    public function testList(thing:List):List
+    {
+        trace("testList({");
+        var first:Bool = true;
+        for (elem in thing) {
+            if (first) {
+                first = false;
+            } else {
+                trace(", ");
+            };
+            trace(elem);
+        };
+        trace("})");
+        return thing;
+    }
+
+    /**
+    * Prints 'testEnum("%d")' where thing has been formatted into it's numeric value
+    * @param Numberz thing - the Numberz to print
+    * @return Numberz - returns the Numberz 'thing'
+    *
+    * @param thing
+    */
+    public function testEnum(thing:Int):Int
+    {
+        trace("testEnum(" + thing + ")");
+        return thing;
+    }
+
+    /**
+    * Prints 'testTypedef("%d")' with thing as '%d'
+    * @param UserId thing - the UserId to print
+    * @return UserId - returns the UserId 'thing'
+    *
+    * @param thing
+    */
+    public function testTypedef(thing:haxe.Int64):haxe.Int64
+    {
+        trace("testTypedef(" + thing + ")");
+        return thing;
+    }
+
+    /**
+    * Prints 'testMapMap("%d")' with hello as '%d'
+    * @param i32 hello - the i32 to print
+    * @return map> - returns a dictionary with these values:
+    *   {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, },
+    *     4 => {1 => 1, 2 => 2, 3 => 3, 4 => 4, }, }
+    *
+    * @param hello
+    */
+    public function testMapMap(hello:haxe.Int32):IntMap>
+    {
+        trace("testMapMap(" + hello + ")");
+        var mapmap = new IntMap>();
+        var pos = new IntMap();
+        var neg = new IntMap();
+        for (i in 1 ... 5) {
+            pos.set(i, i);
+            neg.set(-i, -i);
+        };
+        mapmap.set(4, pos);
+        mapmap.set(-4, neg);
+        return mapmap;
+    }
+
+    /**
+    * So you think you've got this all worked, out eh?
+    *
+    * Creates a the returned map with these values and prints it out:
+    *   { 1 => { 2 => argument,
+    *            3 => argument,
+    *          },
+    *     2 => { 6 => , },
+    *   }
+    * @return map> - a map with the above values
+    *
+    * @param argument
+    */
+    public function testInsanity(argument : Insanity) : Int64Map< IntMap< Insanity>>
+    {
+        trace("testInsanity()");
+
+        var first_map = new IntMap< Insanity>();
+        first_map.set(Numberz.TWO, argument);
+        first_map.set(Numberz.THREE, argument);
+
+        var second_map = new IntMap< Insanity>();
+        var looney = new Insanity();
+        second_map.set(Numberz.SIX, looney);
+
+        var insane = new Int64Map< IntMap< Insanity>>();
+        insane.set( Int64.make(0,1), first_map);
+        insane.set( Int64.make(0,2), second_map);
+
+        return insane;
+    }
+
+    /**
+    * Prints 'testMulti()'
+    * @param byte arg0 -
+    * @param i32 arg1 -
+    * @param i64 arg2 -
+    * @param map arg3 -
+    * @param Numberz arg4 -
+    * @param UserId arg5 -
+    * @return Xtruct - returns an Xtruct
+    *    with string_thing = "Hello2, byte_thing = arg0, i32_thing = arg1
+    *    and i64_thing = arg2
+    *
+    * @param arg0
+    * @param arg1
+    * @param arg2
+    * @param arg3
+    * @param arg4
+    * @param arg5
+    */
+    public function testMulti(arg0:haxe.Int32, arg1:haxe.Int32, arg2:haxe.Int64,
+        arg3:IntMap, arg4:Int, arg5:haxe.Int64):Xtruct
+    {
+        trace("testMulti()");
+        var hello = new Xtruct();
+        hello.string_thing = "Hello2";
+        hello.byte_thing = arg0;
+        hello.i32_thing = arg1;
+        hello.i64_thing = arg2;
+        return hello;
+    }
+
+    /**
+    * Print 'testException(%s)' with arg as '%s'
+    * @param string arg - a string indication what type of exception to throw
+    * if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
+    * elsen if arg == "TException" throw TException
+    * else do not throw anything
+    *
+    * @param arg
+    */
+    public function testException(arg:String):Void
+    {
+        trace("testException(" + arg + ")");
+        if (arg == "Xception") {
+            var x = new Xception();
+            x.errorCode = 1001;
+            x.message = arg;
+            throw x;
+        };
+        if (arg == "TException") {
+            throw new TException();
+        };
+        return;
+    }
+
+    /**
+    * Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s'
+    * @param string arg - a string indication what type of exception to throw
+    * if arg0 == "Xception"
+    * throw Xception with errorCode = 1001 and message = "This is an Xception"
+    * else if arg0 == "Xception2"
+    * throw Xception2 with errorCode = 2002 and message = "This is an Xception2"
+    * else do not throw anything
+    * @return Xtruct - an Xtruct with string_thing = arg1
+    *
+    * @param arg0
+    * @param arg1
+    */
+    public function testMultiException(arg0:String, arg1:String):Xtruct
+    {
+        trace("testMultiException(" + arg0 + ", " + arg1 + ")");
+        if (arg0 == "Xception") {
+            var x = new Xception();
+            x.errorCode = 1001;
+            x.message = "This is an Xception";
+            throw x;
+        } else if (arg0 == "Xception2") {
+            var x = new Xception2();
+            x.errorCode = 2002;
+            x.struct_thing = new Xtruct();
+            x.struct_thing.string_thing = "This is an Xception2";
+            throw x;
+        };
+        var result = new Xtruct();
+        result.string_thing = arg1;
+        return result;
+    }
+
+    /**
+    * Print 'testOneway(%d): Sleeping...' with secondsToSleep as '%d'
+    * sleep 'secondsToSleep'
+    * Print 'testOneway(%d): done sleeping!' with secondsToSleep as '%d'
+    * @param i32 secondsToSleep - the number of seconds to sleep
+    *
+    * @param secondsToSleep
+    */
+    public function testOneway(secondsToSleep:haxe.Int32):Void
+    {
+        trace("testOneway(" + secondsToSleep + "), sleeping...");
+        Sys.sleep(secondsToSleep);
+        trace("testOneway finished");
+    }
+
+    public function testStop():Void
+    {
+        if (server != null) {
+            server.Stop();
+        };
+    }
+}
diff --git a/test/hs/CMakeLists.txt b/test/hs/CMakeLists.txt
new file mode 100644
index 0000000..eaca3fa
--- /dev/null
+++ b/test/hs/CMakeLists.txt
@@ -0,0 +1,114 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+set(hs_test_gen
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ConstantsDemo_Consts.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ConstantsDemo_Types.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/DebugProtoTest_Consts.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/DebugProtoTest_Types.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/EmptyService_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/EmptyService.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/EmptyService_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Include_Consts.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Include_Types.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Inherited_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Inherited.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Inherited_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ReverseOrderService_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ReverseOrderService.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ReverseOrderService_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/SecondService_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/SecondService.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/SecondService_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ServiceForExceptionWithAMap_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ServiceForExceptionWithAMap.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ServiceForExceptionWithAMap_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Srv_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Srv.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Srv_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ThriftTest_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ThriftTest_Consts.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ThriftTest.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ThriftTest_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ThriftTest_Types.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Yowza_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Yowza.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Yowza_Iface.hs
+)
+
+set(hs_crosstest_apps
+    ${CMAKE_CURRENT_BINARY_DIR}/TestServer
+    ${CMAKE_CURRENT_BINARY_DIR}/TestClient
+)
+set(hs_crosstest_args
+    -igen-hs
+    -odir=${CMAKE_CURRENT_BINARY_DIR}
+    -hidir=${CMAKE_CURRENT_BINARY_DIR}
+)
+
+if (CMAKE_BUILD_TYPE STREQUAL "Debug")
+  set(hs_optimize -O0)
+else()
+  set(hs_optimize -O1)
+endif()
+
+add_custom_command(
+    OUTPUT ${hs_crosstest_apps}
+    COMMAND ${GHC} ${hs_optimize} ${hs_crosstest_args} ${CMAKE_CURRENT_SOURCE_DIR}/TestServer.hs -o TestServer
+    COMMAND ${GHC} ${hs_optimize} ${hs_crosstest_args} ${CMAKE_CURRENT_SOURCE_DIR}/TestClient.hs -o TestClient
+    DEPENDS ${hs_test_gen} haskell_library TestServer.hs TestClient.hs
+)
+add_custom_target(haskell_crosstest ALL
+    COMMENT "Building Haskell cross test executables"
+    DEPENDS ${hs_crosstest_apps}
+)
+
+set(hs_test_sources
+    ConstantsDemo_Main.hs
+    DebugProtoTest_Main.hs
+    Include_Main.hs
+    ThriftTest_Main.hs
+)
+set(hs_test_args
+    -Wall
+    -XScopedTypeVariables
+    -i${PROJECT_SOURCE_DIR}/lib/hs/src
+    -i${CMAKE_CURRENT_BINARY_DIR}/gen-hs
+)
+add_custom_target(haskell_tests ALL DEPENDS ${hs_test_gen})
+foreach(SRC ${hs_test_sources})
+    get_filename_component(BASE ${SRC} NAME_WE)
+    add_test(NAME HaskellTests-${BASE}
+        COMMAND ${RUN_HASKELL} ${hs_test_args} ${SRC}
+        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+endforeach()
+
+set(hs_test_gen_sources
+    ${PROJECT_SOURCE_DIR}/test/ConstantsDemo.thrift
+    ${PROJECT_SOURCE_DIR}/test/DebugProtoTest.thrift
+    ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
+    ${PROJECT_SOURCE_DIR}/test/Include.thrift
+)
+add_custom_command(OUTPUT ${hs_test_gen}
+    COMMAND ${THRIFT_COMPILER} --gen hs ${PROJECT_SOURCE_DIR}/test/ConstantsDemo.thrift
+    COMMAND ${THRIFT_COMPILER} --gen hs ${PROJECT_SOURCE_DIR}/test/DebugProtoTest.thrift
+    COMMAND ${THRIFT_COMPILER} --gen hs ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
+    COMMAND ${THRIFT_COMPILER} --gen hs ${PROJECT_SOURCE_DIR}/test/Include.thrift
+    DEPENDS ${hs_test_gen_sources}
+)
diff --git a/test/hs/ConstantsDemo_Main.hs b/test/hs/ConstantsDemo_Main.hs
new file mode 100644
index 0000000..28de4f7
--- /dev/null
+++ b/test/hs/ConstantsDemo_Main.hs
@@ -0,0 +1,68 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+module Main where
+
+
+import qualified Control.Exception
+import qualified Network
+
+import Thrift.Protocol.Binary
+import Thrift.Server
+import Thrift.Transport.Handle
+
+import qualified ThriftTestUtils
+
+import qualified Yowza
+import qualified Yowza_Client as Client
+import qualified Yowza_Iface as Iface
+
+
+data YowzaHandler = YowzaHandler
+instance Iface.Yowza_Iface YowzaHandler where
+    blingity _ = do
+        ThriftTestUtils.serverLog "SERVER: Got blingity"
+        return ()
+
+    blangity _ = do
+        ThriftTestUtils.serverLog "SERVER: Got blangity"
+        return $ 31
+
+
+client :: (String, Network.PortID) -> IO ()
+client addr = do
+    to <- hOpen addr
+    let ps = (BinaryProtocol to, BinaryProtocol to)
+
+    Client.blingity ps
+
+    rv <- Client.blangity ps
+    ThriftTestUtils.clientLog $ show rv
+
+    tClose to
+
+server :: Network.PortNumber -> IO ()
+server port = do 
+    ThriftTestUtils.serverLog "Ready..."
+    (runBasicServer YowzaHandler Yowza.process port)
+    `Control.Exception.catch`
+    (\(TransportExn s _) -> error $ "FAILURE: " ++ show s)
+
+main :: IO ()
+main = ThriftTestUtils.runTest server client
diff --git a/test/hs/DebugProtoTest_Main.hs b/test/hs/DebugProtoTest_Main.hs
new file mode 100644
index 0000000..fb28963
--- /dev/null
+++ b/test/hs/DebugProtoTest_Main.hs
@@ -0,0 +1,168 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main where
+
+
+import qualified Control.Exception
+import qualified Data.ByteString.Lazy as DBL
+import qualified Data.HashMap.Strict as Map
+import qualified Data.HashSet as Set
+import qualified Data.Vector as Vector
+import qualified Network
+
+import Thrift.Protocol.Binary
+import Thrift.Server
+import Thrift.Transport.Handle
+
+import qualified ThriftTestUtils
+
+import qualified DebugProtoTest_Types as Types
+import qualified Inherited
+import qualified Inherited_Client as IClient
+import qualified Inherited_Iface as IIface
+import qualified Srv_Client as SClient
+import qualified Srv_Iface as SIface
+
+-- we don't actually need this import, but force it to check the code generator exports proper Haskell syntax
+import qualified Srv()
+
+
+data InheritedHandler = InheritedHandler
+instance SIface.Srv_Iface InheritedHandler where
+    janky _ arg = do
+        ThriftTestUtils.serverLog $ "Got janky method call: " ++ show arg
+        return $ 31
+
+    voidMethod _ = do
+        ThriftTestUtils.serverLog "Got voidMethod method call"
+        return ()
+
+    primitiveMethod _ = do
+        ThriftTestUtils.serverLog "Got primitiveMethod call"
+        return $ 42
+
+    structMethod _ = do
+        ThriftTestUtils.serverLog "Got structMethod call"
+        return $ Types.CompactProtoTestStruct {
+            Types.compactProtoTestStruct_a_byte = 0x01,
+            Types.compactProtoTestStruct_a_i16 = 0x02,
+            Types.compactProtoTestStruct_a_i32 = 0x03,
+            Types.compactProtoTestStruct_a_i64 = 0x04,
+            Types.compactProtoTestStruct_a_double = 0.1,
+            Types.compactProtoTestStruct_a_string = "abcdef",
+            Types.compactProtoTestStruct_a_binary = DBL.empty,
+            Types.compactProtoTestStruct_true_field = True,
+            Types.compactProtoTestStruct_false_field = False,
+            Types.compactProtoTestStruct_empty_struct_field = Types.Empty,
+            
+            Types.compactProtoTestStruct_byte_list = Vector.empty,
+            Types.compactProtoTestStruct_i16_list = Vector.empty,
+            Types.compactProtoTestStruct_i32_list = Vector.empty,
+            Types.compactProtoTestStruct_i64_list = Vector.empty,
+            Types.compactProtoTestStruct_double_list = Vector.empty,
+            Types.compactProtoTestStruct_string_list = Vector.empty,
+            Types.compactProtoTestStruct_binary_list = Vector.empty,
+            Types.compactProtoTestStruct_boolean_list = Vector.empty,
+            Types.compactProtoTestStruct_struct_list = Vector.empty,
+
+            Types.compactProtoTestStruct_byte_set = Set.empty,
+            Types.compactProtoTestStruct_i16_set = Set.empty,
+            Types.compactProtoTestStruct_i32_set = Set.empty,
+            Types.compactProtoTestStruct_i64_set = Set.empty,
+            Types.compactProtoTestStruct_double_set = Set.empty,
+            Types.compactProtoTestStruct_string_set = Set.empty,
+            Types.compactProtoTestStruct_binary_set = Set.empty,
+            Types.compactProtoTestStruct_boolean_set = Set.empty,
+            Types.compactProtoTestStruct_struct_set = Set.empty,
+
+            Types.compactProtoTestStruct_byte_byte_map = Map.empty,
+            Types.compactProtoTestStruct_i16_byte_map = Map.empty,
+            Types.compactProtoTestStruct_i32_byte_map = Map.empty,
+            Types.compactProtoTestStruct_i64_byte_map = Map.empty,
+            Types.compactProtoTestStruct_double_byte_map = Map.empty,
+            Types.compactProtoTestStruct_string_byte_map = Map.empty,
+            Types.compactProtoTestStruct_binary_byte_map = Map.empty,
+            Types.compactProtoTestStruct_boolean_byte_map = Map.empty,
+
+            Types.compactProtoTestStruct_byte_i16_map = Map.empty,
+            Types.compactProtoTestStruct_byte_i32_map = Map.empty,
+            Types.compactProtoTestStruct_byte_i64_map = Map.empty,
+            Types.compactProtoTestStruct_byte_double_map = Map.empty,
+            Types.compactProtoTestStruct_byte_string_map = Map.empty,
+            Types.compactProtoTestStruct_byte_binary_map = Map.empty,
+            Types.compactProtoTestStruct_byte_boolean_map = Map.empty,
+
+            Types.compactProtoTestStruct_list_byte_map = Map.empty,
+            Types.compactProtoTestStruct_set_byte_map = Map.empty,
+            Types.compactProtoTestStruct_map_byte_map = Map.empty,
+
+            Types.compactProtoTestStruct_byte_map_map = Map.empty,
+            Types.compactProtoTestStruct_byte_set_map = Map.empty,
+            Types.compactProtoTestStruct_byte_list_map = Map.empty }
+
+    methodWithDefaultArgs _ arg = do
+        ThriftTestUtils.serverLog $ "Got methodWithDefaultArgs: " ++ show arg
+        return ()
+
+    onewayMethod _ = do
+        ThriftTestUtils.serverLog "Got onewayMethod"
+
+instance IIface.Inherited_Iface InheritedHandler where
+    identity _ arg = do
+        ThriftTestUtils.serverLog $ "Got identity method: " ++ show arg
+        return arg
+
+client :: (String, Network.PortID) -> IO ()
+client addr = do
+    to <- hOpen addr
+    let p =  BinaryProtocol to
+    let ps = (p,p)
+
+    v1 <- SClient.janky ps 42
+    ThriftTestUtils.clientLog $ show v1
+
+    SClient.voidMethod ps
+
+    v2 <- SClient.primitiveMethod ps
+    ThriftTestUtils.clientLog $ show v2
+
+    v3 <- SClient.structMethod ps
+    ThriftTestUtils.clientLog $ show v3
+
+    SClient.methodWithDefaultArgs ps 42
+
+    SClient.onewayMethod ps
+
+    v4 <- IClient.identity ps 42
+    ThriftTestUtils.clientLog $ show v4
+
+    return ()
+
+server :: Network.PortNumber -> IO ()
+server port = do 
+    ThriftTestUtils.serverLog "Ready..."
+    (runBasicServer InheritedHandler Inherited.process port)
+    `Control.Exception.catch`
+    (\(TransportExn s _) -> error $ "FAILURE: " ++ show s)
+
+main :: IO ()
+main = ThriftTestUtils.runTest server client
diff --git a/test/hs/Include_Main.hs b/test/hs/Include_Main.hs
new file mode 100644
index 0000000..d3977a1
--- /dev/null
+++ b/test/hs/Include_Main.hs
@@ -0,0 +1,7 @@
+module Main where
+
+import Include_Types
+import ThriftTest_Types
+
+main :: IO ()
+main = putStrLn ("Includes work: " ++ (show (IncludeTest $ Bools True False)))
diff --git a/test/hs/Makefile b/test/hs/Makefile
new file mode 100644
index 0000000..ac60cd9
--- /dev/null
+++ b/test/hs/Makefile
@@ -0,0 +1,646 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# test/hs/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/thrift
+pkgincludedir = $(includedir)/thrift
+pkglibdir = $(libdir)/thrift
+pkglibexecdir = $(libexecdir)/thrift
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = test/hs
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15
+ALLOCA = 
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+ANT = /usr/bin/ant
+ANT_FLAGS = 
+AR = ar
+AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf
+AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader
+AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15
+AWK = gawk
+BISON = bison
+BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a
+BOOST_CPPFLAGS = -I/usr/include
+BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a
+BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu
+BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu
+BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a
+BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a
+BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a
+BUNDLER = /usr/bin/bundle
+CABAL = /usr/bin/cabal
+CABAL_CONFIGURE_FLAGS = 
+CARGO = /usr/bin/cargo
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CLASSPATH = 
+CPP = gcc -E
+CPPFLAGS = 
+CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;
+CXX = g++ -std=c++11
+CXXCPP = g++ -E -std=c++11
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DART = /usr/lib/dart/bin/dart
+DARTPUB = /usr/lib/dart/bin/pub
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DMD = dmd
+DMD_LIBEVENT_FLAGS = 
+DMD_OF_DIRSEP = /
+DMD_OPENSSL_FLAGS = 
+DOTNETCORE = /usr/bin/dotnet
+DOTNETCORE_VERSION = 2.0.3
+DSYMUTIL = 
+DUMPBIN = 
+D_EVENT_LIB_NAME = libthriftd-event.a
+D_IMPORT_PREFIX = ${prefix}/include/d2
+D_LIB_NAME = libthriftd.a
+D_SSL_LIB_NAME = libthriftd-ssl.a
+ECHO_C = 
+ECHO_N = -n
+ECHO_T = 
+EGREP = /bin/grep -E
+ENABLE_COVERAGE = 2
+ERL = /usr/bin/erl
+ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib
+ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0
+ERLANG_LIB_DIR = /usr/lib/erlang/lib
+ERLC = /usr/bin/erlc
+ERLCFLAGS = 
+EXEEXT = 
+FGREP = /bin/grep -F
+GCOV_CFLAGS = 
+GCOV_CXXFLAGS = 
+GCOV_LDFLAGS = 
+GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GLIB_LIBS = -lglib-2.0
+GO = /usr/bin/go
+GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0
+GREP = /bin/grep
+HAVE_CXX11 = 1
+HAXE = /usr/bin/haxe
+HAXE_VERSION = 3.2.1
+INSTALL = /usr/bin/install -c
+INSTALLDIRS = vendor
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+JAVA_PREFIX = /usr/local/lib
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS = 
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBEVENT_CPPFLAGS = 
+LIBEVENT_LDFLAGS = 
+LIBEVENT_LIBS = -levent
+LIBOBJS = 
+LIBS = -lrt -lpthread 
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO = 
+LN_S = ln -s
+LTLIBOBJS = 
+LT_SYS_LIBRARY_PATH = 
+LUA = /usr/bin/lua5.3
+LUA_EXEC_PREFIX = ${exec_prefix}
+LUA_INCLUDE = -I/usr/include/lua5.3
+LUA_LIB = -llua5.3  -ldl
+LUA_PLATFORM = unknown
+LUA_PREFIX = ${prefix}
+LUA_SHORT_VERSION = 53
+LUA_VERSION = 5.3
+MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo
+MANIFEST_TOOL = :
+MAYBE_CPP = cpp
+MAYBE_CSHARP = csharp
+MAYBE_C_GLIB = c_glib
+MAYBE_D = 
+MAYBE_DART = dart
+MAYBE_DOTNETCORE = netcore
+MAYBE_ERLANG = erl
+MAYBE_GO = go
+MAYBE_HASKELL = hs
+MAYBE_JAVA = java
+MAYBE_LUA = lua
+MAYBE_NODEJS = nodejs
+MAYBE_PERL = perl
+MAYBE_PHP = php
+MAYBE_PY3 = py3
+MAYBE_PYTHON = py
+MAYBE_RS = rs
+MAYBE_RUBY = rb
+MCS = /usr/bin/mcs
+MKDIR_P = /bin/mkdir -p
+MONO_CFLAGS = 
+MONO_LIBS = 
+NM = /usr/bin/nm -B
+NMEDIT = 
+NODEJS = /usr/bin/nodejs
+NPM = /usr/bin/npm
+OBJDUMP = objdump
+OBJEXT = o
+OPENSSL_INCLUDES = 
+OPENSSL_LDFLAGS = 
+OPENSSL_LIBS = -lssl -lcrypto
+OTOOL = 
+OTOOL64 = 
+PACKAGE = thrift
+PACKAGE_BUGREPORT = 
+PACKAGE_NAME = thrift
+PACKAGE_STRING = thrift 0.11.0
+PACKAGE_TARNAME = thrift
+PACKAGE_URL = 
+PACKAGE_VERSION = 0.11.0
+PATH_SEPARATOR = :
+PERL = /usr/bin/perl
+PERL_PREFIX = /usr/local
+PHP = /usr/bin/php
+PHPUNIT = /usr/bin/phpunit
+PHP_CONFIG = /usr/bin/php-config
+PHP_CONFIG_PREFIX = /etc/php.d
+PHP_PREFIX = /usr/lib/php
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR = 
+PKG_CONFIG_PATH = 
+PYTHON = /usr/bin/python
+PYTHON3 = /usr/bin/python3
+PYTHON_EXEC_PREFIX = ${exec_prefix}
+PYTHON_PLATFORM = linux2
+PYTHON_PREFIX = ${prefix}
+PYTHON_VERSION = 2.7
+PY_PREFIX = /usr
+QT5_CFLAGS = 
+QT5_LIBS = 
+QT5_MOC = 
+QT_CFLAGS = 
+QT_LIBS = 
+QT_MOC = 
+RANLIB = ranlib
+REBAR = /usr/bin/rebar
+RUBY = /usr/bin/ruby
+RUBY_PREFIX = 
+RUNHASKELL = /usr/bin/runhaskell
+RUSTC = /usr/bin/rustc
+SED = /bin/sed
+SET_MAKE = 
+SHELL = /bin/bash
+STRIP = strip
+THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift
+TRIAL = /usr/bin/trial
+VERSION = 0.11.0
+YACC = bison -y
+YFLAGS = 
+ZLIB_CPPFLAGS = 
+ZLIB_LDFLAGS = 
+ZLIB_LIBS = -lz
+abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/test/hs
+abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/test/hs
+abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift
+abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+ac_ct_DUMPBIN = 
+am__include = include
+am__leading_dot = .
+am__quote = 
+am__tar = tar --format=ustar -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias = 
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+golang_version = 1.6.2
+have_prog_bison = yes
+host = x86_64-pc-linux-gnu
+host_alias = 
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+luadir = ${prefix}/share/lua/5.3
+luaexecdir = ${exec_prefix}/lib/lua/5.3
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+pkgluadir = ${luadir}/thrift
+pkgluaexecdir = ${luaexecdir}/thrift
+pkgpyexecdir = ${pyexecdir}/thrift
+pkgpythondir = ${pythondir}/thrift
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages
+pythondir = ${prefix}/lib/python2.7/dist-packages
+runstatedir = ${localstatedir}/run
+rustc_version = rustc 1.17.0
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+subdirs =  lib/php/src/ext/thrift_protocol
+sysconfdir = ${prefix}/etc
+target_alias = 
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/hs/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/hs/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile all-local
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am all-local check check-am clean clean-generic \
+	clean-libtool clean-local cscopelist-am ctags-am distclean \
+	distclean-generic distclean-libtool distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \
+	tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+stubs: $(THRIFT) ../ConstantsDemo.thrift ../DebugProtoTest.thrift ../ThriftTest.thrift ../Include.thrift
+	$(THRIFT) --gen hs ../ConstantsDemo.thrift
+	$(THRIFT) --gen hs ../DebugProtoTest.thrift
+	$(THRIFT) --gen hs ../ThriftTest.thrift
+	$(THRIFT) --gen hs ../Include.thrift
+
+check: stubs
+	sh run-test.sh ConstantsDemo
+	sh run-test.sh DebugProtoTest
+	sh run-test.sh ThriftTest
+	sh run-test.sh Include
+
+clean-local:
+	$(RM) -r gen-hs
+	$(RM) *.hi
+	$(RM) *.o
+
+all-local: stubs
+	ghc -igen-hs TestServer.hs
+	ghc -igen-hs TestClient.hs
+
+precross: all-local
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/hs/Makefile.am b/test/hs/Makefile.am
new file mode 100644
index 0000000..1748906
--- /dev/null
+++ b/test/hs/Makefile.am
@@ -0,0 +1,41 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+stubs: $(THRIFT) ../ConstantsDemo.thrift ../DebugProtoTest.thrift ../ThriftTest.thrift ../Include.thrift
+	$(THRIFT) --gen hs ../ConstantsDemo.thrift
+	$(THRIFT) --gen hs ../DebugProtoTest.thrift
+	$(THRIFT) --gen hs ../ThriftTest.thrift
+	$(THRIFT) --gen hs ../Include.thrift
+
+check: stubs
+	sh run-test.sh ConstantsDemo
+	sh run-test.sh DebugProtoTest
+	sh run-test.sh ThriftTest
+	sh run-test.sh Include
+
+clean-local:
+	$(RM) -r gen-hs
+	$(RM) *.hi
+	$(RM) *.o
+
+all-local: stubs
+	ghc -igen-hs TestServer.hs
+	ghc -igen-hs TestClient.hs
+
+precross: all-local
diff --git a/test/hs/Makefile.in b/test/hs/Makefile.in
new file mode 100644
index 0000000..aefe684
--- /dev/null
+++ b/test/hs/Makefile.in
@@ -0,0 +1,646 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/hs
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/hs/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/hs/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile all-local
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am all-local check check-am clean clean-generic \
+	clean-libtool clean-local cscopelist-am ctags-am distclean \
+	distclean-generic distclean-libtool distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \
+	tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+stubs: $(THRIFT) ../ConstantsDemo.thrift ../DebugProtoTest.thrift ../ThriftTest.thrift ../Include.thrift
+	$(THRIFT) --gen hs ../ConstantsDemo.thrift
+	$(THRIFT) --gen hs ../DebugProtoTest.thrift
+	$(THRIFT) --gen hs ../ThriftTest.thrift
+	$(THRIFT) --gen hs ../Include.thrift
+
+check: stubs
+	sh run-test.sh ConstantsDemo
+	sh run-test.sh DebugProtoTest
+	sh run-test.sh ThriftTest
+	sh run-test.sh Include
+
+clean-local:
+	$(RM) -r gen-hs
+	$(RM) *.hi
+	$(RM) *.o
+
+all-local: stubs
+	ghc -igen-hs TestServer.hs
+	ghc -igen-hs TestClient.hs
+
+precross: all-local
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/hs/TestClient.hs b/test/hs/TestClient.hs
new file mode 100644
index 0000000..93fb591
--- /dev/null
+++ b/test/hs/TestClient.hs
@@ -0,0 +1,306 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+{-# LANGUAGE OverloadedStrings, RecordWildCards, ScopedTypeVariables #-}
+module Main where
+
+import Control.Exception
+import Control.Monad
+import Data.Functor
+import Data.List.Split
+import Data.String
+import Network
+import Network.URI
+import System.Environment
+import System.Exit
+import qualified Data.ByteString.Lazy as LBS
+import qualified Data.HashMap.Strict as Map
+import qualified Data.HashSet as Set
+import qualified Data.Vector as Vector
+import qualified System.IO as IO
+
+import ThriftTest_Iface
+import ThriftTest_Types
+import qualified ThriftTest_Client as Client
+
+import Thrift.Transport
+import Thrift.Transport.Framed
+import Thrift.Transport.Handle
+import Thrift.Transport.HttpClient
+import Thrift.Protocol
+import Thrift.Protocol.Binary
+import Thrift.Protocol.Compact
+import Thrift.Protocol.Header
+import Thrift.Protocol.JSON
+
+data Options = Options
+  { host         :: String
+  , port         :: Int
+  , domainSocket :: String
+  , transport    :: String
+  , protocol     :: ProtocolType
+  -- TODO: Haskell lib does not have SSL support
+  , ssl          :: Bool
+  , testLoops    :: Int
+  }
+  deriving (Show, Eq)
+
+data TransportType = Buffered IO.Handle
+                   | Framed (FramedTransport IO.Handle)
+                   | Http HttpClient
+                   | NoTransport String
+
+getTransport :: String -> String -> Int -> (IO TransportType)
+getTransport "buffered" host port = do
+  h <- hOpen (host, PortNumber $ fromIntegral port)
+  IO.hSetBuffering h $ IO.BlockBuffering Nothing
+  return $ Buffered h
+getTransport "framed" host port = do
+  h <- hOpen (host, PortNumber $ fromIntegral port)
+  t <- openFramedTransport h
+  return $ Framed t
+getTransport "http" host port = let uriStr = "http://" ++ host ++ ":" ++ show port in
+                                case parseURI uriStr of
+                                  Nothing -> do return (NoTransport $ "Failed to parse URI: " ++ uriStr)
+                                  Just(uri) -> do
+                                    t <- openHttpClient uri
+                                    return $ Http t
+getTransport t host port = do return (NoTransport $ "Unsupported transport: " ++ t)
+
+data ProtocolType = Binary
+                  | Compact
+                  | JSON
+                  | Header
+                  deriving (Show, Eq)
+
+getProtocol :: String -> ProtocolType
+getProtocol "binary"  = Binary
+getProtocol "compact" = Compact
+getProtocol "json"    = JSON
+getProtocol "header" = Header
+getProtocol p = error $ "Unsupported Protocol: " ++ p
+
+defaultOptions :: Options
+defaultOptions = Options
+  { port         = 9090
+  , domainSocket = ""
+  , host         = "localhost"
+  , transport    = "buffered"
+  , protocol     = Binary
+  , ssl          = False
+  , testLoops    = 1
+  }
+
+runClient :: Protocol p => p -> IO ()
+runClient p = do
+  let prot = (p,p)
+  putStrLn "Starting Tests"
+
+  -- VOID Test
+  putStrLn "testVoid"
+  Client.testVoid prot
+
+  -- String Test
+  putStrLn "testString"
+  s <- Client.testString prot "Test"
+  when (s /= "Test") exitFailure
+
+  -- Bool Test
+  putStrLn "testBool"
+  bool <- Client.testBool prot True
+  when (not bool) exitFailure
+  putStrLn "testBool"
+  bool <- Client.testBool prot False
+  when (bool) exitFailure
+
+  -- Byte Test
+  putStrLn "testByte"
+  byte <- Client.testByte prot 1
+  when (byte /= 1) exitFailure
+
+  -- I32 Test
+  putStrLn "testI32"
+  i32 <- Client.testI32 prot (-1)
+  when (i32 /= -1) exitFailure
+
+  -- I64 Test
+  putStrLn "testI64"
+  i64 <- Client.testI64 prot (-34359738368)
+  when (i64 /= -34359738368) exitFailure
+
+  -- Double Test
+  putStrLn "testDouble"
+  dub <- Client.testDouble prot (-5.2098523)
+  when (abs (dub + 5.2098523) > 0.001) exitFailure
+
+  -- Binary Test
+  putStrLn "testBinary"
+  bin <- Client.testBinary prot (LBS.pack . reverse $ [-128..127])
+  when ((reverse [-128..127]) /= LBS.unpack bin) exitFailure
+  
+  -- Struct Test
+  let structIn = Xtruct{ xtruct_string_thing = "Zero"
+                       , xtruct_byte_thing   = 1
+                       , xtruct_i32_thing    = -3
+                       , xtruct_i64_thing    = -5
+                       }
+  putStrLn "testStruct"
+  structOut <- Client.testStruct prot structIn
+  when (structIn /= structOut) exitFailure
+
+  -- Nested Struct Test
+  let nestIn = Xtruct2{ xtruct2_byte_thing   = 1
+                      , xtruct2_struct_thing = structIn
+                      , xtruct2_i32_thing    = 5
+                      }
+  putStrLn "testNest"
+  nestOut <- Client.testNest prot nestIn
+  when (nestIn /= nestOut) exitFailure
+
+  -- Map Test
+  let mapIn = Map.fromList $ map (\i -> (i, i-10)) [1..5]
+  putStrLn "testMap"
+  mapOut <- Client.testMap prot mapIn
+  when (mapIn /= mapOut) exitFailure
+
+  -- Set Test
+  let setIn = Set.fromList [-2..3]
+  putStrLn "testSet"
+  setOut <- Client.testSet prot setIn
+  when (setIn /= setOut) exitFailure
+
+  -- List Test
+  let listIn = Vector.fromList [-2..3]
+  putStrLn "testList"
+  listOut <- Client.testList prot listIn
+  when (listIn /= listOut) exitFailure
+
+  -- Enum Test
+  putStrLn "testEnum"
+  numz1 <- Client.testEnum prot ONE
+  when (numz1 /= ONE) exitFailure
+
+  putStrLn "testEnum"
+  numz2 <- Client.testEnum prot TWO
+  when (numz2 /= TWO) exitFailure
+
+  putStrLn "testEnum"
+  numz5 <- Client.testEnum prot FIVE
+  when (numz5 /= FIVE) exitFailure
+
+  -- Typedef Test
+  putStrLn "testTypedef"
+  uid <- Client.testTypedef prot 309858235082523
+  when (uid /= 309858235082523) exitFailure
+
+  -- Nested Map Test
+  putStrLn "testMapMap"
+  _ <- Client.testMapMap prot 1
+
+  -- Exception Test
+  putStrLn "testException"
+  exn1 <- try $ Client.testException prot "Xception"
+  case exn1 of
+    Left (Xception _ _) -> return ()
+    _ -> putStrLn (show exn1) >> exitFailure
+
+  putStrLn "testException"
+  exn2 <- try $ Client.testException prot "TException"
+  case exn2 of
+    Left (_ :: SomeException) -> return ()
+    Right _ -> exitFailure
+
+  putStrLn "testException"
+  exn3 <- try $ Client.testException prot "success"
+  case exn3 of
+    Left (_ :: SomeException) -> exitFailure
+    Right _ -> return ()
+
+  -- Multi Exception Test
+  putStrLn "testMultiException"
+  multi1 <- try $ Client.testMultiException prot "Xception" "test 1"
+  case multi1 of
+    Left (Xception _ _) -> return ()
+    _ -> exitFailure
+
+  putStrLn "testMultiException"
+  multi2 <- try $ Client.testMultiException prot "Xception2" "test 2"
+  case multi2 of
+    Left (Xception2 _ _) -> return ()
+    _ -> exitFailure
+
+  putStrLn "testMultiException"
+  multi3 <- try $ Client.testMultiException prot "success" "test 3"
+  case multi3 of
+    Left (_ :: SomeException) -> exitFailure
+    Right _ -> return ()
+
+
+main :: IO ()
+main = do
+  options <- flip parseFlags defaultOptions <$> getArgs
+  case options of
+    Nothing -> showHelp
+    Just Options{..} -> do
+      trans <- Main.getTransport transport host port
+      case trans of
+        Buffered t -> runTest testLoops protocol t
+        Framed t   -> runTest testLoops protocol t
+        Http t     -> runTest testLoops protocol t
+        NoTransport err -> putStrLn err
+  where
+    makeClient p t = case p of
+                       Binary  -> runClient $ BinaryProtocol t
+                       Compact -> runClient $ CompactProtocol t
+                       JSON    -> runClient $ JSONProtocol t
+                       Header  -> createHeaderProtocol t t >>= runClient
+    runTest loops p t = do
+      let client = makeClient p t
+      replicateM_ loops client
+      putStrLn "COMPLETED SUCCESSFULLY"
+
+parseFlags :: [String] -> Options -> Maybe Options
+parseFlags (flag : flags) opts = do
+  let pieces = splitOn "=" flag
+  case pieces of
+    "--port" : arg : _ -> parseFlags flags opts{ port = read arg }
+    "--domain-socket" : arg : _ -> parseFlags flags opts{ domainSocket = read arg }
+    "--host" : arg : _ -> parseFlags flags opts{ host = arg }
+    "--transport" : arg : _ -> parseFlags flags opts{ transport = arg }
+    "--protocol" : arg : _ -> parseFlags flags opts{ protocol = getProtocol arg }
+    "-n" : arg : _ -> parseFlags flags opts{ testLoops = read arg }
+    "--h" : _ -> Nothing
+    "--help" : _ -> Nothing
+    "--ssl" : _ -> parseFlags flags opts{ ssl = True }
+    "--processor-events" : _ -> parseFlags flags opts
+    _ -> Nothing
+parseFlags [] opts = Just opts
+
+showHelp :: IO ()
+showHelp = putStrLn
+  "Allowed options:\n\
+  \  -h [ --help ]               produce help message\n\
+  \  --host arg (=localhost)     Host to connect\n\
+  \  --port arg (=9090)          Port number to connect\n\
+  \  --domain-socket arg         Domain Socket (e.g. /tmp/ThriftTest.thrift),\n\
+  \                              instead of host and port\n\
+  \  --transport arg (=buffered) Transport: buffered, framed, http\n\
+  \  --protocol arg (=binary)    Protocol: binary, compact, json\n\
+  \  --ssl                       Encrypted Transport using SSL\n\
+  \  -n [ --testloops ] arg (=1) Number of Tests"
diff --git a/test/hs/TestServer.hs b/test/hs/TestServer.hs
new file mode 100644
index 0000000..b7731ab
--- /dev/null
+++ b/test/hs/TestServer.hs
@@ -0,0 +1,312 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+{-# LANGUAGE OverloadedStrings,RecordWildCards #-}
+module Main where
+
+import Control.Exception
+import Control.Monad
+import Data.Functor
+import Data.HashMap.Strict (HashMap)
+import Data.List
+import Data.List.Split
+import Data.String
+import Network
+import System.Environment
+import System.Exit
+import System.IO
+import Control.Concurrent (threadDelay)
+import qualified System.IO as IO
+import qualified Data.HashMap.Strict as Map
+import qualified Data.HashSet as Set
+import qualified Data.Text.Lazy as Text
+import qualified Data.Vector as Vector
+
+import ThriftTest
+import ThriftTest_Iface
+import ThriftTest_Types
+
+import Thrift
+import Thrift.Server
+import Thrift.Transport.Framed
+import Thrift.Transport.Handle
+import Thrift.Protocol.Binary
+import Thrift.Protocol.Compact
+import Thrift.Protocol.Header
+import Thrift.Protocol.JSON
+
+data Options = Options
+  { port         :: Int
+  , domainSocket :: String
+  , serverType   :: ServerType
+  , transport    :: String
+  , protocol     :: ProtocolType
+  , ssl          :: Bool
+  , workers      :: Int
+  }
+
+data ServerType = Simple
+                | ThreadPool
+                | Threaded
+                | NonBlocking
+                deriving (Show, Eq)
+
+instance IsString ServerType where
+  fromString "simple"      = Simple
+  fromString "thread-pool" = ThreadPool
+  fromString "threaded"    = Threaded
+  fromString "nonblocking" = NonBlocking
+  fromString _ = error "not a valid server type"
+
+data TransportType = Buffered (Socket -> (IO IO.Handle))
+                   | Framed (Socket -> (IO (FramedTransport IO.Handle)))
+                   | NoTransport String
+
+getTransport :: String -> TransportType
+getTransport "buffered" = Buffered $ \s -> do
+  (h, _, _) <- (accept s)
+  IO.hSetBuffering h $ IO.BlockBuffering Nothing
+  return h
+getTransport "framed" = Framed $ \s -> do
+  (h, _, _) <- (accept s)
+  openFramedTransport h
+getTransport t = NoTransport $ "Unsupported transport: " ++ t
+
+data ProtocolType = Binary
+                  | Compact
+                  | JSON
+                  | Header
+
+getProtocol :: String -> ProtocolType
+getProtocol "binary"  = Binary
+getProtocol "compact" = Compact
+getProtocol "json"    = JSON
+getProtocol "header"  = Header
+getProtocol p = error $"Unsupported Protocol: " ++ p
+
+defaultOptions :: Options
+defaultOptions = Options
+  { port         = 9090
+  , domainSocket = ""
+  , serverType   = Threaded
+  , transport    = "buffered"
+  , protocol     = Binary
+  -- TODO: Haskell lib does not have SSL support
+  , ssl          = False
+  , workers      = 4
+  }
+
+stringifyMap :: (Show a, Show b) => Map.HashMap a b -> String
+stringifyMap = Data.List.intercalate ", " . Data.List.map joinKV . Map.toList
+  where joinKV (k, v) = show k ++ " => " ++ show v
+
+stringifySet :: Show a => Set.HashSet a -> String
+stringifySet = Data.List.intercalate ", " . Data.List.map show . Set.toList
+
+stringifyList :: Show a => Vector.Vector a -> String
+stringifyList = Data.List.intercalate ", " . Data.List.map show . Vector.toList
+
+data TestHandler = TestHandler
+instance ThriftTest_Iface TestHandler where
+  testVoid _ = System.IO.putStrLn "testVoid()"
+
+  testString _ s = do
+    System.IO.putStrLn $ "testString(" ++ show s ++ ")"
+    return s
+
+  testBool _ x = do
+    System.IO.putStrLn $ "testBool(" ++ show x ++ ")"
+    return x
+
+  testByte _ x = do
+    System.IO.putStrLn $ "testByte(" ++ show x ++ ")"
+    return x
+
+  testI32 _ x = do
+    System.IO.putStrLn $ "testI32(" ++ show x ++ ")"
+    return x
+
+  testI64 _ x = do
+    System.IO.putStrLn $ "testI64(" ++ show x ++ ")"
+    return x
+
+  testDouble _ x = do
+    System.IO.putStrLn $ "testDouble(" ++ show x ++ ")"
+    return x
+
+  testBinary _ x = do
+    System.IO.putStrLn $ "testBinary(" ++ show x ++ ")"
+    return x
+
+  testStruct _ struct@Xtruct{..} = do
+    System.IO.putStrLn $ "testStruct({" ++ show xtruct_string_thing
+                      ++ ", " ++ show xtruct_byte_thing
+                      ++ ", " ++ show xtruct_i32_thing
+                      ++ ", " ++ show xtruct_i64_thing
+                      ++ "})"
+    return struct
+
+  testNest _ nest@Xtruct2{..} = do
+    let Xtruct{..} = xtruct2_struct_thing
+    System.IO.putStrLn $ "testNest({" ++ show xtruct2_byte_thing
+                   ++ "{, " ++ show xtruct_string_thing
+                   ++  ", " ++ show xtruct_byte_thing
+                   ++  ", " ++ show xtruct_i32_thing
+                   ++  ", " ++ show xtruct_i64_thing
+                   ++ "}, " ++ show xtruct2_i32_thing
+    return nest
+
+  testMap _ m = do
+    System.IO.putStrLn $ "testMap({" ++ stringifyMap m ++ "})"
+    return m
+
+  testStringMap _ m = do
+    System.IO.putStrLn $ "testStringMap(" ++ stringifyMap m ++ "})"
+    return m
+
+  testSet _ x = do
+    System.IO.putStrLn $ "testSet({" ++ stringifySet x ++ "})"
+    return x
+
+  testList _ x = do
+    System.IO.putStrLn $ "testList(" ++ stringifyList x ++ "})"
+    return x
+
+  testEnum _ x = do
+    System.IO.putStrLn $ "testEnum(" ++ show x ++ ")"
+    return x
+
+  testTypedef _ x = do
+    System.IO.putStrLn $ "testTypedef(" ++ show x ++ ")"
+    return x
+
+  testMapMap _ x = do
+    System.IO.putStrLn $ "testMapMap(" ++ show x ++ ")"
+    return $ Map.fromList [ (-4, Map.fromList [ (-4, -4)
+                                              , (-3, -3)
+                                              , (-2, -2)
+                                              , (-1, -1)
+                                              ])
+                          , (4,  Map.fromList [ (1, 1)
+                                              , (2, 2)
+                                              , (3, 3)
+                                              , (4, 4)
+                                              ])
+                          ]
+
+  testInsanity _ x = do
+    System.IO.putStrLn "testInsanity()"
+    return $ Map.fromList [ (1, Map.fromList [ (TWO  , x)
+                                             , (THREE, x)
+                                             ])
+                          , (2, Map.fromList [ (SIX, default_Insanity)
+                                             ])
+                          ]
+
+  testMulti _ byte i32 i64 _ _ _ = do
+    System.IO.putStrLn "testMulti()"
+    return Xtruct{ xtruct_string_thing = Text.pack "Hello2"
+                 , xtruct_byte_thing   = byte
+                 , xtruct_i32_thing    = i32
+                 , xtruct_i64_thing    = i64
+                 }
+
+  testException _ s = do
+    System.IO.putStrLn $ "testException(" ++ show s ++ ")"
+    case s of
+      "Xception"   -> throw $ Xception 1001 s
+      "TException" -> throw ThriftException
+      _ -> return ()
+
+  testMultiException _ s1 s2 = do
+    System.IO.putStrLn $ "testMultiException(" ++ show s1 ++ ", " ++ show s2 ++  ")"
+    case s1 of
+      "Xception"   -> throw $ Xception 1001 "This is an Xception"
+      "Xception2"  -> throw $ Xception2 2002 $ Xtruct "This is an Xception2" 0 0 0
+      "TException" -> throw ThriftException
+      _ -> return default_Xtruct{ xtruct_string_thing = s2 }
+
+  testOneway _ i = do
+    System.IO.putStrLn $ "testOneway(" ++ show i ++ "): Sleeping..."
+    threadDelay $ (fromIntegral i) * 1000000
+    System.IO.putStrLn $ "testOneway(" ++ show i ++ "): done sleeping!"
+
+main :: IO ()
+main = do
+  options <- flip parseFlags defaultOptions <$> getArgs
+  case options of
+    Nothing -> showHelp
+    Just Options{..} -> do
+      case Main.getTransport transport of
+        Buffered f -> runServer protocol f port
+        Framed   f -> runServer protocol f port
+        NoTransport err -> putStrLn err
+      System.IO.putStrLn $ "Starting \"" ++ show serverType ++ "\" server (" ++
+        show transport ++ ") listen on: " ++ domainSocket ++ show port
+      where
+        acceptor p f socket = do
+          t <- f socket
+          return (p t, p t)
+
+        headerAcceptor f socket = do
+          t <- f socket
+          p <- createHeaderProtocol1 t
+          return (p, p)
+
+        doRunServer p f = do
+          runThreadedServer (acceptor p f) TestHandler ThriftTest.process . PortNumber . fromIntegral
+
+        runServer p f port = case p of
+          Binary  -> doRunServer BinaryProtocol f port
+          Compact -> doRunServer CompactProtocol f port
+          JSON    -> doRunServer JSONProtocol f port
+          Header  -> runThreadedServer (headerAcceptor f) TestHandler ThriftTest.process (PortNumber $ fromIntegral port)
+
+parseFlags :: [String] -> Options -> Maybe Options
+parseFlags (flag : flags) opts = do
+  let pieces = splitOn "=" flag
+  case pieces of
+    "--port" : arg : _ -> parseFlags flags opts{ port = read arg }
+    "--domain-socket" : arg : _ -> parseFlags flags opts{ domainSocket = read arg }
+    "--server-type" : arg : _ -> parseFlags flags opts{ serverType = fromString arg }
+    "--transport" : arg : _ -> parseFlags flags opts{ transport = arg }
+    "--protocol" : arg : _ -> parseFlags flags opts{ protocol = getProtocol arg }
+    "--workers" : arg : _ -> parseFlags flags opts{ workers = read arg }
+    "-n" : arg : _ -> parseFlags flags opts{ workers = read arg }
+    "--h" : _ -> Nothing
+    "--help" : _ -> Nothing
+    "--ssl" : _ -> parseFlags flags opts{ ssl = True }
+    "--processor-events" : _ -> parseFlags flags opts
+    _ -> Nothing
+parseFlags [] opts = Just opts
+
+showHelp :: IO ()
+showHelp = System.IO.putStrLn
+  "Allowed options:\n\
+  \  -h [ --help ]               produce help message\n\
+  \  --port arg (=9090)          Port number to listen\n\
+  \  --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)\n\
+  \  --server-type arg (=simple) type of server, \"simple\", \"thread-pool\",\n\
+  \                              \"threaded\", or \"nonblocking\"\n\
+  \  --transport arg (=buffered) transport: buffered, framed\n\
+  \  --protocol arg (=binary)    protocol: binary, compact, json\n\
+  \  --ssl                       Encrypted Transport using SSL\n\
+  \  --processor-events          processor-events\n\
+  \  -n [ --workers ] arg (=4)   Number of thread pools workers. Only valid for\n\
+  \                              thread-pool server type"
diff --git a/test/hs/ThriftTestUtils.hs b/test/hs/ThriftTestUtils.hs
new file mode 100644
index 0000000..9c19b56
--- /dev/null
+++ b/test/hs/ThriftTestUtils.hs
@@ -0,0 +1,65 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+module ThriftTestUtils (ClientFunc, ServerFunc, clientLog, serverLog, testLog, runTest) where
+
+
+import qualified Control.Concurrent
+import qualified Network
+import qualified System.IO
+
+
+serverPort :: Network.PortNumber
+serverPort = 9090
+
+serverAddress :: (String, Network.PortID)
+serverAddress = ("localhost", Network.PortNumber serverPort)
+
+
+testLog :: String -> IO ()
+testLog str = do
+    System.IO.hPutStr System.IO.stdout $ str ++ "\n"
+    System.IO.hFlush System.IO.stdout
+
+
+clientLog :: String -> IO ()
+clientLog str = testLog $ "CLIENT: " ++ str
+
+serverLog :: String -> IO ()
+serverLog str = testLog $ "SERVER: " ++ str
+
+
+type ServerFunc = Network.PortNumber -> IO ()
+type ClientFunc = (String, Network.PortID) -> IO ()
+
+runTest :: ServerFunc -> ClientFunc -> IO ()
+runTest server client = do
+    _ <- Control.Concurrent.forkIO (server serverPort)
+
+    -- Fairly horrible; this does not 100% guarantees that the other thread
+    -- has actually opened the socket we need... but not much else we can do
+    -- without this, the client races the server to the socket, and wins every
+    -- time
+    Control.Concurrent.yield
+    Control.Concurrent.threadDelay $ 500 * 1000 -- unit is in _micro_seconds
+    Control.Concurrent.yield
+
+    client serverAddress
+
+    testLog "SUCCESS"
diff --git a/test/hs/ThriftTest_Main.hs b/test/hs/ThriftTest_Main.hs
new file mode 100644
index 0000000..670023e
--- /dev/null
+++ b/test/hs/ThriftTest_Main.hs
@@ -0,0 +1,214 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main where
+
+
+import qualified Control.Exception
+import qualified Data.HashMap.Strict as Map
+import qualified Data.HashSet as Set
+import qualified Data.Vector as Vector
+
+import qualified Network
+
+import Thrift
+import Thrift.Protocol.Binary
+import Thrift.Server
+import Thrift.Transport.Handle
+
+import qualified ThriftTestUtils
+
+import qualified ThriftTest
+import qualified ThriftTest_Client as Client
+import qualified ThriftTest_Iface as Iface
+import qualified ThriftTest_Types as Types
+
+
+data TestHandler = TestHandler
+instance Iface.ThriftTest_Iface TestHandler where
+    testVoid _ = return ()
+
+    testString _ s = do
+        ThriftTestUtils.serverLog $ show s
+        return s
+
+    testByte _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
+
+    testI32 _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
+
+    testI64 _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
+
+    testDouble _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
+
+    testBinary _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
+
+    testStruct _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
+
+    testNest _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
+
+    testMap _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
+
+    testStringMap _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
+
+    testSet _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
+
+    testList _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
+
+    testEnum _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
+
+    testTypedef _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
+
+    testMapMap _ _ = do
+        return (Map.fromList [(1, Map.fromList [(2, 2)])])
+
+    testInsanity _ x = do
+        return (Map.fromList [(1, Map.fromList [(Types.ONE, x)])])
+
+    testMulti _ _ _ _ _ _ _ = do
+        return (Types.Xtruct "" 0 0 0)
+
+    testException _ _ = do
+        Control.Exception.throw (Types.Xception 1 "bya")
+
+    testMultiException _ _ _ = do
+        Control.Exception.throw (Types.Xception 1 "xyz")
+
+    testOneway _ i = do
+        ThriftTestUtils.serverLog $ show i
+
+
+client :: (String, Network.PortID) -> IO ()
+client addr = do
+    to <- hOpen addr
+    let ps = (BinaryProtocol to, BinaryProtocol to)
+
+    v1 <- Client.testString ps "bya"
+    ThriftTestUtils.clientLog $ show v1
+
+    v2 <- Client.testByte ps 8
+    ThriftTestUtils.clientLog $ show v2
+
+    v3 <- Client.testByte ps (-8)
+    ThriftTestUtils.clientLog $ show v3
+
+    v4 <- Client.testI32 ps 32
+    ThriftTestUtils.clientLog $ show v4
+
+    v5 <- Client.testI32 ps (-32)
+    ThriftTestUtils.clientLog $ show v5
+
+    v6 <- Client.testI64 ps 64
+    ThriftTestUtils.clientLog $ show v6
+
+    v7 <- Client.testI64 ps (-64)
+    ThriftTestUtils.clientLog $ show v7
+
+    v8 <- Client.testDouble ps 3.14
+    ThriftTestUtils.clientLog $ show v8
+
+    v9 <- Client.testDouble ps (-3.14)
+    ThriftTestUtils.clientLog $ show v9
+
+    -- TODO: Client.testBinary ...
+	
+    v10 <- Client.testMap ps (Map.fromList [(1,1),(2,2),(3,3)])
+    ThriftTestUtils.clientLog $ show v10
+
+    v11 <- Client.testStringMap ps (Map.fromList [("a","123"),("a b","with spaces "),("same","same"),("0","numeric key")])
+    ThriftTestUtils.clientLog $ show v11
+
+    v12 <- Client.testList ps (Vector.fromList [1,2,3,4,5])
+    ThriftTestUtils.clientLog $ show v12
+
+    v13 <- Client.testSet ps (Set.fromList [1,2,3,4,5])
+    ThriftTestUtils.clientLog $ show v13
+
+    v14 <- Client.testStruct ps (Types.Xtruct "hi" 4 5 0)
+    ThriftTestUtils.clientLog $ show v14
+
+    (testException ps "bad") `Control.Exception.catch` testExceptionHandler
+
+    (testMultiException ps "ok") `Control.Exception.catch` testMultiExceptionHandler1
+    (testMultiException ps "bad") `Control.Exception.catch` testMultiExceptionHandler2 `Control.Exception.catch` testMultiExceptionHandler3
+
+    -- (  (Client.testMultiException ps "e" "e2">> ThriftTestUtils.clientLog "bad") `Control.Exception.catch` 
+
+    tClose to
+  where testException ps msg = do
+            _ <- Client.testException ps "e"
+            ThriftTestUtils.clientLog msg
+            return ()
+
+        testExceptionHandler (e :: Types.Xception) = do
+            ThriftTestUtils.clientLog $ show e
+
+        testMultiException ps msg = do
+            _ <- Client.testMultiException ps "e" "e2"
+            ThriftTestUtils.clientLog msg
+            return ()
+
+        testMultiExceptionHandler1 (e :: Types.Xception) = do
+            ThriftTestUtils.clientLog $ show e
+
+        testMultiExceptionHandler2 (e :: Types.Xception2) = do
+            ThriftTestUtils.clientLog $ show e
+
+        testMultiExceptionHandler3 (_ :: Control.Exception.SomeException) = do
+            ThriftTestUtils.clientLog "ok"
+
+
+server :: Network.PortNumber -> IO ()
+server port = do
+    ThriftTestUtils.serverLog "Ready..."
+    (runBasicServer TestHandler ThriftTest.process port)
+    `Control.Exception.catch`
+    (\(TransportExn s _) -> error $ "FAILURE: " ++ s)
+
+
+main :: IO ()
+main = ThriftTestUtils.runTest server client
diff --git a/test/hs/run-test.sh b/test/hs/run-test.sh
new file mode 100755
index 0000000..ecafc18
--- /dev/null
+++ b/test/hs/run-test.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if [ "x" = "x$1" ]; then
+  printf "run-test.sh needs an argument, the name of the test to run. Try 'ThriftTest' or 'ProtoDebugTest'\n"
+  exit 2
+fi
+
+# Check some basics
+if [ -z $BASE ]; then
+    BASE=../..
+fi
+
+# Figure out what file to run has a server
+if [ -z $TEST_SOURCE_FILE ]; then
+    TEST_SOURCE_FILE=$BASE/test/hs/$1_Main.hs
+fi
+
+if [ ! -e $TEST_SOURCE_FILE ]; then
+    printf "Missing server code file $TEST_SOURCE_FILE \n"
+    exit 3
+fi
+
+printf "Running test... \n"
+runhaskell -Wall -XScopedTypeVariables -i$BASE/lib/hs/src -igen-hs $TEST_SOURCE_FILE
diff --git a/test/index.html b/test/index.html
new file mode 100644
index 0000000..3611a92
--- /dev/null
+++ b/test/index.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+Apache Thrift - integration test suite
+
+
+
+
+
+
+

Apache Thrift - integration test suite: Results

+ + + + + + + + + + + +
ServerClientProtocolTransportResult (log)Expected
+

Test Information

+

+
+browse raw log
+
+
+
diff --git a/test/keys/CA.pem b/test/keys/CA.pem
new file mode 100644
index 0000000..a747b9a
--- /dev/null
+++ b/test/keys/CA.pem
@@ -0,0 +1,82 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 16582080088954381212 (0xe61f61fc3b34239c)
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, ST=Maryland, L=Forest Hill, O=The Apache Software Foundation, OU=Apache Thrift, CN=localhost/emailAddress=dev@thrift.apache.org
+        Validity
+            Not Before: Apr  7 18:58:00 2014 GMT
+            Not After : Jun 24 18:58:00 2022 GMT
+        Subject: C=US, ST=Maryland, L=Forest Hill, O=The Apache Software Foundation, OU=Apache Thrift, CN=localhost/emailAddress=dev@thrift.apache.org
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:aa:13:d4:c4:f7:01:17:a7:92:d1:b4:b4:15:0d:
+                    21:90:19:5e:fc:fb:b6:6d:3f:f2:3f:65:a2:7a:43:
+                    a6:46:95:fc:43:16:f6:63:14:5e:f7:b1:e3:61:02:
+                    f9:4a:95:89:bf:8d:f9:48:1d:82:e7:34:e0:b2:48:
+                    df:08:d9:7c:3a:2f:d3:1b:0b:e8:ef:c2:41:0a:7d:
+                    0a:38:78:3a:31:66:73:99:8c:d1:79:27:5f:e5:66:
+                    d0:5e:3a:8c:0c:92:18:73:04:c1:f5:45:db:37:e7:
+                    5f:c7:8c:a3:60:e9:92:a0:d8:29:5d:77:48:fb:1d:
+                    b0:ed:12:2c:4e:2e:02:db:3d:1a:41:71:a6:2b:2e:
+                    b3:4c:6a:c7:f7:1d:a9:7e:c7:cf:db:f2:e7:b6:f3:
+                    1f:77:1d:24:01:1a:66:66:30:85:30:02:29:c4:bb:
+                    f7:cd:3f:89:4b:1a:5f:f4:91:96:fb:e9:39:f2:46:
+                    96:12:3d:8a:23:b5:2e:82:9e:41:fe:40:b6:27:b1:
+                    14:44:5c:96:30:0f:55:e4:bb:ad:8b:8a:99:17:c0:
+                    29:11:4e:76:79:9d:4b:03:31:7e:85:3c:a8:23:40:
+                    54:02:58:35:c6:fc:dd:3d:eb:e3:d1:51:00:02:86:
+                    1a:d7:b0:9f:a0:17:73:6a:5a:d0:e6:b6:b8:55:40:
+                    5e:27
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                28:F2:FD:30:CD:03:F1:DC:41:1E:C4:93:C6:97:13:CA:D4:FA:60:2A
+            X509v3 Authority Key Identifier: 
+                keyid:28:F2:FD:30:CD:03:F1:DC:41:1E:C4:93:C6:97:13:CA:D4:FA:60:2A
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha1WithRSAEncryption
+         46:15:18:89:b2:57:17:d1:a2:64:c1:9a:73:4f:04:94:76:07:
+         1f:29:ba:6f:34:46:c2:36:d5:68:85:f4:15:4c:8e:1a:fe:83:
+         79:53:ec:aa:0d:92:60:de:f3:9a:3a:e8:80:66:ac:87:70:89:
+         59:f2:ac:9e:b0:28:11:37:7d:78:4e:5e:3f:25:0f:be:09:6f:
+         26:2a:3d:66:79:38:28:e5:81:71:71:96:26:4f:db:ec:23:70:
+         be:37:39:fc:e0:32:0d:80:8f:66:c7:ac:a4:b4:8b:77:40:e2:
+         99:44:3a:73:c8:f9:14:cf:1b:32:27:c2:78:db:b0:da:8a:60:
+         eb:8d:34:7e:7d:3c:03:d4:38:74:f7:17:9e:32:74:9a:e7:37:
+         95:d4:71:03:c8:94:ea:09:7b:ad:2d:eb:70:43:f2:32:7e:63:
+         01:84:8c:7e:9e:f0:79:7f:ae:e9:cf:f9:be:0e:fe:95:d2:bd:
+         c8:a7:81:c2:71:d9:c3:50:31:89:6d:fa:ad:a2:ab:00:01:34:
+         10:58:ef:96:5a:eb:30:07:a9:8e:84:36:ef:3d:3c:61:46:96:
+         6a:e8:09:20:5a:ab:f8:4b:eb:b7:33:61:8e:af:9a:7d:16:b0:
+         60:6a:f0:30:e5:b2:8e:e7:80:b4:a1:02:a9:37:fe:5f:b5:ae:
+         65:e9:6b:34
+-----BEGIN CERTIFICATE-----
+MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD
+VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs
+MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV
+BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3
+DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy
+MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU
+MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh
+cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ
+bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ
+GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6
+L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg
+2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw
+AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX
+wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n
+AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME
+GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
+DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5
+U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm
+T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD
+1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I
+p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO
+r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0
+-----END CERTIFICATE-----
diff --git a/test/keys/README.md b/test/keys/README.md
new file mode 100755
index 0000000..010835d
--- /dev/null
+++ b/test/keys/README.md
@@ -0,0 +1,102 @@
+# Test Keys and Certificates
+This folder is dedicated to test keys and certificates provided in multiple formats.
+Primary use are unit test suites and cross language tests.
+
+    test/keys
+
+**The files in this directory must never be used on production systems.**
+
+## SSL Keys and Certificates
+
+
+## create certificates
+
+we use the following parameters for test key and certificate creation
+
+    C=US,
+    ST=Maryland,
+    L=Forest Hill,
+    O=The Apache Software Foundation,
+    OU=Apache Thrift,
+    CN=localhost/emailAddress=dev@thrift.apache.org
+
+### create self-signed server key and certificate
+
+    openssl req -new -x509 -nodes  -days 3000 -out server.crt -keyout server.key
+    openssl x509 -in server.crt -text > CA.pem
+    cat server.crt server.key > server.pem
+
+Export password is "thrift" without the quotes
+
+    openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.p12
+
+### create client key and certificate
+
+    openssl genrsa -out client.key
+
+create a signing request:
+
+    openssl req -new -key client.key -out client.csr
+
+sign the client certificate with the server.key
+
+    openssl x509 -req -days 3000 -in client.csr -CA CA.pem -CAkey server.key -set_serial 01 -out client.crt
+
+export certificate in PKCS12 format (Export password is "thrift" without the quotes)
+
+    openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12
+
+export certificate in PEM format for OpenSSL usage
+
+    openssl pkcs12 -in client.p12 -out client.pem -clcerts
+
+### create client key and certificate with altnames
+
+copy openssl.cnf from your system e.g. /etc/ssl/openssl.cnf and append following to the end of [ v3_req ]
+
+    subjectAltName=@alternate_names
+
+    [ alternate_names ]
+    IP.1=127.0.0.1
+    IP.2=::1
+    IP.3=::ffff:127.0.0.1
+
+create a signing request:
+
+    openssl req -new -key client_v3.key -out client_v3.csr -config openssl.cnf \
+        -subj "/C=US/ST=Maryland/L=Forest Hill/O=The Apache Software Foundation/OU=Apache Thrift/CN=localhost" -extensions v3_req
+
+sign the client certificate with the server.key
+
+    openssl x509 -req -days 3000 -in client_v3.csr -CA CA.pem -CAkey server.key -set_serial 01 -out client_v3.crt -extensions v3_req -extfile openssl.cnf
+
+## Java key and certificate import
+Java Test Environment uses key and trust store password "thrift" without the quotes
+
+list keystore entries
+
+    keytool -list -storepass thrift -keystore ../../lib/java/test/.keystore
+
+list truststore entries
+
+    keytool -list -storepass thrift -keystore ../../lib/java/test/.truststore
+
+
+delete an entry
+
+    keytool -delete -storepass thrift -keystore ../../lib/java/test/.truststore -alias ssltest
+
+
+import certificate into truststore
+
+    keytool -importcert -storepass thrift -keystore ../../lib/java/test/.truststore -alias localhost --file server.crt
+
+import key into keystore
+
+    keytool -importkeystore -storepass thrift -keystore ../../lib/java/test/.keystore -srcstoretype pkcs12 -srckeystore server.p12
+
+# Test SSL server and clients
+
+    openssl s_client -connect localhost:9090
+    openssl s_server -accept 9090 -www
+
diff --git a/test/keys/client.crt b/test/keys/client.crt
new file mode 100644
index 0000000..80a9ad0
--- /dev/null
+++ b/test/keys/client.crt
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID2DCCAsACAQEwDQYJKoZIhvcNAQELBQAwgbExCzAJBgNVBAYTAlVTMREwDwYD
+VQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRo
+ZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRo
+cmlmdDESMBAGA1UEAwwJbG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhy
+aWZ0LmFwYWNoZS5vcmcwHhcNMTUxMjIzMDcwNzUwWhcNMjQwMzEwMDcwNzUwWjCB
+sTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1hcnlsYW5kMRQwEgYDVQQHDAtGb3Jl
+c3QgSGlsbDEnMCUGA1UECgweVGhlIEFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9u
+MRYwFAYDVQQLDA1BcGFjaGUgVGhyaWZ0MRIwEAYDVQQDDAlsb2NhbGhvc3QxJDAi
+BgkqhkiG9w0BCQEWFWRldkB0aHJpZnQuYXBhY2hlLm9yZzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALl/bJhg17Pu1t785JIuwlh7e2E51eoWFvuxMWfH
+dsUAVqDaOz99O5sv8pgWKXrkPBttE98T+Mx/Pwz5JHs4Qcre3A5adm6cdab0AKug
+eVG1PvHrWzV4aheg4KUfVSiMz8BG2K3Q1VGvZkgMRa/Q409FKjU6Z4D9vBG4Pas3
+PN5FxnAL6P70yWCEr2Vu/tWJlCN+qrRDfSaE2hqmT1irxaoPa61GvuRVsGQ3TeoE
+mGfENtvFqC6qQWuSCbG5aI47Rv66pqoWWxqkrcolNc7+vhx6rW+wdFO3IlqIT8IG
+sdQVp+Y4ir/dGp2ejzqGZCremPJ1uEKjLMpIukdg25ymHC0CAwEAATANBgkqhkiG
+9w0BAQsFAAOCAQEABcRdwc9mdY9zOvTixtThHrciVvqwp6RaiQqMEVomozYilZDR
+J90M3H6KnlADJbCv0FXujsaApB53awq5I7sObAYWFhDJZ9LKlw0lDF7KchLXiAlk
+XVyvL2nJjuJcxPCFPWktwrw5bTguRCBzG12Hzikn+xs6uPur7VQYM33jbXEda5PS
+UEqvAVWaONJCX8MDYOscVoJF0ESyI+fN92ipFaXR7fGajod/rc0AfeN2GVMZETve
+21pkUyDwwCGA44uvNUCd1e32NxE3ah9UApCRn5sGJ64R6urpFTXT3IALF3kaOO7U
+VsMhFrUiZ7+Bw5nIeiK0QOF6Eipj+bJvrLZpSg==
+-----END CERTIFICATE-----
diff --git a/test/keys/client.key b/test/keys/client.key
new file mode 100644
index 0000000..25dcfd7
--- /dev/null
+++ b/test/keys/client.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAuX9smGDXs+7W3vzkki7CWHt7YTnV6hYW+7ExZ8d2xQBWoNo7
+P307my/ymBYpeuQ8G20T3xP4zH8/DPkkezhByt7cDlp2bpx1pvQAq6B5UbU+8etb
+NXhqF6DgpR9VKIzPwEbYrdDVUa9mSAxFr9DjT0UqNTpngP28Ebg9qzc83kXGcAvo
+/vTJYISvZW7+1YmUI36qtEN9JoTaGqZPWKvFqg9rrUa+5FWwZDdN6gSYZ8Q228Wo
+LqpBa5IJsblojjtG/rqmqhZbGqStyiU1zv6+HHqtb7B0U7ciWohPwgax1BWn5jiK
+v90anZ6POoZkKt6Y8nW4QqMsyki6R2DbnKYcLQIDAQABAoIBAFotbCmXysUaczLs
+VmIKgUhqn0xgxXGLU5kARzhga4jR5UtFTFBNHVEQOitdesTXd7ENkf98whMIOSqh
+Y+7TJojtVqVTrQeQ4FFNhZXp6ZCjP/pzpF+WLl1WRF+Bn/Cao9ShnGzDfTC8yEh2
+Ttpt/lNnGGHQBslakLc8jh5SODEFfbugX8SdTCwZYsesKNrXm1pS/5IEunPqaRi0
+II0EcnqHEsgqSo+CljpW7uNxSryA2vSAVdlPej6+9FZjdIHLP5AEKYvk7e9D2CMV
+1+grNe/QkQppShizPirbb93tHm86v5bkDFCM9yWrhcMcjvILMXETxIppMGPmacRu
+jqtYcAECgYEA8VDzylTz4kS3+D3n3hTgb41XVYa7feUsh99GWRO1wXIFpHjCIRjA
+9r/BXW9+Rx3puVPhS8hwLQ4BLdA7lFpV1C8ag0e3+vn6zVirnz1jtI+uHMvStzhO
+d6i0nf+w4HYXo7mN6o9ZdHEfC8SFNbymhCoVKh2DILDwb4EX9RXNpy0CgYEAxMj4
++vrklJ/ilH+Ry1zst4zQYIwmm3QWjarDrypGucHgd4jg5v9A/CJIKUi8x0MjrcuN
+wVb7R8XJyYzFQRXIUXR6GnLeeSnfpxzt4YlifCvXxnOi8w4fv7KeGBV5np1Egpo8
+nWNyZFxdvQDuCopr3SUoS9JI8JPwVgA7T+7DaQECgYAGoavhbo45NJw9pS3fC4HT
+bvXscsRqREcCAN/FCOagx0piZ7MmB7Ed1s0wjSTSPX8zyZtSYtK6Wj0sDiHlBMqB
+Bz5aRzlGG2KKDBrDSIOZ7aziO7Oxt0lovmkgQmuQ743cwPemb4QM0CMDRsZGYMXO
+sf1c5+y3lEU3Ozv2T0AUjQKBgBlnzOUyMQKTJcCAO8ViiNkln91nGrDlKug9TKg3
+sAvZYO5tyINqHuyuTFywHFcpbtjIN9PnM+fPPD7+IpVFh6gkfoMdo2VHJ62+iWOd
+xg475s6jLT1t7GFmYQzA8QOuUCMAYKT9Ks6UMjHthc3skwJpAqvPSUVuBBBGVWH7
+dFUBAoGBAL67ARLujiAEVNHt5rajixB6ncl7/R+Z2uawI1JfmdnCZonAKVZYHuXU
+/4j2+o4QhJIPLtWIoaxAkMigQtAkesqirn3Kk/c7kZRIoN549HTJuwZqYqNp7CB/
+kVi5R335+M9z49i6qA0RZsJGSoSBk7PufG4RmLimcRbGwrY93sPD
+-----END RSA PRIVATE KEY-----
diff --git a/test/keys/client.p12 b/test/keys/client.p12
new file mode 100644
index 0000000000000000000000000000000000000000..5d2669c12d033a694573f70491b91bb72e252748
GIT binary patch
literal 2589
zcmY+^cQhM}8U}D7V(&d_uc{HFMr*~^Qk$Yyh*IN=t))f~ql(t7O_8ec88u3yR*g2O
zRcUIE+G>l0x_ZvN_q+Fx_q^vk&pFSZKQMxtixfZxMo`Uzs3ehw$WuB11)u~$^%aPq
z!d%6JU<5Ggp9)lh0K%^#A5s9x)r0-h0KmK;>VGfL0zhDTASLR0_hCJhJdTuZk
zU3r8a>eCDoxo6m3_`4gkdDLFB#T$pV3%q_4oxmfK$;GMyD}TQGg_R#~-E!?k`n<-@
zvn0CrcOS%mk8WD=nmbw0xL;G*&VRu0+RDE5WOYvDz*yLc(OP-yd0cOH>X|~Oa^ou>
zNXYuy6Ut}2-?o!eihrsM36IF}NWHJ}Q2OZXypQJ2Q^$k=RWJ%#R^7O^v#`oomsM}C
zjF^9T=xsw$)b6(X7=imA>YaGv>Db8|fppCM^)Od8BJcL=4pA
zuLSpBWn&$#RE44jd@Hnio~Iz2Q3ZqID27QtPh;Yad2l7S{O<64+MarKDQ#~u3DpIC
z992{Uf-oz~7Pk4MQDWeme>oWgTXU+*c2_6o*~$)cCZz`L>ctXE(m_C1IEQ6>
zhMX?AjFaibx!V@kk`xnkjvDD#<%K--$$6(%3jn&{RzDi{457}ys%Ky0%MW8N6kmx=
zT9WY^4eXHPC@4;L@bEjxQoXUv{D_Yi&7qX6Q$LL7{x#Nn`1j^oP1A~>FDtwDZIBVG
z_gC<;;+@GkCEbKzM`q3*bU%S~K~20}l}CW{xsM>5Wc&FEmWN6&vR2eGyG?PFKOgZs
zd7?R{Ubz$B=y%+&YZq(A9i@EP-<)F#Y>~DOo&dnO?RjR_kj;G|qD{cLaGJ4rX&y!_
zz_e9AN*fW1cO^c+Pl^ip?bo1?!EKwaIRZlYHlx5=S(?W?jyH%kFE_J>GPpml8|N68
z)Gu}yh8%}+JJhIj%F-AQ9YbUi+!hkWi|2DV!eVzRL!AEM{HE!Q1QJ=ORiaK58X^)|hn0-}@1Mqfle)-2NV4kJyLp9l5AV(8@lRTiQ|AdHyi-e}S5mqi&=8dG{1h_Sl*`hH!M9}7HjY&nPv`ot*xldmL*
zq$L5*jbkTg$>j2~xggqj^DwB=>qGI*M~l;Wsb;5(^L=__kj*N%9n<|Y%j!tGZ3e(j
zxoXe}L`YuMGC=*>B-xpUGB#YaS5L+cyqa(#FPhSvOz1sZVa(LSy54+rb5N_(?xCb+SP(xz#RKgR{OZ>7IXtL8iVtbVfE5iI6YIr
zYA0tZ-ekh{;PUtZ>v>vbQq3!bt}b)Ojw+RNSY=21M0VP^t{E`Zrr0HPuEN6FS3Gl1
z{Ftz2>aQ#T?(zB
za_%rSx?f>K0W0W%ct=vA=*av3+JstJ2COzrVVomf3Mex=Chd*x9S+J@h(%!$Z}DVl
zkIvz;9y^l4AVPC88#^I_2x+sudAC&V=t$(}(wm%~3iN$ebYL!2TM19xaYViv{U!W@
z^p~>r$mM4W^IMKeTp5$Moy33}_DhX37Vo?JDWH6#$5?&N_nY<7(({$Mj22(cLN%*Tz)Q*J2V*09;2JI#*1{Qq
zyQc6c_bnNLc!6#n`igIN1()AgNouES?pb9=Uf;=L=fxO@QS5>D7(ZLqpJLsQ{1(<7
z4udQ%U(mCw$#>slKG-qAPb+kDS_YZsZu<91N+||9kT`xZ0B9BUfvdl$BS*R3trUJT
zPcl?TmoQ*UUJl;sSF@Z2oa8UAc`e3w?KMpNQt
ztY-r&+~z}$zZ>dRk%_#++CW()V;xZ!yJT?F`HNg`Ld>q3{;INH`85=>M-2O;u7_SN
zU*ywn`;j{zGIPV>o>OBS1*+~@;`fU)3-4llpK5wZV_=O2hnz{4A=P8IB4ypF8`7
z<%8+NysXqgr0RE>REWJrV}&NTqU9o~CMLN8m2kp+$X|i+mOe9ckmh{OuJW-lppY7d*xsAe+=wxDUz!kQ*Jh6`0#p{{z
z504HYGm)#}QY-_w2)LXmSops>QnAUg16ftK)g2@_aI;iTpq^8@`~yq)g<-H9SP)DF
vBELaTM#@c20%Uzh5vW-IGBo836;-aHyNXmK>YV~9>-eMJD}vg${wVn`wx!*G

literal 0
HcmV?d00001

diff --git a/test/keys/client.pem b/test/keys/client.pem
new file mode 100644
index 0000000..66ef626
--- /dev/null
+++ b/test/keys/client.pem
@@ -0,0 +1,60 @@
+Bag Attributes
+    localKeyID: 39 EC 3D 5B 28 17 DA DD 09 7A 62 68 D5 44 1F C7 E2 F8 E0 CD 
+subject=/C=US/ST=Maryland/L=Forest Hill/O=The Apache Software Foundation/OU=Apache Thrift/CN=localhost/emailAddress=dev@thrift.apache.org
+issuer=/C=US/ST=Maryland/L=Forest Hill/O=The Apache Software Foundation/OU=Apache Thrift/CN=localhost/emailAddress=dev@thrift.apache.org
+-----BEGIN CERTIFICATE-----
+MIID2DCCAsACAQEwDQYJKoZIhvcNAQELBQAwgbExCzAJBgNVBAYTAlVTMREwDwYD
+VQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRo
+ZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRo
+cmlmdDESMBAGA1UEAwwJbG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhy
+aWZ0LmFwYWNoZS5vcmcwHhcNMTUxMjIzMDcwNzUwWhcNMjQwMzEwMDcwNzUwWjCB
+sTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1hcnlsYW5kMRQwEgYDVQQHDAtGb3Jl
+c3QgSGlsbDEnMCUGA1UECgweVGhlIEFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9u
+MRYwFAYDVQQLDA1BcGFjaGUgVGhyaWZ0MRIwEAYDVQQDDAlsb2NhbGhvc3QxJDAi
+BgkqhkiG9w0BCQEWFWRldkB0aHJpZnQuYXBhY2hlLm9yZzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALl/bJhg17Pu1t785JIuwlh7e2E51eoWFvuxMWfH
+dsUAVqDaOz99O5sv8pgWKXrkPBttE98T+Mx/Pwz5JHs4Qcre3A5adm6cdab0AKug
+eVG1PvHrWzV4aheg4KUfVSiMz8BG2K3Q1VGvZkgMRa/Q409FKjU6Z4D9vBG4Pas3
+PN5FxnAL6P70yWCEr2Vu/tWJlCN+qrRDfSaE2hqmT1irxaoPa61GvuRVsGQ3TeoE
+mGfENtvFqC6qQWuSCbG5aI47Rv66pqoWWxqkrcolNc7+vhx6rW+wdFO3IlqIT8IG
+sdQVp+Y4ir/dGp2ejzqGZCremPJ1uEKjLMpIukdg25ymHC0CAwEAATANBgkqhkiG
+9w0BAQsFAAOCAQEABcRdwc9mdY9zOvTixtThHrciVvqwp6RaiQqMEVomozYilZDR
+J90M3H6KnlADJbCv0FXujsaApB53awq5I7sObAYWFhDJZ9LKlw0lDF7KchLXiAlk
+XVyvL2nJjuJcxPCFPWktwrw5bTguRCBzG12Hzikn+xs6uPur7VQYM33jbXEda5PS
+UEqvAVWaONJCX8MDYOscVoJF0ESyI+fN92ipFaXR7fGajod/rc0AfeN2GVMZETve
+21pkUyDwwCGA44uvNUCd1e32NxE3ah9UApCRn5sGJ64R6urpFTXT3IALF3kaOO7U
+VsMhFrUiZ7+Bw5nIeiK0QOF6Eipj+bJvrLZpSg==
+-----END CERTIFICATE-----
+Bag Attributes
+    localKeyID: 39 EC 3D 5B 28 17 DA DD 09 7A 62 68 D5 44 1F C7 E2 F8 E0 CD 
+Key Attributes: 
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIRKol42bAS3ACAggA
+MBQGCCqGSIb3DQMHBAjOulcyHMaWsQSCBMgbeXQ8pIYTENKm08UPeqxkCR2nLxSO
+gtRmBxDYjqYv35y4K8KhybBvSBlIPgE5jEWxUCcc1Qvy5ydUQ/X9pmkU8dnmAmDC
+o0zwd3lt2eNPy+4WliqFDVmHrLfYQFOoIrHjuzC0lI4C2iPOjxhfa1zFumedgwGS
+Gx10X5uEVH5N64fW6B3BvzQM0rn2qr0ONuSRmteRtI8NsznfkgeJ9a4CIAF7E5Z2
+JTGI12edNzzUJ1JhX47ZW4miQwCU5Lcy01UZqTFuUpmK7FUQegtLy3e5eDKq+bIg
+ZYq6Hx7lu8hjT5kWZGKy71aYmHKEjI0f727cAbqDTG5uZBHBjwK/3p/znQVQXxBb
+1+E9CiKeFdXj2ElptsnDyoTvrSwJ/Jqu1wkXBcH5Embg7aJMod1IOs6OQB1rPDvd
+FFa84zbqRNWHSxxxYZxcB8YZinL6/dQJnisKu9LMQd3BBGsGWqH8Zz5tEvXjS5Kv
+3g9JRa7QDkSF005x6U+q/678G2MG+W+NWqje3NZx9Psh/Ptm+h+q9n2GSvnibiK5
+mEj9FIwGquGpbZUTK5aXHcKN657dKiICsEJeNar1iZznRmzrMbZJ+DxqJnTw+GAv
+7Yb63/CNAtqSxiyNHGZ6NM2ZA9vAKY1HXn0RVC0y1+9FmNpSRwv3u/+ydSCnJonR
+GEKjzOqM9Dn7qxd+h4UnnA7hXWxITageB6G6KmfiXRxhiWyqtOICdCneCwpq8UZ4
+e0fm05NRW6M2mqGQHsMNSvTWddwz5b8wgw4eVsb+xQytxVdj9lpBuB9KyjQjxUgU
+3oZx4KyWLoEWjkztPAiK3uv5GfotNIMdznRfON1+xm1M5swtn3y3Ru1f6STZC7Sp
+qvbG7jPmpB5gLEUri+chw+aKUYbJ0b820Od4FLQYnwLWr46VelYmV44xuR06wgqP
+1HchMSsHtS+ZlIiQQU9jhdyTrl86EQHH33dh+Sua8AhfewPRy2VFp3Zk34AUsWcX
+EfIYGemhqUD3drG0SMVbFFNOaFGp9e0tQouYOC6/qFBv/SNgQz3mAEkciJYbUuUZ
+V4YQPvtdvSrISV0e7bjFgdSEjG7P7F6CFrWTrjUlHZuWj6/rJ3+/1PHeJViyhsrJ
+ZYFe14W/48PDxBRl4IEAmxcN1Eb2Ez9eCqv0HW77HviG6zIgnkPrhWHjFGUpxKk4
+jLfuB2Tfq9F7ozv4L2QAn+F/yKt1Rm2Hh5J61eUJtAT60pajg+gJtjmpu5Pr4HDn
+b6p3xmYwaL5Let1zCAbbMfdlDK14YjdOdM/BEKpXb9y4EIubX5AMY4ljXeG9gx+T
+B1TuQVdJ0P5wIK/D10TQzAWDKam0kv3RXidlzRxpZ3snRnN/L3EVd58Rntj1Oc0y
+FiIiSKRszDbPzKDxQE2sNgQcdO24JNLSa/sZYtq2gRgspl/YqIDo4ZYqi9x8F5OS
+rdPU5D/H8LWR4vpJLL8DYrHh5qFG3BX2OJIhPRS+48pDYtrRjp7S/1ZU64OJAytk
+99hDqSrn1j2a6yFE8L2Ptz+4UCF2OQXEc9Rqqeb8QEUuMSkNH4oQ+A2F6uzLpZi0
+XH64R2niNC56LxV2i+3T5KREFLahyk8epLZlv8YdxYR4Sb7J/5yiooK3g9hmYVKO
+zLc=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/test/keys/client_v3.crt b/test/keys/client_v3.crt
new file mode 100644
index 0000000..a47f156
--- /dev/null
+++ b/test/keys/client_v3.crt
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIECDCCAvCgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UEBhMCVVMx
+ETAPBgNVBAgMCE1hcnlsYW5kMRQwEgYDVQQHDAtGb3Jlc3QgSGlsbDEnMCUGA1UE
+CgweVGhlIEFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9uMRYwFAYDVQQLDA1BcGFj
+aGUgVGhyaWZ0MRIwEAYDVQQDDAlsb2NhbGhvc3QxJDAiBgkqhkiG9w0BCQEWFWRl
+dkB0aHJpZnQuYXBhY2hlLm9yZzAeFw0xNjAyMjIxMTU4NDFaFw0yNDA1MTAxMTU4
+NDFaMIGLMQswCQYDVQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcM
+C0ZvcmVzdCBIaWxsMScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5k
+YXRpb24xFjAUBgNVBAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9z
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALZ0wiQnXg5QMZZWugd/
+O3woatyHuczJuFSmYiRGWLr3PugB+xtvjy0rTcE2MNx/bdsVxrapCKA+tMFORbEl
+sF6jk0H+B7BzGoIwHr6N8GP1VOoA2esrhsNEz22aJI00VaFTFE8G/qgFcihyaVWH
+ZsLa3MakOzFUmOBaV2tLBjCjaznqXw3eo3XwUI0BkgS9b9vqXjScmfWXDw5+1is4
+bCgumG2zj9EpLypc9qCGNKFBO2YIg0XsIIJ8RprlianjL6P4MfC6GPOyW4NbZaLd
+ESv/bumpVyuV/C/xqkPahvOwBuPE1loxZZPx6Qv368qn7SVNVZOLyX722spooA5G
+6csCAwEAAaNPME0wCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwMwYDVR0RBCwwKocE
+fwAAAYcQAAAAAAAAAAAAAAAAAAAAAYcQAAAAAAAAAAAAAP//fwAAATANBgkqhkiG
+9w0BAQsFAAOCAQEABUEmeQkG/PS935jMHDrg/5zm4X2xrnFtmTwb0jdxfau6z/7h
+AbxD5ioyY7FUTNCzI6SyMo9vJJtYCTCuEGr84JjT2R7232z60k4c1z/av01W3Orv
+ExHfAZ8llhkfu0209T5TaIYCB7hDFj5KDbta8c6fEcwtmlHQWj3M31lSNsr4ZtWW
+wObhK3sqTsOluHbhKNwlNEat48lbOQUC19I1Wi3dAS6n8lr0lEhfGKvqxu0ViASS
+N1nLfdkREGp39bYpKg0n6EFw5bYyV4qE3cnIedFJp7NIOM/6xndJMh/c5l6N2uyZ
+upArRQpw/3j+HkL1x9bs+900QK0GI6AxgjbopA==
+-----END CERTIFICATE-----
diff --git a/test/keys/client_v3.key b/test/keys/client_v3.key
new file mode 100644
index 0000000..b989f73
--- /dev/null
+++ b/test/keys/client_v3.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAtnTCJCdeDlAxlla6B387fChq3Ie5zMm4VKZiJEZYuvc+6AH7
+G2+PLStNwTYw3H9t2xXGtqkIoD60wU5FsSWwXqOTQf4HsHMagjAevo3wY/VU6gDZ
+6yuGw0TPbZokjTRVoVMUTwb+qAVyKHJpVYdmwtrcxqQ7MVSY4FpXa0sGMKNrOepf
+Dd6jdfBQjQGSBL1v2+peNJyZ9ZcPDn7WKzhsKC6YbbOP0SkvKlz2oIY0oUE7ZgiD
+RewggnxGmuWJqeMvo/gx8LoY87Jbg1tlot0RK/9u6alXK5X8L/GqQ9qG87AG48TW
+WjFlk/HpC/fryqftJU1Vk4vJfvbaymigDkbpywIDAQABAoIBAQCJpyUhaaIIYnBG
+4D+RkGgsj8Gvh6ah3j53ft/kRj6DMC4BlB0C4fO/PEB5WI0cjfcvpwo4nOapHyX4
+ATmLIMgjXn2m+CSM9wo01mEbmrKWd20M7n96cWhGwg9MvVJ+RdGk2K0lwj02PoWW
+Blt576GTuNN/+j++Q/jiqsXxaLTO0/Wj+4b2gQh3n8I0u6bkolDLoERKIdrLGHH+
+FU3sk8bpUhHmeiUTfwwci+juhtOY9e30AEst6xakCHbq1lRRyEYPtWL7oLds6yv0
+UAKP7wS9Yl6dcekXSF1RZpB+fovTW+qPYn8aEuksaMz0wK96FCOjVNGYxMp+Xnvl
+sKx63UZBAoGBAOCbCbJtO0HsgIauvCvGZ50aZ1vDvQReCwri4ioutEg4JCAXHEsX
++axz2J5j3UEQhGKr0EX9BG6YbxGW0Mmjf3QxeRB+0WLpMMY2SFt93oC2R1AX9l0I
+h50O6tYv5SXm96pKxwRz01d84mCJgwn/G+cZ/EJj4rfZsNbQst6JQFvzAoGBAM/1
+gLVQt5l+IK+6s68EnADI66i7cKe6sj3rFRTahZJxL2vY28J9EB2mF/XEgARSNJQV
+X/H9zDrwKm9MX87/eCH2nEbc+5qSGpDPQm482C9DqsMitxCKD8bble1BlpjFb8hr
+R0Q3v5q8u5uomLBds5eUBeRKMtu9tOMA9KRSDGjJAoGAF44K2Ux9T2+XFwjSMSEQ
+krhHKKeBdijKrayXnWbif0Rr/XWPAQ0VoRFRIWNFu+IYkCSGpiBfy51u4IBZixv7
+bNsXYDR8jwv3koH02qt7nzH+jpbEvoL7fewnkqjZNj1fsds/vebLvjwZnZguRukb
+KwRdoTTKfQ92bUDb0VzBhCMCgYB7H+3ObDXoCQctRCsyilYbGNp+EkxG4oC5rD/V
+EvRWmfDrt3+VjRpHk5lIB8mLxWgf7O/bhNqwYpWdQ+jN0++6nBo20oudHrff2PaJ
+8jhE85lc42bjwfpJUKVZzaVuWicu0GVnfGJTKT8ikBWnBjNYoWlDmrK164H3jQ9L
+YtC6EQKBgQCabFXXHx5cIJ2XOm4K/nTOG7ClvD80xapqyGroQd9E/cJUHHPp/wQ4
+c1dMO5EViM7JRsKfxkl9vM5o9IM7swlYh4EMFSLJNjzgOY9XVkvQh0uGbiJOBO4f
+inUuWn1YWUj/HFtrT+0No+cYvZVcMKrFAy3K/AwpTbfKCk6roullNA==
+-----END RSA PRIVATE KEY-----
diff --git a/test/keys/server.crt b/test/keys/server.crt
new file mode 100644
index 0000000..8a5ef3c
--- /dev/null
+++ b/test/keys/server.crt
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD
+VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs
+MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV
+BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3
+DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy
+MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU
+MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh
+cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ
+bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ
+GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6
+L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg
+2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw
+AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX
+wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n
+AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME
+GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
+DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5
+U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm
+T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD
+1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I
+p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO
+r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0
+-----END CERTIFICATE-----
diff --git a/test/keys/server.key b/test/keys/server.key
new file mode 100644
index 0000000..263cfce
--- /dev/null
+++ b/test/keys/server.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR
+tLQVDSGQGV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCy
+SN8I2Xw6L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/H
+jKNg6ZKg2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQB
+GmZmMIUwAinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xk
+u62LipkXwCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDm
+trhVQF4nAgMBAAECggEAW/y52YYW6ypROGbZ94DQpFV0kLO7qT8q0Ksxw5sPNaIt
+fEPRIymDa8ikyHWJS5Oxmw84wo5jnJV26jaLmwe2Lupq7Xf1lqej8f5LJtuv7cQR
+xfzp1vM65KJFFJHp6WqjGqJ6HSSZOpVDsnQYcXQjQCdpyAmaSWd3p+FqYSZ1mQmD
+bFNI7jqpczWSZhTdotQ7p7Hn9TVCehflP3yGIB3bQ+wCcCB85dOBz201L+YgaIck
+Sz43A4NvWaQIRLRDw7s9GW4jY5T0Jv282WIeAlVpVxLIwu48r4R4yGTIx9Ydowvq
+57+Y5iPPjAXxu0V9t00oS3bYxDaKh2DUfc/5zowq8QKBgQDYNVPXmaG0aIH4vjQ9
+7fRdw/UDkYcQbn6CnglQOu77/S8ogQzpKCVJgJgkZNqOVtQMEPzekGEcLTbje1gU
+8Bky2k+PL9UwbFy0emnOVh4rqrNXHsRvJcehNT/PRb5hjF3MUMFV/0iD4b+naFaE
+jrSWiZ2ZXj2qfwAK52GFbtOuBQKBgQDJYQuGiY0r22E4waJmCSKczoBT3cwlVzWj
+V2ljgA9RHLNTVkvNNYQLGu2qngFrtwpeaSnsMDerVG4wKAQWyCnYzxVrlnC4uDrJ
+HXuFEltBWi9Ffbgfsnd3749AT0oBP1NT2tMleguyf5DFgjCR3VRJLdrVaaZ8row/
+LqKcFMqnOwKBgB+OIO99l7E584Y3VG6ZdSneOLtNmRXX2pT7tcZE465ZdHGH7Dd3
+SYHhx9K/+Xn+yDH+pLli/xlarAEldmSP6k2WuTfftlC78AfTOfAId5zN7CDR9791
+Fx67I9X/itq33tS8EIuZl57P6uXm/4GXRloWOa8xpvRkVsBApuYPl8t1AoGATQDS
+y2sllDObBXzlgGbV2WgNIgSZ311toTv3jJiXQsjauW8yJRHln+l4H9mzaWDgkiFc
+ang1kUoDqF5k0eFQPxtQcYdhKwEnWWfwp33RbzfxA32DPnubuzzbZhfrkHaKgnIW
+cyor9uFYlm2l7ODZLfJez2RKyTplXnOSsmQw6akCgYAz3dj9Hskyj+HVJ+ht1OcE
+c7ai/ESkSA7Vajp0tjJp0EKjW/zq8DvUSXOtcdnJgkKycFluLwbmnaN4txBds1C1
+Qr8Rt2sUCCBNZe1L6DHe3XBdbkJe9sgZVNTjtUSQrzy8UhvsCqG4YWeCu07Szcbc
+rdPUV9/uQkdx8VrShxlD8A==
+-----END PRIVATE KEY-----
diff --git a/test/keys/server.p12 b/test/keys/server.p12
new file mode 100644
index 0000000000000000000000000000000000000000..f3908a4389be7cbb88edb3f2aba0938fb6767da9
GIT binary patch
literal 2685
zcmY+^c{CJ^8U}DPW~>=AWr$Jsv1_c8t?Z2`WS5fp${wPzd<+^I5!o}6J!_0@Y$aQE
z1}Q|=2-!Y{VU)Oi=iGb0d;fUPd(QKm^ZfZk5jcW@0A>_{<1!1o3=u;--~zA$atRzL
z5P?JPcPxb>fadAlE5Ww{Nb^X%-P=YKR|6Vu+U_n7ZY|(g~7Rx2udLWRE
zDS`kZnLE)}3JB@CjO7QCxK39wy4T}+NR0I7bSjeayxwDHG~gh?VcSMF9=;2S8%r;@
zO^sNFWK`IW>7;D(8#F07#yMxqt?liY+)h}UzkX@2$Kf>}$q5MNT0hz%spVu0#Em>|
z$RdY(^XEG5R0e#xB+{09NAjU_SxWy?YMU@|X#x4o*pw_0UM%#YvfO;!C~R8DD~a-G
z_9VFYu`fNcD2nF=P31|x=ONsr%*3Ew#hxe8o1A`w;m?Cx%b<5j2
z^@+D`D6Cm_lCd^li)^!N=GLFbc#>uFsTz_k30!+mIc89TYT%}?VGm;+t0uNJ;)RitWASDB=i3n$i{`s2R#Iw*SLOt9BqYtZ`j11WqbD`5MM&sWC
zUibzo)+Y6QDvM528`vu-(N+9v(`k0)WTX5`@azER*4y6LzD%udSSR1l?<((mTnlOU
z<*UvEGC&eJ$2P6zQd*R|GcpFQ-G@67Aw{pvzYmtwuld(9V6Xg)3~PwerI|dRp;!uS
zw4>1M^^c60XOea3uC7{`b;3hicx6%ll+9wGn@Gg@kh~{}Wh<^!Uxj^&%%k;6wUM8t
z*RCs-*v0%@FqIar_T2cgou;c=jwZGrh)jE?;!&-x7uZli-rf5jX$
zTN*0xlJQ3Npkx_mR=U3N9n~>L5WXrPNKO!_^252WCu`hqK2gE~S%<|sTi$l2HU#W(
zIA9#MDV1tbw84l?^ttJ?1o}#Md(N_PoD7Y04sqAV1?hY%@AlQu%t(JT?AWyy^8t5$M>dY5-m|DX-`$>h5SSwZz2o$}M={Qg*xl2BVOW8H
za)FN_R<$Slo}BZMn&IXfz5-7Fx??JcG+xkG#iJd0j-;sMff<&MtZ-sH4z0Xy{!F<;
zJH=;6(n-}wzdEd}`Ms71Tf^bl=NM8;?jA7XKD*G9&bv?lxV2GnhatT9rV{9QYL;2#
ztH4l+XkcY&kn#2FHTzsICz2k*@Vg6Nm6ByfDt(cxIg4Yo*_%&8HNU%@XU_|#M{Hla
z*I~vNtF~gMyd$q^D#je_GJ4r!Ms*^3V7nttRHMC4Ug}-3_VLKc5
zMY|R!iY$gt;|@k{M+Yo>UynXu@)JUK(nh-mrb{$w#I`2%htc|Ff|c3F=g|{nv3USy>;5^@rRig
z1gRY=vZ`&R^*Xw0XPCCm2r`-#!pP<~s%)z8LvOWfdRIWN(|uyX$m-5Zi^s43ctIkK
z&2JV5ox;;;n3Sb`=a-IhTpZxzTHLTl8gy_gXb5Nid>HKYst|gpa!TsmJ)Ty$#<$L9
z_aiIrQqdL->%Jof4jTezPw;X(nQy6uWZ3%_+>O+0=|g`gt;!*3!#)_OZGk$00B1Vgku?n55+viH;7daO~PK&v%6Tp6b
z9?F)cGltxKM+g9#PJYA{D6I^*u{5Y$qXG8Vrp9D6Hx8~8%#NjP54ZFJ&JK#d#2`w}
zMuHVsS~3Iz0DK|pWNvBYOGR^wTx&FiitglYLGB!iN5GE@QF4Dcpll`Cd_~exp
zEHL&38;TMrvH$AG4p-y_@o?s)>6;a)n88BN4fQR|-mL1npNvvOiJ;h7z_Ji#pa7T&
m#KTS7SYWuH2#E96A8vLFjF9C#H9%}vgu@^UTswJxEBP;7kMQUK

literal 0
HcmV?d00001

diff --git a/test/keys/server.pem b/test/keys/server.pem
new file mode 100644
index 0000000..c45a9f8
--- /dev/null
+++ b/test/keys/server.pem
@@ -0,0 +1,53 @@
+-----BEGIN CERTIFICATE-----
+MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD
+VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs
+MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV
+BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3
+DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy
+MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU
+MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh
+cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ
+bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ
+GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6
+L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg
+2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw
+AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX
+wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n
+AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME
+GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
+DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5
+U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm
+T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD
+1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I
+p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO
+r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR
+tLQVDSGQGV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCy
+SN8I2Xw6L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/H
+jKNg6ZKg2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQB
+GmZmMIUwAinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xk
+u62LipkXwCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDm
+trhVQF4nAgMBAAECggEAW/y52YYW6ypROGbZ94DQpFV0kLO7qT8q0Ksxw5sPNaIt
+fEPRIymDa8ikyHWJS5Oxmw84wo5jnJV26jaLmwe2Lupq7Xf1lqej8f5LJtuv7cQR
+xfzp1vM65KJFFJHp6WqjGqJ6HSSZOpVDsnQYcXQjQCdpyAmaSWd3p+FqYSZ1mQmD
+bFNI7jqpczWSZhTdotQ7p7Hn9TVCehflP3yGIB3bQ+wCcCB85dOBz201L+YgaIck
+Sz43A4NvWaQIRLRDw7s9GW4jY5T0Jv282WIeAlVpVxLIwu48r4R4yGTIx9Ydowvq
+57+Y5iPPjAXxu0V9t00oS3bYxDaKh2DUfc/5zowq8QKBgQDYNVPXmaG0aIH4vjQ9
+7fRdw/UDkYcQbn6CnglQOu77/S8ogQzpKCVJgJgkZNqOVtQMEPzekGEcLTbje1gU
+8Bky2k+PL9UwbFy0emnOVh4rqrNXHsRvJcehNT/PRb5hjF3MUMFV/0iD4b+naFaE
+jrSWiZ2ZXj2qfwAK52GFbtOuBQKBgQDJYQuGiY0r22E4waJmCSKczoBT3cwlVzWj
+V2ljgA9RHLNTVkvNNYQLGu2qngFrtwpeaSnsMDerVG4wKAQWyCnYzxVrlnC4uDrJ
+HXuFEltBWi9Ffbgfsnd3749AT0oBP1NT2tMleguyf5DFgjCR3VRJLdrVaaZ8row/
+LqKcFMqnOwKBgB+OIO99l7E584Y3VG6ZdSneOLtNmRXX2pT7tcZE465ZdHGH7Dd3
+SYHhx9K/+Xn+yDH+pLli/xlarAEldmSP6k2WuTfftlC78AfTOfAId5zN7CDR9791
+Fx67I9X/itq33tS8EIuZl57P6uXm/4GXRloWOa8xpvRkVsBApuYPl8t1AoGATQDS
+y2sllDObBXzlgGbV2WgNIgSZ311toTv3jJiXQsjauW8yJRHln+l4H9mzaWDgkiFc
+ang1kUoDqF5k0eFQPxtQcYdhKwEnWWfwp33RbzfxA32DPnubuzzbZhfrkHaKgnIW
+cyor9uFYlm2l7ODZLfJez2RKyTplXnOSsmQw6akCgYAz3dj9Hskyj+HVJ+ht1OcE
+c7ai/ESkSA7Vajp0tjJp0EKjW/zq8DvUSXOtcdnJgkKycFluLwbmnaN4txBds1C1
+Qr8Rt2sUCCBNZe1L6DHe3XBdbkJe9sgZVNTjtUSQrzy8UhvsCqG4YWeCu07Szcbc
+rdPUV9/uQkdx8VrShxlD8A==
+-----END PRIVATE KEY-----
diff --git a/test/known_failures_Linux.json b/test/known_failures_Linux.json
new file mode 100644
index 0000000..754535f
--- /dev/null
+++ b/test/known_failures_Linux.json
@@ -0,0 +1,336 @@
+[
+  "c_glib-csharp_multi-binary_buffered-ip",
+  "c_glib-csharp_multi-binary_framed-ip",
+  "c_glib-csharp_multi_buffered-ip",
+  "c_glib-csharp_multi_framed-ip",
+  "c_glib-csharp_multic-compact_buffered-ip",
+  "c_glib-csharp_multic-compact_framed-ip",
+  "c_glib-csharp_multic_buffered-ip",
+  "c_glib-csharp_multic_framed-ip",
+  "c_glib-rs_multi_buffered-ip",
+  "c_glib-rs_multi_framed-ip",
+  "c_glib-rs_multic_buffered-ip",
+  "c_glib-rs_multic_framed-ip",
+  "cpp-cpp_binary_http-domain",
+  "cpp-cpp_compact_http-domain",
+  "cpp-cpp_compact_http-ip",
+  "cpp-cpp_header_http-domain",
+  "cpp-cpp_json_http-domain",
+  "cpp-cpp_json_http-ip",
+  "cpp-cpp_multi-binary_http-domain",
+  "cpp-cpp_multi-binary_http-ip",
+  "cpp-cpp_multi_http-domain",
+  "cpp-cpp_multi_http-ip",
+  "cpp-cpp_multic-compact_http-domain",
+  "cpp-cpp_multic-compact_http-ip",
+  "cpp-cpp_multic_http-domain",
+  "cpp-cpp_multic_http-ip",
+  "cpp-cpp_multih-header_http-domain",
+  "cpp-cpp_multih-header_http-ip",
+  "cpp-cpp_multih_http-domain",
+  "cpp-cpp_multih_http-ip",
+  "cpp-cpp_multij-json_http-domain",
+  "cpp-cpp_multij-json_http-ip",
+  "cpp-cpp_multij_http-domain",
+  "cpp-cpp_multij_http-ip",
+  "cpp-dart_binary_http-ip",
+  "cpp-dart_compact_http-ip",
+  "cpp-dart_json_http-ip",
+  "cpp-dart_multi-binary_http-ip",
+  "cpp-dart_multic-compact_http-ip",
+  "cpp-dart_multij-json_http-ip",
+  "cpp-go_binary_http-ip",
+  "cpp-go_binary_http-ip-ssl",
+  "cpp-go_compact_http-ip",
+  "cpp-go_compact_http-ip-ssl",
+  "cpp-go_json_http-ip",
+  "cpp-go_json_http-ip-ssl",
+  "cpp-go_multi-binary_http-ip",
+  "cpp-go_multi-binary_http-ip-ssl",
+  "cpp-go_multic-compact_http-ip",
+  "cpp-go_multic-compact_http-ip-ssl",
+  "cpp-go_multij-json_http-ip",
+  "cpp-go_multij-json_http-ip-ssl",
+  "cpp-java_binary_http-ip",
+  "cpp-java_binary_http-ip-ssl",
+  "cpp-java_compact_http-ip",
+  "cpp-java_compact_http-ip-ssl",
+  "cpp-java_json_http-ip",
+  "cpp-java_json_http-ip-ssl",
+  "cpp-java_multi-binary_http-ip",
+  "cpp-java_multi-binary_http-ip-ssl",
+  "cpp-java_multi_http-ip",
+  "cpp-java_multi_http-ip-ssl",
+  "cpp-java_multic-compact_http-ip",
+  "cpp-java_multic-compact_http-ip-ssl",
+  "cpp-java_multic_http-ip",
+  "cpp-java_multic_http-ip-ssl",
+  "cpp-java_multij-json_http-ip",
+  "cpp-java_multij-json_http-ip-ssl",
+  "cpp-java_multij_http-ip",
+  "cpp-java_multij_http-ip-ssl",
+  "cpp-nodejs_binary_http-ip",
+  "cpp-nodejs_binary_http-ip-ssl",
+  "cpp-nodejs_compact_http-ip",
+  "cpp-nodejs_compact_http-ip-ssl",
+  "cpp-nodejs_json_http-ip",
+  "cpp-nodejs_json_http-ip-ssl",
+  "cpp-nodejs_multi-binary_http-ip",
+  "cpp-nodejs_multi-binary_http-ip-ssl",
+  "cpp-nodejs_multic-compact_http-ip",
+  "cpp-nodejs_multic-compact_http-ip-ssl",
+  "cpp-nodejs_multij-json_http-ip",
+  "cpp-nodejs_multij-json_http-ip-ssl",
+  "cpp-rs_multi_buffered-ip",
+  "cpp-rs_multi_framed-ip",
+  "cpp-rs_multic_buffered-ip",
+  "cpp-rs_multic_framed-ip",
+  "csharp-d_binary_buffered-ip-ssl",
+  "csharp-d_binary_framed-ip-ssl",
+  "csharp-d_compact_buffered-ip-ssl",
+  "csharp-d_compact_framed-ip-ssl",
+  "csharp-d_json_buffered-ip-ssl",
+  "csharp-d_json_framed-ip-ssl",
+  "csharp-erl_binary_buffered-ip-ssl",
+  "csharp-erl_binary_framed-ip-ssl",
+  "csharp-erl_compact_buffered-ip-ssl",
+  "csharp-erl_compact_framed-ip-ssl",
+  "d-cpp_binary_buffered-ip",
+  "d-cpp_binary_buffered-ip-ssl",
+  "d-cpp_binary_framed-ip",
+  "d-cpp_binary_framed-ip-ssl",
+  "d-cpp_binary_http-ip",
+  "d-cpp_binary_http-ip-ssl",
+  "d-cpp_compact_buffered-ip",
+  "d-cpp_compact_buffered-ip-ssl",
+  "d-cpp_compact_framed-ip",
+  "d-cpp_compact_framed-ip-ssl",
+  "d-cpp_compact_http-ip",
+  "d-cpp_compact_http-ip-ssl",
+  "d-cpp_json_buffered-ip",
+  "d-cpp_json_buffered-ip-ssl",
+  "d-cpp_json_framed-ip",
+  "d-cpp_json_framed-ip-ssl",
+  "d-cpp_json_http-ip",
+  "d-cpp_json_http-ip-ssl",
+  "d-d_binary_http-ip",
+  "d-d_compact_http-ip",
+  "d-d_json_http-ip",
+  "d-dart_binary_framed-ip",
+  "d-dart_binary_http-ip",
+  "d-dart_compact_framed-ip",
+  "d-dart_compact_http-ip",
+  "d-dart_json_framed-ip",
+  "d-dart_json_http-ip",
+  "d-go_binary_http-ip",
+  "d-go_binary_http-ip-ssl",
+  "d-go_compact_http-ip",
+  "d-go_compact_http-ip-ssl",
+  "d-go_json_http-ip",
+  "d-go_json_http-ip-ssl",
+  "d-java_binary_http-ip",
+  "d-java_binary_http-ip-ssl",
+  "d-java_compact_http-ip",
+  "d-java_compact_http-ip-ssl",
+  "d-java_json_http-ip",
+  "d-java_json_http-ip-ssl",
+  "d-js_json_http-ip",
+  "d-lua_json_buffered-ip",
+  "d-lua_json_framed-ip",
+  "d-nodejs_binary_buffered-ip",
+  "d-nodejs_binary_buffered-ip-ssl",
+  "d-nodejs_binary_framed-ip",
+  "d-nodejs_binary_framed-ip-ssl",
+  "d-nodejs_binary_http-ip",
+  "d-nodejs_binary_http-ip-ssl",
+  "d-nodejs_compact_buffered-ip",
+  "d-nodejs_compact_buffered-ip-ssl",
+  "d-nodejs_compact_framed-ip",
+  "d-nodejs_compact_framed-ip-ssl",
+  "d-nodejs_compact_http-ip",
+  "d-nodejs_compact_http-ip-ssl",
+  "d-nodejs_json_buffered-ip",
+  "d-nodejs_json_buffered-ip-ssl",
+  "d-nodejs_json_framed-ip",
+  "d-nodejs_json_framed-ip-ssl",
+  "d-nodejs_json_http-ip",
+  "d-nodejs_json_http-ip-ssl",
+  "d-py3_binary-accel_buffered-ip",
+  "d-py3_binary-accel_buffered-ip-ssl",
+  "d-py3_binary-accel_framed-ip",
+  "d-py3_binary-accel_framed-ip-ssl",
+  "d-py3_binary_buffered-ip",
+  "d-py3_binary_buffered-ip-ssl",
+  "d-py3_binary_framed-ip",
+  "d-py3_binary_framed-ip-ssl",
+  "d-py3_compact-accelc_buffered-ip",
+  "d-py3_compact-accelc_buffered-ip-ssl",
+  "d-py3_compact-accelc_framed-ip",
+  "d-py3_compact-accelc_framed-ip-ssl",
+  "d-py3_compact_buffered-ip",
+  "d-py3_compact_buffered-ip-ssl",
+  "d-py3_compact_framed-ip",
+  "d-py3_compact_framed-ip-ssl",
+  "d-py3_json_buffered-ip",
+  "d-py3_json_buffered-ip-ssl",
+  "d-py3_json_framed-ip",
+  "d-py3_json_framed-ip-ssl",
+  "d-py_binary-accel_buffered-ip",
+  "d-py_binary-accel_buffered-ip-ssl",
+  "d-py_binary-accel_framed-ip",
+  "d-py_binary-accel_framed-ip-ssl",
+  "d-py_binary_buffered-ip",
+  "d-py_binary_buffered-ip-ssl",
+  "d-py_binary_framed-ip",
+  "d-py_binary_framed-ip-ssl",
+  "d-py_compact-accelc_buffered-ip",
+  "d-py_compact-accelc_buffered-ip-ssl",
+  "d-py_compact-accelc_framed-ip",
+  "d-py_compact-accelc_framed-ip-ssl",
+  "d-py_compact_buffered-ip",
+  "d-py_compact_buffered-ip-ssl",
+  "d-py_compact_framed-ip",
+  "d-py_compact_framed-ip-ssl",
+  "d-py_json_buffered-ip",
+  "d-py_json_buffered-ip-ssl",
+  "d-py_json_framed-ip",
+  "d-py_json_framed-ip-ssl",
+  "erl-cpp_binary_buffered-ip",
+  "erl-cpp_compact_buffered-ip",
+  "erl-csharp_binary_buffered-ip",
+  "erl-csharp_compact_buffered-ip",
+  "erl-nodejs_binary_buffered-ip",
+  "erl-nodejs_compact_buffered-ip",
+  "erl-rb_binary-accel_buffered-ip",
+  "erl-rb_binary-accel_framed-ip",
+  "erl-rb_binary_buffered-ip",
+  "erl-rb_binary_framed-ip",
+  "erl-rb_compact_buffered-ip",
+  "erl-rb_compact_framed-ip",
+  "go-cpp_binary_http-ip",
+  "go-cpp_binary_http-ip-ssl",
+  "go-cpp_compact_http-ip",
+  "go-cpp_compact_http-ip-ssl",
+  "go-cpp_json_http-ip",
+  "go-cpp_json_http-ip-ssl",
+  "go-d_binary_http-ip",
+  "go-d_binary_http-ip-ssl",
+  "go-d_compact_http-ip",
+  "go-d_compact_http-ip-ssl",
+  "go-d_json_http-ip",
+  "go-d_json_http-ip-ssl",
+  "go-dart_binary_http-ip",
+  "go-dart_compact_http-ip",
+  "go-dart_json_http-ip",
+  "go-java_binary_http-ip",
+  "go-java_binary_http-ip-ssl",
+  "go-java_compact_http-ip",
+  "go-java_compact_http-ip-ssl",
+  "go-java_json_http-ip",
+  "go-java_json_http-ip-ssl",
+  "go-nodejs_json_framed-ip",
+  "hs-csharp_binary_framed-ip",
+  "hs-csharp_compact_framed-ip",
+  "hs-dart_binary_framed-ip",
+  "hs-dart_compact_framed-ip",
+  "hs-dart_json_framed-ip",
+  "java-d_compact_buffered-ip",
+  "java-d_compact_buffered-ip-ssl",
+  "java-d_compact_framed-ip",
+  "nodejs-cpp_binary_http-ip",
+  "nodejs-cpp_binary_http-ip-ssl",
+  "nodejs-cpp_compact_http-ip",
+  "nodejs-cpp_compact_http-ip-ssl",
+  "nodejs-cpp_json_http-ip",
+  "nodejs-cpp_json_http-ip-ssl",
+  "nodejs-d_binary_buffered-ip",
+  "nodejs-d_binary_buffered-ip-ssl",
+  "nodejs-d_binary_framed-ip",
+  "nodejs-d_binary_framed-ip-ssl",
+  "nodejs-d_binary_http-ip",
+  "nodejs-d_binary_http-ip-ssl",
+  "nodejs-d_compact_buffered-ip",
+  "nodejs-d_compact_buffered-ip-ssl",
+  "nodejs-d_compact_framed-ip",
+  "nodejs-d_compact_framed-ip-ssl",
+  "nodejs-d_compact_http-ip",
+  "nodejs-d_compact_http-ip-ssl",
+  "nodejs-d_json_buffered-ip",
+  "nodejs-d_json_buffered-ip-ssl",
+  "nodejs-d_json_framed-ip",
+  "nodejs-d_json_framed-ip-ssl",
+  "nodejs-d_json_http-ip",
+  "nodejs-d_json_http-ip-ssl",
+  "nodejs-dart_binary_buffered-ip",
+  "nodejs-dart_binary_framed-ip",
+  "nodejs-dart_binary_http-ip",
+  "nodejs-dart_compact_buffered-ip",
+  "nodejs-dart_compact_framed-ip",
+  "nodejs-dart_compact_http-ip",
+  "nodejs-dart_json_buffered-ip",
+  "nodejs-dart_json_framed-ip",
+  "nodejs-dart_json_http-ip",
+  "nodejs-go_binary_http-ip",
+  "nodejs-go_binary_http-ip-ssl",
+  "nodejs-go_compact_http-ip",
+  "nodejs-go_compact_http-ip-ssl",
+  "nodejs-go_json_http-ip",
+  "nodejs-go_json_http-ip-ssl",
+  "nodejs-hs_binary_http-ip",
+  "nodejs-hs_compact_http-ip",
+  "nodejs-hs_json_http-ip",
+  "nodejs-java_binary_http-ip",
+  "nodejs-java_binary_http-ip-ssl",
+  "nodejs-java_compact_http-ip",
+  "nodejs-java_compact_http-ip-ssl",
+  "nodejs-java_json_http-ip",
+  "nodejs-java_json_http-ip-ssl",
+  "nodejs-js_json_http-ip",
+  "nodejs-lua_binary_http-ip",
+  "nodejs-lua_compact_http-ip",
+  "nodejs-lua_json_http-ip",
+  "nodejs-netcore_binary_buffered-ip",
+  "nodejs-netcore_binary_buffered-ip-ssl",
+  "nodejs-netcore_binary_framed-ip",
+  "nodejs-netcore_binary_framed-ip-ssl",
+  "nodejs-netcore_compact_buffered-ip",
+  "nodejs-netcore_compact_buffered-ip-ssl",
+  "nodejs-netcore_compact_framed-ip",
+  "nodejs-netcore_compact_framed-ip-ssl",
+  "nodejs-netcore_json_buffered-ip",
+  "nodejs-netcore_json_buffered-ip-ssl",
+  "nodejs-netcore_json_framed-ip",
+  "nodejs-netcore_json_framed-ip-ssl",
+  "perl-rs_multi_buffered-ip",
+  "perl-rs_multi_framed-ip",
+  "rb-cpp_json_buffered-ip",
+  "rb-cpp_json_framed-ip",
+  "rs-cpp_binary_buffered-ip",
+  "rs-cpp_binary_framed-ip",
+  "rs-cpp_compact_buffered-ip",
+  "rs-cpp_compact_framed-ip",
+  "rs-cpp_multi-binary_buffered-ip",
+  "rs-cpp_multi-binary_framed-ip",
+  "rs-cpp_multi_buffered-ip",
+  "rs-cpp_multi_framed-ip",
+  "rs-cpp_multic-compact_buffered-ip",
+  "rs-cpp_multic-compact_framed-ip",
+  "rs-cpp_multic_buffered-ip",
+  "rs-cpp_multic_framed-ip",
+  "rs-csharp_binary_buffered-ip",
+  "rs-csharp_binary_framed-ip",
+  "rs-csharp_compact_buffered-ip",
+  "rs-csharp_compact_framed-ip",
+  "rs-csharp_multi-binary_buffered-ip",
+  "rs-csharp_multi-binary_framed-ip",
+  "rs-csharp_multi_buffered-ip",
+  "rs-csharp_multi_framed-ip",
+  "rs-csharp_multic-compact_buffered-ip",
+  "rs-csharp_multic-compact_framed-ip",
+  "rs-csharp_multic_buffered-ip",
+  "rs-csharp_multic_framed-ip",
+  "rs-dart_binary_framed-ip",
+  "rs-dart_compact_framed-ip",
+  "rs-dart_multi-binary_framed-ip",
+  "rs-dart_multic-compact_framed-ip"
+]
diff --git a/test/lua/Makefile b/test/lua/Makefile
new file mode 100644
index 0000000..2a438e3
--- /dev/null
+++ b/test/lua/Makefile
@@ -0,0 +1,633 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# test/lua/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/thrift
+pkgincludedir = $(includedir)/thrift
+pkglibdir = $(libdir)/thrift
+pkglibexecdir = $(libexecdir)/thrift
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = test/lua
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15
+ALLOCA = 
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+ANT = /usr/bin/ant
+ANT_FLAGS = 
+AR = ar
+AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf
+AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader
+AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15
+AWK = gawk
+BISON = bison
+BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a
+BOOST_CPPFLAGS = -I/usr/include
+BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a
+BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu
+BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu
+BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a
+BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a
+BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a
+BUNDLER = /usr/bin/bundle
+CABAL = /usr/bin/cabal
+CABAL_CONFIGURE_FLAGS = 
+CARGO = /usr/bin/cargo
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CLASSPATH = 
+CPP = gcc -E
+CPPFLAGS = 
+CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;
+CXX = g++ -std=c++11
+CXXCPP = g++ -E -std=c++11
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DART = /usr/lib/dart/bin/dart
+DARTPUB = /usr/lib/dart/bin/pub
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DMD = dmd
+DMD_LIBEVENT_FLAGS = 
+DMD_OF_DIRSEP = /
+DMD_OPENSSL_FLAGS = 
+DOTNETCORE = /usr/bin/dotnet
+DOTNETCORE_VERSION = 2.0.3
+DSYMUTIL = 
+DUMPBIN = 
+D_EVENT_LIB_NAME = libthriftd-event.a
+D_IMPORT_PREFIX = ${prefix}/include/d2
+D_LIB_NAME = libthriftd.a
+D_SSL_LIB_NAME = libthriftd-ssl.a
+ECHO_C = 
+ECHO_N = -n
+ECHO_T = 
+EGREP = /bin/grep -E
+ENABLE_COVERAGE = 2
+ERL = /usr/bin/erl
+ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib
+ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0
+ERLANG_LIB_DIR = /usr/lib/erlang/lib
+ERLC = /usr/bin/erlc
+ERLCFLAGS = 
+EXEEXT = 
+FGREP = /bin/grep -F
+GCOV_CFLAGS = 
+GCOV_CXXFLAGS = 
+GCOV_LDFLAGS = 
+GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GLIB_LIBS = -lglib-2.0
+GO = /usr/bin/go
+GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0
+GREP = /bin/grep
+HAVE_CXX11 = 1
+HAXE = /usr/bin/haxe
+HAXE_VERSION = 3.2.1
+INSTALL = /usr/bin/install -c
+INSTALLDIRS = vendor
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+JAVA_PREFIX = /usr/local/lib
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS = 
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBEVENT_CPPFLAGS = 
+LIBEVENT_LDFLAGS = 
+LIBEVENT_LIBS = -levent
+LIBOBJS = 
+LIBS = -lrt -lpthread 
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO = 
+LN_S = ln -s
+LTLIBOBJS = 
+LT_SYS_LIBRARY_PATH = 
+LUA = /usr/bin/lua5.3
+LUA_EXEC_PREFIX = ${exec_prefix}
+LUA_INCLUDE = -I/usr/include/lua5.3
+LUA_LIB = -llua5.3  -ldl
+LUA_PLATFORM = unknown
+LUA_PREFIX = ${prefix}
+LUA_SHORT_VERSION = 53
+LUA_VERSION = 5.3
+MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo
+MANIFEST_TOOL = :
+MAYBE_CPP = cpp
+MAYBE_CSHARP = csharp
+MAYBE_C_GLIB = c_glib
+MAYBE_D = 
+MAYBE_DART = dart
+MAYBE_DOTNETCORE = netcore
+MAYBE_ERLANG = erl
+MAYBE_GO = go
+MAYBE_HASKELL = hs
+MAYBE_JAVA = java
+MAYBE_LUA = lua
+MAYBE_NODEJS = nodejs
+MAYBE_PERL = perl
+MAYBE_PHP = php
+MAYBE_PY3 = py3
+MAYBE_PYTHON = py
+MAYBE_RS = rs
+MAYBE_RUBY = rb
+MCS = /usr/bin/mcs
+MKDIR_P = /bin/mkdir -p
+MONO_CFLAGS = 
+MONO_LIBS = 
+NM = /usr/bin/nm -B
+NMEDIT = 
+NODEJS = /usr/bin/nodejs
+NPM = /usr/bin/npm
+OBJDUMP = objdump
+OBJEXT = o
+OPENSSL_INCLUDES = 
+OPENSSL_LDFLAGS = 
+OPENSSL_LIBS = -lssl -lcrypto
+OTOOL = 
+OTOOL64 = 
+PACKAGE = thrift
+PACKAGE_BUGREPORT = 
+PACKAGE_NAME = thrift
+PACKAGE_STRING = thrift 0.11.0
+PACKAGE_TARNAME = thrift
+PACKAGE_URL = 
+PACKAGE_VERSION = 0.11.0
+PATH_SEPARATOR = :
+PERL = /usr/bin/perl
+PERL_PREFIX = /usr/local
+PHP = /usr/bin/php
+PHPUNIT = /usr/bin/phpunit
+PHP_CONFIG = /usr/bin/php-config
+PHP_CONFIG_PREFIX = /etc/php.d
+PHP_PREFIX = /usr/lib/php
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR = 
+PKG_CONFIG_PATH = 
+PYTHON = /usr/bin/python
+PYTHON3 = /usr/bin/python3
+PYTHON_EXEC_PREFIX = ${exec_prefix}
+PYTHON_PLATFORM = linux2
+PYTHON_PREFIX = ${prefix}
+PYTHON_VERSION = 2.7
+PY_PREFIX = /usr
+QT5_CFLAGS = 
+QT5_LIBS = 
+QT5_MOC = 
+QT_CFLAGS = 
+QT_LIBS = 
+QT_MOC = 
+RANLIB = ranlib
+REBAR = /usr/bin/rebar
+RUBY = /usr/bin/ruby
+RUBY_PREFIX = 
+RUNHASKELL = /usr/bin/runhaskell
+RUSTC = /usr/bin/rustc
+SED = /bin/sed
+SET_MAKE = 
+SHELL = /bin/bash
+STRIP = strip
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+TRIAL = /usr/bin/trial
+VERSION = 0.11.0
+YACC = bison -y
+YFLAGS = 
+ZLIB_CPPFLAGS = 
+ZLIB_LDFLAGS = 
+ZLIB_LIBS = -lz
+abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/test/lua
+abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/test/lua
+abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift
+abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+ac_ct_DUMPBIN = 
+am__include = include
+am__leading_dot = .
+am__quote = 
+am__tar = tar --format=ustar -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias = 
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+golang_version = 1.6.2
+have_prog_bison = yes
+host = x86_64-pc-linux-gnu
+host_alias = 
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+luadir = ${prefix}/share/lua/5.3
+luaexecdir = ${exec_prefix}/lib/lua/5.3
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+pkgluadir = ${luadir}/thrift
+pkgluaexecdir = ${luaexecdir}/thrift
+pkgpyexecdir = ${pyexecdir}/thrift
+pkgpythondir = ${pythondir}/thrift
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages
+pythondir = ${prefix}/lib/python2.7/dist-packages
+runstatedir = ${localstatedir}/run
+rustc_version = rustc 1.17.0
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+subdirs =  lib/php/src/ext/thrift_protocol
+sysconfdir = ${prefix}/etc
+target_alias = 
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/lua/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/lua/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	clean-local cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Remove "MapType =" line to ignore some map bug for now
+stubs: ../ThriftTest.thrift $(THRIFT)
+	$(THRIFT) --gen lua $<
+	$(SED) -i.bak 's/MapType =//g' gen-lua/ThriftTest_ttypes.lua
+	$(RM) gen-lua/ThriftTest_ttypes.lua.bak
+
+precross: stubs
+
+clean-local:
+	$(RM) -r gen-lua
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/lua/Makefile.am b/test/lua/Makefile.am
new file mode 100644
index 0000000..ed8c5ae
--- /dev/null
+++ b/test/lua/Makefile.am
@@ -0,0 +1,31 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+# Remove "MapType =" line to ignore some map bug for now
+stubs: ../ThriftTest.thrift $(THRIFT)
+	$(THRIFT) --gen lua $<
+	$(SED) -i.bak 's/MapType =//g' gen-lua/ThriftTest_ttypes.lua
+	$(RM) gen-lua/ThriftTest_ttypes.lua.bak
+
+precross: stubs
+
+clean-local:
+	$(RM) -r gen-lua
diff --git a/test/lua/Makefile.in b/test/lua/Makefile.in
new file mode 100644
index 0000000..5528672
--- /dev/null
+++ b/test/lua/Makefile.in
@@ -0,0 +1,633 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/lua
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/lua/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/lua/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	clean-local cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Remove "MapType =" line to ignore some map bug for now
+stubs: ../ThriftTest.thrift $(THRIFT)
+	$(THRIFT) --gen lua $<
+	$(SED) -i.bak 's/MapType =//g' gen-lua/ThriftTest_ttypes.lua
+	$(RM) gen-lua/ThriftTest_ttypes.lua.bak
+
+precross: stubs
+
+clean-local:
+	$(RM) -r gen-lua
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/lua/test_basic_client.lua b/test/lua/test_basic_client.lua
new file mode 100644
index 0000000..77d8d07
--- /dev/null
+++ b/test/lua/test_basic_client.lua
@@ -0,0 +1,179 @@
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+
+--   http://www.apache.org/licenses/LICENSE-2.0
+
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+
+
+require('TSocket')
+require('TBufferedTransport')
+require('TFramedTransport')
+require('THttpTransport')
+require('TCompactProtocol')
+require('TJsonProtocol')
+require('TBinaryProtocol')
+require('ThriftTest_ThriftTest')
+require('liblualongnumber')
+
+local client
+
+function teardown()
+  if client then
+    -- close the connection
+    client:close()
+  end
+end
+
+function parseArgs(rawArgs)
+  local opt = {
+    protocol='binary',
+    transport='buffered',
+    port='9090',
+  }
+  for i, str in pairs(rawArgs) do
+    if i > 0 then
+      k, v = string.match(str, '--(%w+)=(%w+)')
+      assert(opt[k] ~= nil, 'Unknown argument')
+      opt[k] = v
+    end
+  end
+  return opt
+end
+
+function assertEqual(val1, val2, msg)
+  assert(val1 == val2, msg)
+end
+
+function testBasicClient(rawArgs)
+  local opt = parseArgs(rawArgs)
+  local socket = TSocket:new{
+    port = tonumber(opt.port)
+  }
+  assert(socket, 'Failed to create client socket')
+  socket:setTimeout(5000)
+
+  local transports = {
+    buffered = TBufferedTransport,
+    framed = TFramedTransport,
+    http = THttpTransport,
+  }
+  assert(transports[opt.transport] ~= nil)
+  local transport = transports[opt.transport]:new{
+    trans = socket,
+    isServer = false
+  }
+
+  local protocols = {
+    binary = TBinaryProtocol,
+    compact = TCompactProtocol,
+    json = TJSONProtocol,
+  }
+  assert(protocols[opt.protocol] ~= nil)
+  local protocol = protocols[opt.protocol]:new{
+    trans = transport
+  }
+  assert(protocol, 'Failed to create binary protocol')
+
+  client = ThriftTestClient:new{
+    protocol = protocol
+  }
+  assert(client, 'Failed to create client')
+
+  -- Open the transport
+  local status, _ = pcall(transport.open, transport)
+  assert(status, 'Failed to connect to server')
+
+  -- String
+  assertEqual(client:testString('lala'),  'lala',  'Failed testString')
+  assertEqual(client:testString('wahoo'), 'wahoo', 'Failed testString')
+
+  -- Bool
+  assertEqual(client:testBool(true), true, 'Failed testBool true')
+  assertEqual(client:testBool(false), false, 'Failed testBool false')
+
+  -- Byte
+  assertEqual(client:testByte(0x01), 1,    'Failed testByte 1')
+  assertEqual(client:testByte(0x40), 64,   'Failed testByte 2')
+  assertEqual(client:testByte(0x7f), 127,  'Failed testByte 3')
+  assertEqual(client:testByte(0x80), -128, 'Failed testByte 4')
+  assertEqual(client:testByte(0xbf), -65,  'Failed testByte 5')
+  assertEqual(client:testByte(0xff), -1,   'Failed testByte 6')
+  assertEqual(client:testByte(128), -128,  'Failed testByte 7')
+  assertEqual(client:testByte(255), -1,    'Failed testByte 8')
+
+  -- I32
+  assertEqual(client:testI32(0x00000001), 1,           'Failed testI32 1')
+  assertEqual(client:testI32(0x40000000), 1073741824,  'Failed testI32 2')
+  assertEqual(client:testI32(0x7fffffff), 2147483647,  'Failed testI32 3')
+  assertEqual(client:testI32(0x80000000), -2147483648, 'Failed testI32 4')
+  assertEqual(client:testI32(0xbfffffff), -1073741825, 'Failed testI32 5')
+  assertEqual(client:testI32(0xffffffff), -1,          'Failed testI32 6')
+  assertEqual(client:testI32(2147483648), -2147483648, 'Failed testI32 7')
+  assertEqual(client:testI32(4294967295), -1,          'Failed testI32 8')
+
+  -- I64 (lua only supports 16 decimal precision so larger numbers are
+  -- initialized by their string value)
+  local long = liblualongnumber.new
+  assertEqual(client:testI64(long(0x0000000000000001)),
+                   long(1),
+                   'Failed testI64 1')
+  assertEqual(client:testI64(long(0x4000000000000000)),
+                   long(4611686018427387904),
+                   'Failed testI64 2')
+  assertEqual(client:testI64(long('0x7fffffffffffffff')),
+                   long('9223372036854775807'),
+                   'Failed testI64 3')
+  assertEqual(client:testI64(long(0x8000000000000000)),
+                   long(-9223372036854775808),
+                   'Failed testI64 4')
+  assertEqual(client:testI64(long('0xbfffffffffffffff')),
+                   long('-4611686018427387905'),
+                   'Failed testI64 5')
+  assertEqual(client:testI64(long('0xffffffffffffffff')),
+                   long(-1),
+                   'Failed testI64 6')
+
+  -- Double
+  assertEqual(
+      client:testDouble(1.23456789), 1.23456789, 'Failed testDouble 1')
+  assertEqual(
+      client:testDouble(0.123456789), 0.123456789, 'Failed testDouble 2')
+  assertEqual(
+      client:testDouble(0.123456789), 0.123456789, 'Failed testDouble 3')
+
+  -- TODO testBinary() ...
+	  
+  -- Accuracy of 16 decimal digits (rounds)
+  local a, b = 1.12345678906666663, 1.12345678906666661
+  assertEqual(a, b)
+  assertEqual(client:testDouble(a), b, 'Failed testDouble 5')
+
+  -- Struct
+  local o = Xtruct:new{
+    string_thing = 'Zero',
+    byte_thing = 1,
+    i32_thing = -3,
+    i64_thing = long(-5)
+  }
+  local r = client:testStruct(o)
+  assertEqual(o.string_thing, r.string_thing, 'Failed testStruct 1')
+  assertEqual(o.byte_thing, r.byte_thing, 'Failed testStruct 2')
+  assertEqual(o.i32_thing, r.i32_thing, 'Failed testStruct 3')
+  assertEqual(o.i64_thing, r.i64_thing, 'Failed testStruct 4')
+
+  -- TODO add list map set exception etc etc
+end
+
+testBasicClient(arg)
+teardown()
diff --git a/test/lua/test_basic_server.lua b/test/lua/test_basic_server.lua
new file mode 100644
index 0000000..acd2d79
--- /dev/null
+++ b/test/lua/test_basic_server.lua
@@ -0,0 +1,142 @@
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+
+--   http://www.apache.org/licenses/LICENSE-2.0
+
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+
+require('ThriftTest_ThriftTest')
+require('TSocket')
+require('TBufferedTransport')
+require('TFramedTransport')
+require('THttpTransport')
+require('TCompactProtocol')
+require('TJsonProtocol')
+require('TBinaryProtocol')
+require('TServer')
+require('liblualongnumber')
+
+--------------------------------------------------------------------------------
+-- Handler
+TestHandler = ThriftTestIface:new{}
+
+-- Stops the server
+function TestHandler:testVoid()
+end
+
+function TestHandler:testString(str)
+  return str
+end
+
+function TestHandler:testBool(bool)
+  return bool
+end
+
+function TestHandler:testByte(byte)
+  return byte
+end
+
+function TestHandler:testI32(i32)
+  return i32
+end
+
+function TestHandler:testI64(i64)
+  return i64
+end
+
+function TestHandler:testDouble(d)
+  return d
+end
+
+function TestHandler:testBinary(by)
+  return by
+end
+
+function TestHandler:testStruct(thing)
+  return thing
+end
+
+--------------------------------------------------------------------------------
+-- Test
+local server
+
+function teardown()
+  if server then
+    server:close()
+  end
+end
+
+function parseArgs(rawArgs)
+  local opt = {
+    protocol='binary',
+    transport='buffered',
+    port='9090',
+  }
+  for i, str in pairs(rawArgs) do
+    if i > 0 then
+      k, v = string.match(str, '--(%w+)=(%w+)')
+      assert(opt[k] ~= nil, 'Unknown argument')
+      opt[k] = v
+    end
+  end
+  return opt
+end
+
+function testBasicServer(rawArgs)
+  local opt = parseArgs(rawArgs)
+  -- Handler & Processor
+  local handler = TestHandler:new{}
+  assert(handler, 'Failed to create handler')
+  local processor = ThriftTestProcessor:new{
+    handler = handler
+  }
+  assert(processor, 'Failed to create processor')
+
+  -- Server Socket
+  local socket = TServerSocket:new{
+    port = opt.port
+  }
+  assert(socket, 'Failed to create server socket')
+
+  -- Transport & Factory
+  local transports = {
+    buffered = TBufferedTransportFactory,
+    framed = TFramedTransportFactory,
+    http = THttpTransportFactory,
+  }
+  assert(transports[opt.transport], 'Failed to create framed transport factory')
+  local trans_factory = transports[opt.transport]:new{}
+  local protocols = {
+    binary = TBinaryProtocolFactory,
+    compact = TCompactProtocolFactory,
+    json = TJSONProtocolFactory,
+  }
+  local prot_factory = protocols[opt.protocol]:new{}
+  assert(prot_factory, 'Failed to create binary protocol factory')
+
+  -- Simple Server
+  server = TSimpleServer:new{
+    processor = processor,
+    serverTransport = socket,
+    transportFactory = trans_factory,
+    protocolFactory = prot_factory
+  }
+  assert(server, 'Failed to create server')
+
+  -- Serve
+  server:serve()
+  server = nil
+end
+
+testBasicServer(arg)
+teardown()
diff --git a/test/netcore/Makefile.am b/test/netcore/Makefile.am
new file mode 100644
index 0000000..e029a24
--- /dev/null
+++ b/test/netcore/Makefile.am
@@ -0,0 +1,59 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+SUBDIRS = . 
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+GENDIR = ThriftTest/gen-netcore
+
+THRIFTCODE = \
+			ThriftTest/TestClient.cs \
+			ThriftTest/TestServer.cs \
+			ThriftTest/Properties/AssemblyInfo.cs \
+			ThriftTest/Program.cs 
+
+all-local: \
+	ThriftTest/stage/ThriftTest.dll
+
+ThriftTest/stage/ThriftTest.dll: $(THRIFTCODE)
+	$(MKDIR_P) $(GENDIR)
+	$(THRIFT)  -gen netcore:wcf   -r  -out $(GENDIR)  $(top_srcdir)/test/ThriftTest.thrift
+	$(DOTNETCORE) --info
+	$(DOTNETCORE) restore
+	$(DOTNETCORE) build
+
+precross: \
+	ThriftTest/stage/ThriftTest.dll
+
+clean-local:
+	$(RM) ThriftTest.exe
+	$(RM) -r $(GENDIR)
+	$(RM) -r ThriftTest/bin
+	$(RM) -r ThriftTest/obj
+
+EXTRA_DIST = \
+			 $(THRIFTCODE) \
+			 ThriftTest.sln \
+			 ThriftTest/ThriftTest.csproj \
+			 ThriftTest/Properties/launchSettings.json \
+			 build.cmd \
+			 build.sh \
+			 README.md
+			 
diff --git a/test/netcore/Makefile.in b/test/netcore/Makefile.in
new file mode 100644
index 0000000..8165db4
--- /dev/null
+++ b/test/netcore/Makefile.in
@@ -0,0 +1,839 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/netcore
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	distdir
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = . 
+GENDIR = ThriftTest/gen-netcore
+THRIFTCODE = \
+			ThriftTest/TestClient.cs \
+			ThriftTest/TestServer.cs \
+			ThriftTest/Properties/AssemblyInfo.cs \
+			ThriftTest/Program.cs 
+
+EXTRA_DIST = \
+			 $(THRIFTCODE) \
+			 ThriftTest.sln \
+			 ThriftTest/ThriftTest.csproj \
+			 ThriftTest/Properties/launchSettings.json \
+			 build.cmd \
+			 build.sh \
+			 README.md
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/netcore/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/netcore/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+style-local: 
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-recursive
+all-am: Makefile all-local
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+style: style-recursive
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \
+	check check-am clean clean-generic clean-libtool clean-local \
+	cscopelist-am ctags ctags-am distclean distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs installdirs-am maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+all-local: \
+	ThriftTest/stage/ThriftTest.dll
+
+ThriftTest/stage/ThriftTest.dll: $(THRIFTCODE)
+	$(MKDIR_P) $(GENDIR)
+	$(THRIFT)  -gen netcore:wcf   -r  -out $(GENDIR)  $(top_srcdir)/test/ThriftTest.thrift
+	$(DOTNETCORE) --info
+	$(DOTNETCORE) restore
+	$(DOTNETCORE) build
+
+precross: \
+	ThriftTest/stage/ThriftTest.dll
+
+clean-local:
+	$(RM) ThriftTest.exe
+	$(RM) -r $(GENDIR)
+	$(RM) -r ThriftTest/bin
+	$(RM) -r ThriftTest/obj
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/netcore/README.md b/test/netcore/README.md
new file mode 100644
index 0000000..05eb0e2
--- /dev/null
+++ b/test/netcore/README.md
@@ -0,0 +1,17 @@
+# Apache Thrift net-core-lib tests
+
+Tests for Thrift client library ported to Microsoft .Net Core 
+
+# Content
+- ThriftTest - tests for Thrift library 
+
+# Reused components 
+- NET Core Standard 1.6 (SDK 2.0.0)
+
+# How to build on Windows
+- Open ThriftTest.sln in Visual Studio and build
+
+# How to build on Unix
+- Ensure you have .NET Core 2.0.0 SDK installed or use the Ubuntu Xenial docker image
+- Follow common build practice for Thrift: bootstrap, configure, and make precross
+
diff --git a/test/netcore/ThriftTest.sln b/test/netcore/ThriftTest.sln
new file mode 100644
index 0000000..c3f194b
--- /dev/null
+++ b/test/netcore/ThriftTest.sln
@@ -0,0 +1,50 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26730.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThriftTest", "ThriftTest\ThriftTest.csproj", "{DDED46FF-F359-47B4-BA7E-9B70F216BD44}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift", "..\..\lib\netcore\Thrift\Thrift.csproj", "{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{DDED46FF-F359-47B4-BA7E-9B70F216BD44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DDED46FF-F359-47B4-BA7E-9B70F216BD44}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DDED46FF-F359-47B4-BA7E-9B70F216BD44}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{DDED46FF-F359-47B4-BA7E-9B70F216BD44}.Debug|x64.Build.0 = Debug|Any CPU
+		{DDED46FF-F359-47B4-BA7E-9B70F216BD44}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{DDED46FF-F359-47B4-BA7E-9B70F216BD44}.Debug|x86.Build.0 = Debug|Any CPU
+		{DDED46FF-F359-47B4-BA7E-9B70F216BD44}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DDED46FF-F359-47B4-BA7E-9B70F216BD44}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DDED46FF-F359-47B4-BA7E-9B70F216BD44}.Release|x64.ActiveCfg = Release|Any CPU
+		{DDED46FF-F359-47B4-BA7E-9B70F216BD44}.Release|x64.Build.0 = Release|Any CPU
+		{DDED46FF-F359-47B4-BA7E-9B70F216BD44}.Release|x86.ActiveCfg = Release|Any CPU
+		{DDED46FF-F359-47B4-BA7E-9B70F216BD44}.Release|x86.Build.0 = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x64.Build.0 = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x86.Build.0 = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x64.ActiveCfg = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x64.Build.0 = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x86.ActiveCfg = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {52CE9A12-F6CB-4F0C-BB42-0105612F5FF4}
+	EndGlobalSection
+EndGlobal
diff --git a/test/netcore/ThriftTest/Program.cs b/test/netcore/ThriftTest/Program.cs
new file mode 100644
index 0000000..94ed9d9
--- /dev/null
+++ b/test/netcore/ThriftTest/Program.cs
@@ -0,0 +1,76 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System;
+using System.Collections.Generic;
+using Test;
+
+namespace ThriftTest
+{
+    public class Program
+    {
+        public static int Main(string[] args)
+        {
+            try
+            {
+                Console.SetBufferSize(Console.BufferWidth, 4096);
+            }
+            catch (Exception)
+            {
+                Console.WriteLine("Failed to grow scroll-back buffer");
+            }
+
+            // split mode and options
+            var subArgs = new List(args);
+            var firstArg = string.Empty;
+            if (subArgs.Count > 0)
+            { 
+                firstArg = subArgs[0];
+                subArgs.RemoveAt(0);
+            }
+
+            // run whatever mode is choosen
+            switch(firstArg)
+            {
+                case "client":
+                    return TestClient.Execute(subArgs);
+                case "server":
+                    return TestServer.Execute(subArgs);
+                case "--help":
+                    PrintHelp();
+                    return 0;
+                default:
+                    PrintHelp();
+                    return -1;
+            }
+        }
+
+        private static void PrintHelp()
+        {
+            Console.WriteLine("Usage:");
+            Console.WriteLine("  ThriftTest  server  [options]'");
+            Console.WriteLine("  ThriftTest  client  [options]'");
+            Console.WriteLine("  ThriftTest  --help");
+            Console.WriteLine("");
+
+            TestServer.PrintOptionsHelp();
+            TestClient.PrintOptionsHelp();
+        }
+    }
+}
+
+
diff --git a/test/netcore/ThriftTest/Properties/AssemblyInfo.cs b/test/netcore/ThriftTest/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..efc9e33
--- /dev/null
+++ b/test/netcore/ThriftTest/Properties/AssemblyInfo.cs
@@ -0,0 +1,43 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+
+[assembly: AssemblyTitle("ThriftTest")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+
+[assembly: Guid("B0C13DA0-3117-4844-8AE8-B1775E46223D")]
+
diff --git a/test/netcore/ThriftTest/Properties/launchSettings.json b/test/netcore/ThriftTest/Properties/launchSettings.json
new file mode 100644
index 0000000..ddafa79
--- /dev/null
+++ b/test/netcore/ThriftTest/Properties/launchSettings.json
@@ -0,0 +1,7 @@
+{
+  "profiles": {
+    "ThriftTest": {
+      "commandName": "Project"
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/netcore/ThriftTest/TestClient.cs b/test/netcore/ThriftTest/TestClient.cs
new file mode 100644
index 0000000..f6cc900
--- /dev/null
+++ b/test/netcore/ThriftTest/TestClient.cs
@@ -0,0 +1,898 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Net;
+using System.Reflection;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using ThriftAsync.Test;
+using Thrift.Collections;
+using Thrift.Protocols;
+using Thrift.Transports;
+using Thrift.Transports.Client;
+
+namespace Test
+{
+    public class TestClient
+    {
+        private class TestParams
+        {
+            public int numIterations = 1;
+            public IPAddress host = IPAddress.Loopback;
+            public int port = 9090;
+            public int numThreads = 1;
+            public string url;
+            public string pipe;
+            public bool buffered;
+            public bool framed;
+            public string protocol;
+            public bool encrypted = false;
+
+            internal void Parse( List args)
+            {
+                for (var i = 0; i < args.Count; ++i)
+                {
+                    if (args[i] == "-u")
+                    {
+                        url = args[++i];
+                    }
+                    else if (args[i] == "-n")
+                    {
+                        numIterations = Convert.ToInt32(args[++i]);
+                    }
+                    else if (args[i].StartsWith("--pipe="))
+                    {
+                        pipe = args[i].Substring(args[i].IndexOf("=") + 1);
+                        Console.WriteLine("Using named pipes transport");
+                    }
+                    else if (args[i].StartsWith("--host="))
+                    {
+                        // check there for ipaddress
+                        host = new IPAddress(Encoding.Unicode.GetBytes(args[i].Substring(args[i].IndexOf("=") + 1)));
+                    }
+                    else if (args[i].StartsWith("--port="))
+                    {
+                        port = int.Parse(args[i].Substring(args[i].IndexOf("=") + 1));
+                    }
+                    else if (args[i] == "-b" || args[i] == "--buffered" || args[i] == "--transport=buffered")
+                    {
+                        buffered = true;
+                        Console.WriteLine("Using buffered sockets");
+                    }
+                    else if (args[i] == "-f" || args[i] == "--framed" || args[i] == "--transport=framed")
+                    {
+                        framed = true;
+                        Console.WriteLine("Using framed transport");
+                    }
+                    else if (args[i] == "-t")
+                    {
+                        numThreads = Convert.ToInt32(args[++i]);
+                    }
+                    else if (args[i] == "--binary" || args[i] == "--protocol=binary")
+                    {
+                        protocol = "binary";
+                        Console.WriteLine("Using binary protocol");
+                    }
+                    else if (args[i] == "--compact" || args[i] == "--protocol=compact")
+                    {
+                        protocol = "compact";
+                        Console.WriteLine("Using compact protocol");
+                    }
+                    else if (args[i] == "--json" || args[i] == "--protocol=json")
+                    {
+                        protocol = "json";
+                        Console.WriteLine("Using JSON protocol");
+                    }
+                    else if (args[i] == "--ssl")
+                    {
+                        encrypted = true;
+                        Console.WriteLine("Using encrypted transport");
+                    }
+                    else
+                    {
+                        throw new ArgumentException(args[i]);
+                    }
+                }
+            }
+
+            public TClientTransport CreateTransport()
+            {
+                if (url == null)
+                {
+                    // endpoint transport
+                    TClientTransport trans = null;
+
+                    if (pipe != null)
+                    {
+                        trans = new TNamedPipeClientTransport(pipe);
+                    }
+                    else
+                    {
+                        if (encrypted)
+                        {
+                            var certPath = "../../keys/client.p12";
+                            var cert = new X509Certificate2(certPath, "thrift");
+                            trans = new TTlsSocketClientTransport(host, port, 0, cert, (o, c, chain, errors) => true, null, SslProtocols.Tls);
+                        }
+                        else
+                        {
+                            trans = new TSocketClientTransport(host, port);
+                        }
+                    }
+
+                    // layered transport
+                    if (buffered)
+                    {
+                        trans = new TBufferedClientTransport(trans);
+                    }
+
+                    if (framed)
+                    {
+                        trans = new TFramedClientTransport(trans);
+                    }
+
+                    return trans;
+                }
+
+                return new THttpClientTransport(new Uri(url), null);
+            }
+
+            public TProtocol CreateProtocol(TClientTransport transport)
+            {
+                if (protocol == "compact")
+                {
+                    return new TCompactProtocol(transport);
+                }
+
+                if (protocol == "json")
+                {
+                    return new TJsonProtocol(transport);
+                }
+
+                return new TBinaryProtocol(transport);
+            }
+        }
+
+
+        private const int ErrorBaseTypes = 1;
+        private const int ErrorStructs = 2;
+        private const int ErrorContainers = 4;
+        private const int ErrorExceptions = 8;
+        private const int ErrorUnknown = 64;
+
+        private class ClientTest
+        {
+            private readonly TClientTransport transport;
+            private readonly ThriftAsync.Test.ThriftTest.Client client;
+            private readonly int numIterations;
+            private bool done;
+
+            public int ReturnCode { get; set; }
+
+            public ClientTest(TestParams param)
+            {
+                transport = param.CreateTransport();
+                client = new ThriftAsync.Test.ThriftTest.Client(param.CreateProtocol(transport));
+                numIterations = param.numIterations;
+            }
+
+            public void Execute()
+            {
+                var token = CancellationToken.None;
+
+                if (done)
+                {
+                    Console.WriteLine("Execute called more than once");
+                    throw new InvalidOperationException();
+                }
+
+                for (var i = 0; i < numIterations; i++)
+                {
+                    try
+                    {
+                        if (!transport.IsOpen)
+                        {
+                            transport.OpenAsync(token).GetAwaiter().GetResult();
+                        }
+                    }
+                    catch (TTransportException ex)
+                    {
+                        Console.WriteLine("*** FAILED ***");
+                        Console.WriteLine("Connect failed: " + ex.Message);
+                        ReturnCode |= ErrorUnknown;
+                        Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                        continue;
+                    }
+
+                    try
+                    {
+                        ReturnCode |= ExecuteClientTestAsync(client).GetAwaiter().GetResult(); ;
+                    }
+                    catch (Exception ex)
+                    {
+                        Console.WriteLine("*** FAILED ***");
+                        Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                        ReturnCode |= ErrorUnknown;
+                    }
+                }
+                try
+                {
+                    transport.Close();
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("Error while closing transport");
+                    Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                }
+                done = true;
+            }
+        }
+
+        internal static void PrintOptionsHelp()
+        {
+            Console.WriteLine("Client options:");
+            Console.WriteLine("  -u ");
+            Console.WriteLine("  -t <# of threads to run>        default = 1");
+            Console.WriteLine("  -n <# of iterations>            per thread");
+            Console.WriteLine("  --pipe=");
+            Console.WriteLine("  --host=");
+            Console.WriteLine("  --port=");
+            Console.WriteLine("  --transport=    one of buffered,framed  (defaults to none)");
+            Console.WriteLine("  --protocol=      one of compact,json  (defaults to binary)");
+            Console.WriteLine("  --ssl");
+            Console.WriteLine();
+        }
+
+        public static int Execute(List args)
+        {
+            try
+            {
+                var param = new TestParams();
+
+                try
+                {
+                    param.Parse(args);
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    Console.WriteLine("Error while  parsing arguments");
+                    Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                    return ErrorUnknown;
+                }
+
+                var tests = Enumerable.Range(0, param.numThreads).Select(_ => new ClientTest(param)).ToArray();
+
+                //issue tests on separate threads simultaneously
+                var threads = tests.Select(test => new Thread(test.Execute)).ToArray();
+                var start = DateTime.Now;
+                foreach (var t in threads)
+                {
+                    t.Start();
+                }
+
+                foreach (var t in threads)
+                {
+                    t.Join();
+                }
+
+                Console.WriteLine("Total time: " + (DateTime.Now - start));
+                Console.WriteLine();
+                return tests.Select(t => t.ReturnCode).Aggregate((r1, r2) => r1 | r2);
+            }
+            catch (Exception outerEx)
+            {
+                Console.WriteLine("*** FAILED ***");
+                Console.WriteLine("Unexpected error");
+                Console.WriteLine(outerEx.Message + " ST: " + outerEx.StackTrace);
+                return ErrorUnknown;
+            }
+        }
+
+        public static string BytesToHex(byte[] data)
+        {
+            return BitConverter.ToString(data).Replace("-", string.Empty);
+        }
+
+        public static byte[] PrepareTestData(bool randomDist)
+        {
+            var retval = new byte[0x100];
+            var initLen = Math.Min(0x100, retval.Length);
+
+            // linear distribution, unless random is requested
+            if (!randomDist)
+            {
+                for (var i = 0; i < initLen; ++i)
+                {
+                    retval[i] = (byte)i;
+                }
+                return retval;
+            }
+
+            // random distribution
+            for (var i = 0; i < initLen; ++i)
+            {
+                retval[i] = (byte)0;
+            }
+            var rnd = new Random();
+            for (var i = 1; i < initLen; ++i)
+            {
+                while (true)
+                {
+                    var nextPos = rnd.Next() % initLen;
+                    if (retval[nextPos] == 0)
+                    {
+                        retval[nextPos] = (byte)i;
+                        break;
+                    }
+                }
+            }
+            return retval;
+        }
+
+        public static async Task ExecuteClientTestAsync(ThriftAsync.Test.ThriftTest.Client client)
+        {
+            var token = CancellationToken.None;
+            var returnCode = 0;
+
+            Console.Write("testVoid()");
+            await client.testVoidAsync(token);
+            Console.WriteLine(" = void");
+
+            Console.Write("testString(\"Test\")");
+            var s = await client.testStringAsync("Test", token);
+            Console.WriteLine(" = \"" + s + "\"");
+            if ("Test" != s)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testBool(true)");
+            var t = await client.testBoolAsync((bool)true, token);
+            Console.WriteLine(" = " + t);
+            if (!t)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+            Console.Write("testBool(false)");
+            var f = await client.testBoolAsync((bool)false, token);
+            Console.WriteLine(" = " + f);
+            if (f)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testByte(1)");
+            var i8 = await client.testByteAsync((sbyte)1, token);
+            Console.WriteLine(" = " + i8);
+            if (1 != i8)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testI32(-1)");
+            var i32 = await client.testI32Async(-1, token);
+            Console.WriteLine(" = " + i32);
+            if (-1 != i32)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testI64(-34359738368)");
+            var i64 = await client.testI64Async(-34359738368, token);
+            Console.WriteLine(" = " + i64);
+            if (-34359738368 != i64)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            // TODO: Validate received message
+            Console.Write("testDouble(5.325098235)");
+            var dub = await client.testDoubleAsync(5.325098235, token);
+            Console.WriteLine(" = " + dub);
+            if (5.325098235 != dub)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+            Console.Write("testDouble(-0.000341012439638598279)");
+            dub = await client.testDoubleAsync(-0.000341012439638598279, token);
+            Console.WriteLine(" = " + dub);
+            if (-0.000341012439638598279 != dub)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            var binOut = PrepareTestData(true);
+            Console.Write("testBinary(" + BytesToHex(binOut) + ")");
+            try
+            {
+                var binIn = await client.testBinaryAsync(binOut, token);
+                Console.WriteLine(" = " + BytesToHex(binIn));
+                if (binIn.Length != binOut.Length)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorBaseTypes;
+                }
+                for (var ofs = 0; ofs < Math.Min(binIn.Length, binOut.Length); ++ofs)
+                    if (binIn[ofs] != binOut[ofs])
+                    {
+                        Console.WriteLine("*** FAILED ***");
+                        returnCode |= ErrorBaseTypes;
+                    }
+            }
+            catch (Thrift.TApplicationException ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+
+            // binary equals? only with hashcode option enabled ...
+            Console.WriteLine("Test CrazyNesting");
+            var one = new CrazyNesting();
+            var two = new CrazyNesting();
+            one.String_field = "crazy";
+            two.String_field = "crazy";
+            one.Binary_field = new byte[] { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xFF };
+            two.Binary_field = new byte[10] { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xFF };
+            if (typeof(CrazyNesting).GetMethod("Equals")?.DeclaringType == typeof(CrazyNesting))
+            {
+                if (!one.Equals(two))
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorContainers;
+                    throw new Exception("CrazyNesting.Equals failed");
+                }
+            }
+
+            // TODO: Validate received message
+            Console.Write("testStruct({\"Zero\", 1, -3, -5})");
+            var o = new Xtruct();
+            o.String_thing = "Zero";
+            o.Byte_thing = (sbyte)1;
+            o.I32_thing = -3;
+            o.I64_thing = -5;
+            var i = await client.testStructAsync(o, token);
+            Console.WriteLine(" = {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}");
+
+            // TODO: Validate received message
+            Console.Write("testNest({1, {\"Zero\", 1, -3, -5}, 5})");
+            var o2 = new Xtruct2();
+            o2.Byte_thing = (sbyte)1;
+            o2.Struct_thing = o;
+            o2.I32_thing = 5;
+            var i2 = await client.testNestAsync(o2, token);
+            i = i2.Struct_thing;
+            Console.WriteLine(" = {" + i2.Byte_thing + ", {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}, " + i2.I32_thing + "}");
+
+            var mapout = new Dictionary();
+            for (var j = 0; j < 5; j++)
+            {
+                mapout[j] = j - 10;
+            }
+            Console.Write("testMap({");
+            var first = true;
+            foreach (var key in mapout.Keys)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(key + " => " + mapout[key]);
+            }
+            Console.Write("})");
+
+            var mapin = await client.testMapAsync(mapout, token);
+
+            Console.Write(" = {");
+            first = true;
+            foreach (var key in mapin.Keys)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(key + " => " + mapin[key]);
+            }
+            Console.WriteLine("}");
+
+            // TODO: Validate received message
+            var listout = new List();
+            for (var j = -2; j < 3; j++)
+            {
+                listout.Add(j);
+            }
+            Console.Write("testList({");
+            first = true;
+            foreach (var j in listout)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.Write("})");
+
+            var listin = await client.testListAsync(listout, token);
+
+            Console.Write(" = {");
+            first = true;
+            foreach (var j in listin)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.WriteLine("}");
+
+            //set
+            // TODO: Validate received message
+            var setout = new THashSet();
+            for (var j = -2; j < 3; j++)
+            {
+                setout.Add(j);
+            }
+            Console.Write("testSet({");
+            first = true;
+            foreach (int j in setout)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.Write("})");
+
+            var setin = await client.testSetAsync(setout, token);
+
+            Console.Write(" = {");
+            first = true;
+            foreach (int j in setin)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.WriteLine("}");
+
+
+            Console.Write("testEnum(ONE)");
+            var ret = await client.testEnumAsync(Numberz.ONE, token);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.ONE != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(TWO)");
+            ret = await client.testEnumAsync(Numberz.TWO, token);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.TWO != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(THREE)");
+            ret = await client.testEnumAsync(Numberz.THREE, token);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.THREE != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(FIVE)");
+            ret = await client.testEnumAsync(Numberz.FIVE, token);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.FIVE != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(EIGHT)");
+            ret = await client.testEnumAsync(Numberz.EIGHT, token);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.EIGHT != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testTypedef(309858235082523)");
+            var uid = await client.testTypedefAsync(309858235082523L, token);
+            Console.WriteLine(" = " + uid);
+            if (309858235082523L != uid)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            // TODO: Validate received message
+            Console.Write("testMapMap(1)");
+            var mm = await client.testMapMapAsync(1, token);
+            Console.Write(" = {");
+            foreach (var key in mm.Keys)
+            {
+                Console.Write(key + " => {");
+                var m2 = mm[key];
+                foreach (var k2 in m2.Keys)
+                {
+                    Console.Write(k2 + " => " + m2[k2] + ", ");
+                }
+                Console.Write("}, ");
+            }
+            Console.WriteLine("}");
+
+            // TODO: Validate received message
+            var insane = new Insanity();
+            insane.UserMap = new Dictionary();
+            insane.UserMap[Numberz.FIVE] = 5000L;
+            var truck = new Xtruct();
+            truck.String_thing = "Truck";
+            truck.Byte_thing = (sbyte)8;
+            truck.I32_thing = 8;
+            truck.I64_thing = 8;
+            insane.Xtructs = new List();
+            insane.Xtructs.Add(truck);
+            Console.Write("testInsanity()");
+            var whoa = await client.testInsanityAsync(insane, token);
+            Console.Write(" = {");
+            foreach (var key in whoa.Keys)
+            {
+                var val = whoa[key];
+                Console.Write(key + " => {");
+
+                foreach (var k2 in val.Keys)
+                {
+                    var v2 = val[k2];
+
+                    Console.Write(k2 + " => {");
+                    var userMap = v2.UserMap;
+
+                    Console.Write("{");
+                    if (userMap != null)
+                    {
+                        foreach (var k3 in userMap.Keys)
+                        {
+                            Console.Write(k3 + " => " + userMap[k3] + ", ");
+                        }
+                    }
+                    else
+                    {
+                        Console.Write("null");
+                    }
+                    Console.Write("}, ");
+
+                    var xtructs = v2.Xtructs;
+
+                    Console.Write("{");
+                    if (xtructs != null)
+                    {
+                        foreach (var x in xtructs)
+                        {
+                            Console.Write("{\"" + x.String_thing + "\", " + x.Byte_thing + ", " + x.I32_thing + ", " + x.I32_thing + "}, ");
+                        }
+                    }
+                    else
+                    {
+                        Console.Write("null");
+                    }
+                    Console.Write("}");
+
+                    Console.Write("}, ");
+                }
+                Console.Write("}, ");
+            }
+            Console.WriteLine("}");
+
+            sbyte arg0 = 1;
+            var arg1 = 2;
+            var arg2 = long.MaxValue;
+            var multiDict = new Dictionary();
+            multiDict[1] = "one";
+
+            var tmpMultiDict = new List();
+            foreach (var pair in multiDict)
+                tmpMultiDict.Add(pair.Key +" => "+ pair.Value);
+
+            var arg4 = Numberz.FIVE;
+            long arg5 = 5000000;
+            Console.Write("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + ",{" + string.Join(",", tmpMultiDict) + "}," + arg4 + "," + arg5 + ")");
+            var multiResponse = await client.testMultiAsync(arg0, arg1, arg2, multiDict, arg4, arg5, token);
+            Console.Write(" = Xtruct(byte_thing:" + multiResponse.Byte_thing + ",String_thing:" + multiResponse.String_thing
+                          + ",i32_thing:" + multiResponse.I32_thing + ",i64_thing:" + multiResponse.I64_thing + ")\n");
+
+            try
+            {
+                Console.WriteLine("testException(\"Xception\")");
+                await client.testExceptionAsync("Xception", token);
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Xception ex)
+            {
+                if (ex.ErrorCode != 1001 || ex.Message != "Xception")
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testException(\"TException\")");
+                await client.testExceptionAsync("TException", token);
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Thrift.TException)
+            {
+                // OK
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testException(\"ok\")");
+                await client.testExceptionAsync("ok", token);
+                // OK
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+
+            try
+            {
+                Console.WriteLine("testMultiException(\"Xception\", ...)");
+                await client.testMultiExceptionAsync("Xception", "ignore", token);
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Xception ex)
+            {
+                if (ex.ErrorCode != 1001 || ex.Message != "This is an Xception")
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testMultiException(\"Xception2\", ...)");
+                await client.testMultiExceptionAsync("Xception2", "ignore", token);
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Xception2 ex)
+            {
+                if (ex.ErrorCode != 2002 || ex.Struct_thing.String_thing != "This is an Xception2")
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testMultiException(\"success\", \"OK\")");
+                if ("OK" != (await client.testMultiExceptionAsync("success", "OK", token)).String_thing)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+
+            var sw = new Stopwatch();
+            sw.Start();
+            Console.WriteLine("Test Oneway(1)");
+            await client.testOnewayAsync(1, token);
+            sw.Stop();
+            if (sw.ElapsedMilliseconds > 1000)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("Test Calltime()");
+            var times = 50;
+            sw.Reset();
+            sw.Start();
+            for (var k = 0; k < times; ++k)
+                await client.testVoidAsync(token);
+            sw.Stop();
+            Console.WriteLine(" = {0} ms a testVoid() call", sw.ElapsedMilliseconds / times);
+            return returnCode;
+        }
+    }
+}
diff --git a/test/netcore/ThriftTest/TestServer.cs b/test/netcore/ThriftTest/TestServer.cs
new file mode 100644
index 0000000..aa25c91
--- /dev/null
+++ b/test/netcore/ThriftTest/TestServer.cs
@@ -0,0 +1,560 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System;
+using System.Collections.Generic;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using ThriftAsync.Test;
+using Thrift;
+using Thrift.Collections;
+using Thrift.Protocols;
+using Thrift.Server;
+using Thrift.Transports;
+using Thrift.Transports.Server;
+
+namespace Test
+{
+    internal class ServerParam
+    {
+        internal bool useBufferedSockets = false;
+        internal bool useFramed = false;
+        internal bool useEncryption = false;
+        internal bool compact = false;
+        internal bool json = false;
+        internal int port = 9090;
+        internal string pipe = null;
+
+        internal void Parse(List args)
+        {
+            for (var i = 0; i < args.Count; i++)
+            {
+                if (args[i].StartsWith("--pipe="))
+                {
+                    pipe = args[i].Substring(args[i].IndexOf("=") + 1);
+                }
+                else if (args[i].StartsWith("--port="))
+                {
+                    port = int.Parse(args[i].Substring(args[i].IndexOf("=") + 1));
+                }
+                else if (args[i] == "-b" || args[i] == "--buffered" || args[i] == "--transport=buffered")
+                {
+                    useBufferedSockets = true;
+                }
+                else if (args[i] == "-f" || args[i] == "--framed" || args[i] == "--transport=framed")
+                {
+                    useFramed = true;
+                }
+                else if (args[i] == "--binary" || args[i] == "--protocol=binary")
+                {
+                    // nothing needed
+                }
+                else if (args[i] == "--compact" || args[i] == "--protocol=compact")
+                {
+                    compact = true;
+                }
+                else if (args[i] == "--json" || args[i] == "--protocol=json")
+                {
+                    json = true;
+                }
+                else if (args[i] == "--threaded" || args[i] == "--server-type=threaded")
+                {
+                    throw new NotImplementedException(args[i]);
+                }
+                else if (args[i] == "--threadpool" || args[i] == "--server-type=threadpool")
+                {
+                    throw new NotImplementedException(args[i]);
+                }
+                else if (args[i] == "--prototype" || args[i] == "--processor=prototype")
+                {
+                    throw new NotImplementedException(args[i]);
+                }
+                else if (args[i] == "--ssl")
+                {
+                    useEncryption = true;
+                }
+                else
+                {
+                    throw new ArgumentException(args[i]);
+                }
+            }
+
+        }
+    }
+
+    public class TestServer
+    {
+        public static int _clientID = -1;
+        public delegate void TestLogDelegate(string msg, params object[] values);
+
+        public class MyServerEventHandler : TServerEventHandler
+        {
+            public int callCount = 0;
+
+            public Task PreServeAsync(CancellationToken cancellationToken)
+            {
+                callCount++;
+                return Task.CompletedTask;
+            }
+
+            public Task CreateContextAsync(TProtocol input, TProtocol output, CancellationToken cancellationToken)
+            {
+                callCount++;
+                return Task.FromResult(null);
+            }
+
+            public Task DeleteContextAsync(object serverContext, TProtocol input, TProtocol output, CancellationToken cancellationToken)
+            {
+                callCount++;
+                return Task.CompletedTask;
+            }
+
+            public Task ProcessContextAsync(object serverContext, TClientTransport transport, CancellationToken cancellationToken)
+            {
+                callCount++;
+                return Task.CompletedTask;
+            }
+        };
+
+        public class TestHandlerAsync : ThriftAsync.Test.ThriftTest.IAsync
+        {
+            public TBaseServer server { get; set; }
+            private int handlerID;
+            private StringBuilder sb = new StringBuilder();
+            private TestLogDelegate logger;
+
+            public TestHandlerAsync()
+            {
+                handlerID = Interlocked.Increment(ref _clientID);
+                logger += testConsoleLogger;
+                logger.Invoke("New TestHandler instance created");
+            }
+
+            public void testConsoleLogger(string msg, params object[] values)
+            {
+                sb.Clear();
+                sb.AppendFormat("handler{0:D3}:", handlerID);
+                sb.AppendFormat(msg, values);
+                sb.AppendLine();
+                Console.Write(sb.ToString());
+            }
+
+            public Task testVoidAsync(CancellationToken cancellationToken)
+            {
+                logger.Invoke("testVoid()");
+                return Task.CompletedTask;
+            }
+
+            public Task testStringAsync(string thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testString({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task testBoolAsync(bool thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testBool({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task testByteAsync(sbyte thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testByte({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task testI32Async(int thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testI32({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task testI64Async(long thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testI64({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task testDoubleAsync(double thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testDouble({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task testBinaryAsync(byte[] thing, CancellationToken cancellationToken)
+            {
+                var hex = BitConverter.ToString(thing).Replace("-", string.Empty);
+                logger.Invoke("testBinary({0:X})", hex);
+                return Task.FromResult(thing);
+            }
+
+            public Task testStructAsync(Xtruct thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testStruct({{\"{0}\", {1}, {2}, {3}}})", thing.String_thing, thing.Byte_thing, thing.I32_thing, thing.I64_thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task testNestAsync(Xtruct2 nest, CancellationToken cancellationToken)
+            {
+                var thing = nest.Struct_thing;
+                logger.Invoke("testNest({{{0}, {{\"{1}\", {2}, {3}, {4}, {5}}}}})",
+                    nest.Byte_thing,
+                    thing.String_thing,
+                    thing.Byte_thing,
+                    thing.I32_thing,
+                    thing.I64_thing,
+                    nest.I32_thing);
+                return Task.FromResult(nest);
+            }
+
+            public Task> testMapAsync(Dictionary thing, CancellationToken cancellationToken)
+            {
+                sb.Clear();
+                sb.Append("testMap({{");
+                var first = true;
+                foreach (var key in thing.Keys)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        sb.Append(", ");
+                    }
+                    sb.AppendFormat("{0} => {1}", key, thing[key]);
+                }
+                sb.Append("}})");
+                logger.Invoke(sb.ToString());
+                return Task.FromResult(thing);
+            }
+
+            public Task> testStringMapAsync(Dictionary thing, CancellationToken cancellationToken)
+            {
+                sb.Clear();
+                sb.Append("testStringMap({{");
+                var first = true;
+                foreach (var key in thing.Keys)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        sb.Append(", ");
+                    }
+                    sb.AppendFormat("{0} => {1}", key, thing[key]);
+                }
+                sb.Append("}})");
+                logger.Invoke(sb.ToString());
+                return Task.FromResult(thing);
+            }
+
+            public Task> testSetAsync(THashSet thing, CancellationToken cancellationToken)
+            {
+                sb.Clear();
+                sb.Append("testSet({{");
+                var first = true;
+                foreach (int elem in thing)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        sb.Append(", ");
+                    }
+                    sb.AppendFormat("{0}", elem);
+                }
+                sb.Append("}})");
+                logger.Invoke(sb.ToString());
+                return Task.FromResult(thing);
+            }
+
+            public Task> testListAsync(List thing, CancellationToken cancellationToken)
+            {
+                sb.Clear();
+                sb.Append("testList({{");
+                var first = true;
+                foreach (var elem in thing)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        sb.Append(", ");
+                    }
+                    sb.AppendFormat("{0}", elem);
+                }
+                sb.Append("}})");
+                logger.Invoke(sb.ToString());
+                return Task.FromResult(thing);
+            }
+
+            public Task testEnumAsync(Numberz thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testEnum({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task testTypedefAsync(long thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testTypedef({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task>> testMapMapAsync(int hello, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testMapMap({0})", hello);
+                var mapmap = new Dictionary>();
+
+                var pos = new Dictionary();
+                var neg = new Dictionary();
+                for (var i = 1; i < 5; i++)
+                {
+                    pos[i] = i;
+                    neg[-i] = -i;
+                }
+
+                mapmap[4] = pos;
+                mapmap[-4] = neg;
+
+                return Task.FromResult(mapmap);
+            }
+
+            public Task>> testInsanityAsync(Insanity argument, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testInsanity()");
+
+                /** from ThriftTest.thrift:
+                 * So you think you've got this all worked, out eh?
+                 *
+                 * Creates a the returned map with these values and prints it out:
+                 *   { 1 => { 2 => argument,
+                 *            3 => argument,
+                 *          },
+                 *     2 => { 6 => , },
+                 *   }
+                 * @return map> - a map with the above values
+                 */
+
+                var first_map = new Dictionary();
+                var second_map = new Dictionary(); ;
+
+                first_map[Numberz.TWO] = argument;
+                first_map[Numberz.THREE] = argument;
+
+                second_map[Numberz.SIX] = new Insanity();
+
+                var insane = new Dictionary>
+                {
+                    [1] = first_map,
+                    [2] = second_map
+                };
+
+                return Task.FromResult(insane);
+            }
+
+            public Task testMultiAsync(sbyte arg0, int arg1, long arg2, Dictionary arg3, Numberz arg4, long arg5,
+                CancellationToken cancellationToken)
+            {
+                logger.Invoke("testMulti()");
+
+                var hello = new Xtruct(); ;
+                hello.String_thing = "Hello2";
+                hello.Byte_thing = arg0;
+                hello.I32_thing = arg1;
+                hello.I64_thing = arg2;
+                return Task.FromResult(hello);
+            }
+
+            public Task testExceptionAsync(string arg, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testException({0})", arg);
+                if (arg == "Xception")
+                {
+                    var x = new Xception
+                    {
+                        ErrorCode = 1001,
+                        Message = arg
+                    };
+                    throw x;
+                }
+                if (arg == "TException")
+                {
+                    throw new TException();
+                }
+                return Task.CompletedTask;
+            }
+
+            public Task testMultiExceptionAsync(string arg0, string arg1, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testMultiException({0}, {1})", arg0, arg1);
+                if (arg0 == "Xception")
+                {
+                    var x = new Xception
+                    {
+                        ErrorCode = 1001,
+                        Message = "This is an Xception"
+                    };
+                    throw x;
+                }
+
+                if (arg0 == "Xception2")
+                {
+                    var x = new Xception2
+                    {
+                        ErrorCode = 2002,
+                        Struct_thing = new Xtruct { String_thing = "This is an Xception2" }
+                    };
+                    throw x;
+                }
+
+                var result = new Xtruct { String_thing = arg1 };
+                return Task.FromResult(result);
+            }
+
+            public Task testOnewayAsync(int secondsToSleep, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testOneway({0}), sleeping...", secondsToSleep);
+                Thread.Sleep(secondsToSleep * 1000);
+                logger.Invoke("testOneway finished");
+
+                return Task.CompletedTask;
+            }
+        }
+
+
+        private enum ProcessorFactoryType
+        {
+            TSingletonProcessorFactory,
+            TPrototypeProcessorFactory,
+        }
+
+        internal static void PrintOptionsHelp()
+        {
+            Console.WriteLine("Server options:");
+            Console.WriteLine("  --pipe=");
+            Console.WriteLine("  --port=");
+            Console.WriteLine("  --transport=    one of buffered,framed  (defaults to none)");
+            Console.WriteLine("  --protocol=      one of compact,json  (defaults to binary)");
+            Console.WriteLine("  --server-type=            one of threaded,threadpool  (defaults to simple)");
+            Console.WriteLine("  --processor=");
+            Console.WriteLine("  --ssl");
+            Console.WriteLine();
+        }
+
+        public static int Execute(List args)
+        {
+            var logger = new LoggerFactory().CreateLogger("Test");
+
+            try
+            {
+                var param = new ServerParam();
+
+                try
+                {
+                    param.Parse(args);
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    Console.WriteLine("Error while  parsing arguments");
+                    Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                    return 1;
+                }
+
+
+                // Transport
+                TServerTransport trans;
+                if (param.pipe != null)
+                {
+                    trans = new TNamedPipeServerTransport(param.pipe);
+                }
+                else
+                {
+                    if (param.useEncryption)
+                    {
+                        var certPath = "../../keys/server.p12";
+                        trans = new TTlsServerSocketTransport(param.port, param.useBufferedSockets, new X509Certificate2(certPath, "thrift"), null, null, SslProtocols.Tls);
+                    }
+                    else
+                    {
+                        trans = new TServerSocketTransport(param.port, 0, param.useBufferedSockets);
+                    }
+                }
+
+                ITProtocolFactory proto;
+                if (param.compact)
+                    proto = new TCompactProtocol.Factory();
+                else if (param.json)
+                    proto = new TJsonProtocol.Factory();
+                else
+                    proto = new TBinaryProtocol.Factory();
+
+                ITProcessorFactory processorFactory;
+
+                // Processor
+                var testHandler = new TestHandlerAsync();
+                var testProcessor = new ThriftAsync.Test.ThriftTest.AsyncProcessor(testHandler);
+                processorFactory = new SingletonTProcessorFactory(testProcessor);
+
+
+                TTransportFactory transFactory;
+                if (param.useFramed)
+                    throw new NotImplementedException("framed"); // transFactory = new TFramedTransport.Factory();
+                else
+                    transFactory = new TTransportFactory();
+
+                TBaseServer serverEngine = new AsyncBaseServer(processorFactory, trans, transFactory, transFactory, proto, proto, logger);
+
+                //Server event handler
+                var serverEvents = new MyServerEventHandler();
+                serverEngine.SetEventHandler(serverEvents);
+
+                // Run it
+                var where = (! string.IsNullOrEmpty(param.pipe)) ? "on pipe " + param.pipe : "on port " + param.port;
+                Console.WriteLine("Starting the AsyncBaseServer " + where +
+                                  " with processor TPrototypeProcessorFactory prototype factory " +
+                                  (param.useBufferedSockets ? " with buffered socket" : "") +
+                                  (param.useFramed ? " with framed transport" : "") +
+                                  (param.useEncryption ? " with encryption" : "") +
+                                  (param.compact ? " with compact protocol" : "") +
+                                  (param.json ? " with json protocol" : "") +
+                                  "...");
+                serverEngine.ServeAsync(CancellationToken.None).GetAwaiter().GetResult();
+                Console.ReadLine();
+            }
+            catch (Exception x)
+            {
+                Console.Error.Write(x);
+                return 1;
+            }
+            Console.WriteLine("done.");
+            return 0;
+        }
+    }
+
+}
diff --git a/test/netcore/ThriftTest/ThriftTest.csproj b/test/netcore/ThriftTest/ThriftTest.csproj
new file mode 100644
index 0000000..6647101
--- /dev/null
+++ b/test/netcore/ThriftTest/ThriftTest.csproj
@@ -0,0 +1,27 @@
+
+
+  
+    netcoreapp2.0
+    ThriftTest
+    ThriftTest
+    Exe
+    false
+    false
+    false
+    false
+    false
+    false
+  
+
+  
+    
+    
+    
+    
+  
+
+  
+    
+  
+
+
diff --git a/test/netcore/build.cmd b/test/netcore/build.cmd
new file mode 100644
index 0000000..e971799
--- /dev/null
+++ b/test/netcore/build.cmd
@@ -0,0 +1,30 @@
+@echo off
+rem /*
+rem  * Licensed to the Apache Software Foundation (ASF) under one
+rem  * or more contributor license agreements. See the NOTICE file
+rem  * distributed with this work for additional information
+rem  * regarding copyright ownership. The ASF licenses this file
+rem  * to you under the Apache License, Version 2.0 (the
+rem  * "License"); you may not use this file except in compliance
+rem  * with the License. You may obtain a copy of the License at
+rem  *
+rem  *   http://www.apache.org/licenses/LICENSE-2.0
+rem  *
+rem  * Unless required by applicable law or agreed to in writing,
+rem  * software distributed under the License is distributed on an
+rem  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem  * KIND, either express or implied. See the License for the
+rem  * specific language governing permissions and limitations
+rem  * under the License.
+rem  */
+setlocal
+
+cd Interfaces
+thrift  -gen netcore:wcf   -r  ..\..\tutorial.thrift
+cd ..
+
+dotnet --info
+dotnet restore
+dotnet build
+
+:eof
diff --git a/test/netcore/build.sh b/test/netcore/build.sh
new file mode 100755
index 0000000..626635c
--- /dev/null
+++ b/test/netcore/build.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#exit if any command fails
+set -e
+
+cd ThriftTest
+../../../compiler/cpp/thrift  -gen netcore:wcf   -r  ../../ThriftTest.thrift
+cd ..
+
+dotnet --info
+dotnet restore
+dotnet build
diff --git a/test/ocaml/Makefile b/test/ocaml/Makefile
new file mode 100644
index 0000000..a543ce5
--- /dev/null
+++ b/test/ocaml/Makefile
@@ -0,0 +1,24 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+all:
+	cd client; make; cd ..; cd server; make
+clean:
+	cd client; make clean; cd ..; cd server; make clean
+
diff --git a/test/ocaml/client/Makefile b/test/ocaml/client/Makefile
new file mode 100644
index 0000000..806ed20
--- /dev/null
+++ b/test/ocaml/client/Makefile
@@ -0,0 +1,26 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+SOURCES = ../gen-ocaml/ThriftTest_types.ml ../gen-ocaml/ThriftTest_consts.ml ../gen-ocaml/SecondService.ml ../gen-ocaml/ThriftTest.ml TestClient.ml
+RESULT = tc
+INCDIRS = "../../../lib/ocaml/src/" "../gen-ocaml/"
+LIBS = unix thrift
+all: nc
+OCAMLMAKEFILE = ../../../lib/ocaml/OCamlMakefile
+include $(OCAMLMAKEFILE)
diff --git a/test/ocaml/client/TestClient.ml b/test/ocaml/client/TestClient.ml
new file mode 100644
index 0000000..91783ae
--- /dev/null
+++ b/test/ocaml/client/TestClient.ml
@@ -0,0 +1,82 @@
+(*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*)
+
+open Thrift;;
+open ThriftTest_types;;
+
+let s = new TSocket.t "127.0.0.1" 9090;;
+let p = new TBinaryProtocol.t s;;
+let c = new ThriftTest.client p p;;
+let sod = function
+    Some v -> v
+  | None -> raise Thrift_error;;
+
+s#opn;
+print_string (c#testString "bya");
+print_char '\n';
+print_int (c#testByte 8);
+print_char '\n';
+print_int (c#testByte (-8));
+print_char '\n';
+print_int (c#testI32 32);
+print_char '\n';
+print_string (Int64.to_string (c#testI64 64L));
+print_char '\n';
+print_float (c#testDouble 3.14);
+print_char '\n';
+
+let l = [1;2;3;4] in
+  if l = (c#testList l) then print_string "list ok\n" else print_string "list fail\n";;
+let h = Hashtbl.create 5 in
+let a = Hashtbl.add h in
+  for i=1 to 10 do
+    a i (10*i)
+  done;
+  let r = c#testMap h in
+    for i=1 to 10 do
+      try
+        let g = Hashtbl.find r i in
+          print_int i;
+          print_char ' ';
+          print_int g;
+          print_char '\n'
+      with Not_found -> print_string ("Can't find "^(string_of_int i)^"\n")
+    done;;
+
+let s = Hashtbl.create 5 in
+let a = Hashtbl.add s in
+  for i = 1 to 10 do
+    a i true
+  done;
+  let r = c#testSet s in
+    for i = 1 to 10 do
+      try
+        let g = Hashtbl.find r i in
+          print_int i;
+          print_char '\n'
+      with Not_found -> print_string ("Can't find "^(string_of_int i)^"\n")
+    done;;
+try
+  c#testException "Xception"
+with Xception _ -> print_string "testException ok\n";;
+try
+  ignore(c#testMultiException "Xception" "bya")
+with Xception e -> Printf.printf "%d %s\n" (sod e#get_errorCode) (sod e#get_message);;
+
+
diff --git a/test/ocaml/server/Makefile b/test/ocaml/server/Makefile
new file mode 100644
index 0000000..44dcac7
--- /dev/null
+++ b/test/ocaml/server/Makefile
@@ -0,0 +1,27 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+SOURCES = ../gen-ocaml/ThriftTest_types.ml ../gen-ocaml/ThriftTest_consts.ml ../gen-ocaml/SecondService.ml ../gen-ocaml/ThriftTest.ml TestServer.ml
+RESULT = ts
+INCDIRS = "../../../lib/ocaml/src/" "../gen-ocaml/"
+LIBS = thrift
+THREADS = yes
+all: nc
+OCAMLMAKEFILE = ../../../lib/ocaml/OCamlMakefile
+include $(OCAMLMAKEFILE)
diff --git a/test/ocaml/server/TestServer.ml b/test/ocaml/server/TestServer.ml
new file mode 100644
index 0000000..efe0f4b
--- /dev/null
+++ b/test/ocaml/server/TestServer.ml
@@ -0,0 +1,137 @@
+(*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*)
+
+open Thrift
+open ThriftTest_types
+
+let p = Printf.printf;;
+exception Die;;
+let sod = function
+    Some v -> v
+  | None -> raise Die;;
+
+
+class test_handler =
+object (self)
+  inherit ThriftTest.iface
+  method testVoid = p "testVoid()\n"
+  method testString x = p "testString(%s)\n" (sod x); (sod x)
+  method testByte x = p "testByte(%d)\n" (sod x); (sod x)
+  method testI32 x = p "testI32(%d)\n" (sod x); (sod x)
+  method testI64 x = p "testI64(%s)\n" (Int64.to_string (sod x)); (sod x)
+  method testDouble x = p "testDouble(%f)\n" (sod x); (sod x)
+  method testBinary x = p "testBinary(%s)\n" (sod x); (sod x)
+  method testStruct x = p "testStruct(---)\n"; (sod x)
+  method testNest x = p "testNest(---)\n"; (sod x)
+  method testMap x = p "testMap(---)\n"; (sod x)
+  method testSet x = p "testSet(---)\n"; (sod x)
+  method testList x = p "testList(---)\n"; (sod x)
+  method testEnum x = p "testEnum(---)\n"; (sod x)
+  method testTypedef x = p "testTypedef(---)\n"; (sod x)
+  method testMapMap x = p "testMapMap(%d)\n" (sod x);
+    let mm = Hashtbl.create 3 in
+    let pos = Hashtbl.create 7 in
+    let neg = Hashtbl.create 7 in
+      for i=1 to 4 do
+        Hashtbl.add pos i i;
+        Hashtbl.add neg (-i) (-i);
+      done;
+      Hashtbl.add mm 4 pos;
+      Hashtbl.add mm (-4) neg;
+      mm
+  method testInsanity x = p "testInsanity()\n";
+    p "testinsanity()\n";
+    let hello = new xtruct in
+    let goodbye = new xtruct in
+    let crazy = new insanity in
+    let looney = new insanity in
+    let cumap = Hashtbl.create 7 in
+    let insane = Hashtbl.create 7 in
+    let firstmap = Hashtbl.create 7 in
+    let secondmap = Hashtbl.create 7 in
+      hello#set_string_thing "Hello2";
+      hello#set_byte_thing 2;
+      hello#set_i32_thing 2;
+      hello#set_i64_thing 2L;
+      goodbye#set_string_thing "Goodbye4";
+      goodbye#set_byte_thing 4;
+      goodbye#set_i32_thing 4;
+      goodbye#set_i64_thing 4L;
+      Hashtbl.add cumap Numberz.EIGHT 8L;
+      Hashtbl.add cumap Numberz.FIVE 5L;
+      crazy#set_userMap cumap;
+      crazy#set_xtructs [goodbye; hello];
+      Hashtbl.add firstmap Numberz.TWO crazy;
+      Hashtbl.add firstmap Numberz.THREE crazy;
+      Hashtbl.add secondmap Numberz.SIX looney;
+      Hashtbl.add insane 1L firstmap;
+      Hashtbl.add insane 2L secondmap;
+      insane
+  method testMulti a0 a1 a2 a3 a4 a5 =
+    p "testMulti()\n";
+    let hello = new xtruct in
+      hello#set_string_thing "Hello2";
+      hello#set_byte_thing (sod a0);
+      hello#set_i32_thing (sod a1);
+      hello#set_i64_thing (sod a2);
+      hello
+  method testException s =
+    p "testException(%S)\n" (sod s);
+    if (sod s) = "Xception" then
+      let x = new xception in
+        x#set_errorCode 1001;
+        x#set_message "This is an Xception";
+        raise (Xception x)
+    else ()
+  method testMultiException a0 a1 =
+    p "testMultiException(%S, %S)\n" (sod a0) (sod a1);
+    if (sod a0) = "Xception" then
+      let x = new xception in
+        x#set_errorCode 1001;
+        x#set_message "This is an Xception";
+        raise (Xception x)
+    else (if (sod a0) = "Xception2" then
+              let x = new xception2 in
+              let s = new xtruct in
+                x#set_errorCode 2002;
+                s#set_string_thing "This as an Xception2";
+                x#set_struct_thing s;
+                raise (Xception2 x)
+          else ());
+    let res = new xtruct in
+      res#set_string_thing (sod a1);
+      res
+  method testOneway i =
+    Unix.sleep (sod i)
+end;;
+
+let h = new test_handler in
+let proc = new ThriftTest.processor h in
+let port = 9090 in
+let pf = new TBinaryProtocol.factory in
+let server = new TThreadedServer.t
+  proc
+  (new TServerSocket.t port)
+  (new Transport.factory)
+  pf
+  pf
+in
+  server#serve
+
+
diff --git a/test/perl/Makefile b/test/perl/Makefile
new file mode 100644
index 0000000..f886805
--- /dev/null
+++ b/test/perl/Makefile
@@ -0,0 +1,632 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# test/perl/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/thrift
+pkgincludedir = $(includedir)/thrift
+pkglibdir = $(libdir)/thrift
+pkglibexecdir = $(libexecdir)/thrift
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = test/perl
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15
+ALLOCA = 
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+ANT = /usr/bin/ant
+ANT_FLAGS = 
+AR = ar
+AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf
+AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader
+AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15
+AWK = gawk
+BISON = bison
+BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a
+BOOST_CPPFLAGS = -I/usr/include
+BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a
+BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu
+BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu
+BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a
+BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a
+BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a
+BUNDLER = /usr/bin/bundle
+CABAL = /usr/bin/cabal
+CABAL_CONFIGURE_FLAGS = 
+CARGO = /usr/bin/cargo
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CLASSPATH = 
+CPP = gcc -E
+CPPFLAGS = 
+CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;
+CXX = g++ -std=c++11
+CXXCPP = g++ -E -std=c++11
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DART = /usr/lib/dart/bin/dart
+DARTPUB = /usr/lib/dart/bin/pub
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DMD = dmd
+DMD_LIBEVENT_FLAGS = 
+DMD_OF_DIRSEP = /
+DMD_OPENSSL_FLAGS = 
+DOTNETCORE = /usr/bin/dotnet
+DOTNETCORE_VERSION = 2.0.3
+DSYMUTIL = 
+DUMPBIN = 
+D_EVENT_LIB_NAME = libthriftd-event.a
+D_IMPORT_PREFIX = ${prefix}/include/d2
+D_LIB_NAME = libthriftd.a
+D_SSL_LIB_NAME = libthriftd-ssl.a
+ECHO_C = 
+ECHO_N = -n
+ECHO_T = 
+EGREP = /bin/grep -E
+ENABLE_COVERAGE = 2
+ERL = /usr/bin/erl
+ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib
+ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0
+ERLANG_LIB_DIR = /usr/lib/erlang/lib
+ERLC = /usr/bin/erlc
+ERLCFLAGS = 
+EXEEXT = 
+FGREP = /bin/grep -F
+GCOV_CFLAGS = 
+GCOV_CXXFLAGS = 
+GCOV_LDFLAGS = 
+GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GLIB_LIBS = -lglib-2.0
+GO = /usr/bin/go
+GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0
+GREP = /bin/grep
+HAVE_CXX11 = 1
+HAXE = /usr/bin/haxe
+HAXE_VERSION = 3.2.1
+INSTALL = /usr/bin/install -c
+INSTALLDIRS = vendor
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+JAVA_PREFIX = /usr/local/lib
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS = 
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBEVENT_CPPFLAGS = 
+LIBEVENT_LDFLAGS = 
+LIBEVENT_LIBS = -levent
+LIBOBJS = 
+LIBS = -lrt -lpthread 
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO = 
+LN_S = ln -s
+LTLIBOBJS = 
+LT_SYS_LIBRARY_PATH = 
+LUA = /usr/bin/lua5.3
+LUA_EXEC_PREFIX = ${exec_prefix}
+LUA_INCLUDE = -I/usr/include/lua5.3
+LUA_LIB = -llua5.3  -ldl
+LUA_PLATFORM = unknown
+LUA_PREFIX = ${prefix}
+LUA_SHORT_VERSION = 53
+LUA_VERSION = 5.3
+MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo
+MANIFEST_TOOL = :
+MAYBE_CPP = cpp
+MAYBE_CSHARP = csharp
+MAYBE_C_GLIB = c_glib
+MAYBE_D = 
+MAYBE_DART = dart
+MAYBE_DOTNETCORE = netcore
+MAYBE_ERLANG = erl
+MAYBE_GO = go
+MAYBE_HASKELL = hs
+MAYBE_JAVA = java
+MAYBE_LUA = lua
+MAYBE_NODEJS = nodejs
+MAYBE_PERL = perl
+MAYBE_PHP = php
+MAYBE_PY3 = py3
+MAYBE_PYTHON = py
+MAYBE_RS = rs
+MAYBE_RUBY = rb
+MCS = /usr/bin/mcs
+MKDIR_P = /bin/mkdir -p
+MONO_CFLAGS = 
+MONO_LIBS = 
+NM = /usr/bin/nm -B
+NMEDIT = 
+NODEJS = /usr/bin/nodejs
+NPM = /usr/bin/npm
+OBJDUMP = objdump
+OBJEXT = o
+OPENSSL_INCLUDES = 
+OPENSSL_LDFLAGS = 
+OPENSSL_LIBS = -lssl -lcrypto
+OTOOL = 
+OTOOL64 = 
+PACKAGE = thrift
+PACKAGE_BUGREPORT = 
+PACKAGE_NAME = thrift
+PACKAGE_STRING = thrift 0.11.0
+PACKAGE_TARNAME = thrift
+PACKAGE_URL = 
+PACKAGE_VERSION = 0.11.0
+PATH_SEPARATOR = :
+PERL = /usr/bin/perl
+PERL_PREFIX = /usr/local
+PHP = /usr/bin/php
+PHPUNIT = /usr/bin/phpunit
+PHP_CONFIG = /usr/bin/php-config
+PHP_CONFIG_PREFIX = /etc/php.d
+PHP_PREFIX = /usr/lib/php
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR = 
+PKG_CONFIG_PATH = 
+PYTHON = /usr/bin/python
+PYTHON3 = /usr/bin/python3
+PYTHON_EXEC_PREFIX = ${exec_prefix}
+PYTHON_PLATFORM = linux2
+PYTHON_PREFIX = ${prefix}
+PYTHON_VERSION = 2.7
+PY_PREFIX = /usr
+QT5_CFLAGS = 
+QT5_LIBS = 
+QT5_MOC = 
+QT_CFLAGS = 
+QT_LIBS = 
+QT_MOC = 
+RANLIB = ranlib
+REBAR = /usr/bin/rebar
+RUBY = /usr/bin/ruby
+RUBY_PREFIX = 
+RUNHASKELL = /usr/bin/runhaskell
+RUSTC = /usr/bin/rustc
+SED = /bin/sed
+SET_MAKE = 
+SHELL = /bin/bash
+STRIP = strip
+THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift
+TRIAL = /usr/bin/trial
+VERSION = 0.11.0
+YACC = bison -y
+YFLAGS = 
+ZLIB_CPPFLAGS = 
+ZLIB_LDFLAGS = 
+ZLIB_LIBS = -lz
+abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/test/perl
+abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/test/perl
+abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift
+abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+ac_ct_DUMPBIN = 
+am__include = include
+am__leading_dot = .
+am__quote = 
+am__tar = tar --format=ustar -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias = 
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+golang_version = 1.6.2
+have_prog_bison = yes
+host = x86_64-pc-linux-gnu
+host_alias = 
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+luadir = ${prefix}/share/lua/5.3
+luaexecdir = ${exec_prefix}/lib/lua/5.3
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+pkgluadir = ${luadir}/thrift
+pkgluaexecdir = ${luaexecdir}/thrift
+pkgpyexecdir = ${pyexecdir}/thrift
+pkgpythondir = ${pythondir}/thrift
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages
+pythondir = ${prefix}/lib/python2.7/dist-packages
+runstatedir = ${localstatedir}/run
+rustc_version = rustc 1.17.0
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+subdirs =  lib/php/src/ext/thrift_protocol
+sysconfdir = ${prefix}/etc
+target_alias = 
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/perl/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/perl/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	clean-local cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) --gen perl ../ThriftTest.thrift
+
+precross: stubs
+
+check: stubs
+
+clean-local:
+	$(RM) -r gen-perl
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/perl/Makefile.am b/test/perl/Makefile.am
new file mode 100644
index 0000000..165b9a7
--- /dev/null
+++ b/test/perl/Makefile.am
@@ -0,0 +1,29 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) --gen perl ../ThriftTest.thrift
+
+precross: stubs
+
+check: stubs
+
+clean-local:
+	$(RM) -r gen-perl
+
diff --git a/test/perl/Makefile.in b/test/perl/Makefile.in
new file mode 100644
index 0000000..12fa1c8
--- /dev/null
+++ b/test/perl/Makefile.in
@@ -0,0 +1,632 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/perl
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/perl/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/perl/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	clean-local cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) --gen perl ../ThriftTest.thrift
+
+precross: stubs
+
+check: stubs
+
+clean-local:
+	$(RM) -r gen-perl
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/perl/TestClient.pl b/test/perl/TestClient.pl
new file mode 100755
index 0000000..990274c
--- /dev/null
+++ b/test/perl/TestClient.pl
@@ -0,0 +1,463 @@
+#!/usr/bin/env perl
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+use Data::Dumper;
+use Getopt::Long qw(GetOptions);
+use Time::HiRes qw(gettimeofday);
+
+use lib '../../lib/perl/lib';
+use lib 'gen-perl';
+
+use Thrift;
+use Thrift::BinaryProtocol;
+use Thrift::BufferedTransport;
+use Thrift::FramedTransport;
+use Thrift::MultiplexedProtocol;
+use Thrift::SSLSocket;
+use Thrift::Socket;
+use Thrift::UnixSocket;
+
+use ThriftTest::SecondService;
+use ThriftTest::ThriftTest;
+use ThriftTest::Types;
+
+$|++;
+
+sub usage {
+    print <                       Use a unix domain socket.
+  --help                                       Show usage.
+  --key                                        Certificate key.
+                                               Required if using --ssl.
+  --port                 9090         Port to use.
+  --protocol {binary}             binary       Protocol to use.
+  --ssl                                        If present, use SSL.
+  --transport {buffered|framed}   buffered     Transport to use.
+
+EOF
+}
+
+my %opts = (
+    'port' => 9090,
+    'protocol' => 'binary',
+    'transport' => 'buffered'
+);
+
+GetOptions(\%opts, qw (
+    ca=s
+    cert=s
+    ciphers=s
+    key=s
+    domain-socket=s
+    help
+    host=s
+    port=i
+    protocol=s
+    ssl
+    transport=s
+)) || exit 1;
+
+if ($opts{help}) {
+    usage();
+    exit 0;
+}
+
+my $socket = undef;
+if ($opts{"domain-socket"}) {
+    $socket = new Thrift::UnixSocket($opts{"domain-socket"});
+} elsif ($opts{ssl}) {
+  $socket = new Thrift::SSLSocket(\%opts);
+} else {
+  $socket = new Thrift::Socket($opts{host}, $opts{port});
+}
+
+my $transport;
+if ($opts{transport} eq 'buffered') {
+    $transport = new Thrift::BufferedTransport($socket, 1024, 1024);
+} elsif ($opts{transport} eq 'framed') {
+    $transport = new Thrift::FramedTransport($socket);
+} else {
+    usage();
+    exit 1;
+}
+
+my $protocol;
+my $protocol2;
+if ($opts{protocol} eq 'binary' || $opts{protocol} eq 'multi') {
+    $protocol = new Thrift::BinaryProtocol($transport);
+} else {
+    usage();
+    exit 1;
+}
+
+my $secondService = undef;
+if (index($opts{protocol}, 'multi') == 0) {
+  $protocol2 = new Thrift::MultiplexedProtocol($protocol, "SecondService");
+  $protocol = new Thrift::MultiplexedProtocol($protocol, "ThriftTest");
+  $secondService = new ThriftTest::SecondServiceClient($protocol2);
+}
+
+my $testClient = new ThriftTest::ThriftTestClient($protocol);
+
+eval {
+  $transport->open();
+};
+if($@){
+    die(Dumper($@));
+}
+
+use constant ERR_BASETYPES => 1;
+use constant ERR_STRUCTS => 2;
+use constant ERR_CONTAINERS => 4;
+use constant ERR_EXCEPTIONS => 8;
+use constant ERR_PROTOCOL => 16;
+use constant ERR_UNKNOWN => 64;
+
+my $start = gettimeofday();
+
+#
+# VOID TEST
+#
+print("testVoid()");
+$testClient->testVoid();
+print(" = void\n");
+
+#
+# STRING TEST
+#
+print("testString(\"Test\")");
+my $s = $testClient->testString("Test");
+print(" = \"$s\"\n");
+exit(ERR_BASETYPES) if ($s ne 'Test');
+
+#
+# MULTIPLEXED TEST
+#
+if (index($opts{protocol}, 'multi') == 0) {
+    print("secondtestString(\"Test2\")");
+    $s = $secondService->secondtestString("Test2");
+    print(" = \"$s\"\n");
+    exit(ERR_PROTOCOL) if ($s ne 'testString("Test2")');
+}
+
+#
+# BOOL TEST
+#
+print("testBool(1)");
+my $t = $testClient->testBool(1);
+print(" = $t\n");
+exit(ERR_BASETYPES) if ($t ne 1);
+print("testBool(0)");
+my $f = $testClient->testBool(0);
+print(" = $f\n");
+exit(ERR_BASETYPES) if ($f ne "");
+
+
+#
+# BYTE TEST
+#
+print("testByte(1)");
+my $u8 = $testClient->testByte(1);
+print(" = $u8\n");
+
+#
+# I32 TEST
+#
+print("testI32(-1)");
+my $i32 = $testClient->testI32(-1);
+print(" = $i32\n");
+exit(ERR_BASETYPES) if ($i32 ne -1);
+
+#
+# I64 TEST
+#
+print("testI64(-34359738368)");
+my $i64 = $testClient->testI64(-34359738368);
+print(" = $i64\n");
+exit(ERR_BASETYPES) if ($i64 ne -34359738368);
+
+#
+# DOUBLE TEST
+#
+print("testDouble(-852.234234234)");
+my $dub = $testClient->testDouble(-852.234234234);
+print(" = $dub\n");
+exit(ERR_BASETYPES) if ($dub ne -852.234234234);
+
+#
+# BINARY TEST   ---  TODO
+#
+
+
+#
+# STRUCT TEST
+#
+print("testStruct({\"Zero\", 1, -3, -5})");
+my $out = new ThriftTest::Xtruct();
+$out->string_thing("Zero");
+$out->byte_thing(1);
+$out->i32_thing(-3);
+$out->i64_thing(-5);
+my $in = $testClient->testStruct($out);
+print(" = {\"".$in->string_thing."\", ".
+        $in->byte_thing.", ".
+        $in->i32_thing.", ".
+        $in->i64_thing."}\n");
+
+#
+# NESTED STRUCT TEST
+#
+print("testNest({1, {\"Zero\", 1, -3, -5}, 5}");
+my $out2 = new ThriftTest::Xtruct2();
+$out2->byte_thing(1);
+$out2->struct_thing($out);
+$out2->i32_thing(5);
+my $in2 = $testClient->testNest($out2);
+$in = $in2->struct_thing;
+print(" = {".$in2->byte_thing.", {\"".
+      $in->string_thing."\", ".
+      $in->byte_thing.", ".
+      $in->i32_thing.", ".
+      $in->i64_thing."}, ".
+      $in2->i32_thing."}\n");
+
+#
+# MAP TEST
+#
+my $mapout = {};
+for (my $i = 0; $i < 5; ++$i) {
+  $mapout->{$i} = $i-10;
+}
+print("testMap({");
+my $first = 1;
+while( my($key,$val) = each %$mapout) {
+    if ($first) {
+        $first = 0;
+    } else {
+        print(", ");
+    }
+    print("$key => $val");
+}
+print("})");
+
+
+my $mapin = $testClient->testMap($mapout);
+print(" = {");
+
+$first = 1;
+while( my($key,$val) = each %$mapin){
+    if ($first) {
+        $first = 0;
+    } else {
+        print(", ");
+    }
+    print("$key => $val");
+}
+print("}\n");
+
+#
+# SET TEST
+#
+my $setout = [];
+for (my $i = -2; $i < 3; ++$i) {
+    push(@$setout, $i);
+}
+
+print("testSet({".join(",",@$setout)."})");
+
+my $setin = $testClient->testSet($setout);
+
+print(" = {".join(",",@$setout)."}\n");
+
+#
+# LIST TEST
+#
+my $listout = [];
+for (my $i = -2; $i < 3; ++$i) {
+    push(@$listout, $i);
+}
+
+print("testList({".join(",",@$listout)."})");
+
+my $listin = $testClient->testList($listout);
+
+print(" = {".join(",",@$listin)."}\n");
+
+#
+# ENUM TEST
+#
+print("testEnum(ONE)");
+my $ret = $testClient->testEnum(ThriftTest::Numberz::ONE);
+print(" = $ret\n");
+
+print("testEnum(TWO)");
+$ret = $testClient->testEnum(ThriftTest::Numberz::TWO);
+print(" = $ret\n");
+
+print("testEnum(THREE)");
+$ret = $testClient->testEnum(ThriftTest::Numberz::THREE);
+print(" = $ret\n");
+
+print("testEnum(FIVE)");
+$ret = $testClient->testEnum(ThriftTest::Numberz::FIVE);
+print(" = $ret\n");
+
+print("testEnum(EIGHT)");
+$ret = $testClient->testEnum(ThriftTest::Numberz::EIGHT);
+print(" = $ret\n");
+
+#
+# TYPEDEF TEST
+#
+print("testTypedef(309858235082523)");
+my $uid = $testClient->testTypedef(309858235082523);
+print(" = $uid\n");
+
+#
+# NESTED MAP TEST
+#
+print("testMapMap(1)");
+my $mm = $testClient->testMapMap(1);
+print(" = {");
+while( my ($key,$val) = each %$mm) {
+    print("$key => {");
+    while( my($k2,$v2) = each %$val) {
+        print("$k2 => $v2, ");
+    }
+    print("}, ");
+}
+print("}\n");
+
+#
+# INSANITY TEST
+#
+my $insane = new ThriftTest::Insanity();
+$insane->{userMap}->{ThriftTest::Numberz::FIVE} = 5000;
+my $truck = new ThriftTest::Xtruct();
+$truck->string_thing("Hello2");
+$truck->byte_thing(2);
+$truck->i32_thing(2);
+$truck->i64_thing(2);
+my $truck2 = new ThriftTest::Xtruct();
+$truck2->string_thing("Goodbye4");
+$truck2->byte_thing(4);
+$truck2->i32_thing(4);
+$truck2->i64_thing(4);
+push(@{$insane->{xtructs}}, $truck);
+push(@{$insane->{xtructs}}, $truck2);
+
+print("testInsanity()");
+my $whoa = $testClient->testInsanity($insane);
+print(" = {");
+while( my ($key,$val) = each %$whoa) {
+    print("$key => {");
+    while( my($k2,$v2) = each %$val) {
+        print("$k2 => {");
+        my $userMap = $v2->{userMap};
+        print("{");
+        if (ref($userMap) eq "HASH") {
+            while( my($k3,$v3) = each %$userMap) {
+                print("$k3 => $v3, ");
+            }
+        }
+        print("}, ");
+
+        my $xtructs = $v2->{xtructs};
+        print("{");
+        if (ref($xtructs) eq "ARRAY") {
+            foreach my $x (@$xtructs) {
+                print("{\"".$x->{string_thing}."\", ".
+                      $x->{byte_thing}.", ".$x->{i32_thing}.", ".$x->{i64_thing}."}, ");
+            }
+        }
+        print("}");
+
+        print("}, ");
+    }
+    print("}, ");
+}
+print("}\n");
+
+#
+# EXCEPTION TEST
+#
+print("testException('Xception')");
+eval {
+    $testClient->testException('Xception');
+    print("  void\nFAILURE\n");
+}; if($@ && $@->UNIVERSAL::isa('ThriftTest::Xception')) {
+    print(' caught xception '.$@->{errorCode}.': '.$@->{message}."\n");
+}
+
+
+#
+# Normal tests done.
+#
+my $stop = gettimeofday();
+my $elp  = sprintf("%d",1000*($stop - $start), 0);
+print("Total time: $elp ms\n");
+
+#
+# Extraneous "I don't trust PHP to pack/unpack integer" tests
+#
+
+# Max I32
+my $num = 2**30 + 2**30 - 1;
+my $num2 = $testClient->testI32($num);
+if ($num != $num2) {
+    print "Missed max32 $num = $num2\n";
+}
+
+# Min I32
+$num = 0 - 2**31;
+$num2 = $testClient->testI32($num);
+if ($num != $num2) {
+    print "Missed min32 $num = $num2\n";
+}
+
+# Max Number I can get out of my perl
+$num = 2**40;
+$num2 = $testClient->testI64($num);
+if ($num != $num2) {
+    print "Missed max64 $num = $num2\n";
+}
+
+# Max Number I can get out of my perl
+$num = 0 - 2**40;
+$num2 = $testClient->testI64($num);
+if ($num != $num2) {
+    print "Missed min64 $num = $num2\n";
+}
+
+$transport->close();
+
+
+
diff --git a/test/perl/TestServer.pl b/test/perl/TestServer.pl
new file mode 100644
index 0000000..7d8f929
--- /dev/null
+++ b/test/perl/TestServer.pl
@@ -0,0 +1,430 @@
+#!/usr/bin/env perl
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+use Data::Dumper;
+use Getopt::Long qw(GetOptions);
+use Time::HiRes qw(gettimeofday);
+
+use lib '../../lib/perl/lib';
+use lib 'gen-perl';
+
+use Thrift;
+use Thrift::BinaryProtocol;
+use Thrift::BufferedTransport;
+use Thrift::FramedTransport;
+use Thrift::MultiplexedProcessor;
+use Thrift::SSLServerSocket;
+use Thrift::ServerSocket;
+use Thrift::Server;
+use Thrift::UnixServerSocket;
+
+use ThriftTest::SecondService;
+use ThriftTest::ThriftTest;
+use ThriftTest::Types;
+
+$|++;
+
+sub usage {
+    print <                       Use a unix domain socket.
+  --help                                       Show usage.
+  --key                                        Private key file for certificate.
+                                               Required if using --ssl and private key is
+                                               not in the certificate file.
+  --port                 9090         Port to use.
+  --protocol {binary}             binary       Protocol to use.
+  --ssl                                        If present, use SSL/TLS.
+  --transport {buffered|framed}   buffered     Transport to use.
+
+EOF
+}
+
+my %opts = (
+    'port' => 9090,
+    'protocol' => 'binary',
+    'transport' => 'buffered'
+);
+
+GetOptions(\%opts, qw (
+    ca=s
+    cert=s
+    ciphers=s
+    domain-socket=s
+    help
+    host=s
+    key=s
+    port=i
+    protocol=s
+    ssl
+    transport=s
+)) || exit 1;
+
+if ($opts{help}) {
+    usage();
+    exit 0;
+}
+
+if ($opts{ssl} and not defined $opts{cert}) {
+    usage();
+    exit 1;
+}
+
+my $handler = new ThriftTestHandler();
+my $handler2 = new SecondServiceHandler();
+my $processor = new ThriftTest::ThriftTestProcessor($handler);
+my $processor2 = new ThriftTest::SecondServiceProcessor($handler2);
+my $serversocket;
+if ($opts{"domain-socket"}) {
+    unlink($opts{"domain-socket"});
+    $serversocket = new Thrift::UnixServerSocket($opts{"domain-socket"});
+} elsif ($opts{ssl}) {
+    $serversocket = new Thrift::SSLServerSocket(\%opts);
+} else {
+    $serversocket = new Thrift::ServerSocket(\%opts);
+}
+my $transport;
+if ($opts{transport} eq 'buffered') {
+    $transport = new Thrift::BufferedTransportFactory();
+} elsif ($opts{transport} eq 'framed') {
+    $transport = new Thrift::FramedTransportFactory();
+} else {
+    usage();
+    exit 1;
+}
+my $protocol;
+if ($opts{protocol} eq 'binary' || $opts{protocol} eq 'multi') {
+    $protocol = new Thrift::BinaryProtocolFactory();
+} else {
+    usage();
+    exit 1;
+}
+
+if (index($opts{protocol}, 'multi') == 0) {
+  my $newProcessor = new Thrift::MultiplexedProcessor($protocol);
+  $newProcessor->defaultProcessor($processor);
+  $newProcessor->registerProcessor("ThriftTest", $processor);
+  $newProcessor->registerProcessor("SecondService", $processor2);
+  $processor = $newProcessor;
+}
+
+my $ssltag = '';
+if ($opts{ssl}) {
+    $ssltag = "(SSL)";
+}
+my $listening_on = "$opts{port} $ssltag";
+if ($opts{"domain-socket"}) {
+    $listening_on = $opts{"domain-socket"};
+}
+my $server = new Thrift::SimpleServer($processor, $serversocket, $transport, $protocol);
+print "Starting \"simple\" server ($opts{transport}/$opts{protocol}) listen on: $listening_on\n";
+$server->serve();
+
+###
+### Test server implementation
+###
+
+package ThriftTestHandler;
+
+use base qw( ThriftTest::ThriftTestIf );
+
+sub new {
+    my $classname = shift;
+    my $self = {};
+    return bless($self, $classname);
+}
+
+sub testVoid() {
+  print("testVoid()\n");
+}
+
+sub testString() {
+  my $self = shift;
+  my $thing = shift;
+  print("testString($thing)\n");
+  return $thing;
+}
+
+sub testBool() {
+  my $self = shift;
+  my $thing = shift;
+  my $str = $thing ? "true" : "false";
+  print("testBool($str)\n");
+  return $thing;
+}
+
+sub testByte() {
+  my $self = shift;
+  my $thing = shift;
+  print("testByte($thing)\n");
+  return $thing;
+}
+
+sub testI32() {
+  my $self = shift;
+  my $thing = shift;
+  print("testI32($thing)\n");
+  return $thing;
+}
+
+sub testI64() {
+  my $self = shift;
+  my $thing = shift;
+  print("testI64($thing)\n");
+  return $thing;
+}
+
+sub testDouble() {
+  my $self = shift;
+  my $thing = shift;
+  print("testDouble($thing)\n");
+  return $thing;
+}
+
+sub testBinary() {
+    my $self = shift;
+    my $thing = shift;
+    my @bytes = split //, $thing;
+    print("testBinary(");
+    foreach (@bytes)
+    {
+        printf "%02lx", ord $_;
+    }
+    print(")\n");
+    return $thing;
+}
+
+sub testStruct() {
+  my $self = shift;
+  my $thing = shift;
+  printf("testStruct({\"%s\", %d, %d, %lld})\n",
+           $thing->{string_thing},
+           $thing->{byte_thing},
+           $thing->{i32_thing},
+           $thing->{i64_thing});
+  return $thing;
+}
+
+sub testNest() {
+  my $self = shift;
+  my $nest = shift;
+  my $thing = $nest->{struct_thing};
+  printf("testNest({%d, {\"%s\", %d, %d, %lld}, %d})\n",
+           $nest->{byte_thing},
+           $thing->{string_thing},
+           $thing->{byte_thing},
+           $thing->{i32_thing},
+           $thing->{i64_thing},
+           $nest->{i32_thing});
+  return $nest;
+}
+
+sub testMap() {
+  my $self = shift;
+  my $thing = shift;
+  print("testMap({");
+  my $first = 1;
+  foreach my $key (keys %$thing) {
+    if ($first) {
+        $first = 0;
+    } else {
+        print(", ");
+    }
+    print("$key => $thing->{$key}");
+  }
+  print("})\n");
+  return $thing;
+}
+
+sub testStringMap() {
+  my $self = shift;
+  my $thing = shift;
+  print("testStringMap({");
+  my $first = 1;
+  foreach my $key (keys %$thing) {
+    if ($first) {
+        $first = 0;
+    } else {
+        print(", ");
+    }
+    print("$key => $thing->{$key}");
+  }
+  print("})\n");
+  return $thing;
+}
+
+sub testSet() {
+  my $self = shift;
+  my $thing = shift;
+  my @arr;
+  my $result = \@arr;
+  print("testSet({");
+  my $first = 1;
+  foreach my $key (keys %$thing) {
+    if ($first) {
+        $first = 0;
+    } else {
+        print(", ");
+    }
+    print("$key");
+    push(@arr, $key);
+  }
+  print("})\n");
+  return $result;
+}
+
+sub testList() {
+  my $self = shift;
+  my $thing = shift;
+  print("testList({");
+  my $first = 1;
+  foreach my $key (@$thing) {
+    if ($first) {
+        $first = 0;
+    } else {
+        print(", ");
+    }
+    print("$key");
+  }
+  print("})\n");
+  return $thing;
+}
+
+sub testEnum() {
+  my $self = shift;
+  my $thing = shift;
+  print("testEnum($thing)\n");
+  return $thing;
+}
+
+sub testTypedef() {
+  my $self = shift;
+  my $thing = shift;
+  print("testTypedef($thing)\n");
+  return $thing;
+}
+
+sub testMapMap() {
+  my $self = shift;
+  my $hello = shift;
+
+  printf("testMapMap(%d)\n", $hello);
+  my $result = { 4 => { 1 => 1, 2 => 2, 3 => 3, 4 => 4 }, -4 => { -1 => -1, -2 => -2, -3 => -3, -4 => -4 } };
+  return $result;
+}
+
+sub testInsanity() {
+  my $self = shift;
+  my $argument = shift;
+  print("testInsanity()\n");
+
+  my $hello = new ThriftTest::Xtruct({string_thing => "Hello2", byte_thing => 2, i32_thing => 2, i64_thing => 2});
+  my @hellos;
+  push(@hellos, $hello);
+  my $goodbye = new ThriftTest::Xtruct({string_thing => "Goodbye4", byte_thing => 4, i32_thing => 4, i64_thing => 4});
+  my @goodbyes;
+  push(@goodbyes, $goodbye);
+  my $crazy = new ThriftTest::Insanity({userMap => { ThriftTest::Numberz::EIGHT => 8 }, xtructs => \@goodbyes});
+  my $loony = new ThriftTest::Insanity();
+  my $result = { 1 => { ThriftTest::Numberz::TWO => $argument, ThriftTest::Numberz::THREE => $argument },
+                 2 => { ThriftTest::Numberz::SIX => $loony } };
+  return $result;
+}
+
+sub testMulti() {
+  my $self = shift;
+  my $arg0 = shift;
+  my $arg1 = shift;
+  my $arg2 = shift;
+  my $arg3 = shift;
+  my $arg4 = shift;
+  my $arg5 = shift;
+
+  print("testMulti()\n");
+  return new ThriftTest::Xtruct({string_thing => "Hello2", byte_thing => $arg0, i32_thing => $arg1, i64_thing => $arg2});
+}
+
+sub testException() {
+  my $self = shift;
+  my $arg = shift;
+  print("testException($arg)\n");
+  if ($arg eq "Xception") {
+    die new ThriftTest::Xception({errorCode => 1001, message => $arg});
+  } elsif ($arg eq "TException") {
+    die "astring"; # all unhandled exceptions become TExceptions
+  } else {
+    return new ThriftTest::Xtruct({string_thing => $arg});
+  }
+}
+
+sub testMultiException() {
+  my $self = shift;
+  my $arg0 = shift;
+  my $arg1 = shift;
+
+  printf("testMultiException(%s, %s)\n", $arg0, $arg1);
+  if ($arg0 eq "Xception") {
+    die new ThriftTest::Xception({errorCode => 1001, message => "This is an Xception"});
+  } elsif ($arg0 eq "Xception2") {
+    my $struct_thing = new ThriftTest::Xtruct({string_thing => "This is an Xception2"});
+    die new ThriftTest::Xception2({errorCode => 2002, struct_thing => $struct_thing});
+  } else {
+    return new ThriftTest::Xtruct({string_thing => $arg1});
+  }
+}
+
+sub testOneway() {
+  my $self = shift;
+  my $num = shift;
+  print("testOneway($num): received\n");
+}
+
+###
+### Test server implementation
+###
+
+package SecondServiceHandler;
+
+use base qw( ThriftTest::SecondServiceIf );
+
+sub new {
+    my $classname = shift;
+    my $self = {};
+    return bless($self, $classname);
+}
+
+sub secondtestString() {
+  my $self = shift;
+  my $thing = shift;
+  print("testString($thing)\n");
+  return "testString(\"" . $thing . "\")";
+}
+
+1;
diff --git a/test/php/Makefile b/test/php/Makefile
new file mode 100644
index 0000000..ae07396
--- /dev/null
+++ b/test/php/Makefile
@@ -0,0 +1,643 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# test/php/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/thrift
+pkgincludedir = $(includedir)/thrift
+pkglibdir = $(libdir)/thrift
+pkglibexecdir = $(libexecdir)/thrift
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = test/php
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15
+ALLOCA = 
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+ANT = /usr/bin/ant
+ANT_FLAGS = 
+AR = ar
+AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf
+AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader
+AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15
+AWK = gawk
+BISON = bison
+BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a
+BOOST_CPPFLAGS = -I/usr/include
+BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a
+BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu
+BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu
+BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a
+BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a
+BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a
+BUNDLER = /usr/bin/bundle
+CABAL = /usr/bin/cabal
+CABAL_CONFIGURE_FLAGS = 
+CARGO = /usr/bin/cargo
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CLASSPATH = 
+CPP = gcc -E
+CPPFLAGS = 
+CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;
+CXX = g++ -std=c++11
+CXXCPP = g++ -E -std=c++11
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DART = /usr/lib/dart/bin/dart
+DARTPUB = /usr/lib/dart/bin/pub
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DMD = dmd
+DMD_LIBEVENT_FLAGS = 
+DMD_OF_DIRSEP = /
+DMD_OPENSSL_FLAGS = 
+DOTNETCORE = /usr/bin/dotnet
+DOTNETCORE_VERSION = 2.0.3
+DSYMUTIL = 
+DUMPBIN = 
+D_EVENT_LIB_NAME = libthriftd-event.a
+D_IMPORT_PREFIX = ${prefix}/include/d2
+D_LIB_NAME = libthriftd.a
+D_SSL_LIB_NAME = libthriftd-ssl.a
+ECHO_C = 
+ECHO_N = -n
+ECHO_T = 
+EGREP = /bin/grep -E
+ENABLE_COVERAGE = 2
+ERL = /usr/bin/erl
+ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib
+ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0
+ERLANG_LIB_DIR = /usr/lib/erlang/lib
+ERLC = /usr/bin/erlc
+ERLCFLAGS = 
+EXEEXT = 
+FGREP = /bin/grep -F
+GCOV_CFLAGS = 
+GCOV_CXXFLAGS = 
+GCOV_LDFLAGS = 
+GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GLIB_LIBS = -lglib-2.0
+GO = /usr/bin/go
+GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0
+GREP = /bin/grep
+HAVE_CXX11 = 1
+HAXE = /usr/bin/haxe
+HAXE_VERSION = 3.2.1
+INSTALL = /usr/bin/install -c
+INSTALLDIRS = vendor
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+JAVA_PREFIX = /usr/local/lib
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS = 
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBEVENT_CPPFLAGS = 
+LIBEVENT_LDFLAGS = 
+LIBEVENT_LIBS = -levent
+LIBOBJS = 
+LIBS = -lrt -lpthread 
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO = 
+LN_S = ln -s
+LTLIBOBJS = 
+LT_SYS_LIBRARY_PATH = 
+LUA = /usr/bin/lua5.3
+LUA_EXEC_PREFIX = ${exec_prefix}
+LUA_INCLUDE = -I/usr/include/lua5.3
+LUA_LIB = -llua5.3  -ldl
+LUA_PLATFORM = unknown
+LUA_PREFIX = ${prefix}
+LUA_SHORT_VERSION = 53
+LUA_VERSION = 5.3
+MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo
+MANIFEST_TOOL = :
+MAYBE_CPP = cpp
+MAYBE_CSHARP = csharp
+MAYBE_C_GLIB = c_glib
+MAYBE_D = 
+MAYBE_DART = dart
+MAYBE_DOTNETCORE = netcore
+MAYBE_ERLANG = erl
+MAYBE_GO = go
+MAYBE_HASKELL = hs
+MAYBE_JAVA = java
+MAYBE_LUA = lua
+MAYBE_NODEJS = nodejs
+MAYBE_PERL = perl
+MAYBE_PHP = php
+MAYBE_PY3 = py3
+MAYBE_PYTHON = py
+MAYBE_RS = rs
+MAYBE_RUBY = rb
+MCS = /usr/bin/mcs
+MKDIR_P = /bin/mkdir -p
+MONO_CFLAGS = 
+MONO_LIBS = 
+NM = /usr/bin/nm -B
+NMEDIT = 
+NODEJS = /usr/bin/nodejs
+NPM = /usr/bin/npm
+OBJDUMP = objdump
+OBJEXT = o
+OPENSSL_INCLUDES = 
+OPENSSL_LDFLAGS = 
+OPENSSL_LIBS = -lssl -lcrypto
+OTOOL = 
+OTOOL64 = 
+PACKAGE = thrift
+PACKAGE_BUGREPORT = 
+PACKAGE_NAME = thrift
+PACKAGE_STRING = thrift 0.11.0
+PACKAGE_TARNAME = thrift
+PACKAGE_URL = 
+PACKAGE_VERSION = 0.11.0
+PATH_SEPARATOR = :
+PERL = /usr/bin/perl
+PERL_PREFIX = /usr/local
+PHP = /usr/bin/php
+PHPUNIT = /usr/bin/phpunit
+PHP_CONFIG = /usr/bin/php-config
+PHP_CONFIG_PREFIX = /etc/php.d
+PHP_PREFIX = /usr/lib/php
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR = 
+PKG_CONFIG_PATH = 
+PYTHON = /usr/bin/python
+PYTHON3 = /usr/bin/python3
+PYTHON_EXEC_PREFIX = ${exec_prefix}
+PYTHON_PLATFORM = linux2
+PYTHON_PREFIX = ${prefix}
+PYTHON_VERSION = 2.7
+PY_PREFIX = /usr
+QT5_CFLAGS = 
+QT5_LIBS = 
+QT5_MOC = 
+QT_CFLAGS = 
+QT_LIBS = 
+QT_MOC = 
+RANLIB = ranlib
+REBAR = /usr/bin/rebar
+RUBY = /usr/bin/ruby
+RUBY_PREFIX = 
+RUNHASKELL = /usr/bin/runhaskell
+RUSTC = /usr/bin/rustc
+SED = /bin/sed
+SET_MAKE = 
+SHELL = /bin/bash
+STRIP = strip
+THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift
+TRIAL = /usr/bin/trial
+VERSION = 0.11.0
+YACC = bison -y
+YFLAGS = 
+ZLIB_CPPFLAGS = 
+ZLIB_LDFLAGS = 
+ZLIB_LIBS = -lz
+abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/test/php
+abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/test/php
+abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift
+abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+ac_ct_DUMPBIN = 
+am__include = include
+am__leading_dot = .
+am__quote = 
+am__tar = tar --format=ustar -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias = 
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+golang_version = 1.6.2
+have_prog_bison = yes
+host = x86_64-pc-linux-gnu
+host_alias = 
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+luadir = ${prefix}/share/lua/5.3
+luaexecdir = ${exec_prefix}/lib/lua/5.3
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+pkgluadir = ${luadir}/thrift
+pkgluaexecdir = ${luaexecdir}/thrift
+pkgpyexecdir = ${pyexecdir}/thrift
+pkgpythondir = ${pythondir}/thrift
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages
+pythondir = ${prefix}/lib/python2.7/dist-packages
+runstatedir = ${localstatedir}/run
+rustc_version = rustc 1.17.0
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+subdirs =  lib/php/src/ext/thrift_protocol
+sysconfdir = ${prefix}/etc
+target_alias = 
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/php/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/php/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	clean-local cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) --gen php ../ThriftTest.thrift
+	$(THRIFT) --gen php:inlined ../ThriftTest.thrift
+	$(MKDIR_P) gen-php-psr4
+	$(THRIFT) -out gen-php-psr4 --gen php:psr4 ../ThriftTest.thrift
+
+php_ext_dir:
+	mkdir -p php_ext_dir
+	ln -s ../../../lib/php/src/ext/thrift_protocol/modules/thrift_protocol.so php_ext_dir/
+	ln -s "$$(php-config --extension-dir)/sockets.so" php_ext_dir/
+
+precross: stubs php_ext_dir
+
+check: stubs php_ext_dir
+
+clean-local:
+	$(RM) -r gen-php gen-phpi gen-php-psr4 php_ext_dir
+
+client: stubs php_ext_dir
+	php TestClient.php
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/php/Makefile.am b/test/php/Makefile.am
new file mode 100755
index 0000000..28357f6
--- /dev/null
+++ b/test/php/Makefile.am
@@ -0,0 +1,39 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) --gen php ../ThriftTest.thrift
+	$(THRIFT) --gen php:inlined ../ThriftTest.thrift
+	$(MKDIR_P) gen-php-psr4
+	$(THRIFT) -out gen-php-psr4 --gen php:psr4 ../ThriftTest.thrift
+
+php_ext_dir:
+	mkdir -p php_ext_dir
+	ln -s ../../../lib/php/src/ext/thrift_protocol/modules/thrift_protocol.so php_ext_dir/
+	ln -s "$$(php-config --extension-dir)/sockets.so" php_ext_dir/
+
+precross: stubs php_ext_dir
+
+check: stubs php_ext_dir
+
+clean-local:
+	$(RM) -r gen-php gen-phpi gen-php-psr4 php_ext_dir
+
+client: stubs php_ext_dir
+	php TestClient.php
diff --git a/test/php/Makefile.in b/test/php/Makefile.in
new file mode 100644
index 0000000..be6a380
--- /dev/null
+++ b/test/php/Makefile.in
@@ -0,0 +1,643 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/php
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/php/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/php/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	clean-local cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) --gen php ../ThriftTest.thrift
+	$(THRIFT) --gen php:inlined ../ThriftTest.thrift
+	$(MKDIR_P) gen-php-psr4
+	$(THRIFT) -out gen-php-psr4 --gen php:psr4 ../ThriftTest.thrift
+
+php_ext_dir:
+	mkdir -p php_ext_dir
+	ln -s ../../../lib/php/src/ext/thrift_protocol/modules/thrift_protocol.so php_ext_dir/
+	ln -s "$$(php-config --extension-dir)/sockets.so" php_ext_dir/
+
+precross: stubs php_ext_dir
+
+check: stubs php_ext_dir
+
+clean-local:
+	$(RM) -r gen-php gen-phpi gen-php-psr4 php_ext_dir
+
+client: stubs php_ext_dir
+	php TestClient.php
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/php/TestClient.php b/test/php/TestClient.php
new file mode 100755
index 0000000..1591027
--- /dev/null
+++ b/test/php/TestClient.php
@@ -0,0 +1,556 @@
+registerNamespace('Thrift', __DIR__ . '/../../lib/php/lib');
+if ($GEN_DIR === 'gen-php-psr4') {
+  $loader->registerNamespace('ThriftTest', $GEN_DIR);
+} else {
+  $loader->registerDefinition('ThriftTest', $GEN_DIR);
+}
+$loader->register();
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/** Include the Thrift base */
+/** Include the protocols */
+use Thrift\Protocol\TBinaryProtocol;
+use Thrift\Protocol\TBinaryProtocolAccelerated;
+use Thrift\Protocol\TCompactProtocol;
+use Thrift\Protocol\TJSONProtocol;
+
+/** Include the socket layer */
+use Thrift\Transport\TSocket;
+use Thrift\Transport\TSocketPool;
+
+/** Include the socket layer */
+use Thrift\Transport\TFramedTransport;
+use Thrift\Transport\TBufferedTransport;
+
+function makeProtocol($transport, $PROTO)
+{
+  if ($PROTO == 'binary') {
+    return new TBinaryProtocol($transport);
+  } else if ($PROTO == 'compact') {
+    return new TCompactProtocol($transport);
+  } else if ($PROTO == 'json') {
+    return new TJSONProtocol($transport);
+  } else if ($PROTO == 'accel') {
+    if (!function_exists('thrift_protocol_write_binary')) {
+      echo "Acceleration extension is not loaded\n";
+      exit(1);
+    }
+    return new TBinaryProtocolAccelerated($transport);
+  }
+
+  echo "--protocol must be one of {binary|compact|json|accel}\n";
+  exit(1);
+}
+
+$host = 'localhost';
+$port = 9090;
+
+if ($argc > 1) {
+  $host = $argv[0];
+}
+
+if ($argc > 2) {
+  $host = $argv[1];
+}
+
+foreach ($argv as $arg) {
+  if (substr($arg, 0, 7) == '--port=') {
+    $port = substr($arg, 7);
+  } else if (substr($arg, 0, 12) == '--transport=') {
+    $MODE = substr($arg, 12);
+  } else if (substr($arg, 0, 11) == '--protocol=') {
+    $PROTO = substr($arg, 11);
+  } 
+}
+
+$hosts = array('localhost');
+
+$socket = new TSocket($host, $port);
+$socket = new TSocketPool($hosts, $port);
+$socket->setDebug(TRUE);
+
+if ($MODE == 'inline') {
+  $transport = $socket;
+  $testClient = new \ThriftTest\ThriftTestClient($transport);
+} else if ($MODE == 'framed') {
+  $framedSocket = new TFramedTransport($socket);
+  $transport = $framedSocket;
+  $protocol = makeProtocol($transport, $PROTO);
+  $testClient = new \ThriftTest\ThriftTestClient($protocol);
+} else {
+  $bufferedSocket = new TBufferedTransport($socket, 1024, 1024);
+  $transport = $bufferedSocket;
+  $protocol = makeProtocol($transport, $PROTO);
+  $testClient = new \ThriftTest\ThriftTestClient($protocol);
+}
+
+$transport->open();
+
+$start = microtime(true);
+
+define('ERR_BASETYPES', 1);
+define('ERR_STRUCTS', 2);
+define('ERR_CONTAINERS', 4);
+define('ERR_EXCEPTIONS', 8);
+define('ERR_UNKNOWN', 64);
+$exitcode = 0;
+/**
+ * VOID TEST
+ */
+print_r("testVoid()");
+$testClient->testVoid();
+print_r(" = void\n");
+
+function roundtrip($testClient, $method, $value) {
+  global $exitcode;
+  print_r("$method($value)");
+  $ret = $testClient->$method($value);
+  print_r(" = \"$ret\"\n");
+  if ($value !== $ret) {
+    print_r("*** FAILED ***\n");
+    $exitcode |= ERR_BASETYPES;
+  }
+}
+
+/**
+ * STRING TEST
+ */
+roundtrip($testClient, 'testString', "Test");
+
+/**
+ * BOOL TEST
+ */
+roundtrip($testClient, 'testBool', true);
+roundtrip($testClient, 'testBool', false);
+
+/**
+ * BYTE TEST
+ */
+roundtrip($testClient, 'testByte', 1);
+roundtrip($testClient, 'testByte', -1);
+roundtrip($testClient, 'testByte', 127);
+roundtrip($testClient, 'testByte', -128);
+
+/**
+ * I32 TEST
+ */
+roundtrip($testClient, 'testI32', -1);
+
+/**
+ * I64 TEST
+ */
+roundtrip($testClient, 'testI64', 0);
+roundtrip($testClient, 'testI64', 1);
+roundtrip($testClient, 'testI64', -1);
+roundtrip($testClient, 'testI64', -34359738368);
+
+/**
+ * DOUBLE TEST
+ */
+roundtrip($testClient, 'testDouble', -852.234234234);
+
+/**
+ * BINARY TEST  --  TODO
+ */
+
+/**
+ * STRUCT TEST
+ */
+print_r("testStruct({\"Zero\", 1, -3, -5})");
+$out = new \ThriftTest\Xtruct();
+$out->string_thing = "Zero";
+$out->byte_thing = 1;
+$out->i32_thing = -3;
+$out->i64_thing = -5;
+$in = $testClient->testStruct($out);
+print_r(" = {\"".$in->string_thing."\", ".
+        $in->byte_thing.", ".
+        $in->i32_thing.", ".
+        $in->i64_thing."}\n");
+
+if ($in != $out) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
+
+/**
+ * NESTED STRUCT TEST
+ */
+print_r("testNest({1, {\"Zero\", 1, -3, -5}), 5}");
+$out2 = new \ThriftTest\Xtruct2();
+$out2->byte_thing = 1;
+$out2->struct_thing = $out;
+$out2->i32_thing = 5;
+$in2 = $testClient->testNest($out2);
+$in = $in2->struct_thing;
+print_r(" = {".$in2->byte_thing.", {\"".
+        $in->string_thing."\", ".
+        $in->byte_thing.", ".
+        $in->i32_thing.", ".
+        $in->i64_thing."}, ".
+        $in2->i32_thing."}\n");
+
+if ($in2 != $out2) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
+
+/**
+ * MAP TEST
+ */
+$mapout = array();
+for ($i = 0; $i < 5; ++$i) {
+  $mapout[$i] = $i-10;
+}
+print_r("testMap({");
+$first = true;
+foreach ($mapout as $key => $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r("$key => $val");
+}
+print_r("})");
+
+$mapin = $testClient->testMap($mapout);
+print_r(" = {");
+$first = true;
+foreach ($mapin as $key => $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r("$key => $val");
+}
+print_r("}\n");
+
+if ($mapin != $mapout) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_CONTAINERS;
+}
+
+$mapout = array();
+for ($i = 0; $i < 10; $i++) {
+    $mapout["key$i"] = "val$i";
+}
+print_r('testStringMap({');
+$first = true;
+foreach ($mapout as $key => $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r("\"$key\" => \"$val\"");
+}
+print_r("})");
+$mapin = $testClient->testStringMap($mapout);
+print_r(" = {");
+$first = true;
+foreach ($mapin as $key => $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r("\"$key\" => \"$val\"");
+}
+print_r("}\n");
+ksort($mapin);
+if ($mapin != $mapout) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_CONTAINERS;
+}
+
+/**
+ * SET TEST
+ */
+$setout = array();;
+for ($i = -2; $i < 3; ++$i) {
+  $setout[$i]= true;
+}
+print_r("testSet({");
+echo implode(',', array_keys($setout));
+print_r("})");
+$setin = $testClient->testSet($setout);
+print_r(" = {");
+echo implode(', ', array_keys($setin));
+print_r("}\n");
+// Order of keys in set does not matter
+ksort($setin);
+if ($setout !== $setin) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_CONTAINERS;
+}
+// Regression test for corrupted array
+if ($setin[2] !== $setout[2] || is_int($setin[2])) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_CONTAINERS;
+}
+
+/**
+ * LIST TEST
+ */
+$listout = array();
+for ($i = -2; $i < 3; ++$i) {
+  $listout []= $i;
+}
+print_r("testList({");
+$first = true;
+foreach ($listout as $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r($val);
+}
+print_r("})");
+$listin = $testClient->testList($listout);
+print_r(" = {");
+$first = true;
+foreach ($listin as $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r($val);
+}
+print_r("}\n");
+if ($listin !== $listout) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_CONTAINERS;
+}
+
+/**
+ * ENUM TEST
+ */
+print_r("testEnum(ONE)");
+$ret = $testClient->testEnum(\ThriftTest\Numberz::ONE);
+print_r(" = $ret\n");
+if ($ret != \ThriftTest\Numberz::ONE) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
+
+print_r("testEnum(TWO)");
+$ret = $testClient->testEnum(\ThriftTest\Numberz::TWO);
+print_r(" = $ret\n");
+if ($ret != \ThriftTest\Numberz::TWO) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
+
+print_r("testEnum(THREE)");
+$ret = $testClient->testEnum(\ThriftTest\Numberz::THREE);
+print_r(" = $ret\n");
+if ($ret != \ThriftTest\Numberz::THREE) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
+
+print_r("testEnum(FIVE)");
+$ret = $testClient->testEnum(\ThriftTest\Numberz::FIVE);
+print_r(" = $ret\n");
+if ($ret != \ThriftTest\Numberz::FIVE) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
+
+print_r("testEnum(EIGHT)");
+$ret = $testClient->testEnum(\ThriftTest\Numberz::EIGHT);
+print_r(" = $ret\n");
+if ($ret != \ThriftTest\Numberz::EIGHT) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
+
+/**
+ * TYPEDEF TEST
+ */
+print_r("testTypedef(309858235082523)");
+$uid = $testClient->testTypedef(309858235082523);
+print_r(" = $uid\n");
+if ($uid !== 309858235082523) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
+
+/**
+ * NESTED MAP TEST
+ */
+print_r("testMapMap(1)");
+$mm = $testClient->testMapMap(1);
+print_r(" = {");
+foreach ($mm as $key => $val) {
+  print_r("$key => {");
+  foreach ($val as $k2 => $v2) {
+    print_r("$k2 => $v2, ");
+  }
+  print_r("}, ");
+}
+print_r("}\n");
+$expected_mm = [
+  -4 => [-4 => -4, -3 => -3, -2 => -2, -1 => -1],
+  4 => [4 => 4, 3 => 3, 2 => 2, 1 => 1],
+];
+if ($mm != $expected_mm) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_CONTAINERS;
+}
+
+/**
+ * INSANITY TEST
+ */
+$insane = new \ThriftTest\Insanity();
+$insane->userMap[\ThriftTest\Numberz::FIVE] = 5000;
+$truck = new \ThriftTest\Xtruct();
+$truck->string_thing = "Truck";
+$truck->byte_thing = 8;
+$truck->i32_thing = 8;
+$truck->i64_thing = 8;
+$insane->xtructs []= $truck;
+print_r("testInsanity()");
+$whoa = $testClient->testInsanity($insane);
+print_r(" = {");
+foreach ($whoa as $key => $val) {
+  print_r("$key => {");
+  foreach ($val as $k2 => $v2) {
+    print_r("$k2 => {");
+    $userMap = $v2->userMap;
+    print_r("{");
+    if (is_array($userMap)) {
+      foreach ($userMap as $k3 => $v3) {
+        print_r("$k3 => $v3, ");
+      }
+    }
+    print_r("}, ");
+
+    $xtructs = $v2->xtructs;
+    print_r("{");
+    if (is_array($xtructs)) {
+      foreach ($xtructs as $x) {
+        print_r("{\"".$x->string_thing."\", ".
+                $x->byte_thing.", ".$x->i32_thing.", ".$x->i64_thing."}, ");
+      }
+    }
+    print_r("}");
+
+    print_r("}, ");
+  }
+  print_r("}, ");
+}
+print_r("}\n");
+
+/**
+ * EXCEPTION TEST
+ */
+print_r("testException('Xception')");
+try {
+  $testClient->testException('Xception');
+  print_r("  void\nFAILURE\n");
+  $exitcode |= ERR_EXCEPTIONS;
+} catch (\ThriftTest\Xception $x) {
+  print_r(' caught xception '.$x->errorCode.': '.$x->message."\n");
+}
+
+// Regression test for THRIFT-4263
+print_r("testBinarySerializer_Deserialize('foo')");
+try {
+  \Thrift\Serializer\TBinarySerializer::deserialize(base64_decode('foo'), \ThriftTest\Xtruct2::class);
+  echo "**FAILED**\n";
+  $exitcode |= ERR_STRUCTS;
+} catch (\Thrift\Exception\TTransportException $happy_exception) {
+  // We expected this due to binary data of base64_decode('foo') is less then 4
+  // bytes and it tries to find thrift version number in the transport by
+  // reading i32() at the beginning.  Casting to string validates that
+  // exception is still accessible in memory and not corrupted.  Without patch,
+  // PHP will error log that the exception doesn't have any tostring method,
+  // which is a lie due to corrupted memory.
+  for($i=99; $i > 0; $i--) {
+    (string)$happy_exception;
+  }
+  print_r("  SUCCESS\n");
+}
+
+/**
+ * Normal tests done.
+ */
+
+$stop = microtime(true);
+$elp = round(1000*($stop - $start), 0);
+print_r("Total time: $elp ms\n");
+
+/**
+ * Extraneous "I don't trust PHP to pack/unpack integer" tests
+ */
+
+if ($protocol instanceof TBinaryProtocolAccelerated) {
+    // Regression check: check that method name is not double-freed
+    // Method name should not be an interned string.
+    $method_name = "Void";
+    $method_name = "test$method_name";
+
+    $seqid = 0;
+    $args = new \ThriftTest\ThriftTest_testVoid_args();
+    thrift_protocol_write_binary($protocol, $method_name, \Thrift\Type\TMessageType::CALL, $args, $seqid, $protocol->isStrictWrite());
+    $testClient->recv_testVoid();
+
+}
+
+// Max I32
+$num = pow(2, 30) + (pow(2, 30) - 1);
+roundtrip($testClient, 'testI32', $num);
+
+// Min I32
+$num = 0 - pow(2, 31);
+roundtrip($testClient, 'testI32', $num);
+
+// Max I64
+$num = pow(2, 62) + (pow(2, 62) - 1);
+roundtrip($testClient, 'testI64', $num);
+
+// Min I64
+$num = 0 - pow(2, 62) - pow(2, 62);
+roundtrip($testClient, 'testI64', $num);
+
+$transport->close();
+exit($exitcode);
diff --git a/test/php/TestInline.php b/test/php/TestInline.php
new file mode 100644
index 0000000..7066c46
--- /dev/null
+++ b/test/php/TestInline.php
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
diff --git a/test/php/TestPsr4.php b/test/php/TestPsr4.php
new file mode 100644
index 0000000..d30bf1c
--- /dev/null
+++ b/test/php/TestPsr4.php
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
diff --git a/test/php/test_php.ini b/test/php/test_php.ini
new file mode 100644
index 0000000..3f9bb21
--- /dev/null
+++ b/test/php/test_php.ini
@@ -0,0 +1,2 @@
+extension=thrift_protocol.so
+extension=sockets.so
diff --git a/test/py.tornado/Makefile b/test/py.tornado/Makefile
new file mode 100644
index 0000000..909bde4
--- /dev/null
+++ b/test/py.tornado/Makefile
@@ -0,0 +1,632 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# test/py.tornado/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/thrift
+pkgincludedir = $(includedir)/thrift
+pkglibdir = $(libdir)/thrift
+pkglibexecdir = $(libexecdir)/thrift
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = test/py.tornado
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15
+ALLOCA = 
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+ANT = /usr/bin/ant
+ANT_FLAGS = 
+AR = ar
+AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf
+AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader
+AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15
+AWK = gawk
+BISON = bison
+BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a
+BOOST_CPPFLAGS = -I/usr/include
+BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a
+BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu
+BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu
+BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a
+BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a
+BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a
+BUNDLER = /usr/bin/bundle
+CABAL = /usr/bin/cabal
+CABAL_CONFIGURE_FLAGS = 
+CARGO = /usr/bin/cargo
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CLASSPATH = 
+CPP = gcc -E
+CPPFLAGS = 
+CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;
+CXX = g++ -std=c++11
+CXXCPP = g++ -E -std=c++11
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DART = /usr/lib/dart/bin/dart
+DARTPUB = /usr/lib/dart/bin/pub
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DMD = dmd
+DMD_LIBEVENT_FLAGS = 
+DMD_OF_DIRSEP = /
+DMD_OPENSSL_FLAGS = 
+DOTNETCORE = /usr/bin/dotnet
+DOTNETCORE_VERSION = 2.0.3
+DSYMUTIL = 
+DUMPBIN = 
+D_EVENT_LIB_NAME = libthriftd-event.a
+D_IMPORT_PREFIX = ${prefix}/include/d2
+D_LIB_NAME = libthriftd.a
+D_SSL_LIB_NAME = libthriftd-ssl.a
+ECHO_C = 
+ECHO_N = -n
+ECHO_T = 
+EGREP = /bin/grep -E
+ENABLE_COVERAGE = 2
+ERL = /usr/bin/erl
+ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib
+ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0
+ERLANG_LIB_DIR = /usr/lib/erlang/lib
+ERLC = /usr/bin/erlc
+ERLCFLAGS = 
+EXEEXT = 
+FGREP = /bin/grep -F
+GCOV_CFLAGS = 
+GCOV_CXXFLAGS = 
+GCOV_LDFLAGS = 
+GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GLIB_LIBS = -lglib-2.0
+GO = /usr/bin/go
+GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0
+GREP = /bin/grep
+HAVE_CXX11 = 1
+HAXE = /usr/bin/haxe
+HAXE_VERSION = 3.2.1
+INSTALL = /usr/bin/install -c
+INSTALLDIRS = vendor
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+JAVA_PREFIX = /usr/local/lib
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS = 
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBEVENT_CPPFLAGS = 
+LIBEVENT_LDFLAGS = 
+LIBEVENT_LIBS = -levent
+LIBOBJS = 
+LIBS = -lrt -lpthread 
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO = 
+LN_S = ln -s
+LTLIBOBJS = 
+LT_SYS_LIBRARY_PATH = 
+LUA = /usr/bin/lua5.3
+LUA_EXEC_PREFIX = ${exec_prefix}
+LUA_INCLUDE = -I/usr/include/lua5.3
+LUA_LIB = -llua5.3  -ldl
+LUA_PLATFORM = unknown
+LUA_PREFIX = ${prefix}
+LUA_SHORT_VERSION = 53
+LUA_VERSION = 5.3
+MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo
+MANIFEST_TOOL = :
+MAYBE_CPP = cpp
+MAYBE_CSHARP = csharp
+MAYBE_C_GLIB = c_glib
+MAYBE_D = 
+MAYBE_DART = dart
+MAYBE_DOTNETCORE = netcore
+MAYBE_ERLANG = erl
+MAYBE_GO = go
+MAYBE_HASKELL = hs
+MAYBE_JAVA = java
+MAYBE_LUA = lua
+MAYBE_NODEJS = nodejs
+MAYBE_PERL = perl
+MAYBE_PHP = php
+MAYBE_PY3 = py3
+MAYBE_PYTHON = py
+MAYBE_RS = rs
+MAYBE_RUBY = rb
+MCS = /usr/bin/mcs
+MKDIR_P = /bin/mkdir -p
+MONO_CFLAGS = 
+MONO_LIBS = 
+NM = /usr/bin/nm -B
+NMEDIT = 
+NODEJS = /usr/bin/nodejs
+NPM = /usr/bin/npm
+OBJDUMP = objdump
+OBJEXT = o
+OPENSSL_INCLUDES = 
+OPENSSL_LDFLAGS = 
+OPENSSL_LIBS = -lssl -lcrypto
+OTOOL = 
+OTOOL64 = 
+PACKAGE = thrift
+PACKAGE_BUGREPORT = 
+PACKAGE_NAME = thrift
+PACKAGE_STRING = thrift 0.11.0
+PACKAGE_TARNAME = thrift
+PACKAGE_URL = 
+PACKAGE_VERSION = 0.11.0
+PATH_SEPARATOR = :
+PERL = /usr/bin/perl
+PERL_PREFIX = /usr/local
+PHP = /usr/bin/php
+PHPUNIT = /usr/bin/phpunit
+PHP_CONFIG = /usr/bin/php-config
+PHP_CONFIG_PREFIX = /etc/php.d
+PHP_PREFIX = /usr/lib/php
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR = 
+PKG_CONFIG_PATH = 
+PYTHON = /usr/bin/python
+PYTHON3 = /usr/bin/python3
+PYTHON_EXEC_PREFIX = ${exec_prefix}
+PYTHON_PLATFORM = linux2
+PYTHON_PREFIX = ${prefix}
+PYTHON_VERSION = 2.7
+PY_PREFIX = /usr
+QT5_CFLAGS = 
+QT5_LIBS = 
+QT5_MOC = 
+QT_CFLAGS = 
+QT_LIBS = 
+QT_MOC = 
+RANLIB = ranlib
+REBAR = /usr/bin/rebar
+RUBY = /usr/bin/ruby
+RUBY_PREFIX = 
+RUNHASKELL = /usr/bin/runhaskell
+RUSTC = /usr/bin/rustc
+SED = /bin/sed
+SET_MAKE = 
+SHELL = /bin/bash
+STRIP = strip
+THRIFT = $(top_srcdir)/compiler/cpp/thrift
+TRIAL = /usr/bin/trial
+VERSION = 0.11.0
+YACC = bison -y
+YFLAGS = 
+ZLIB_CPPFLAGS = 
+ZLIB_LDFLAGS = 
+ZLIB_LIBS = -lz
+abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/test/py.tornado
+abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/test/py.tornado
+abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift
+abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+ac_ct_DUMPBIN = 
+am__include = include
+am__leading_dot = .
+am__quote = 
+am__tar = tar --format=ustar -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias = 
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+golang_version = 1.6.2
+have_prog_bison = yes
+host = x86_64-pc-linux-gnu
+host_alias = 
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+luadir = ${prefix}/share/lua/5.3
+luaexecdir = ${exec_prefix}/lib/lua/5.3
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+pkgluadir = ${luadir}/thrift
+pkgluaexecdir = ${luaexecdir}/thrift
+pkgpyexecdir = ${pyexecdir}/thrift
+pkgpythondir = ${pythondir}/thrift
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages
+pythondir = ${prefix}/lib/python2.7/dist-packages
+runstatedir = ${localstatedir}/run
+rustc_version = rustc 1.17.0
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+subdirs =  lib/php/src/ext/thrift_protocol
+sysconfdir = ${prefix}/etc
+target_alias = 
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/py.tornado/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/py.tornado/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	clean-local cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+thrift_gen: ../ThriftTest.thrift ../SmallTest.thrift
+	$(THRIFT) --gen py:tornado ../ThriftTest.thrift
+	$(THRIFT) --gen py:tornado ../SmallTest.thrift
+
+check: thrift_gen
+	./test_suite.py
+
+clean-local:
+	$(RM) -r gen-py.tornado
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/py.tornado/Makefile.am b/test/py.tornado/Makefile.am
new file mode 100644
index 0000000..a8e680a
--- /dev/null
+++ b/test/py.tornado/Makefile.am
@@ -0,0 +1,30 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+THRIFT = $(top_srcdir)/compiler/cpp/thrift
+
+thrift_gen: ../ThriftTest.thrift ../SmallTest.thrift
+	$(THRIFT) --gen py:tornado ../ThriftTest.thrift
+	$(THRIFT) --gen py:tornado ../SmallTest.thrift
+
+check: thrift_gen
+	./test_suite.py
+
+clean-local:
+	$(RM) -r gen-py.tornado
diff --git a/test/py.tornado/Makefile.in b/test/py.tornado/Makefile.in
new file mode 100644
index 0000000..0fcd913
--- /dev/null
+++ b/test/py.tornado/Makefile.in
@@ -0,0 +1,632 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/py.tornado
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = $(top_srcdir)/compiler/cpp/thrift
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/py.tornado/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/py.tornado/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	clean-local cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+thrift_gen: ../ThriftTest.thrift ../SmallTest.thrift
+	$(THRIFT) --gen py:tornado ../ThriftTest.thrift
+	$(THRIFT) --gen py:tornado ../SmallTest.thrift
+
+check: thrift_gen
+	./test_suite.py
+
+clean-local:
+	$(RM) -r gen-py.tornado
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/py.tornado/setup.cfg b/test/py.tornado/setup.cfg
new file mode 100644
index 0000000..ae587c4
--- /dev/null
+++ b/test/py.tornado/setup.cfg
@@ -0,0 +1,3 @@
+[flake8]
+ignore = E402
+max-line-length = 100
diff --git a/test/py.tornado/test_suite.py b/test/py.tornado/test_suite.py
new file mode 100755
index 0000000..447fde6
--- /dev/null
+++ b/test/py.tornado/test_suite.py
@@ -0,0 +1,236 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import datetime
+import glob
+import os
+import sys
+import time
+import unittest
+
+basepath = os.path.abspath(os.path.dirname(__file__))
+sys.path.insert(0, basepath + '/gen-py.tornado')
+sys.path.insert(0, glob.glob(os.path.join(basepath, '../../lib/py/build/lib*'))[0])
+
+try:
+    __import__('tornado')
+except ImportError:
+    print("module `tornado` not found, skipping test")
+    sys.exit(0)
+
+from tornado import gen
+from tornado.testing import AsyncTestCase, get_unused_port, gen_test
+
+from thrift import TTornado
+from thrift.Thrift import TApplicationException
+from thrift.protocol import TBinaryProtocol
+
+from ThriftTest import ThriftTest
+from ThriftTest.ttypes import Xception, Xtruct
+
+
+class TestHandler(object):
+    def __init__(self, test_instance):
+        self.test_instance = test_instance
+
+    def testVoid(self):
+        pass
+
+    def testString(self, s):
+        if s == 'unexpected_error':
+            raise Exception(s)
+        return s
+
+    def testByte(self, b):
+        return b
+
+    def testI16(self, i16):
+        return i16
+
+    def testI32(self, i32):
+        return i32
+
+    def testI64(self, i64):
+        return i64
+
+    def testDouble(self, dub):
+        return dub
+
+    def testBinary(self, thing):
+        return thing
+
+    def testStruct(self, thing):
+        return thing
+
+    def testException(self, s):
+        if s == 'Xception':
+            x = Xception()
+            x.errorCode = 1001
+            x.message = s
+            raise x
+        elif s == 'throw_undeclared':
+            raise ValueError('testing undeclared exception')
+
+    def testOneway(self, seconds):
+        start = time.time()
+
+        def fire_oneway():
+            end = time.time()
+            self.test_instance.stop((start, end, seconds))
+
+        self.test_instance.io_loop.add_timeout(
+            datetime.timedelta(seconds=seconds),
+            fire_oneway)
+        raise Exception('testing exception in oneway method')
+
+    def testNest(self, thing):
+        return thing
+
+    @gen.coroutine
+    def testMap(self, thing):
+        yield gen.moment
+        raise gen.Return(thing)
+
+    def testSet(self, thing):
+        return thing
+
+    def testList(self, thing):
+        return thing
+
+    def testEnum(self, thing):
+        return thing
+
+    def testTypedef(self, thing):
+        return thing
+
+
+class ThriftTestCase(AsyncTestCase):
+    def setUp(self):
+        super(ThriftTestCase, self).setUp()
+
+        self.port = get_unused_port()
+
+        # server
+        self.handler = TestHandler(self)
+        self.processor = ThriftTest.Processor(self.handler)
+        self.pfactory = TBinaryProtocol.TBinaryProtocolFactory()
+
+        self.server = TTornado.TTornadoServer(self.processor, self.pfactory, io_loop=self.io_loop)
+        self.server.bind(self.port)
+        self.server.start(1)
+
+        # client
+        transport = TTornado.TTornadoStreamTransport('localhost', self.port, io_loop=self.io_loop)
+        pfactory = TBinaryProtocol.TBinaryProtocolFactory()
+        self.io_loop.run_sync(transport.open)
+        self.client = ThriftTest.Client(transport, pfactory)
+
+    @gen_test
+    def test_void(self):
+        v = yield self.client.testVoid()
+        self.assertEqual(v, None)
+
+    @gen_test
+    def test_string(self):
+        v = yield self.client.testString('Python')
+        self.assertEqual(v, 'Python')
+
+    @gen_test
+    def test_byte(self):
+        v = yield self.client.testByte(63)
+        self.assertEqual(v, 63)
+
+    @gen_test
+    def test_i32(self):
+        v = yield self.client.testI32(-1)
+        self.assertEqual(v, -1)
+
+        v = yield self.client.testI32(0)
+        self.assertEqual(v, 0)
+
+    @gen_test
+    def test_i64(self):
+        v = yield self.client.testI64(-34359738368)
+        self.assertEqual(v, -34359738368)
+
+    @gen_test
+    def test_double(self):
+        v = yield self.client.testDouble(-5.235098235)
+        self.assertEqual(v, -5.235098235)
+
+    @gen_test
+    def test_struct(self):
+        x = Xtruct()
+        x.string_thing = "Zero"
+        x.byte_thing = 1
+        x.i32_thing = -3
+        x.i64_thing = -5
+        y = yield self.client.testStruct(x)
+
+        self.assertEqual(y.string_thing, "Zero")
+        self.assertEqual(y.byte_thing, 1)
+        self.assertEqual(y.i32_thing, -3)
+        self.assertEqual(y.i64_thing, -5)
+
+    @gen_test
+    def test_oneway(self):
+        self.client.testOneway(1)
+        v = yield self.client.testI32(-1)
+        self.assertEqual(v, -1)
+
+    @gen_test
+    def test_map(self):
+        """
+        TestHandler.testMap is a coroutine, this test checks if gen.Return() from a coroutine works.
+        """
+        expected = {1: 1}
+        res = yield self.client.testMap(expected)
+        self.assertEqual(res, expected)
+
+    @gen_test
+    def test_exception(self):
+        try:
+            yield self.client.testException('Xception')
+        except Xception as ex:
+            self.assertEqual(ex.errorCode, 1001)
+            self.assertEqual(ex.message, 'Xception')
+        else:
+            self.fail("should have gotten exception")
+        try:
+            yield self.client.testException('throw_undeclared')
+        except TApplicationException:
+            pass
+        else:
+            self.fail("should have gotten exception")
+
+        yield self.client.testException('Safe')
+
+
+def suite():
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
+    suite.addTest(loader.loadTestsFromTestCase(ThriftTestCase))
+    return suite
+
+
+if __name__ == '__main__':
+    unittest.TestProgram(defaultTest='suite',
+                         testRunner=unittest.TextTestRunner(verbosity=1))
diff --git a/test/py.twisted/Makefile b/test/py.twisted/Makefile
new file mode 100644
index 0000000..5f46906
--- /dev/null
+++ b/test/py.twisted/Makefile
@@ -0,0 +1,634 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# test/py.twisted/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/thrift
+pkgincludedir = $(includedir)/thrift
+pkglibdir = $(libdir)/thrift
+pkglibexecdir = $(libexecdir)/thrift
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = test/py.twisted
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15
+ALLOCA = 
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+ANT = /usr/bin/ant
+ANT_FLAGS = 
+AR = ar
+AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf
+AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader
+AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15
+AWK = gawk
+BISON = bison
+BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a
+BOOST_CPPFLAGS = -I/usr/include
+BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a
+BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu
+BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu
+BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a
+BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a
+BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a
+BUNDLER = /usr/bin/bundle
+CABAL = /usr/bin/cabal
+CABAL_CONFIGURE_FLAGS = 
+CARGO = /usr/bin/cargo
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CLASSPATH = 
+CPP = gcc -E
+CPPFLAGS = 
+CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;
+CXX = g++ -std=c++11
+CXXCPP = g++ -E -std=c++11
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DART = /usr/lib/dart/bin/dart
+DARTPUB = /usr/lib/dart/bin/pub
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DMD = dmd
+DMD_LIBEVENT_FLAGS = 
+DMD_OF_DIRSEP = /
+DMD_OPENSSL_FLAGS = 
+DOTNETCORE = /usr/bin/dotnet
+DOTNETCORE_VERSION = 2.0.3
+DSYMUTIL = 
+DUMPBIN = 
+D_EVENT_LIB_NAME = libthriftd-event.a
+D_IMPORT_PREFIX = ${prefix}/include/d2
+D_LIB_NAME = libthriftd.a
+D_SSL_LIB_NAME = libthriftd-ssl.a
+ECHO_C = 
+ECHO_N = -n
+ECHO_T = 
+EGREP = /bin/grep -E
+ENABLE_COVERAGE = 2
+ERL = /usr/bin/erl
+ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib
+ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0
+ERLANG_LIB_DIR = /usr/lib/erlang/lib
+ERLC = /usr/bin/erlc
+ERLCFLAGS = 
+EXEEXT = 
+FGREP = /bin/grep -F
+GCOV_CFLAGS = 
+GCOV_CXXFLAGS = 
+GCOV_LDFLAGS = 
+GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GLIB_LIBS = -lglib-2.0
+GO = /usr/bin/go
+GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0
+GREP = /bin/grep
+HAVE_CXX11 = 1
+HAXE = /usr/bin/haxe
+HAXE_VERSION = 3.2.1
+INSTALL = /usr/bin/install -c
+INSTALLDIRS = vendor
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+JAVA_PREFIX = /usr/local/lib
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS = 
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBEVENT_CPPFLAGS = 
+LIBEVENT_LDFLAGS = 
+LIBEVENT_LIBS = -levent
+LIBOBJS = 
+LIBS = -lrt -lpthread 
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO = 
+LN_S = ln -s
+LTLIBOBJS = 
+LT_SYS_LIBRARY_PATH = 
+LUA = /usr/bin/lua5.3
+LUA_EXEC_PREFIX = ${exec_prefix}
+LUA_INCLUDE = -I/usr/include/lua5.3
+LUA_LIB = -llua5.3  -ldl
+LUA_PLATFORM = unknown
+LUA_PREFIX = ${prefix}
+LUA_SHORT_VERSION = 53
+LUA_VERSION = 5.3
+MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo
+MANIFEST_TOOL = :
+MAYBE_CPP = cpp
+MAYBE_CSHARP = csharp
+MAYBE_C_GLIB = c_glib
+MAYBE_D = 
+MAYBE_DART = dart
+MAYBE_DOTNETCORE = netcore
+MAYBE_ERLANG = erl
+MAYBE_GO = go
+MAYBE_HASKELL = hs
+MAYBE_JAVA = java
+MAYBE_LUA = lua
+MAYBE_NODEJS = nodejs
+MAYBE_PERL = perl
+MAYBE_PHP = php
+MAYBE_PY3 = py3
+MAYBE_PYTHON = py
+MAYBE_RS = rs
+MAYBE_RUBY = rb
+MCS = /usr/bin/mcs
+MKDIR_P = /bin/mkdir -p
+MONO_CFLAGS = 
+MONO_LIBS = 
+NM = /usr/bin/nm -B
+NMEDIT = 
+NODEJS = /usr/bin/nodejs
+NPM = /usr/bin/npm
+OBJDUMP = objdump
+OBJEXT = o
+OPENSSL_INCLUDES = 
+OPENSSL_LDFLAGS = 
+OPENSSL_LIBS = -lssl -lcrypto
+OTOOL = 
+OTOOL64 = 
+PACKAGE = thrift
+PACKAGE_BUGREPORT = 
+PACKAGE_NAME = thrift
+PACKAGE_STRING = thrift 0.11.0
+PACKAGE_TARNAME = thrift
+PACKAGE_URL = 
+PACKAGE_VERSION = 0.11.0
+PATH_SEPARATOR = :
+PERL = /usr/bin/perl
+PERL_PREFIX = /usr/local
+PHP = /usr/bin/php
+PHPUNIT = /usr/bin/phpunit
+PHP_CONFIG = /usr/bin/php-config
+PHP_CONFIG_PREFIX = /etc/php.d
+PHP_PREFIX = /usr/lib/php
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR = 
+PKG_CONFIG_PATH = 
+PYTHON = /usr/bin/python
+PYTHON3 = /usr/bin/python3
+PYTHON_EXEC_PREFIX = ${exec_prefix}
+PYTHON_PLATFORM = linux2
+PYTHON_PREFIX = ${prefix}
+PYTHON_VERSION = 2.7
+PY_PREFIX = /usr
+QT5_CFLAGS = 
+QT5_LIBS = 
+QT5_MOC = 
+QT_CFLAGS = 
+QT_LIBS = 
+QT_MOC = 
+RANLIB = ranlib
+REBAR = /usr/bin/rebar
+RUBY = /usr/bin/ruby
+RUBY_PREFIX = 
+RUNHASKELL = /usr/bin/runhaskell
+RUSTC = /usr/bin/rustc
+SED = /bin/sed
+SET_MAKE = 
+SHELL = /bin/bash
+STRIP = strip
+THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift
+TRIAL = /usr/bin/trial
+VERSION = 0.11.0
+YACC = bison -y
+YFLAGS = 
+ZLIB_CPPFLAGS = 
+ZLIB_LDFLAGS = 
+ZLIB_LIBS = -lz
+abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/test/py.twisted
+abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/test/py.twisted
+abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift
+abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+ac_ct_DUMPBIN = 
+am__include = include
+am__leading_dot = .
+am__quote = 
+am__tar = tar --format=ustar -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias = 
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+golang_version = 1.6.2
+have_prog_bison = yes
+host = x86_64-pc-linux-gnu
+host_alias = 
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+luadir = ${prefix}/share/lua/5.3
+luaexecdir = ${exec_prefix}/lib/lua/5.3
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+pkgluadir = ${luadir}/thrift
+pkgluaexecdir = ${luaexecdir}/thrift
+pkgpyexecdir = ${pyexecdir}/thrift
+pkgpythondir = ${pythondir}/thrift
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages
+pythondir = ${prefix}/lib/python2.7/dist-packages
+runstatedir = ${localstatedir}/run
+rustc_version = rustc 1.17.0
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+subdirs =  lib/php/src/ext/thrift_protocol
+sysconfdir = ${prefix}/etc
+target_alias = 
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/py.twisted/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/py.twisted/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	clean-local cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+TRIAL ?= trial
+
+stubs: ../ThriftTest.thrift ../SmallTest.thrift
+	$(THRIFT) --gen py:twisted ../ThriftTest.thrift
+	$(THRIFT) --gen py:twisted ../SmallTest.thrift
+
+check: stubs
+	$(TRIAL) ./test_suite.py
+
+clean-local:
+	$(RM) -r gen-py.twisted
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/py.twisted/Makefile.am b/test/py.twisted/Makefile.am
new file mode 100644
index 0000000..d11908c
--- /dev/null
+++ b/test/py.twisted/Makefile.am
@@ -0,0 +1,30 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+TRIAL ?= trial
+
+stubs: ../ThriftTest.thrift ../SmallTest.thrift
+	$(THRIFT) --gen py:twisted ../ThriftTest.thrift
+	$(THRIFT) --gen py:twisted ../SmallTest.thrift
+
+check: stubs
+	$(TRIAL) ./test_suite.py
+
+clean-local:
+	$(RM) -r gen-py.twisted
diff --git a/test/py.twisted/Makefile.in b/test/py.twisted/Makefile.in
new file mode 100644
index 0000000..c4fc78b
--- /dev/null
+++ b/test/py.twisted/Makefile.in
@@ -0,0 +1,634 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/py.twisted
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/py.twisted/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/py.twisted/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	clean-local cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+TRIAL ?= trial
+
+stubs: ../ThriftTest.thrift ../SmallTest.thrift
+	$(THRIFT) --gen py:twisted ../ThriftTest.thrift
+	$(THRIFT) --gen py:twisted ../SmallTest.thrift
+
+check: stubs
+	$(TRIAL) ./test_suite.py
+
+clean-local:
+	$(RM) -r gen-py.twisted
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/py.twisted/setup.cfg b/test/py.twisted/setup.cfg
new file mode 100644
index 0000000..ae587c4
--- /dev/null
+++ b/test/py.twisted/setup.cfg
@@ -0,0 +1,3 @@
+[flake8]
+ignore = E402
+max-line-length = 100
diff --git a/test/py.twisted/test_suite.py b/test/py.twisted/test_suite.py
new file mode 100755
index 0000000..02eb7f1
--- /dev/null
+++ b/test/py.twisted/test_suite.py
@@ -0,0 +1,198 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import glob
+import os
+import sys
+import time
+
+basepath = os.path.abspath(os.path.dirname(__file__))
+sys.path.insert(0, os.path.join(basepath, 'gen-py.twisted'))
+sys.path.insert(0, glob.glob(os.path.join(basepath, '../../lib/py/build/lib.*'))[0])
+
+from thrift.Thrift import TApplicationException
+
+from ThriftTest import ThriftTest
+from ThriftTest.ttypes import Xception, Xtruct
+from thrift.transport import TTwisted
+from thrift.protocol import TBinaryProtocol
+
+from twisted.trial import unittest
+from twisted.internet import defer, reactor
+from twisted.internet.protocol import ClientCreator
+
+from zope.interface import implementer
+
+
+@implementer(ThriftTest.Iface)
+class TestHandler:
+    def __init__(self):
+        self.onewaysQueue = defer.DeferredQueue()
+
+    def testVoid(self):
+        pass
+
+    def testString(self, s):
+        return s
+
+    def testByte(self, b):
+        return b
+
+    def testI16(self, i16):
+        return i16
+
+    def testI32(self, i32):
+        return i32
+
+    def testI64(self, i64):
+        return i64
+
+    def testDouble(self, dub):
+        return dub
+
+    def testBinary(self, thing):
+        return thing
+
+    def testStruct(self, thing):
+        return thing
+
+    def testException(self, s):
+        if s == 'Xception':
+            x = Xception()
+            x.errorCode = 1001
+            x.message = s
+            raise x
+        elif s == "throw_undeclared":
+            raise ValueError("foo")
+
+    def testOneway(self, seconds):
+        def fireOneway(t):
+            self.onewaysQueue.put((t, time.time(), seconds))
+        reactor.callLater(seconds, fireOneway, time.time())
+        raise Exception('')
+
+    def testNest(self, thing):
+        return thing
+
+    def testMap(self, thing):
+        return thing
+
+    def testSet(self, thing):
+        return thing
+
+    def testList(self, thing):
+        return thing
+
+    def testEnum(self, thing):
+        return thing
+
+    def testTypedef(self, thing):
+        return thing
+
+
+class ThriftTestCase(unittest.TestCase):
+
+    @defer.inlineCallbacks
+    def setUp(self):
+        self.handler = TestHandler()
+        self.processor = ThriftTest.Processor(self.handler)
+        self.pfactory = TBinaryProtocol.TBinaryProtocolFactory()
+
+        self.server = reactor.listenTCP(
+            0, TTwisted.ThriftServerFactory(self.processor, self.pfactory), interface="127.0.0.1")
+
+        self.portNo = self.server.getHost().port
+
+        self.txclient = yield ClientCreator(reactor,
+                                            TTwisted.ThriftClientProtocol,
+                                            ThriftTest.Client,
+                                            self.pfactory).connectTCP("127.0.0.1", self.portNo)
+        self.client = self.txclient.client
+
+    @defer.inlineCallbacks
+    def tearDown(self):
+        yield self.server.stopListening()
+        self.txclient.transport.loseConnection()
+
+    @defer.inlineCallbacks
+    def testVoid(self):
+        self.assertEquals((yield self.client.testVoid()), None)
+
+    @defer.inlineCallbacks
+    def testString(self):
+        self.assertEquals((yield self.client.testString('Python')), 'Python')
+
+    @defer.inlineCallbacks
+    def testByte(self):
+        self.assertEquals((yield self.client.testByte(63)), 63)
+
+    @defer.inlineCallbacks
+    def testI32(self):
+        self.assertEquals((yield self.client.testI32(-1)), -1)
+        self.assertEquals((yield self.client.testI32(0)), 0)
+
+    @defer.inlineCallbacks
+    def testI64(self):
+        self.assertEquals((yield self.client.testI64(-34359738368)), -34359738368)
+
+    @defer.inlineCallbacks
+    def testDouble(self):
+        self.assertEquals((yield self.client.testDouble(-5.235098235)), -5.235098235)
+
+    # TODO: def testBinary(self) ...
+
+    @defer.inlineCallbacks
+    def testStruct(self):
+        x = Xtruct()
+        x.string_thing = "Zero"
+        x.byte_thing = 1
+        x.i32_thing = -3
+        x.i64_thing = -5
+        y = yield self.client.testStruct(x)
+
+        self.assertEquals(y.string_thing, "Zero")
+        self.assertEquals(y.byte_thing, 1)
+        self.assertEquals(y.i32_thing, -3)
+        self.assertEquals(y.i64_thing, -5)
+
+    @defer.inlineCallbacks
+    def testException(self):
+        try:
+            yield self.client.testException('Xception')
+            self.fail("should have gotten exception")
+        except Xception as x:
+            self.assertEquals(x.errorCode, 1001)
+            self.assertEquals(x.message, 'Xception')
+
+        try:
+            yield self.client.testException("throw_undeclared")
+            self.fail("should have gotten exception")
+        except TApplicationException:
+            pass
+
+        yield self.client.testException('Safe')
+
+    @defer.inlineCallbacks
+    def testOneway(self):
+        yield self.client.testOneway(1)
+        start, end, seconds = yield self.handler.onewaysQueue.get()
+        self.assertAlmostEquals(seconds, (end - start), places=1)
+        self.assertEquals((yield self.client.testI32(-1)), -1)
diff --git a/test/py/CMakeLists.txt b/test/py/CMakeLists.txt
new file mode 100644
index 0000000..fbc2217
--- /dev/null
+++ b/test/py/CMakeLists.txt
@@ -0,0 +1,34 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+add_test(NAME python_test_generate
+    COMMAND ${CMAKE_COMMAND}
+            -DTHRIFTCOMPILER=$
+            -DMY_PROJECT_DIR=${PROJECT_SOURCE_DIR}
+            -DMY_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
+            -DMY_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
+    -P ${CMAKE_CURRENT_SOURCE_DIR}/generate.cmake
+)
+
+add_test(NAME python_test
+    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/RunClientServer.py --gen-base=${CMAKE_CURRENT_BINARY_DIR}
+    DEPENDS python_test_generate
+    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
diff --git a/test/py/FastbinaryTest.py b/test/py/FastbinaryTest.py
new file mode 100755
index 0000000..05c0bb6
--- /dev/null
+++ b/test/py/FastbinaryTest.py
@@ -0,0 +1,256 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+r"""
+PYTHONPATH=./gen-py:../../lib/py/build/lib... ./FastbinaryTest.py
+"""
+
+# TODO(dreiss): Test error cases.  Check for memory leaks.
+
+from __future__ import print_function
+
+import math
+import os
+import sys
+import timeit
+
+from copy import deepcopy
+from pprint import pprint
+
+from thrift.transport import TTransport
+from thrift.protocol.TBinaryProtocol import TBinaryProtocol, TBinaryProtocolAccelerated
+from thrift.protocol.TCompactProtocol import TCompactProtocol, TCompactProtocolAccelerated
+
+from DebugProtoTest import Srv
+from DebugProtoTest.ttypes import Backwards, Bonk, Empty, HolyMoley, OneOfEach, RandomStuff, Wrapper
+
+
+class TDevNullTransport(TTransport.TTransportBase):
+    def __init__(self):
+        pass
+
+    def isOpen(self):
+        return True
+
+
+ooe1 = OneOfEach()
+ooe1.im_true = True
+ooe1.im_false = False
+ooe1.a_bite = 0xd6
+ooe1.integer16 = 27000
+ooe1.integer32 = 1 << 24
+ooe1.integer64 = 6000 * 1000 * 1000
+ooe1.double_precision = math.pi
+ooe1.some_characters = "Debug THIS!"
+ooe1.zomg_unicode = u"\xd7\n\a\t"
+
+ooe2 = OneOfEach()
+ooe2.integer16 = 16
+ooe2.integer32 = 32
+ooe2.integer64 = 64
+ooe2.double_precision = (math.sqrt(5) + 1) / 2
+ooe2.some_characters = ":R (me going \"rrrr\")"
+ooe2.zomg_unicode = u"\xd3\x80\xe2\x85\xae\xce\x9d\x20"\
+                    u"\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe"\
+                    u"\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"\
+                    u"\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba"\
+                    u"\xc7\x83\xe2\x80\xbc"
+
+if sys.version_info[0] == 2 and os.environ.get('THRIFT_TEST_PY_NO_UTF8STRINGS'):
+    ooe1.zomg_unicode = ooe1.zomg_unicode.encode('utf8')
+    ooe2.zomg_unicode = ooe2.zomg_unicode.encode('utf8')
+
+hm = HolyMoley(**{"big": [], "contain": set(), "bonks": {}})
+hm.big.append(ooe1)
+hm.big.append(ooe2)
+hm.big[0].a_bite = 0x22
+hm.big[1].a_bite = 0x22
+
+hm.contain.add(("and a one", "and a two"))
+hm.contain.add(("then a one, two", "three!", "FOUR!"))
+if sys.version_info[0] == 2 and os.environ.get('THRIFT_TEST_PY_NO_UTF8STRINGS'):
+    hm.contain.add((u"\xd7\n\a\t".encode('utf8'),))
+else:
+    hm.contain.add((u"\xd7\n\a\t",))
+hm.contain.add(())
+
+hm.bonks["nothing"] = []
+hm.bonks["something"] = [
+    Bonk(**{"type": 1, "message": "Wait."}),
+    Bonk(**{"type": 2, "message": "What?"}),
+]
+hm.bonks["poe"] = [
+    Bonk(**{"type": 3, "message": "quoth"}),
+    Bonk(**{"type": 4, "message": "the raven"}),
+    Bonk(**{"type": 5, "message": "nevermore"}),
+]
+
+rs = RandomStuff()
+rs.a = 1
+rs.b = 2
+rs.c = 3
+rs.myintlist = list(range(20))
+rs.maps = {1: Wrapper(**{"foo": Empty()}), 2: Wrapper(**{"foo": Empty()})}
+rs.bigint = 124523452435
+rs.triple = 3.14
+
+# make sure this splits two buffers in a buffered protocol
+rshuge = RandomStuff()
+rshuge.myintlist = list(range(10000))
+
+my_zero = Srv.Janky_result(**{"success": 5})
+
+
+class Test(object):
+    def __init__(self, fast, slow):
+        self._fast = fast
+        self._slow = slow
+
+    def _check_write(self, o):
+        trans_fast = TTransport.TMemoryBuffer()
+        trans_slow = TTransport.TMemoryBuffer()
+        prot_fast = self._fast(trans_fast, fallback=False)
+        prot_slow = self._slow(trans_slow)
+
+        o.write(prot_fast)
+        o.write(prot_slow)
+        ORIG = trans_slow.getvalue()
+        MINE = trans_fast.getvalue()
+        if ORIG != MINE:
+            print("actual  : %s\nexpected: %s" % (repr(MINE), repr(ORIG)))
+            raise Exception('write value mismatch')
+
+    def _check_read(self, o):
+        prot = self._slow(TTransport.TMemoryBuffer())
+        o.write(prot)
+
+        slow_version_binary = prot.trans.getvalue()
+
+        prot = self._fast(
+            TTransport.TMemoryBuffer(slow_version_binary), fallback=False)
+        c = o.__class__()
+        c.read(prot)
+        if c != o:
+            print("actual  : ")
+            pprint(repr(c))
+            print("expected: ")
+            pprint(repr(o))
+            raise Exception('read value mismatch')
+
+        prot = self._fast(
+            TTransport.TBufferedTransport(
+                TTransport.TMemoryBuffer(slow_version_binary)), fallback=False)
+        c = o.__class__()
+        c.read(prot)
+        if c != o:
+            print("actual  : ")
+            pprint(repr(c))
+            print("expected: ")
+            pprint(repr(o))
+            raise Exception('read value mismatch')
+
+    def do_test(self):
+        self._check_write(HolyMoley())
+        self._check_read(HolyMoley())
+
+        self._check_write(hm)
+        no_set = deepcopy(hm)
+        no_set.contain = set()
+        self._check_read(no_set)
+        self._check_read(hm)
+
+        self._check_write(rs)
+        self._check_read(rs)
+
+        self._check_write(rshuge)
+        self._check_read(rshuge)
+
+        self._check_write(my_zero)
+        self._check_read(my_zero)
+
+        self._check_read(Backwards(**{"first_tag2": 4, "second_tag1": 2}))
+
+        # One case where the serialized form changes, but only superficially.
+        o = Backwards(**{"first_tag2": 4, "second_tag1": 2})
+        trans_fast = TTransport.TMemoryBuffer()
+        trans_slow = TTransport.TMemoryBuffer()
+        prot_fast = self._fast(trans_fast, fallback=False)
+        prot_slow = self._slow(trans_slow)
+
+        o.write(prot_fast)
+        o.write(prot_slow)
+        ORIG = trans_slow.getvalue()
+        MINE = trans_fast.getvalue()
+        assert id(ORIG) != id(MINE)
+
+        prot = self._fast(TTransport.TMemoryBuffer(), fallback=False)
+        o.write(prot)
+        prot = self._slow(
+            TTransport.TMemoryBuffer(prot.trans.getvalue()))
+        c = o.__class__()
+        c.read(prot)
+        if c != o:
+            print("copy: ")
+            pprint(repr(c))
+            print("orig: ")
+            pprint(repr(o))
+
+
+def do_test(fast, slow):
+    Test(fast, slow).do_test()
+
+
+def do_benchmark(protocol, iters=5000, skip_slow=False):
+    setup = """
+from __main__ import hm, rs, TDevNullTransport
+from thrift.protocol.{0} import {0}{1}
+trans = TDevNullTransport()
+prot = {0}{1}(trans{2})
+"""
+
+    setup_fast = setup.format(protocol, 'Accelerated', ', fallback=False')
+    if not skip_slow:
+        setup_slow = setup.format(protocol, '', '')
+
+    print("Starting Benchmarks")
+
+    if not skip_slow:
+        print("HolyMoley Standard = %f" %
+              timeit.Timer('hm.write(prot)', setup_slow).timeit(number=iters))
+
+    print("HolyMoley Acceler. = %f" %
+          timeit.Timer('hm.write(prot)', setup_fast).timeit(number=iters))
+
+    if not skip_slow:
+        print("FastStruct Standard = %f" %
+              timeit.Timer('rs.write(prot)', setup_slow).timeit(number=iters))
+
+    print("FastStruct Acceler. = %f" %
+          timeit.Timer('rs.write(prot)', setup_fast).timeit(number=iters))
+
+
+if __name__ == '__main__':
+    print('Testing TBinaryAccelerated')
+    do_test(TBinaryProtocolAccelerated, TBinaryProtocol)
+    do_benchmark('TBinaryProtocol')
+    print('Testing TCompactAccelerated')
+    do_test(TCompactProtocolAccelerated, TCompactProtocol)
+    do_benchmark('TCompactProtocol')
diff --git a/test/py/Makefile b/test/py/Makefile
new file mode 100644
index 0000000..8173ef6
--- /dev/null
+++ b/test/py/Makefile
@@ -0,0 +1,812 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# test/py/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/thrift
+pkgincludedir = $(includedir)/thrift
+pkglibdir = $(libdir)/thrift
+pkglibexecdir = $(libexecdir)/thrift
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = test/py
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15
+ALLOCA = 
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+ANT = /usr/bin/ant
+ANT_FLAGS = 
+AR = ar
+AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf
+AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader
+AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15
+AWK = gawk
+BISON = bison
+BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a
+BOOST_CPPFLAGS = -I/usr/include
+BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a
+BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu
+BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu
+BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a
+BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a
+BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a
+BUNDLER = /usr/bin/bundle
+CABAL = /usr/bin/cabal
+CABAL_CONFIGURE_FLAGS = 
+CARGO = /usr/bin/cargo
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CLASSPATH = 
+CPP = gcc -E
+CPPFLAGS = 
+CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;
+CXX = g++ -std=c++11
+CXXCPP = g++ -E -std=c++11
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DART = /usr/lib/dart/bin/dart
+DARTPUB = /usr/lib/dart/bin/pub
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DMD = dmd
+DMD_LIBEVENT_FLAGS = 
+DMD_OF_DIRSEP = /
+DMD_OPENSSL_FLAGS = 
+DOTNETCORE = /usr/bin/dotnet
+DOTNETCORE_VERSION = 2.0.3
+DSYMUTIL = 
+DUMPBIN = 
+D_EVENT_LIB_NAME = libthriftd-event.a
+D_IMPORT_PREFIX = ${prefix}/include/d2
+D_LIB_NAME = libthriftd.a
+D_SSL_LIB_NAME = libthriftd-ssl.a
+ECHO_C = 
+ECHO_N = -n
+ECHO_T = 
+EGREP = /bin/grep -E
+ENABLE_COVERAGE = 2
+ERL = /usr/bin/erl
+ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib
+ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0
+ERLANG_LIB_DIR = /usr/lib/erlang/lib
+ERLC = /usr/bin/erlc
+ERLCFLAGS = 
+EXEEXT = 
+FGREP = /bin/grep -F
+GCOV_CFLAGS = 
+GCOV_CXXFLAGS = 
+GCOV_LDFLAGS = 
+GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GLIB_LIBS = -lglib-2.0
+GO = /usr/bin/go
+GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0
+GREP = /bin/grep
+HAVE_CXX11 = 1
+HAXE = /usr/bin/haxe
+HAXE_VERSION = 3.2.1
+INSTALL = /usr/bin/install -c
+INSTALLDIRS = vendor
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+JAVA_PREFIX = /usr/local/lib
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS = 
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBEVENT_CPPFLAGS = 
+LIBEVENT_LDFLAGS = 
+LIBEVENT_LIBS = -levent
+LIBOBJS = 
+LIBS = -lrt -lpthread 
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO = 
+LN_S = ln -s
+LTLIBOBJS = 
+LT_SYS_LIBRARY_PATH = 
+LUA = /usr/bin/lua5.3
+LUA_EXEC_PREFIX = ${exec_prefix}
+LUA_INCLUDE = -I/usr/include/lua5.3
+LUA_LIB = -llua5.3  -ldl
+LUA_PLATFORM = unknown
+LUA_PREFIX = ${prefix}
+LUA_SHORT_VERSION = 53
+LUA_VERSION = 5.3
+MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo
+MANIFEST_TOOL = :
+MAYBE_CPP = cpp
+MAYBE_CSHARP = csharp
+MAYBE_C_GLIB = c_glib
+MAYBE_D = 
+MAYBE_DART = dart
+MAYBE_DOTNETCORE = netcore
+MAYBE_ERLANG = erl
+MAYBE_GO = go
+MAYBE_HASKELL = hs
+MAYBE_JAVA = java
+MAYBE_LUA = lua
+MAYBE_NODEJS = nodejs
+MAYBE_PERL = perl
+MAYBE_PHP = php
+MAYBE_PY3 = py3
+MAYBE_PYTHON = py
+MAYBE_RS = rs
+MAYBE_RUBY = rb
+MCS = /usr/bin/mcs
+MKDIR_P = /bin/mkdir -p
+MONO_CFLAGS = 
+MONO_LIBS = 
+NM = /usr/bin/nm -B
+NMEDIT = 
+NODEJS = /usr/bin/nodejs
+NPM = /usr/bin/npm
+OBJDUMP = objdump
+OBJEXT = o
+OPENSSL_INCLUDES = 
+OPENSSL_LDFLAGS = 
+OPENSSL_LIBS = -lssl -lcrypto
+OTOOL = 
+OTOOL64 = 
+PACKAGE = thrift
+PACKAGE_BUGREPORT = 
+PACKAGE_NAME = thrift
+PACKAGE_STRING = thrift 0.11.0
+PACKAGE_TARNAME = thrift
+PACKAGE_URL = 
+PACKAGE_VERSION = 0.11.0
+PATH_SEPARATOR = :
+PERL = /usr/bin/perl
+PERL_PREFIX = /usr/local
+PHP = /usr/bin/php
+PHPUNIT = /usr/bin/phpunit
+PHP_CONFIG = /usr/bin/php-config
+PHP_CONFIG_PREFIX = /etc/php.d
+PHP_PREFIX = /usr/lib/php
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR = 
+PKG_CONFIG_PATH = 
+PYTHON = /usr/bin/python
+PYTHON3 = /usr/bin/python3
+PYTHON_EXEC_PREFIX = ${exec_prefix}
+PYTHON_PLATFORM = linux2
+PYTHON_PREFIX = ${prefix}
+PYTHON_VERSION = 2.7
+PY_PREFIX = /usr
+QT5_CFLAGS = 
+QT5_LIBS = 
+QT5_MOC = 
+QT_CFLAGS = 
+QT_LIBS = 
+QT_MOC = 
+RANLIB = ranlib
+REBAR = /usr/bin/rebar
+RUBY = /usr/bin/ruby
+RUBY_PREFIX = 
+RUNHASKELL = /usr/bin/runhaskell
+RUSTC = /usr/bin/rustc
+SED = /bin/sed
+SET_MAKE = 
+SHELL = /bin/bash
+STRIP = strip
+THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift
+TRIAL = /usr/bin/trial
+VERSION = 0.11.0
+YACC = bison -y
+YFLAGS = 
+ZLIB_CPPFLAGS = 
+ZLIB_LDFLAGS = 
+ZLIB_LIBS = -lz
+abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/test/py
+abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/test/py
+abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift
+abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+ac_ct_DUMPBIN = 
+am__include = include
+am__leading_dot = .
+am__quote = 
+am__tar = tar --format=ustar -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias = 
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+golang_version = 1.6.2
+have_prog_bison = yes
+host = x86_64-pc-linux-gnu
+host_alias = 
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+luadir = ${prefix}/share/lua/5.3
+luaexecdir = ${exec_prefix}/lib/lua/5.3
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+pkgluadir = ${luadir}/thrift
+pkgluaexecdir = ${luaexecdir}/thrift
+pkgpyexecdir = ${pyexecdir}/thrift
+pkgpythondir = ${pythondir}/thrift
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages
+pythondir = ${prefix}/lib/python2.7/dist-packages
+runstatedir = ${localstatedir}/run
+rustc_version = rustc 1.17.0
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+subdirs =  lib/php/src/ext/thrift_protocol
+sysconfdir = ${prefix}/etc
+target_alias = 
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+AUTOMAKE_OPTIONS = serial-tests
+py_unit_tests = RunClientServer.py
+thrift_gen = \
+        gen-py/ThriftTest/__init__.py           \
+        gen-py/DebugProtoTest/__init__.py \
+        gen-py/Recursive/__init__.py \
+        gen-py-default/ThriftTest/__init__.py           \
+        gen-py-default/DebugProtoTest/__init__.py \
+        gen-py-default/Recursive/__init__.py \
+        gen-py-slots/ThriftTest/__init__.py           \
+        gen-py-slots/DebugProtoTest/__init__.py \
+        gen-py-slots/Recursive/__init__.py \
+        gen-py-oldstyle/ThriftTest/__init__.py \
+        gen-py-oldstyle/DebugProtoTest/__init__.py \
+        gen-py-oldstyle/Recursive/__init__.py \
+        gen-py-no_utf8strings/ThriftTest/__init__.py \
+        gen-py-no_utf8strings/DebugProtoTest/__init__.py \
+        gen-py-no_utf8strings/Recursive/__init__.py \
+        gen-py-dynamic/ThriftTest/__init__.py           \
+        gen-py-dynamic/DebugProtoTest/__init__.py \
+        gen-py-dynamic/Recursive/__init__.py \
+        gen-py-dynamicslots/ThriftTest/__init__.py           \
+        gen-py-dynamicslots/DebugProtoTest/__init__.py \
+        gen-py-dynamicslots/Recursive/__init__.py
+
+BUILT_SOURCES = $(thrift_gen)
+helper_scripts = \
+        TestClient.py                           \
+        TestServer.py
+
+check_SCRIPTS = \
+        $(thrift_gen) \
+        $(py_unit_tests)                        \
+        $(helper_scripts)
+
+TESTS = $(py_unit_tests)
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/py/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/py/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list=' $(TESTS) '; \
+	$(am__tty_colors); \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *[\ \	]$$tst[\ \	]*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		col=$$red; res=XPASS; \
+	      ;; \
+	      *) \
+		col=$$grn; res=PASS; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *[\ \	]$$tst[\ \	]*) \
+		xfail=`expr $$xfail + 1`; \
+		col=$$lgn; res=XFAIL; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		col=$$red; res=FAIL; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      col=$$blu; res=SKIP; \
+	    fi; \
+	    echo "$${col}$$res$${std}: $$tst"; \
+	  done; \
+	  if test "$$all" -eq 1; then \
+	    tests="test"; \
+	    All=""; \
+	  else \
+	    tests="tests"; \
+	    All="All "; \
+	  fi; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="$$All$$all $$tests passed"; \
+	    else \
+	      if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+	      banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all $$tests failed"; \
+	    else \
+	      if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+	      banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    if test "$$skip" -eq 1; then \
+	      skipped="($$skip test was not run)"; \
+	    else \
+	      skipped="($$skip tests were not run)"; \
+	    fi; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  if test "$$failed" -eq 0; then \
+	    col="$$grn"; \
+	  else \
+	    col="$$red"; \
+	  fi; \
+	  echo "$${col}$$dashes$${std}"; \
+	  echo "$${col}$$banner$${std}"; \
+	  test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+	  test -z "$$report" || echo "$${col}$$report$${std}"; \
+	  echo "$${col}$$dashes$${std}"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_SCRIPTS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile
+installdirs:
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: all check check-am install install-am install-strip
+
+.PHONY: all all-am check check-TESTS check-am clean clean-generic \
+	clean-libtool clean-local cscopelist-am ctags-am distclean \
+	distclean-generic distclean-libtool distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \
+	tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+precross: $(thrift_gen)
+
+gen-py/%/__init__.py: ../%.thrift $(THRIFT)
+	$(THRIFT) --gen py  $<
+
+gen-py-default/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-default || $(MKDIR_P) gen-py-default
+	$(THRIFT) --gen py -out gen-py-default $<
+
+gen-py-slots/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-slots || $(MKDIR_P) gen-py-slots
+	$(THRIFT) --gen py:slots -out gen-py-slots $<
+
+gen-py-oldstyle/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-oldstyle || $(MKDIR_P) gen-py-oldstyle
+	$(THRIFT) --gen py:old_style -out gen-py-oldstyle $<
+
+gen-py-no_utf8strings/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-no_utf8strings || $(MKDIR_P) gen-py-no_utf8strings
+	$(THRIFT) --gen py:no_utf8strings -out gen-py-no_utf8strings $<
+
+gen-py-dynamic/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-dynamic || $(MKDIR_P) gen-py-dynamic
+	$(THRIFT) --gen py:dynamic -out gen-py-dynamic $<
+
+gen-py-dynamicslots/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-dynamicslots || $(MKDIR_P) gen-py-dynamicslots
+	$(THRIFT) --gen py:dynamic,slots -out gen-py-dynamicslots $<
+
+clean-local:
+	$(RM) -r gen-py gen-py-slots gen-py-default gen-py-oldstyle gen-py-no_utf8strings gen-py-dynamic gen-py-dynamicslots
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/py/Makefile.am b/test/py/Makefile.am
new file mode 100644
index 0000000..b3513dd
--- /dev/null
+++ b/test/py/Makefile.am
@@ -0,0 +1,90 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+AUTOMAKE_OPTIONS = serial-tests
+
+py_unit_tests = RunClientServer.py
+
+thrift_gen =                                    \
+        gen-py/ThriftTest/__init__.py           \
+        gen-py/DebugProtoTest/__init__.py \
+        gen-py/Recursive/__init__.py \
+        gen-py-default/ThriftTest/__init__.py           \
+        gen-py-default/DebugProtoTest/__init__.py \
+        gen-py-default/Recursive/__init__.py \
+        gen-py-slots/ThriftTest/__init__.py           \
+        gen-py-slots/DebugProtoTest/__init__.py \
+        gen-py-slots/Recursive/__init__.py \
+        gen-py-oldstyle/ThriftTest/__init__.py \
+        gen-py-oldstyle/DebugProtoTest/__init__.py \
+        gen-py-oldstyle/Recursive/__init__.py \
+        gen-py-no_utf8strings/ThriftTest/__init__.py \
+        gen-py-no_utf8strings/DebugProtoTest/__init__.py \
+        gen-py-no_utf8strings/Recursive/__init__.py \
+        gen-py-dynamic/ThriftTest/__init__.py           \
+        gen-py-dynamic/DebugProtoTest/__init__.py \
+        gen-py-dynamic/Recursive/__init__.py \
+        gen-py-dynamicslots/ThriftTest/__init__.py           \
+        gen-py-dynamicslots/DebugProtoTest/__init__.py \
+        gen-py-dynamicslots/Recursive/__init__.py
+
+
+precross: $(thrift_gen)
+BUILT_SOURCES = $(thrift_gen)
+
+helper_scripts=                                 \
+        TestClient.py                           \
+        TestServer.py
+
+check_SCRIPTS=                                  \
+        $(thrift_gen) \
+        $(py_unit_tests)                        \
+        $(helper_scripts)
+
+TESTS= $(py_unit_tests)
+
+
+gen-py/%/__init__.py: ../%.thrift $(THRIFT)
+	$(THRIFT) --gen py  $<
+
+gen-py-default/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-default || $(MKDIR_P) gen-py-default
+	$(THRIFT) --gen py -out gen-py-default $<
+
+gen-py-slots/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-slots || $(MKDIR_P) gen-py-slots
+	$(THRIFT) --gen py:slots -out gen-py-slots $<
+
+gen-py-oldstyle/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-oldstyle || $(MKDIR_P) gen-py-oldstyle
+	$(THRIFT) --gen py:old_style -out gen-py-oldstyle $<
+
+gen-py-no_utf8strings/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-no_utf8strings || $(MKDIR_P) gen-py-no_utf8strings
+	$(THRIFT) --gen py:no_utf8strings -out gen-py-no_utf8strings $<
+
+gen-py-dynamic/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-dynamic || $(MKDIR_P) gen-py-dynamic
+	$(THRIFT) --gen py:dynamic -out gen-py-dynamic $<
+
+gen-py-dynamicslots/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-dynamicslots || $(MKDIR_P) gen-py-dynamicslots
+	$(THRIFT) --gen py:dynamic,slots -out gen-py-dynamicslots $<
+
+clean-local:
+	$(RM) -r gen-py gen-py-slots gen-py-default gen-py-oldstyle gen-py-no_utf8strings gen-py-dynamic gen-py-dynamicslots
diff --git a/test/py/Makefile.in b/test/py/Makefile.in
new file mode 100644
index 0000000..b845d1d
--- /dev/null
+++ b/test/py/Makefile.in
@@ -0,0 +1,812 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/py
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+AUTOMAKE_OPTIONS = serial-tests
+py_unit_tests = RunClientServer.py
+thrift_gen = \
+        gen-py/ThriftTest/__init__.py           \
+        gen-py/DebugProtoTest/__init__.py \
+        gen-py/Recursive/__init__.py \
+        gen-py-default/ThriftTest/__init__.py           \
+        gen-py-default/DebugProtoTest/__init__.py \
+        gen-py-default/Recursive/__init__.py \
+        gen-py-slots/ThriftTest/__init__.py           \
+        gen-py-slots/DebugProtoTest/__init__.py \
+        gen-py-slots/Recursive/__init__.py \
+        gen-py-oldstyle/ThriftTest/__init__.py \
+        gen-py-oldstyle/DebugProtoTest/__init__.py \
+        gen-py-oldstyle/Recursive/__init__.py \
+        gen-py-no_utf8strings/ThriftTest/__init__.py \
+        gen-py-no_utf8strings/DebugProtoTest/__init__.py \
+        gen-py-no_utf8strings/Recursive/__init__.py \
+        gen-py-dynamic/ThriftTest/__init__.py           \
+        gen-py-dynamic/DebugProtoTest/__init__.py \
+        gen-py-dynamic/Recursive/__init__.py \
+        gen-py-dynamicslots/ThriftTest/__init__.py           \
+        gen-py-dynamicslots/DebugProtoTest/__init__.py \
+        gen-py-dynamicslots/Recursive/__init__.py
+
+BUILT_SOURCES = $(thrift_gen)
+helper_scripts = \
+        TestClient.py                           \
+        TestServer.py
+
+check_SCRIPTS = \
+        $(thrift_gen) \
+        $(py_unit_tests)                        \
+        $(helper_scripts)
+
+TESTS = $(py_unit_tests)
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/py/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/py/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list=' $(TESTS) '; \
+	$(am__tty_colors); \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *[\ \	]$$tst[\ \	]*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		col=$$red; res=XPASS; \
+	      ;; \
+	      *) \
+		col=$$grn; res=PASS; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *[\ \	]$$tst[\ \	]*) \
+		xfail=`expr $$xfail + 1`; \
+		col=$$lgn; res=XFAIL; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		col=$$red; res=FAIL; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      col=$$blu; res=SKIP; \
+	    fi; \
+	    echo "$${col}$$res$${std}: $$tst"; \
+	  done; \
+	  if test "$$all" -eq 1; then \
+	    tests="test"; \
+	    All=""; \
+	  else \
+	    tests="tests"; \
+	    All="All "; \
+	  fi; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="$$All$$all $$tests passed"; \
+	    else \
+	      if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+	      banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all $$tests failed"; \
+	    else \
+	      if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+	      banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    if test "$$skip" -eq 1; then \
+	      skipped="($$skip test was not run)"; \
+	    else \
+	      skipped="($$skip tests were not run)"; \
+	    fi; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  if test "$$failed" -eq 0; then \
+	    col="$$grn"; \
+	  else \
+	    col="$$red"; \
+	  fi; \
+	  echo "$${col}$$dashes$${std}"; \
+	  echo "$${col}$$banner$${std}"; \
+	  test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+	  test -z "$$report" || echo "$${col}$$report$${std}"; \
+	  echo "$${col}$$dashes$${std}"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_SCRIPTS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile
+installdirs:
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: all check check-am install install-am install-strip
+
+.PHONY: all all-am check check-TESTS check-am clean clean-generic \
+	clean-libtool clean-local cscopelist-am ctags-am distclean \
+	distclean-generic distclean-libtool distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \
+	tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+precross: $(thrift_gen)
+
+gen-py/%/__init__.py: ../%.thrift $(THRIFT)
+	$(THRIFT) --gen py  $<
+
+gen-py-default/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-default || $(MKDIR_P) gen-py-default
+	$(THRIFT) --gen py -out gen-py-default $<
+
+gen-py-slots/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-slots || $(MKDIR_P) gen-py-slots
+	$(THRIFT) --gen py:slots -out gen-py-slots $<
+
+gen-py-oldstyle/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-oldstyle || $(MKDIR_P) gen-py-oldstyle
+	$(THRIFT) --gen py:old_style -out gen-py-oldstyle $<
+
+gen-py-no_utf8strings/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-no_utf8strings || $(MKDIR_P) gen-py-no_utf8strings
+	$(THRIFT) --gen py:no_utf8strings -out gen-py-no_utf8strings $<
+
+gen-py-dynamic/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-dynamic || $(MKDIR_P) gen-py-dynamic
+	$(THRIFT) --gen py:dynamic -out gen-py-dynamic $<
+
+gen-py-dynamicslots/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-dynamicslots || $(MKDIR_P) gen-py-dynamicslots
+	$(THRIFT) --gen py:dynamic,slots -out gen-py-dynamicslots $<
+
+clean-local:
+	$(RM) -r gen-py gen-py-slots gen-py-default gen-py-oldstyle gen-py-no_utf8strings gen-py-dynamic gen-py-dynamicslots
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/py/RunClientServer.py b/test/py/RunClientServer.py
new file mode 100755
index 0000000..7c0f787
--- /dev/null
+++ b/test/py/RunClientServer.py
@@ -0,0 +1,321 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from __future__ import division
+from __future__ import print_function
+import platform
+import copy
+import os
+import signal
+import socket
+import subprocess
+import sys
+import time
+from optparse import OptionParser
+
+from util import local_libpath
+
+SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
+
+SCRIPTS = [
+    'FastbinaryTest.py',
+    'TestFrozen.py',
+    'TSimpleJSONProtocolTest.py',
+    'SerializationTest.py',
+    'TestEof.py',
+    'TestSyntax.py',
+    'TestSocket.py',
+]
+FRAMED = ["TNonblockingServer"]
+SKIP_ZLIB = ['TNonblockingServer', 'THttpServer']
+SKIP_SSL = ['THttpServer']
+EXTRA_DELAY = dict(TProcessPoolServer=5.5)
+
+PROTOS = [
+    'accel',
+    'accelc',
+    'binary',
+    'compact',
+    'json',
+]
+
+
+def default_servers():
+    servers = [
+        'TSimpleServer',
+        'TThreadedServer',
+        'TThreadPoolServer',
+        'TNonblockingServer',
+        'THttpServer',
+    ]
+    if platform.system() != 'Windows':
+        servers.append('TProcessPoolServer')
+        servers.append('TForkingServer')
+    return servers
+
+
+def relfile(fname):
+    return os.path.join(SCRIPT_DIR, fname)
+
+
+def setup_pypath(libdir, gendir):
+    dirs = [libdir, gendir]
+    env = copy.deepcopy(os.environ)
+    pypath = env.get('PYTHONPATH', None)
+    if pypath:
+        dirs.append(pypath)
+    env['PYTHONPATH'] = os.pathsep.join(dirs)
+    if gendir.endswith('gen-py-no_utf8strings'):
+        env['THRIFT_TEST_PY_NO_UTF8STRINGS'] = '1'
+    return env
+
+
+def runScriptTest(libdir, genbase, genpydir, script):
+    env = setup_pypath(libdir, os.path.join(genbase, genpydir))
+    script_args = [sys.executable, relfile(script)]
+    print('\nTesting script: %s\n----' % (' '.join(script_args)))
+    ret = subprocess.call(script_args, env=env)
+    if ret != 0:
+        print('*** FAILED ***', file=sys.stderr)
+        print('LIBDIR: %s' % libdir, file=sys.stderr)
+        print('PY_GEN: %s' % genpydir, file=sys.stderr)
+        print('SCRIPT: %s' % script, file=sys.stderr)
+        raise Exception("Script subprocess failed, retcode=%d, args: %s" % (ret, ' '.join(script_args)))
+
+
+def runServiceTest(libdir, genbase, genpydir, server_class, proto, port, use_zlib, use_ssl, verbose):
+    env = setup_pypath(libdir, os.path.join(genbase, genpydir))
+    # Build command line arguments
+    server_args = [sys.executable, relfile('TestServer.py')]
+    cli_args = [sys.executable, relfile('TestClient.py')]
+    for which in (server_args, cli_args):
+        which.append('--protocol=%s' % proto)  # accel, binary, compact or json
+        which.append('--port=%d' % port)  # default to 9090
+        if use_zlib:
+            which.append('--zlib')
+        if use_ssl:
+            which.append('--ssl')
+        if verbose == 0:
+            which.append('-q')
+        if verbose == 2:
+            which.append('-v')
+    # server-specific option to select server class
+    server_args.append(server_class)
+    # client-specific cmdline options
+    if server_class in FRAMED:
+        cli_args.append('--transport=framed')
+    else:
+        cli_args.append('--transport=buffered')
+    if server_class == 'THttpServer':
+        cli_args.append('--http=/')
+    if verbose > 0:
+        print('Testing server %s: %s' % (server_class, ' '.join(server_args)))
+    serverproc = subprocess.Popen(server_args, env=env)
+
+    def ensureServerAlive():
+        if serverproc.poll() is not None:
+            print(('FAIL: Server process (%s) failed with retcode %d')
+                  % (' '.join(server_args), serverproc.returncode))
+            raise Exception('Server subprocess %s died, args: %s'
+                            % (server_class, ' '.join(server_args)))
+
+    # Wait for the server to start accepting connections on the given port.
+    sleep_time = 0.1  # Seconds
+    max_attempts = 100
+    attempt = 0
+    while True:
+        sock4 = socket.socket()
+        sock6 = socket.socket(socket.AF_INET6)
+        try:
+            if sock4.connect_ex(('127.0.0.1', port)) == 0 \
+                    or sock6.connect_ex(('::1', port)) == 0:
+                break
+            attempt += 1
+            if attempt >= max_attempts:
+                raise Exception("TestServer not ready on port %d after %.2f seconds"
+                                % (port, sleep_time * attempt))
+            ensureServerAlive()
+            time.sleep(sleep_time)
+        finally:
+            sock4.close()
+            sock6.close()
+
+    try:
+        if verbose > 0:
+            print('Testing client: %s' % (' '.join(cli_args)))
+        ret = subprocess.call(cli_args, env=env)
+        if ret != 0:
+            print('*** FAILED ***', file=sys.stderr)
+            print('LIBDIR: %s' % libdir, file=sys.stderr)
+            print('PY_GEN: %s' % genpydir, file=sys.stderr)
+            raise Exception("Client subprocess failed, retcode=%d, args: %s" % (ret, ' '.join(cli_args)))
+    finally:
+        # check that server didn't die
+        ensureServerAlive()
+        extra_sleep = EXTRA_DELAY.get(server_class, 0)
+        if extra_sleep > 0 and verbose > 0:
+            print('Giving %s (proto=%s,zlib=%s,ssl=%s) an extra %d seconds for child'
+                  'processes to terminate via alarm'
+                  % (server_class, proto, use_zlib, use_ssl, extra_sleep))
+            time.sleep(extra_sleep)
+        sig = signal.SIGKILL if platform.system() != 'Windows' else signal.SIGABRT
+        os.kill(serverproc.pid, sig)
+        serverproc.wait()
+
+
+class TestCases(object):
+    def __init__(self, genbase, libdir, port, gendirs, servers, verbose):
+        self.genbase = genbase
+        self.libdir = libdir
+        self.port = port
+        self.verbose = verbose
+        self.gendirs = gendirs
+        self.servers = servers
+
+    def default_conf(self):
+        return {
+            'gendir': self.gendirs[0],
+            'server': self.servers[0],
+            'proto': PROTOS[0],
+            'zlib': False,
+            'ssl': False,
+        }
+
+    def run(self, conf, test_count):
+        with_zlib = conf['zlib']
+        with_ssl = conf['ssl']
+        try_server = conf['server']
+        try_proto = conf['proto']
+        genpydir = conf['gendir']
+        # skip any servers that don't work with the Zlib transport
+        if with_zlib and try_server in SKIP_ZLIB:
+            return False
+        # skip any servers that don't work with SSL
+        if with_ssl and try_server in SKIP_SSL:
+            return False
+        if self.verbose > 0:
+            print('\nTest run #%d:  (includes %s) Server=%s,  Proto=%s,  zlib=%s,  SSL=%s'
+                  % (test_count, genpydir, try_server, try_proto, with_zlib, with_ssl))
+        runServiceTest(self.libdir, self.genbase, genpydir, try_server, try_proto, self.port, with_zlib, with_ssl, self.verbose)
+        if self.verbose > 0:
+            print('OK: Finished (includes %s)  %s / %s proto / zlib=%s / SSL=%s.   %d combinations tested.'
+                  % (genpydir, try_server, try_proto, with_zlib, with_ssl, test_count))
+        return True
+
+    def test_feature(self, name, values):
+        test_count = 0
+        conf = self.default_conf()
+        for try_server in values:
+            conf[name] = try_server
+            if self.run(conf, test_count):
+                test_count += 1
+        return test_count
+
+    def run_all_tests(self):
+        test_count = 0
+        for try_server in self.servers:
+            for genpydir in self.gendirs:
+                for try_proto in PROTOS:
+                    for with_zlib in (False, True):
+                        # skip any servers that don't work with the Zlib transport
+                        if with_zlib and try_server in SKIP_ZLIB:
+                            continue
+                        for with_ssl in (False, True):
+                            # skip any servers that don't work with SSL
+                            if with_ssl and try_server in SKIP_SSL:
+                                continue
+                            test_count += 1
+                            if self.verbose > 0:
+                                print('\nTest run #%d:  (includes %s) Server=%s,  Proto=%s,  zlib=%s,  SSL=%s'
+                                      % (test_count, genpydir, try_server, try_proto, with_zlib, with_ssl))
+                            runServiceTest(self.libdir, self.genbase, genpydir, try_server, try_proto, self.port, with_zlib, with_ssl)
+                            if self.verbose > 0:
+                                print('OK: Finished (includes %s)  %s / %s proto / zlib=%s / SSL=%s.   %d combinations tested.'
+                                      % (genpydir, try_server, try_proto, with_zlib, with_ssl, test_count))
+        return test_count
+
+
+def main():
+    parser = OptionParser()
+    parser.add_option('--all', action="store_true", dest='all')
+    parser.add_option('--genpydirs', type='string', dest='genpydirs',
+                      default='default,slots,oldstyle,no_utf8strings,dynamic,dynamicslots',
+                      help='directory extensions for generated code, used as suffixes for \"gen-py-*\" added sys.path for individual tests')
+    parser.add_option("--port", type="int", dest="port", default=9090,
+                      help="port number for server to listen on")
+    parser.add_option('-v', '--verbose', action="store_const",
+                      dest="verbose", const=2,
+                      help="verbose output")
+    parser.add_option('-q', '--quiet', action="store_const",
+                      dest="verbose", const=0,
+                      help="minimal output")
+    parser.add_option('-L', '--libdir', dest="libdir", default=local_libpath(),
+                      help="directory path that contains Thrift Python library")
+    parser.add_option('--gen-base', dest="gen_base", default=SCRIPT_DIR,
+                      help="directory path that contains Thrift Python library")
+    parser.set_defaults(verbose=1)
+    options, args = parser.parse_args()
+
+    generated_dirs = []
+    for gp_dir in options.genpydirs.split(','):
+        generated_dirs.append('gen-py-%s' % (gp_dir))
+
+    # commandline permits a single class name to be specified to override SERVERS=[...]
+    servers = default_servers()
+    if len(args) == 1:
+        if args[0] in servers:
+            servers = args
+        else:
+            print('Unavailable server type "%s", please choose one of: %s' % (args[0], servers))
+            sys.exit(0)
+
+    tests = TestCases(options.gen_base, options.libdir, options.port, generated_dirs, servers, options.verbose)
+
+    # run tests without a client/server first
+    print('----------------')
+    print(' Executing individual test scripts with various generated code directories')
+    print(' Directories to be tested: ' + ', '.join(generated_dirs))
+    print(' Scripts to be tested: ' + ', '.join(SCRIPTS))
+    print('----------------')
+    for genpydir in generated_dirs:
+        for script in SCRIPTS:
+            runScriptTest(options.libdir, options.gen_base, genpydir, script)
+
+    print('----------------')
+    print(' Executing Client/Server tests with various generated code directories')
+    print(' Servers to be tested: ' + ', '.join(servers))
+    print(' Directories to be tested: ' + ', '.join(generated_dirs))
+    print(' Protocols to be tested: ' + ', '.join(PROTOS))
+    print(' Options to be tested: ZLIB(yes/no), SSL(yes/no)')
+    print('----------------')
+
+    if options.all:
+        tests.run_all_tests()
+    else:
+        tests.test_feature('gendir', generated_dirs)
+        tests.test_feature('server', servers)
+        tests.test_feature('proto', PROTOS)
+        tests.test_feature('zlib', [False, True])
+        tests.test_feature('ssl', [False, True])
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/test/py/SerializationTest.py b/test/py/SerializationTest.py
new file mode 100755
index 0000000..ef79835
--- /dev/null
+++ b/test/py/SerializationTest.py
@@ -0,0 +1,457 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from ThriftTest.ttypes import (
+    Bonk,
+    Bools,
+    LargeDeltas,
+    ListBonks,
+    NestedListsBonk,
+    NestedListsI32x2,
+    NestedListsI32x3,
+    NestedMixedx2,
+    Numberz,
+    VersioningTestV1,
+    VersioningTestV2,
+    Xtruct,
+    Xtruct2,
+)
+
+from Recursive.ttypes import RecTree
+from Recursive.ttypes import RecList
+from Recursive.ttypes import CoRec
+from Recursive.ttypes import CoRec2
+from Recursive.ttypes import VectorTest
+from DebugProtoTest.ttypes import CompactProtoTestStruct, Empty
+from thrift.transport import TTransport
+from thrift.protocol import TBinaryProtocol, TCompactProtocol, TJSONProtocol
+from thrift.TSerialization import serialize, deserialize
+import sys
+import unittest
+
+
+class AbstractTest(unittest.TestCase):
+
+    def setUp(self):
+        self.v1obj = VersioningTestV1(
+            begin_in_both=12345,
+            old_string='aaa',
+            end_in_both=54321,
+        )
+
+        self.v2obj = VersioningTestV2(
+            begin_in_both=12345,
+            newint=1,
+            newbyte=2,
+            newshort=3,
+            newlong=4,
+            newdouble=5.0,
+            newstruct=Bonk(message="Hello!", type=123),
+            newlist=[7, 8, 9],
+            newset=set([42, 1, 8]),
+            newmap={1: 2, 2: 3},
+            newstring="Hola!",
+            end_in_both=54321,
+        )
+
+        self.bools = Bools(im_true=True, im_false=False)
+        self.bools_flipped = Bools(im_true=False, im_false=True)
+
+        self.large_deltas = LargeDeltas(
+            b1=self.bools,
+            b10=self.bools_flipped,
+            b100=self.bools,
+            check_true=True,
+            b1000=self.bools_flipped,
+            check_false=False,
+            vertwo2000=VersioningTestV2(newstruct=Bonk(message='World!', type=314)),
+            a_set2500=set(['lazy', 'brown', 'cow']),
+            vertwo3000=VersioningTestV2(newset=set([2, 3, 5, 7, 11])),
+            big_numbers=[2 ** 8, 2 ** 16, 2 ** 31 - 1, -(2 ** 31 - 1)]
+        )
+
+        self.compact_struct = CompactProtoTestStruct(
+            a_byte=127,
+            a_i16=32000,
+            a_i32=1000000000,
+            a_i64=0xffffffffff,
+            a_double=5.6789,
+            a_string="my string",
+            true_field=True,
+            false_field=False,
+            empty_struct_field=Empty(),
+            byte_list=[-127, -1, 0, 1, 127],
+            i16_list=[-1, 0, 1, 0x7fff],
+            i32_list=[-1, 0, 0xff, 0xffff, 0xffffff, 0x7fffffff],
+            i64_list=[-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff],
+            double_list=[0.1, 0.2, 0.3],
+            string_list=["first", "second", "third"],
+            boolean_list=[True, True, True, False, False, False],
+            struct_list=[Empty(), Empty()],
+            byte_set=set([-127, -1, 0, 1, 127]),
+            i16_set=set([-1, 0, 1, 0x7fff]),
+            i32_set=set([1, 2, 3]),
+            i64_set=set([-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff]),
+            double_set=set([0.1, 0.2, 0.3]),
+            string_set=set(["first", "second", "third"]),
+            boolean_set=set([True, False]),
+            # struct_set=set([Empty()]), # unhashable instance
+            byte_byte_map={1: 2},
+            i16_byte_map={1: 1, -1: 1, 0x7fff: 1},
+            i32_byte_map={1: 1, -1: 1, 0x7fffffff: 1},
+            i64_byte_map={0: 1, 1: 1, -1: 1, 0x7fffffffffffffff: 1},
+            double_byte_map={-1.1: 1, 1.1: 1},
+            string_byte_map={"first": 1, "second": 2, "third": 3, "": 0},
+            boolean_byte_map={True: 1, False: 0},
+            byte_i16_map={1: 1, 2: -1, 3: 0x7fff},
+            byte_i32_map={1: 1, 2: -1, 3: 0x7fffffff},
+            byte_i64_map={1: 1, 2: -1, 3: 0x7fffffffffffffff},
+            byte_double_map={1: 0.1, 2: -0.1, 3: 1000000.1},
+            byte_string_map={1: "", 2: "blah", 3: "loooooooooooooong string"},
+            byte_boolean_map={1: True, 2: False},
+            # list_byte_map # unhashable
+            # set_byte_map={set([1, 2, 3]) : 1, set([0, 1]) : 2, set([]) : 0}, # unhashable
+            # map_byte_map # unhashable
+            byte_map_map={0: {}, 1: {1: 1}, 2: {1: 1, 2: 2}},
+            byte_set_map={0: set([]), 1: set([1]), 2: set([1, 2])},
+            byte_list_map={0: [], 1: [1], 2: [1, 2]},
+        )
+
+        self.nested_lists_i32x2 = NestedListsI32x2(
+            [
+                [1, 1, 2],
+                [2, 7, 9],
+                [3, 5, 8]
+            ]
+        )
+
+        self.nested_lists_i32x3 = NestedListsI32x3(
+            [
+                [
+                    [2, 7, 9],
+                    [3, 5, 8]
+                ],
+                [
+                    [1, 1, 2],
+                    [1, 4, 9]
+                ]
+            ]
+        )
+
+        self.nested_mixedx2 = NestedMixedx2(int_set_list=[
+            set([1, 2, 3]),
+            set([1, 4, 9]),
+            set([1, 2, 3, 5, 8, 13, 21]),
+            set([-1, 0, 1])
+        ],
+            # note, the sets below are sets of chars, since the strings are iterated
+            map_int_strset={10: set('abc'), 20: set('def'), 30: set('GHI')},
+            map_int_strset_list=[
+                {10: set('abc'), 20: set('def'), 30: set('GHI')},
+                {100: set('lmn'), 200: set('opq'), 300: set('RST')},
+                {1000: set('uvw'), 2000: set('wxy'), 3000: set('XYZ')}]
+        )
+
+        self.nested_lists_bonk = NestedListsBonk(
+            [
+                [
+                    [
+                        Bonk(message='inner A first', type=1),
+                        Bonk(message='inner A second', type=1)
+                    ],
+                    [
+                        Bonk(message='inner B first', type=2),
+                        Bonk(message='inner B second', type=2)
+                    ]
+                ]
+            ]
+        )
+
+        self.list_bonks = ListBonks(
+            [
+                Bonk(message='inner A', type=1),
+                Bonk(message='inner B', type=2),
+                Bonk(message='inner C', type=0)
+            ]
+        )
+
+    def _serialize(self, obj):
+        trans = TTransport.TMemoryBuffer()
+        prot = self.protocol_factory.getProtocol(trans)
+        obj.write(prot)
+        return trans.getvalue()
+
+    def _deserialize(self, objtype, data):
+        prot = self.protocol_factory.getProtocol(TTransport.TMemoryBuffer(data))
+        ret = objtype()
+        ret.read(prot)
+        return ret
+
+    def testForwards(self):
+        obj = self._deserialize(VersioningTestV2, self._serialize(self.v1obj))
+        self.assertEquals(obj.begin_in_both, self.v1obj.begin_in_both)
+        self.assertEquals(obj.end_in_both, self.v1obj.end_in_both)
+
+    def testBackwards(self):
+        obj = self._deserialize(VersioningTestV1, self._serialize(self.v2obj))
+        self.assertEquals(obj.begin_in_both, self.v2obj.begin_in_both)
+        self.assertEquals(obj.end_in_both, self.v2obj.end_in_both)
+
+    def testSerializeV1(self):
+        obj = self._deserialize(VersioningTestV1, self._serialize(self.v1obj))
+        self.assertEquals(obj, self.v1obj)
+
+    def testSerializeV2(self):
+        obj = self._deserialize(VersioningTestV2, self._serialize(self.v2obj))
+        self.assertEquals(obj, self.v2obj)
+
+    def testBools(self):
+        self.assertNotEquals(self.bools, self.bools_flipped)
+        self.assertNotEquals(self.bools, self.v1obj)
+        obj = self._deserialize(Bools, self._serialize(self.bools))
+        self.assertEquals(obj, self.bools)
+        obj = self._deserialize(Bools, self._serialize(self.bools_flipped))
+        self.assertEquals(obj, self.bools_flipped)
+        rep = repr(self.bools)
+        self.assertTrue(len(rep) > 0)
+
+    def testLargeDeltas(self):
+        # test large field deltas (meaningful in CompactProto only)
+        obj = self._deserialize(LargeDeltas, self._serialize(self.large_deltas))
+        self.assertEquals(obj, self.large_deltas)
+        rep = repr(self.large_deltas)
+        self.assertTrue(len(rep) > 0)
+
+    def testNestedListsI32x2(self):
+        obj = self._deserialize(NestedListsI32x2, self._serialize(self.nested_lists_i32x2))
+        self.assertEquals(obj, self.nested_lists_i32x2)
+        rep = repr(self.nested_lists_i32x2)
+        self.assertTrue(len(rep) > 0)
+
+    def testNestedListsI32x3(self):
+        obj = self._deserialize(NestedListsI32x3, self._serialize(self.nested_lists_i32x3))
+        self.assertEquals(obj, self.nested_lists_i32x3)
+        rep = repr(self.nested_lists_i32x3)
+        self.assertTrue(len(rep) > 0)
+
+    def testNestedMixedx2(self):
+        obj = self._deserialize(NestedMixedx2, self._serialize(self.nested_mixedx2))
+        self.assertEquals(obj, self.nested_mixedx2)
+        rep = repr(self.nested_mixedx2)
+        self.assertTrue(len(rep) > 0)
+
+    def testNestedListsBonk(self):
+        obj = self._deserialize(NestedListsBonk, self._serialize(self.nested_lists_bonk))
+        self.assertEquals(obj, self.nested_lists_bonk)
+        rep = repr(self.nested_lists_bonk)
+        self.assertTrue(len(rep) > 0)
+
+    def testListBonks(self):
+        obj = self._deserialize(ListBonks, self._serialize(self.list_bonks))
+        self.assertEquals(obj, self.list_bonks)
+        rep = repr(self.list_bonks)
+        self.assertTrue(len(rep) > 0)
+
+    def testCompactStruct(self):
+        # test large field deltas (meaningful in CompactProto only)
+        obj = self._deserialize(CompactProtoTestStruct, self._serialize(self.compact_struct))
+        self.assertEquals(obj, self.compact_struct)
+        rep = repr(self.compact_struct)
+        self.assertTrue(len(rep) > 0)
+
+    def testIntegerLimits(self):
+        if (sys.version_info[0] == 2 and sys.version_info[1] <= 6):
+            print('Skipping testIntegerLimits for Python 2.6')
+            return
+        bad_values = [CompactProtoTestStruct(a_byte=128), CompactProtoTestStruct(a_byte=-129),
+                      CompactProtoTestStruct(a_i16=32768), CompactProtoTestStruct(a_i16=-32769),
+                      CompactProtoTestStruct(a_i32=2147483648), CompactProtoTestStruct(a_i32=-2147483649),
+                      CompactProtoTestStruct(a_i64=9223372036854775808), CompactProtoTestStruct(a_i64=-9223372036854775809)
+                      ]
+
+        for value in bad_values:
+            self.assertRaises(Exception, self._serialize, value)
+
+    def testRecTree(self):
+        """Ensure recursive tree node can be created."""
+        children = []
+        for idx in range(1, 5):
+            node = RecTree(item=idx, children=None)
+            children.append(node)
+
+        parent = RecTree(item=0, children=children)
+        serde_parent = self._deserialize(RecTree, self._serialize(parent))
+        self.assertEquals(0, serde_parent.item)
+        self.assertEquals(4, len(serde_parent.children))
+        for child in serde_parent.children:
+            # Cannot use assertIsInstance in python 2.6?
+            self.assertTrue(isinstance(child, RecTree))
+
+    def _buildLinkedList(self):
+        head = cur = RecList(item=0)
+        for idx in range(1, 5):
+            node = RecList(item=idx)
+            cur.nextitem = node
+            cur = node
+        return head
+
+    def _collapseLinkedList(self, head):
+        out_list = []
+        cur = head
+        while cur is not None:
+            out_list.append(cur.item)
+            cur = cur.nextitem
+        return out_list
+
+    def testRecList(self):
+        """Ensure recursive linked list can be created."""
+        rec_list = self._buildLinkedList()
+        serde_list = self._deserialize(RecList, self._serialize(rec_list))
+        out_list = self._collapseLinkedList(serde_list)
+        self.assertEquals([0, 1, 2, 3, 4], out_list)
+
+    def testCoRec(self):
+        """Ensure co-recursive structures can be created."""
+        item1 = CoRec()
+        item2 = CoRec2()
+
+        item1.other = item2
+        item2.other = item1
+
+        # NOTE [econner724,2017-06-21]: These objects cannot be serialized as serialization
+        # results in an infinite loop. fbthrift also suffers from this
+        # problem.
+
+    def testRecVector(self):
+        """Ensure a list of recursive nodes can be created."""
+        mylist = [self._buildLinkedList(), self._buildLinkedList()]
+        myvec = VectorTest(lister=mylist)
+
+        serde_vec = self._deserialize(VectorTest, self._serialize(myvec))
+        golden_list = [0, 1, 2, 3, 4]
+        for cur_list in serde_vec.lister:
+            out_list = self._collapseLinkedList(cur_list)
+            self.assertEqual(golden_list, out_list)
+
+
+class NormalBinaryTest(AbstractTest):
+    protocol_factory = TBinaryProtocol.TBinaryProtocolFactory()
+
+
+class AcceleratedBinaryTest(AbstractTest):
+    protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False)
+
+
+class CompactProtocolTest(AbstractTest):
+    protocol_factory = TCompactProtocol.TCompactProtocolFactory()
+
+
+class AcceleratedCompactTest(AbstractTest):
+    protocol_factory = TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False)
+
+
+class JSONProtocolTest(AbstractTest):
+    protocol_factory = TJSONProtocol.TJSONProtocolFactory()
+
+
+class AcceleratedFramedTest(unittest.TestCase):
+    def testSplit(self):
+        """Test FramedTransport and BinaryProtocolAccelerated
+
+        Tests that TBinaryProtocolAccelerated and TFramedTransport
+        play nicely together when a read spans a frame"""
+
+        protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory()
+        bigstring = "".join(chr(byte) for byte in range(ord("a"), ord("z") + 1))
+
+        databuf = TTransport.TMemoryBuffer()
+        prot = protocol_factory.getProtocol(databuf)
+        prot.writeI32(42)
+        prot.writeString(bigstring)
+        prot.writeI16(24)
+        data = databuf.getvalue()
+        cutpoint = len(data) // 2
+        parts = [data[:cutpoint], data[cutpoint:]]
+
+        framed_buffer = TTransport.TMemoryBuffer()
+        framed_writer = TTransport.TFramedTransport(framed_buffer)
+        for part in parts:
+            framed_writer.write(part)
+            framed_writer.flush()
+        self.assertEquals(len(framed_buffer.getvalue()), len(data) + 8)
+
+        # Recreate framed_buffer so we can read from it.
+        framed_buffer = TTransport.TMemoryBuffer(framed_buffer.getvalue())
+        framed_reader = TTransport.TFramedTransport(framed_buffer)
+        prot = protocol_factory.getProtocol(framed_reader)
+        self.assertEqual(prot.readI32(), 42)
+        self.assertEqual(prot.readString(), bigstring)
+        self.assertEqual(prot.readI16(), 24)
+
+
+class SerializersTest(unittest.TestCase):
+
+    def testSerializeThenDeserialize(self):
+        obj = Xtruct2(i32_thing=1,
+                      struct_thing=Xtruct(string_thing="foo"))
+
+        s1 = serialize(obj)
+        for i in range(10):
+            self.assertEquals(s1, serialize(obj))
+            objcopy = Xtruct2()
+            deserialize(objcopy, serialize(obj))
+            self.assertEquals(obj, objcopy)
+
+        obj = Xtruct(string_thing="bar")
+        objcopy = Xtruct()
+        deserialize(objcopy, serialize(obj))
+        self.assertEquals(obj, objcopy)
+
+        # test booleans
+        obj = Bools(im_true=True, im_false=False)
+        objcopy = Bools()
+        deserialize(objcopy, serialize(obj))
+        self.assertEquals(obj, objcopy)
+
+        # test enums
+        for num, name in Numberz._VALUES_TO_NAMES.items():
+            obj = Bonk(message='enum Numberz value %d is string %s' % (num, name), type=num)
+            objcopy = Bonk()
+            deserialize(objcopy, serialize(obj))
+            self.assertEquals(obj, objcopy)
+
+
+def suite():
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
+
+    suite.addTest(loader.loadTestsFromTestCase(NormalBinaryTest))
+    suite.addTest(loader.loadTestsFromTestCase(AcceleratedBinaryTest))
+    suite.addTest(loader.loadTestsFromTestCase(AcceleratedCompactTest))
+    suite.addTest(loader.loadTestsFromTestCase(CompactProtocolTest))
+    suite.addTest(loader.loadTestsFromTestCase(JSONProtocolTest))
+    suite.addTest(loader.loadTestsFromTestCase(AcceleratedFramedTest))
+    suite.addTest(loader.loadTestsFromTestCase(SerializersTest))
+    return suite
+
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
diff --git a/test/py/TSimpleJSONProtocolTest.py b/test/py/TSimpleJSONProtocolTest.py
new file mode 100644
index 0000000..7298760
--- /dev/null
+++ b/test/py/TSimpleJSONProtocolTest.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from ThriftTest.ttypes import Bonk, VersioningTestV1, VersioningTestV2
+from thrift.protocol import TJSONProtocol
+from thrift.transport import TTransport
+
+import json
+import unittest
+
+
+class SimpleJSONProtocolTest(unittest.TestCase):
+    protocol_factory = TJSONProtocol.TSimpleJSONProtocolFactory()
+
+    def _assertDictEqual(self, a, b, msg=None):
+        if hasattr(self, 'assertDictEqual'):
+            # assertDictEqual only in Python 2.7. Depends on your machine.
+            self.assertDictEqual(a, b, msg)
+            return
+
+        # Substitute implementation not as good as unittest library's
+        self.assertEquals(len(a), len(b), msg)
+        for k, v in a.iteritems():
+            self.assertTrue(k in b, msg)
+            self.assertEquals(b.get(k), v, msg)
+
+    def _serialize(self, obj):
+        trans = TTransport.TMemoryBuffer()
+        prot = self.protocol_factory.getProtocol(trans)
+        obj.write(prot)
+        return trans.getvalue()
+
+    def _deserialize(self, objtype, data):
+        prot = self.protocol_factory.getProtocol(TTransport.TMemoryBuffer(data))
+        ret = objtype()
+        ret.read(prot)
+        return ret
+
+    def testWriteOnly(self):
+        self.assertRaises(NotImplementedError,
+                          self._deserialize, VersioningTestV1, b'{}')
+
+    def testSimpleMessage(self):
+        v1obj = VersioningTestV1(
+            begin_in_both=12345,
+            old_string='aaa',
+            end_in_both=54321)
+        expected = dict(begin_in_both=v1obj.begin_in_both,
+                        old_string=v1obj.old_string,
+                        end_in_both=v1obj.end_in_both)
+        actual = json.loads(self._serialize(v1obj).decode('ascii'))
+
+        self._assertDictEqual(expected, actual)
+
+    def testComplicated(self):
+        v2obj = VersioningTestV2(
+            begin_in_both=12345,
+            newint=1,
+            newbyte=2,
+            newshort=3,
+            newlong=4,
+            newdouble=5.0,
+            newstruct=Bonk(message="Hello!", type=123),
+            newlist=[7, 8, 9],
+            newset=set([42, 1, 8]),
+            newmap={1: 2, 2: 3},
+            newstring="Hola!",
+            end_in_both=54321)
+        expected = dict(begin_in_both=v2obj.begin_in_both,
+                        newint=v2obj.newint,
+                        newbyte=v2obj.newbyte,
+                        newshort=v2obj.newshort,
+                        newlong=v2obj.newlong,
+                        newdouble=v2obj.newdouble,
+                        newstruct=dict(message=v2obj.newstruct.message,
+                                       type=v2obj.newstruct.type),
+                        newlist=v2obj.newlist,
+                        newset=list(v2obj.newset),
+                        newmap=v2obj.newmap,
+                        newstring=v2obj.newstring,
+                        end_in_both=v2obj.end_in_both)
+
+        # Need to load/dump because map keys get escaped.
+        expected = json.loads(json.dumps(expected))
+        actual = json.loads(self._serialize(v2obj).decode('ascii'))
+        self._assertDictEqual(expected, actual)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/test/py/TestClient.py b/test/py/TestClient.py
new file mode 100755
index 0000000..1ab8e78
--- /dev/null
+++ b/test/py/TestClient.py
@@ -0,0 +1,349 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import os
+import sys
+import time
+import unittest
+from optparse import OptionParser
+
+from util import local_libpath
+
+SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
+
+
+class AbstractTest(unittest.TestCase):
+    def setUp(self):
+        if options.http_path:
+            self.transport = THttpClient.THttpClient(options.host, port=options.port, path=options.http_path)
+        else:
+            if options.ssl:
+                from thrift.transport import TSSLSocket
+                socket = TSSLSocket.TSSLSocket(options.host, options.port, validate=False)
+            else:
+                socket = TSocket.TSocket(options.host, options.port)
+            # frame or buffer depending upon args
+            self.transport = TTransport.TBufferedTransport(socket)
+            if options.trans == 'framed':
+                self.transport = TTransport.TFramedTransport(socket)
+            elif options.trans == 'buffered':
+                self.transport = TTransport.TBufferedTransport(socket)
+            elif options.trans == '':
+                raise AssertionError('Unknown --transport option: %s' % options.trans)
+            if options.zlib:
+                self.transport = TZlibTransport.TZlibTransport(self.transport, 9)
+        self.transport.open()
+        protocol = self.get_protocol(self.transport)
+        self.client = ThriftTest.Client(protocol)
+
+    def tearDown(self):
+        self.transport.close()
+
+    def testVoid(self):
+        print('testVoid')
+        self.client.testVoid()
+
+    def testString(self):
+        print('testString')
+        self.assertEqual(self.client.testString('Python' * 20), 'Python' * 20)
+        self.assertEqual(self.client.testString(''), '')
+        s1 = u'\b\t\n/\\\\\r{}:パイソン"'
+        s2 = u"""Afrikaans, Alemannisch, Aragonés, العربية, مصرى,
+        Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška,
+        Беларуская, Беларуская (тарашкевіца), Български, Bamanankan,
+        বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн,
+        Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg,
+        Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English,
+        Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt,
+        Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego,
+        Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski,
+        Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia,
+        Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa,
+        ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар,
+        Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino,
+        Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa
+        Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa
+        Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪
+        Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad,
+        Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو,
+        Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română,
+        Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple
+        English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk,
+        Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog,
+        Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük,
+        Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文,
+        Bân-lâm-gú, 粵語"""
+        if sys.version_info[0] == 2 and os.environ.get('THRIFT_TEST_PY_NO_UTF8STRINGS'):
+            s1 = s1.encode('utf8')
+            s2 = s2.encode('utf8')
+        self.assertEqual(self.client.testString(s1), s1)
+        self.assertEqual(self.client.testString(s2), s2)
+
+    def testBool(self):
+        print('testBool')
+        self.assertEqual(self.client.testBool(True), True)
+        self.assertEqual(self.client.testBool(False), False)
+
+    def testByte(self):
+        print('testByte')
+        self.assertEqual(self.client.testByte(63), 63)
+        self.assertEqual(self.client.testByte(-127), -127)
+
+    def testI32(self):
+        print('testI32')
+        self.assertEqual(self.client.testI32(-1), -1)
+        self.assertEqual(self.client.testI32(0), 0)
+
+    def testI64(self):
+        print('testI64')
+        self.assertEqual(self.client.testI64(1), 1)
+        self.assertEqual(self.client.testI64(-34359738368), -34359738368)
+
+    def testDouble(self):
+        print('testDouble')
+        self.assertEqual(self.client.testDouble(-5.235098235), -5.235098235)
+        self.assertEqual(self.client.testDouble(0), 0)
+        self.assertEqual(self.client.testDouble(-1), -1)
+        self.assertEqual(self.client.testDouble(-0.000341012439638598279), -0.000341012439638598279)
+
+    def testBinary(self):
+        print('testBinary')
+        val = bytearray([i for i in range(0, 256)])
+        self.assertEqual(bytearray(self.client.testBinary(bytes(val))), val)
+
+    def testStruct(self):
+        print('testStruct')
+        x = Xtruct()
+        x.string_thing = "Zero"
+        x.byte_thing = 1
+        x.i32_thing = -3
+        x.i64_thing = -5
+        y = self.client.testStruct(x)
+        self.assertEqual(y, x)
+
+    def testNest(self):
+        print('testNest')
+        inner = Xtruct(string_thing="Zero", byte_thing=1, i32_thing=-3, i64_thing=-5)
+        x = Xtruct2(struct_thing=inner, byte_thing=0, i32_thing=0)
+        y = self.client.testNest(x)
+        self.assertEqual(y, x)
+
+    def testMap(self):
+        print('testMap')
+        x = {0: 1, 1: 2, 2: 3, 3: 4, -1: -2}
+        y = self.client.testMap(x)
+        self.assertEqual(y, x)
+
+    def testSet(self):
+        print('testSet')
+        x = set([8, 1, 42])
+        y = self.client.testSet(x)
+        self.assertEqual(y, x)
+
+    def testList(self):
+        print('testList')
+        x = [1, 4, 9, -42]
+        y = self.client.testList(x)
+        self.assertEqual(y, x)
+
+    def testEnum(self):
+        print('testEnum')
+        x = Numberz.FIVE
+        y = self.client.testEnum(x)
+        self.assertEqual(y, x)
+
+    def testTypedef(self):
+        print('testTypedef')
+        x = 0xffffffffffffff  # 7 bytes of 0xff
+        y = self.client.testTypedef(x)
+        self.assertEqual(y, x)
+
+    def testMapMap(self):
+        print('testMapMap')
+        x = {
+            -4: {-4: -4, -3: -3, -2: -2, -1: -1},
+            4: {4: 4, 3: 3, 2: 2, 1: 1},
+        }
+        y = self.client.testMapMap(42)
+        self.assertEqual(y, x)
+
+    def testMulti(self):
+        print('testMulti')
+        xpected = Xtruct(string_thing='Hello2', byte_thing=74, i32_thing=0xff00ff, i64_thing=0xffffffffd0d0)
+        y = self.client.testMulti(xpected.byte_thing,
+                                  xpected.i32_thing,
+                                  xpected.i64_thing,
+                                  {0: 'abc'},
+                                  Numberz.FIVE,
+                                  0xf0f0f0)
+        self.assertEqual(y, xpected)
+
+    def testException(self):
+        print('testException')
+        self.client.testException('Safe')
+        try:
+            self.client.testException('Xception')
+            self.fail("should have gotten exception")
+        except Xception as x:
+            self.assertEqual(x.errorCode, 1001)
+            self.assertEqual(x.message, 'Xception')
+            # TODO ensure same behavior for repr within generated python variants
+            # ensure exception's repr method works
+            # x_repr = repr(x)
+            # self.assertEqual(x_repr, 'Xception(errorCode=1001, message=\'Xception\')')
+
+        try:
+            self.client.testException('TException')
+            self.fail("should have gotten exception")
+        except TException as x:
+            pass
+
+        # Should not throw
+        self.client.testException('success')
+
+    def testMultiException(self):
+        print('testMultiException')
+        try:
+            self.client.testMultiException('Xception', 'ignore')
+        except Xception as ex:
+            self.assertEqual(ex.errorCode, 1001)
+            self.assertEqual(ex.message, 'This is an Xception')
+
+        try:
+            self.client.testMultiException('Xception2', 'ignore')
+        except Xception2 as ex:
+            self.assertEqual(ex.errorCode, 2002)
+            self.assertEqual(ex.struct_thing.string_thing, 'This is an Xception2')
+
+        y = self.client.testMultiException('success', 'foobar')
+        self.assertEqual(y.string_thing, 'foobar')
+
+    def testOneway(self):
+        print('testOneway')
+        start = time.time()
+        self.client.testOneway(1)  # type is int, not float
+        end = time.time()
+        self.assertTrue(end - start < 3,
+                        "oneway sleep took %f sec" % (end - start))
+
+    def testOnewayThenNormal(self):
+        print('testOnewayThenNormal')
+        self.client.testOneway(1)  # type is int, not float
+        self.assertEqual(self.client.testString('Python'), 'Python')
+
+
+class NormalBinaryTest(AbstractTest):
+    def get_protocol(self, transport):
+        return TBinaryProtocol.TBinaryProtocolFactory().getProtocol(transport)
+
+
+class CompactTest(AbstractTest):
+    def get_protocol(self, transport):
+        return TCompactProtocol.TCompactProtocolFactory().getProtocol(transport)
+
+
+class JSONTest(AbstractTest):
+    def get_protocol(self, transport):
+        return TJSONProtocol.TJSONProtocolFactory().getProtocol(transport)
+
+
+class AcceleratedBinaryTest(AbstractTest):
+    def get_protocol(self, transport):
+        return TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False).getProtocol(transport)
+
+
+class AcceleratedCompactTest(AbstractTest):
+    def get_protocol(self, transport):
+        return TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False).getProtocol(transport)
+
+
+def suite():
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
+    if options.proto == 'binary':  # look for --proto on cmdline
+        suite.addTest(loader.loadTestsFromTestCase(NormalBinaryTest))
+    elif options.proto == 'accel':
+        suite.addTest(loader.loadTestsFromTestCase(AcceleratedBinaryTest))
+    elif options.proto == 'compact':
+        suite.addTest(loader.loadTestsFromTestCase(CompactTest))
+    elif options.proto == 'accelc':
+        suite.addTest(loader.loadTestsFromTestCase(AcceleratedCompactTest))
+    elif options.proto == 'json':
+        suite.addTest(loader.loadTestsFromTestCase(JSONTest))
+    else:
+        raise AssertionError('Unknown protocol given with --protocol: %s' % options.proto)
+    return suite
+
+
+class OwnArgsTestProgram(unittest.TestProgram):
+    def parseArgs(self, argv):
+        if args:
+            self.testNames = args
+        else:
+            self.testNames = ([self.defaultTest])
+        self.createTests()
+
+
+if __name__ == "__main__":
+    parser = OptionParser()
+    parser.add_option('--libpydir', type='string', dest='libpydir',
+                      help='include this directory in sys.path for locating library code')
+    parser.add_option('--genpydir', type='string', dest='genpydir',
+                      help='include this directory in sys.path for locating generated code')
+    parser.add_option("--port", type="int", dest="port",
+                      help="connect to server at port")
+    parser.add_option("--host", type="string", dest="host",
+                      help="connect to server")
+    parser.add_option("--zlib", action="store_true", dest="zlib",
+                      help="use zlib wrapper for compressed transport")
+    parser.add_option("--ssl", action="store_true", dest="ssl",
+                      help="use SSL for encrypted transport")
+    parser.add_option("--http", dest="http_path",
+                      help="Use the HTTP transport with the specified path")
+    parser.add_option('-v', '--verbose', action="store_const",
+                      dest="verbose", const=2,
+                      help="verbose output")
+    parser.add_option('-q', '--quiet', action="store_const",
+                      dest="verbose", const=0,
+                      help="minimal output")
+    parser.add_option('--protocol', dest="proto", type="string",
+                      help="protocol to use, one of: accel, binary, compact, json")
+    parser.add_option('--transport', dest="trans", type="string",
+                      help="transport to use, one of: buffered, framed")
+    parser.set_defaults(framed=False, http_path=None, verbose=1, host='localhost', port=9090, proto='binary')
+    options, args = parser.parse_args()
+
+    if options.genpydir:
+        sys.path.insert(0, os.path.join(SCRIPT_DIR, options.genpydir))
+    sys.path.insert(0, local_libpath())
+
+    from ThriftTest import ThriftTest
+    from ThriftTest.ttypes import Xtruct, Xtruct2, Numberz, Xception, Xception2
+    from thrift.Thrift import TException
+    from thrift.transport import TTransport
+    from thrift.transport import TSocket
+    from thrift.transport import THttpClient
+    from thrift.transport import TZlibTransport
+    from thrift.protocol import TBinaryProtocol
+    from thrift.protocol import TCompactProtocol
+    from thrift.protocol import TJSONProtocol
+
+    OwnArgsTestProgram(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=1))
diff --git a/test/py/TestEof.py b/test/py/TestEof.py
new file mode 100755
index 0000000..0b4a829
--- /dev/null
+++ b/test/py/TestEof.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from ThriftTest.ttypes import Xtruct
+from thrift.transport import TTransport
+from thrift.protocol import TBinaryProtocol
+from thrift.protocol import TCompactProtocol
+import unittest
+
+
+class TestEof(unittest.TestCase):
+
+    def make_data(self, pfactory=None):
+        trans = TTransport.TMemoryBuffer()
+        if pfactory:
+            prot = pfactory.getProtocol(trans)
+        else:
+            prot = TBinaryProtocol.TBinaryProtocol(trans)
+
+        x = Xtruct()
+        x.string_thing = "Zero"
+        x.byte_thing = 0
+
+        x.write(prot)
+
+        x = Xtruct()
+        x.string_thing = "One"
+        x.byte_thing = 1
+
+        x.write(prot)
+
+        return trans.getvalue()
+
+    def testTransportReadAll(self):
+        """Test that readAll on any type of transport throws an EOFError"""
+        trans = TTransport.TMemoryBuffer(self.make_data())
+        trans.readAll(1)
+
+        try:
+            trans.readAll(10000)
+        except EOFError:
+            return
+
+        self.fail("Should have gotten EOFError")
+
+    def eofTestHelper(self, pfactory):
+        trans = TTransport.TMemoryBuffer(self.make_data(pfactory))
+        prot = pfactory.getProtocol(trans)
+
+        x = Xtruct()
+        x.read(prot)
+        self.assertEqual(x.string_thing, "Zero")
+        self.assertEqual(x.byte_thing, 0)
+
+        x = Xtruct()
+        x.read(prot)
+        self.assertEqual(x.string_thing, "One")
+        self.assertEqual(x.byte_thing, 1)
+
+        try:
+            x = Xtruct()
+            x.read(prot)
+        except EOFError:
+            return
+
+        self.fail("Should have gotten EOFError")
+
+    def eofTestHelperStress(self, pfactory):
+        """Test the ability of TBinaryProtocol to deal with the removal of every byte in the file"""
+        # TODO: we should make sure this covers more of the code paths
+
+        data = self.make_data(pfactory)
+        for i in range(0, len(data) + 1):
+            trans = TTransport.TMemoryBuffer(data[0:i])
+            prot = pfactory.getProtocol(trans)
+            try:
+                x = Xtruct()
+                x.read(prot)
+                x.read(prot)
+                x.read(prot)
+            except EOFError:
+                continue
+            self.fail("Should have gotten an EOFError")
+
+    def testBinaryProtocolEof(self):
+        """Test that TBinaryProtocol throws an EOFError when it reaches the end of the stream"""
+        self.eofTestHelper(TBinaryProtocol.TBinaryProtocolFactory())
+        self.eofTestHelperStress(TBinaryProtocol.TBinaryProtocolFactory())
+
+    def testBinaryProtocolAcceleratedBinaryEof(self):
+        """Test that TBinaryProtocolAccelerated throws an EOFError when it reaches the end of the stream"""
+        self.eofTestHelper(TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False))
+        self.eofTestHelperStress(TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False))
+
+    def testCompactProtocolEof(self):
+        """Test that TCompactProtocol throws an EOFError when it reaches the end of the stream"""
+        self.eofTestHelper(TCompactProtocol.TCompactProtocolFactory())
+        self.eofTestHelperStress(TCompactProtocol.TCompactProtocolFactory())
+
+    def testCompactProtocolAcceleratedCompactEof(self):
+        """Test that TCompactProtocolAccelerated throws an EOFError when it reaches the end of the stream"""
+        self.eofTestHelper(TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False))
+        self.eofTestHelperStress(TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False))
+
+
+def suite():
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
+    suite.addTest(loader.loadTestsFromTestCase(TestEof))
+    return suite
+
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
diff --git a/test/py/TestFrozen.py b/test/py/TestFrozen.py
new file mode 100755
index 0000000..6d2595c
--- /dev/null
+++ b/test/py/TestFrozen.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from DebugProtoTest.ttypes import CompactProtoTestStruct, Empty, Wrapper
+from thrift.Thrift import TFrozenDict
+from thrift.transport import TTransport
+from thrift.protocol import TBinaryProtocol, TCompactProtocol
+import collections
+import unittest
+
+
+class TestFrozenBase(unittest.TestCase):
+    def _roundtrip(self, src, dst):
+        otrans = TTransport.TMemoryBuffer()
+        optoro = self.protocol(otrans)
+        src.write(optoro)
+        itrans = TTransport.TMemoryBuffer(otrans.getvalue())
+        iproto = self.protocol(itrans)
+        return dst.read(iproto) or dst
+
+    def test_dict_is_hashable_only_after_frozen(self):
+        d0 = {}
+        self.assertFalse(isinstance(d0, collections.Hashable))
+        d1 = TFrozenDict(d0)
+        self.assertTrue(isinstance(d1, collections.Hashable))
+
+    def test_struct_with_collection_fields(self):
+        pass
+
+    def test_set(self):
+        """Test that annotated set field can be serialized and deserialized"""
+        x = CompactProtoTestStruct(set_byte_map={
+            frozenset([42, 100, -100]): 99,
+            frozenset([0]): 100,
+            frozenset([]): 0,
+        })
+        x2 = self._roundtrip(x, CompactProtoTestStruct())
+        self.assertEqual(x2.set_byte_map[frozenset([42, 100, -100])], 99)
+        self.assertEqual(x2.set_byte_map[frozenset([0])], 100)
+        self.assertEqual(x2.set_byte_map[frozenset([])], 0)
+
+    def test_map(self):
+        """Test that annotated map field can be serialized and deserialized"""
+        x = CompactProtoTestStruct(map_byte_map={
+            TFrozenDict({42: 42, 100: -100}): 99,
+            TFrozenDict({0: 0}): 100,
+            TFrozenDict({}): 0,
+        })
+        x2 = self._roundtrip(x, CompactProtoTestStruct())
+        self.assertEqual(x2.map_byte_map[TFrozenDict({42: 42, 100: -100})], 99)
+        self.assertEqual(x2.map_byte_map[TFrozenDict({0: 0})], 100)
+        self.assertEqual(x2.map_byte_map[TFrozenDict({})], 0)
+
+    def test_list(self):
+        """Test that annotated list field can be serialized and deserialized"""
+        x = CompactProtoTestStruct(list_byte_map={
+            (42, 100, -100): 99,
+            (0,): 100,
+            (): 0,
+        })
+        x2 = self._roundtrip(x, CompactProtoTestStruct())
+        self.assertEqual(x2.list_byte_map[(42, 100, -100)], 99)
+        self.assertEqual(x2.list_byte_map[(0,)], 100)
+        self.assertEqual(x2.list_byte_map[()], 0)
+
+    def test_empty_struct(self):
+        """Test that annotated empty struct can be serialized and deserialized"""
+        x = CompactProtoTestStruct(empty_struct_field=Empty())
+        x2 = self._roundtrip(x, CompactProtoTestStruct())
+        self.assertEqual(x2.empty_struct_field, Empty())
+
+    def test_struct(self):
+        """Test that annotated struct can be serialized and deserialized"""
+        x = Wrapper(foo=Empty())
+        self.assertEqual(x.foo, Empty())
+        x2 = self._roundtrip(x, Wrapper)
+        self.assertEqual(x2.foo, Empty())
+
+
+class TestFrozen(TestFrozenBase):
+    def protocol(self, trans):
+        return TBinaryProtocol.TBinaryProtocolFactory().getProtocol(trans)
+
+
+class TestFrozenAcceleratedBinary(TestFrozenBase):
+    def protocol(self, trans):
+        return TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False).getProtocol(trans)
+
+
+class TestFrozenAcceleratedCompact(TestFrozenBase):
+    def protocol(self, trans):
+        return TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False).getProtocol(trans)
+
+
+def suite():
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
+    suite.addTest(loader.loadTestsFromTestCase(TestFrozen))
+    suite.addTest(loader.loadTestsFromTestCase(TestFrozenAcceleratedBinary))
+    suite.addTest(loader.loadTestsFromTestCase(TestFrozenAcceleratedCompact))
+    return suite
+
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
diff --git a/test/py/TestServer.py b/test/py/TestServer.py
new file mode 100755
index 0000000..04ad62a
--- /dev/null
+++ b/test/py/TestServer.py
@@ -0,0 +1,316 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+from __future__ import division
+import logging
+import os
+import sys
+import time
+from optparse import OptionParser
+
+from util import local_libpath
+
+SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
+
+
+class TestHandler(object):
+    def testVoid(self):
+        if options.verbose > 1:
+            logging.info('testVoid()')
+
+    def testString(self, str):
+        if options.verbose > 1:
+            logging.info('testString(%s)' % str)
+        return str
+
+    def testBool(self, boolean):
+        if options.verbose > 1:
+            logging.info('testBool(%s)' % str(boolean).lower())
+        return boolean
+
+    def testByte(self, byte):
+        if options.verbose > 1:
+            logging.info('testByte(%d)' % byte)
+        return byte
+
+    def testI16(self, i16):
+        if options.verbose > 1:
+            logging.info('testI16(%d)' % i16)
+        return i16
+
+    def testI32(self, i32):
+        if options.verbose > 1:
+            logging.info('testI32(%d)' % i32)
+        return i32
+
+    def testI64(self, i64):
+        if options.verbose > 1:
+            logging.info('testI64(%d)' % i64)
+        return i64
+
+    def testDouble(self, dub):
+        if options.verbose > 1:
+            logging.info('testDouble(%f)' % dub)
+        return dub
+
+    def testBinary(self, thing):
+        if options.verbose > 1:
+            logging.info('testBinary()')  # TODO: hex output
+        return thing
+
+    def testStruct(self, thing):
+        if options.verbose > 1:
+            logging.info('testStruct({%s, %s, %s, %s})' % (thing.string_thing, thing.byte_thing, thing.i32_thing, thing.i64_thing))
+        return thing
+
+    def testException(self, arg):
+        # if options.verbose > 1:
+        logging.info('testException(%s)' % arg)
+        if arg == 'Xception':
+            raise Xception(errorCode=1001, message=arg)
+        elif arg == 'TException':
+            raise TException(message='This is a TException')
+
+    def testMultiException(self, arg0, arg1):
+        if options.verbose > 1:
+            logging.info('testMultiException(%s, %s)' % (arg0, arg1))
+        if arg0 == 'Xception':
+            raise Xception(errorCode=1001, message='This is an Xception')
+        elif arg0 == 'Xception2':
+            raise Xception2(
+                errorCode=2002,
+                struct_thing=Xtruct(string_thing='This is an Xception2'))
+        return Xtruct(string_thing=arg1)
+
+    def testOneway(self, seconds):
+        if options.verbose > 1:
+            logging.info('testOneway(%d) => sleeping...' % seconds)
+        time.sleep(seconds / 3)  # be quick
+        if options.verbose > 1:
+            logging.info('done sleeping')
+
+    def testNest(self, thing):
+        if options.verbose > 1:
+            logging.info('testNest(%s)' % thing)
+        return thing
+
+    def testMap(self, thing):
+        if options.verbose > 1:
+            logging.info('testMap(%s)' % thing)
+        return thing
+
+    def testStringMap(self, thing):
+        if options.verbose > 1:
+            logging.info('testStringMap(%s)' % thing)
+        return thing
+
+    def testSet(self, thing):
+        if options.verbose > 1:
+            logging.info('testSet(%s)' % thing)
+        return thing
+
+    def testList(self, thing):
+        if options.verbose > 1:
+            logging.info('testList(%s)' % thing)
+        return thing
+
+    def testEnum(self, thing):
+        if options.verbose > 1:
+            logging.info('testEnum(%s)' % thing)
+        return thing
+
+    def testTypedef(self, thing):
+        if options.verbose > 1:
+            logging.info('testTypedef(%s)' % thing)
+        return thing
+
+    def testMapMap(self, thing):
+        if options.verbose > 1:
+            logging.info('testMapMap(%s)' % thing)
+        return {
+            -4: {
+                -4: -4,
+                -3: -3,
+                -2: -2,
+                -1: -1,
+            },
+            4: {
+                4: 4,
+                3: 3,
+                2: 2,
+                1: 1,
+            },
+        }
+
+    def testInsanity(self, argument):
+        if options.verbose > 1:
+            logging.info('testInsanity(%s)' % argument)
+        return {
+            1: {
+                2: argument,
+                3: argument,
+            },
+            2: {6: Insanity()},
+        }
+
+    def testMulti(self, arg0, arg1, arg2, arg3, arg4, arg5):
+        if options.verbose > 1:
+            logging.info('testMulti(%s)' % [arg0, arg1, arg2, arg3, arg4, arg5])
+        return Xtruct(string_thing='Hello2',
+                      byte_thing=arg0, i32_thing=arg1, i64_thing=arg2)
+
+
+def main(options):
+    # set up the protocol factory form the --protocol option
+    prot_factories = {
+        'binary': TBinaryProtocol.TBinaryProtocolFactory,
+        'accel': TBinaryProtocol.TBinaryProtocolAcceleratedFactory,
+        'compact': TCompactProtocol.TCompactProtocolFactory,
+        'accelc': TCompactProtocol.TCompactProtocolAcceleratedFactory,
+        'json': TJSONProtocol.TJSONProtocolFactory,
+    }
+    pfactory_cls = prot_factories.get(options.proto, None)
+    if pfactory_cls is None:
+        raise AssertionError('Unknown --protocol option: %s' % options.proto)
+    pfactory = pfactory_cls()
+    try:
+        pfactory.string_length_limit = options.string_limit
+        pfactory.container_length_limit = options.container_limit
+    except Exception:
+        # Ignore errors for those protocols that does not support length limit
+        pass
+
+    # get the server type (TSimpleServer, TNonblockingServer, etc...)
+    if len(args) > 1:
+        raise AssertionError('Only one server type may be specified, not multiple types.')
+    server_type = args[0]
+
+    # Set up the handler and processor objects
+    handler = TestHandler()
+    processor = ThriftTest.Processor(handler)
+
+    # Handle THttpServer as a special case
+    if server_type == 'THttpServer':
+        server = THttpServer.THttpServer(processor, ('', options.port), pfactory)
+        server.serve()
+        sys.exit(0)
+
+    # set up server transport and transport factory
+
+    abs_key_path = os.path.join(os.path.dirname(SCRIPT_DIR), 'keys', 'server.pem')
+
+    host = None
+    if options.ssl:
+        from thrift.transport import TSSLSocket
+        transport = TSSLSocket.TSSLServerSocket(host, options.port, certfile=abs_key_path)
+    else:
+        transport = TSocket.TServerSocket(host, options.port)
+    tfactory = TTransport.TBufferedTransportFactory()
+    if options.trans == 'buffered':
+        tfactory = TTransport.TBufferedTransportFactory()
+    elif options.trans == 'framed':
+        tfactory = TTransport.TFramedTransportFactory()
+    elif options.trans == '':
+        raise AssertionError('Unknown --transport option: %s' % options.trans)
+    else:
+        tfactory = TTransport.TBufferedTransportFactory()
+    # if --zlib, then wrap server transport, and use a different transport factory
+    if options.zlib:
+        transport = TZlibTransport.TZlibTransport(transport)  # wrap  with zlib
+        tfactory = TZlibTransport.TZlibTransportFactory()
+
+    # do server-specific setup here:
+    if server_type == "TNonblockingServer":
+        server = TNonblockingServer.TNonblockingServer(processor, transport, inputProtocolFactory=pfactory)
+    elif server_type == "TProcessPoolServer":
+        import signal
+        from thrift.server import TProcessPoolServer
+        server = TProcessPoolServer.TProcessPoolServer(processor, transport, tfactory, pfactory)
+        server.setNumWorkers(5)
+
+        def set_alarm():
+            def clean_shutdown(signum, frame):
+                for worker in server.workers:
+                    if options.verbose > 0:
+                        logging.info('Terminating worker: %s' % worker)
+                    worker.terminate()
+                if options.verbose > 0:
+                    logging.info('Requesting server to stop()')
+                try:
+                    server.stop()
+                except Exception:
+                    pass
+            signal.signal(signal.SIGALRM, clean_shutdown)
+            signal.alarm(4)
+        set_alarm()
+    else:
+        # look up server class dynamically to instantiate server
+        ServerClass = getattr(TServer, server_type)
+        server = ServerClass(processor, transport, tfactory, pfactory)
+    # enter server main loop
+    server.serve()
+
+
+if __name__ == '__main__':
+    parser = OptionParser()
+    parser.add_option('--libpydir', type='string', dest='libpydir',
+                      help='include this directory to sys.path for locating library code')
+    parser.add_option('--genpydir', type='string', dest='genpydir',
+                      default='gen-py',
+                      help='include this directory to sys.path for locating generated code')
+    parser.add_option("--port", type="int", dest="port",
+                      help="port number for server to listen on")
+    parser.add_option("--zlib", action="store_true", dest="zlib",
+                      help="use zlib wrapper for compressed transport")
+    parser.add_option("--ssl", action="store_true", dest="ssl",
+                      help="use SSL for encrypted transport")
+    parser.add_option('-v', '--verbose', action="store_const",
+                      dest="verbose", const=2,
+                      help="verbose output")
+    parser.add_option('-q', '--quiet', action="store_const",
+                      dest="verbose", const=0,
+                      help="minimal output")
+    parser.add_option('--protocol', dest="proto", type="string",
+                      help="protocol to use, one of: accel, binary, compact, json")
+    parser.add_option('--transport', dest="trans", type="string",
+                      help="transport to use, one of: buffered, framed")
+    parser.add_option('--container-limit', dest='container_limit', type='int', default=None)
+    parser.add_option('--string-limit', dest='string_limit', type='int', default=None)
+    parser.set_defaults(port=9090, verbose=1, proto='binary')
+    options, args = parser.parse_args()
+
+    # Print TServer log to stdout so that the test-runner can redirect it to log files
+    logging.basicConfig(level=options.verbose)
+
+    sys.path.insert(0, os.path.join(SCRIPT_DIR, options.genpydir))
+    sys.path.insert(0, local_libpath())
+
+    from ThriftTest import ThriftTest
+    from ThriftTest.ttypes import Xtruct, Xception, Xception2, Insanity
+    from thrift.Thrift import TException
+    from thrift.transport import TTransport
+    from thrift.transport import TSocket
+    from thrift.transport import TZlibTransport
+    from thrift.protocol import TBinaryProtocol
+    from thrift.protocol import TCompactProtocol
+    from thrift.protocol import TJSONProtocol
+    from thrift.server import TServer, TNonblockingServer, THttpServer
+
+    sys.exit(main(options))
diff --git a/test/py/TestSocket.py b/test/py/TestSocket.py
new file mode 100755
index 0000000..619eb10
--- /dev/null
+++ b/test/py/TestSocket.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from thrift.transport import TSocket
+import unittest
+import time
+import socket
+import random
+
+
+class TimeoutTest(unittest.TestCase):
+    def setUp(self):
+        for i in range(50):
+            try:
+                # find a port we can use
+                self.listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                self.port = random.randint(10000, 30000)
+                self.listen_sock.bind(('localhost', self.port))
+                self.listen_sock.listen(5)
+                break
+            except Exception:
+                if i == 49:
+                    raise
+
+    def testConnectTimeout(self):
+        starttime = time.time()
+
+        try:
+            leaky = []
+            for i in range(100):
+                socket = TSocket.TSocket('localhost', self.port)
+                socket.setTimeout(10)
+                socket.open()
+                leaky.append(socket)
+        except Exception:
+            self.assert_(time.time() - starttime < 5.0)
+
+    def testWriteTimeout(self):
+        starttime = time.time()
+
+        try:
+            socket = TSocket.TSocket('localhost', self.port)
+            socket.setTimeout(10)
+            socket.open()
+            lsock = self.listen_sock.accept()
+            while True:
+                lsock.write("hi" * 100)
+
+        except Exception:
+            self.assert_(time.time() - starttime < 5.0)
+
+
+if __name__ == '__main__':
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
+
+    suite.addTest(loader.loadTestsFromTestCase(TimeoutTest))
+
+    testRunner = unittest.TextTestRunner(verbosity=2)
+    testRunner.run(suite)
diff --git a/test/py/TestSyntax.py b/test/py/TestSyntax.py
new file mode 100755
index 0000000..dbe7975
--- /dev/null
+++ b/test/py/TestSyntax.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Just import these generated files to make sure they are syntactically valid
+from DebugProtoTest import EmptyService  # noqa
+from DebugProtoTest import Inherited  # noqa
diff --git a/test/py/explicit_module/runtest.sh b/test/py/explicit_module/runtest.sh
new file mode 100755
index 0000000..6d73462
--- /dev/null
+++ b/test/py/explicit_module/runtest.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+rm -rf gen-py
+../../../compiler/cpp/thrift --gen py test1.thrift || exit 1
+../../../compiler/cpp/thrift --gen py test2.thrift || exit 1
+../../../compiler/cpp/thrift --gen py test3.thrift && exit 1  # Fail since test3.thrift has python keywords
+PYTHONPATH=./gen-py python -c 'import foo.bar.baz' || exit 1
+PYTHONPATH=./gen-py python -c 'import test2' || exit 1
+PYTHONPATH=./gen-py python -c 'import test1' &>/dev/null && exit 1  # Should fail.
+cp -r gen-py simple
+../../../compiler/cpp/thrift -r --gen py test2.thrift || exit 1
+PYTHONPATH=./gen-py python -c 'import test2' || exit 1
+diff -ur simple gen-py > thediffs
+file thediffs | grep -s -q empty || exit 1
+rm -rf simple thediffs
+echo 'All tests pass!'
diff --git a/test/py/explicit_module/test1.thrift b/test/py/explicit_module/test1.thrift
new file mode 100644
index 0000000..ec600d7
--- /dev/null
+++ b/test/py/explicit_module/test1.thrift
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace py foo.bar.baz
+
+struct astruct {
+  1: i32 how_unoriginal;
+}
diff --git a/test/py/explicit_module/test2.thrift b/test/py/explicit_module/test2.thrift
new file mode 100644
index 0000000..68f9da4
--- /dev/null
+++ b/test/py/explicit_module/test2.thrift
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+include "test1.thrift"
+
+struct another {
+  1: test1.astruct something;
+}
diff --git a/test/py/explicit_module/test3.thrift b/test/py/explicit_module/test3.thrift
new file mode 100644
index 0000000..154786b
--- /dev/null
+++ b/test/py/explicit_module/test3.thrift
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace py validations
+
+struct from {
+  1: i32 def;
+}
+
diff --git a/test/py/generate.cmake b/test/py/generate.cmake
new file mode 100644
index 0000000..46263c8
--- /dev/null
+++ b/test/py/generate.cmake
@@ -0,0 +1,29 @@
+macro(GENERATE FILENAME GENERATOR OUTPUTDIR)
+  file(MAKE_DIRECTORY ${MY_CURRENT_BINARY_DIR}/${OUTPUTDIR})
+  execute_process(COMMAND ${THRIFTCOMPILER} --gen ${GENERATOR} -out ${MY_CURRENT_BINARY_DIR}/${OUTPUTDIR} ${FILENAME}
+                  RESULT_VARIABLE CMD_RESULT)
+  if(CMD_RESULT)
+        message(FATAL_ERROR "Error generating ${FILENAME} with generator ${GENERATOR}")
+  endif()
+endmacro(GENERATE)
+
+generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py gen-py-default)
+generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:slots gen-py-slots)
+generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:old_style gen-py-oldstyle)
+generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:no_utf8strings gen-py-no_utf8strings)
+generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:dynamic gen-py-dynamic)
+generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:dynamic,slots gen-py-dynamicslots)
+
+generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py gen-py-default)
+generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:slots gen-py-slots)
+generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:old_style gen-py-oldstyle)
+generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:no_utf8strings gen-py-no_utf8strings)
+generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:dynamic gen-py-dynamic)
+generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:dynamic,slots gen-py-dynamicslots)
+
+generate(${MY_PROJECT_DIR}/test/Recursive.thrift py gen-py-default)
+generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:slots gen-py-slots)
+generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:old_style gen-py-oldstyle)
+generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:no_utf8strings gen-py-no_utf8strings)
+generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:dynamic gen-py-dynamic)
+generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:dynamic,slots gen-py-dynamicslots)
diff --git a/test/py/setup.cfg b/test/py/setup.cfg
new file mode 100644
index 0000000..7da1f96
--- /dev/null
+++ b/test/py/setup.cfg
@@ -0,0 +1,2 @@
+[flake8]
+max-line-length = 100
diff --git a/test/py/util.py b/test/py/util.py
new file mode 100644
index 0000000..c2b3f5c
--- /dev/null
+++ b/test/py/util.py
@@ -0,0 +1,32 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import glob
+import os
+import sys
+
+_SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
+_ROOT_DIR = os.path.dirname(os.path.dirname(_SCRIPT_DIR))
+
+
+def local_libpath():
+    globdir = os.path.join(_ROOT_DIR, 'lib', 'py', 'build', 'lib.*')
+    for libpath in glob.glob(globdir):
+        if libpath.endswith('-%d.%d' % (sys.version_info[0], sys.version_info[1])):
+            return libpath
diff --git a/test/rb/Gemfile b/test/rb/Gemfile
new file mode 100644
index 0000000..58c04aa
--- /dev/null
+++ b/test/rb/Gemfile
@@ -0,0 +1,7 @@
+source "http://rubygems.org"
+
+require "rubygems"
+
+gem "rack", "~> 1.5.2"
+gem "thin", "~> 1.5.0"
+gem "test-unit"
diff --git a/test/rb/Makefile b/test/rb/Makefile
new file mode 100644
index 0000000..4fb0e3a
--- /dev/null
+++ b/test/rb/Makefile
@@ -0,0 +1,632 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# test/rb/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/thrift
+pkgincludedir = $(includedir)/thrift
+pkglibdir = $(libdir)/thrift
+pkglibexecdir = $(libexecdir)/thrift
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = test/rb
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15
+ALLOCA = 
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+ANT = /usr/bin/ant
+ANT_FLAGS = 
+AR = ar
+AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf
+AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader
+AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15
+AWK = gawk
+BISON = bison
+BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a
+BOOST_CPPFLAGS = -I/usr/include
+BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a
+BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu
+BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu
+BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a
+BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a
+BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a
+BUNDLER = /usr/bin/bundle
+CABAL = /usr/bin/cabal
+CABAL_CONFIGURE_FLAGS = 
+CARGO = /usr/bin/cargo
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CLASSPATH = 
+CPP = gcc -E
+CPPFLAGS = 
+CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;
+CXX = g++ -std=c++11
+CXXCPP = g++ -E -std=c++11
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DART = /usr/lib/dart/bin/dart
+DARTPUB = /usr/lib/dart/bin/pub
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DMD = dmd
+DMD_LIBEVENT_FLAGS = 
+DMD_OF_DIRSEP = /
+DMD_OPENSSL_FLAGS = 
+DOTNETCORE = /usr/bin/dotnet
+DOTNETCORE_VERSION = 2.0.3
+DSYMUTIL = 
+DUMPBIN = 
+D_EVENT_LIB_NAME = libthriftd-event.a
+D_IMPORT_PREFIX = ${prefix}/include/d2
+D_LIB_NAME = libthriftd.a
+D_SSL_LIB_NAME = libthriftd-ssl.a
+ECHO_C = 
+ECHO_N = -n
+ECHO_T = 
+EGREP = /bin/grep -E
+ENABLE_COVERAGE = 2
+ERL = /usr/bin/erl
+ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib
+ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0
+ERLANG_LIB_DIR = /usr/lib/erlang/lib
+ERLC = /usr/bin/erlc
+ERLCFLAGS = 
+EXEEXT = 
+FGREP = /bin/grep -F
+GCOV_CFLAGS = 
+GCOV_CXXFLAGS = 
+GCOV_LDFLAGS = 
+GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GLIB_LIBS = -lglib-2.0
+GO = /usr/bin/go
+GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0
+GREP = /bin/grep
+HAVE_CXX11 = 1
+HAXE = /usr/bin/haxe
+HAXE_VERSION = 3.2.1
+INSTALL = /usr/bin/install -c
+INSTALLDIRS = vendor
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+JAVA_PREFIX = /usr/local/lib
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS = 
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBEVENT_CPPFLAGS = 
+LIBEVENT_LDFLAGS = 
+LIBEVENT_LIBS = -levent
+LIBOBJS = 
+LIBS = -lrt -lpthread 
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO = 
+LN_S = ln -s
+LTLIBOBJS = 
+LT_SYS_LIBRARY_PATH = 
+LUA = /usr/bin/lua5.3
+LUA_EXEC_PREFIX = ${exec_prefix}
+LUA_INCLUDE = -I/usr/include/lua5.3
+LUA_LIB = -llua5.3  -ldl
+LUA_PLATFORM = unknown
+LUA_PREFIX = ${prefix}
+LUA_SHORT_VERSION = 53
+LUA_VERSION = 5.3
+MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo
+MANIFEST_TOOL = :
+MAYBE_CPP = cpp
+MAYBE_CSHARP = csharp
+MAYBE_C_GLIB = c_glib
+MAYBE_D = 
+MAYBE_DART = dart
+MAYBE_DOTNETCORE = netcore
+MAYBE_ERLANG = erl
+MAYBE_GO = go
+MAYBE_HASKELL = hs
+MAYBE_JAVA = java
+MAYBE_LUA = lua
+MAYBE_NODEJS = nodejs
+MAYBE_PERL = perl
+MAYBE_PHP = php
+MAYBE_PY3 = py3
+MAYBE_PYTHON = py
+MAYBE_RS = rs
+MAYBE_RUBY = rb
+MCS = /usr/bin/mcs
+MKDIR_P = /bin/mkdir -p
+MONO_CFLAGS = 
+MONO_LIBS = 
+NM = /usr/bin/nm -B
+NMEDIT = 
+NODEJS = /usr/bin/nodejs
+NPM = /usr/bin/npm
+OBJDUMP = objdump
+OBJEXT = o
+OPENSSL_INCLUDES = 
+OPENSSL_LDFLAGS = 
+OPENSSL_LIBS = -lssl -lcrypto
+OTOOL = 
+OTOOL64 = 
+PACKAGE = thrift
+PACKAGE_BUGREPORT = 
+PACKAGE_NAME = thrift
+PACKAGE_STRING = thrift 0.11.0
+PACKAGE_TARNAME = thrift
+PACKAGE_URL = 
+PACKAGE_VERSION = 0.11.0
+PATH_SEPARATOR = :
+PERL = /usr/bin/perl
+PERL_PREFIX = /usr/local
+PHP = /usr/bin/php
+PHPUNIT = /usr/bin/phpunit
+PHP_CONFIG = /usr/bin/php-config
+PHP_CONFIG_PREFIX = /etc/php.d
+PHP_PREFIX = /usr/lib/php
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR = 
+PKG_CONFIG_PATH = 
+PYTHON = /usr/bin/python
+PYTHON3 = /usr/bin/python3
+PYTHON_EXEC_PREFIX = ${exec_prefix}
+PYTHON_PLATFORM = linux2
+PYTHON_PREFIX = ${prefix}
+PYTHON_VERSION = 2.7
+PY_PREFIX = /usr
+QT5_CFLAGS = 
+QT5_LIBS = 
+QT5_MOC = 
+QT_CFLAGS = 
+QT_LIBS = 
+QT_MOC = 
+RANLIB = ranlib
+REBAR = /usr/bin/rebar
+RUBY = /usr/bin/ruby
+RUBY_PREFIX = 
+RUNHASKELL = /usr/bin/runhaskell
+RUSTC = /usr/bin/rustc
+SED = /bin/sed
+SET_MAKE = 
+SHELL = /bin/bash
+STRIP = strip
+THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift
+TRIAL = /usr/bin/trial
+VERSION = 0.11.0
+YACC = bison -y
+YFLAGS = 
+ZLIB_CPPFLAGS = 
+ZLIB_LDFLAGS = 
+ZLIB_LIBS = -lz
+abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/test/rb
+abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/test/rb
+abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift
+abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+ac_ct_DUMPBIN = 
+am__include = include
+am__leading_dot = .
+am__quote = 
+am__tar = tar --format=ustar -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias = 
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+golang_version = 1.6.2
+have_prog_bison = yes
+host = x86_64-pc-linux-gnu
+host_alias = 
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+luadir = ${prefix}/share/lua/5.3
+luaexecdir = ${exec_prefix}/lib/lua/5.3
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+pkgluadir = ${luadir}/thrift
+pkgluaexecdir = ${luaexecdir}/thrift
+pkgpyexecdir = ${pyexecdir}/thrift
+pkgpythondir = ${pythondir}/thrift
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages
+pythondir = ${prefix}/lib/python2.7/dist-packages
+runstatedir = ${localstatedir}/run
+rustc_version = rustc 1.17.0
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+subdirs =  lib/php/src/ext/thrift_protocol
+sysconfdir = ${prefix}/etc
+target_alias = 
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/rb/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/rb/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+stubs: $(THRIFT) ../ThriftTest.thrift ../SmallTest.thrift
+	$(THRIFT) --gen rb ../ThriftTest.thrift
+	$(THRIFT) --gen rb ../SmallTest.thrift
+
+precross: stubs
+
+check: stubs
+	$(BUNDLER) install
+	$(BUNDLER) exec $(RUBY) -I. test_suite.rb
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/rb/Makefile.am b/test/rb/Makefile.am
new file mode 100644
index 0000000..4bd4704
--- /dev/null
+++ b/test/rb/Makefile.am
@@ -0,0 +1,31 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+stubs: $(THRIFT) ../ThriftTest.thrift ../SmallTest.thrift
+	$(THRIFT) --gen rb ../ThriftTest.thrift
+	$(THRIFT) --gen rb ../SmallTest.thrift
+
+precross: stubs
+
+check: stubs
+if HAVE_BUNDLER
+	$(BUNDLER) install
+	$(BUNDLER) exec $(RUBY) -I. test_suite.rb
+endif
+
diff --git a/test/rb/Makefile.in b/test/rb/Makefile.in
new file mode 100644
index 0000000..4359764
--- /dev/null
+++ b/test/rb/Makefile.in
@@ -0,0 +1,632 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/rb
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/rb/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/rb/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+stubs: $(THRIFT) ../ThriftTest.thrift ../SmallTest.thrift
+	$(THRIFT) --gen rb ../ThriftTest.thrift
+	$(THRIFT) --gen rb ../SmallTest.thrift
+
+precross: stubs
+
+check: stubs
+@HAVE_BUNDLER_TRUE@	$(BUNDLER) install
+@HAVE_BUNDLER_TRUE@	$(BUNDLER) exec $(RUBY) -I. test_suite.rb
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/rb/benchmarks/protocol_benchmark.rb b/test/rb/benchmarks/protocol_benchmark.rb
new file mode 100644
index 0000000..05a8ee5
--- /dev/null
+++ b/test/rb/benchmarks/protocol_benchmark.rb
@@ -0,0 +1,174 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. .. .. lib rb lib])
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. .. .. lib rb ext])
+
+require 'thrift'
+
+require 'benchmark'
+require 'rubygems'
+require 'set'
+require 'pp'
+
+# require 'ruby-debug'
+# require 'ruby-prof'
+
+require File.join(File.dirname(__FILE__), '../fixtures/structs')
+
+transport1 = Thrift::MemoryBuffer.new
+ruby_binary_protocol = Thrift::BinaryProtocol.new(transport1)
+
+transport2 = Thrift::MemoryBuffer.new
+c_fast_binary_protocol = Thrift::BinaryProtocolAccelerated.new(transport2)
+
+
+ooe = Fixtures::Structs::OneOfEach.new
+ooe.im_true   = true
+ooe.im_false  = false
+ooe.a_bite    = -42
+ooe.integer16 = 27000
+ooe.integer32 = 1<<24
+ooe.integer64 = 6000 * 1000 * 1000
+ooe.double_precision = Math::PI
+ooe.some_characters  = "Debug THIS!"
+ooe.zomg_unicode     = "\xd7\n\a\t"
+
+n1 = Fixtures::Structs::Nested1.new
+n1.a_list = []
+n1.a_list << ooe << ooe << ooe << ooe
+n1.i32_map = {}
+n1.i32_map[1234] = ooe
+n1.i32_map[46345] = ooe
+n1.i32_map[-34264] = ooe
+n1.i64_map = {}
+n1.i64_map[43534986783945] = ooe
+n1.i64_map[-32434639875122] = ooe
+n1.dbl_map = {}
+n1.dbl_map[324.65469834] = ooe
+n1.dbl_map[-9458672340.4986798345112] = ooe
+n1.str_map = {}
+n1.str_map['sdoperuix'] = ooe
+n1.str_map['pwoerxclmn'] = ooe
+
+n2 = Fixtures::Structs::Nested2.new
+n2.a_list = []
+n2.a_list << n1 << n1 << n1 << n1 << n1
+n2.i32_map = {}
+n2.i32_map[398345] = n1
+n2.i32_map[-2345] = n1
+n2.i32_map[12312] = n1
+n2.i64_map = {}
+n2.i64_map[2349843765934] = n1
+n2.i64_map[-123234985495] = n1
+n2.i64_map[0] = n1
+n2.dbl_map = {}
+n2.dbl_map[23345345.38927834] = n1
+n2.dbl_map[-1232349.5489345] = n1
+n2.dbl_map[-234984574.23498725] = n1
+n2.str_map = {}
+n2.str_map[''] = n1
+n2.str_map['sdflkertpioux'] = n1
+n2.str_map['sdfwepwdcjpoi'] = n1
+
+n3 = Fixtures::Structs::Nested3.new
+n3.a_list = []
+n3.a_list << n2 << n2 << n2 << n2 << n2
+n3.i32_map = {}
+n3.i32_map[398345] = n2
+n3.i32_map[-2345] = n2
+n3.i32_map[12312] = n2
+n3.i64_map = {}
+n3.i64_map[2349843765934] = n2
+n3.i64_map[-123234985495] = n2
+n3.i64_map[0] = n2
+n3.dbl_map = {}
+n3.dbl_map[23345345.38927834] = n2
+n3.dbl_map[-1232349.5489345] = n2
+n3.dbl_map[-234984574.23498725] = n2
+n3.str_map = {}
+n3.str_map[''] = n2
+n3.str_map['sdflkertpioux'] = n2
+n3.str_map['sdfwepwdcjpoi'] = n2
+
+n4 = Fixtures::Structs::Nested4.new
+n4.a_list = []
+n4.a_list << n3
+n4.i32_map = {}
+n4.i32_map[-2345] = n3
+n4.i64_map = {}
+n4.i64_map[2349843765934] = n3
+n4.dbl_map = {}
+n4.dbl_map[-1232349.5489345] = n3
+n4.str_map = {}
+n4.str_map[''] = n3
+
+
+# prof = RubyProf.profile do
+#   n4.write(c_fast_binary_protocol)
+#   Fixtures::Structs::Nested4.new.read(c_fast_binary_protocol)
+# end
+# 
+# printer = RubyProf::GraphHtmlPrinter.new(prof)
+# printer.print(STDOUT, :min_percent=>0)
+
+Benchmark.bmbm do |x|
+  x.report("ruby write large (1MB) structure once") do
+    n4.write(ruby_binary_protocol)
+  end
+  
+  x.report("ruby read large (1MB) structure once") do
+    Fixtures::Structs::Nested4.new.read(ruby_binary_protocol)
+  end
+  
+  x.report("c write large (1MB) structure once") do    
+    n4.write(c_fast_binary_protocol)
+  end
+  
+  x.report("c read large (1MB) structure once") do
+    Fixtures::Structs::Nested4.new.read(c_fast_binary_protocol)
+  end
+  
+  
+  
+  x.report("ruby write 10_000 small structures") do
+    10_000.times do
+      ooe.write(ruby_binary_protocol)
+    end
+  end
+  
+  x.report("ruby read 10_000 small structures") do
+    10_000.times do
+      Fixtures::Structs::OneOfEach.new.read(ruby_binary_protocol)
+    end
+  end
+  
+  x.report("c write 10_000 small structures") do
+    10_000.times do
+      ooe.write(c_fast_binary_protocol)
+    end
+  end
+  
+  x.report("c read 10_000 small structures") do
+    10_000.times do
+      Fixtures::Structs::OneOfEach.new.read(c_fast_binary_protocol)
+    end
+  end
+  
+end
diff --git a/test/rb/core/test_backwards_compatability.rb b/test/rb/core/test_backwards_compatability.rb
new file mode 100644
index 0000000..0577515
--- /dev/null
+++ b/test/rb/core/test_backwards_compatability.rb
@@ -0,0 +1,30 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require File.join(File.dirname(__FILE__), '../test_helper')
+
+require 'thrift'
+
+class TestThriftException < Test::Unit::TestCase
+  def test_has_accessible_message
+    msg = "hi there thrift"
+    assert_equal msg, Thrift::Exception.new(msg).message
+  end
+end
+
diff --git a/test/rb/core/test_exceptions.rb b/test/rb/core/test_exceptions.rb
new file mode 100644
index 0000000..f41587a
--- /dev/null
+++ b/test/rb/core/test_exceptions.rb
@@ -0,0 +1,30 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require File.join(File.dirname(__FILE__), '../test_helper')
+
+require 'thrift'
+
+class TestException < Test::Unit::TestCase
+  def test_has_accessible_message
+    msg = "hi there thrift"
+    assert_equal msg, Thrift::Exception.new(msg).message
+  end
+end
+
diff --git a/test/rb/core/transport/test_transport.rb b/test/rb/core/transport/test_transport.rb
new file mode 100644
index 0000000..37afa85
--- /dev/null
+++ b/test/rb/core/transport/test_transport.rb
@@ -0,0 +1,70 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require File.join(File.dirname(__FILE__), '../../test_helper')
+
+require 'thrift'
+
+class DummyTransport < Thrift::BaseTransport
+  def initialize(data)
+    @data = data
+  end
+  
+  def read(size)
+    @data.slice!(0, size)
+  end
+end
+
+# TTransport is basically an abstract class, but isn't raising NotImplementedError
+class TestThriftTransport < Test::Unit::TestCase
+  def setup
+    @trans = Thrift::BaseTransport.new
+  end
+  
+  def test_open?
+    assert_nil @trans.open?
+  end
+  
+  def test_open
+    assert_nil @trans.open
+  end
+  
+  def test_close
+    assert_nil @trans.close
+  end
+  
+  # TODO:
+  # This doesn't necessarily test he right thing.
+  # It _looks_ like read isn't guaranteed to return the length
+  # you ask for and read_all is. This means our test needs to check
+  # for blocking. -- Kevin Clark 3/27/08
+  def test_read_all
+    # Implements read
+    t = DummyTransport.new("hello")
+    assert_equal "hello", t.read_all(5)
+  end
+  
+  def test_write
+    assert_nil @trans.write(5) # arbitrary value
+  end
+  
+  def test_flush
+    assert_nil @trans.flush
+  end
+end
diff --git a/test/rb/fixtures/structs.rb b/test/rb/fixtures/structs.rb
new file mode 100644
index 0000000..ebbeb0a
--- /dev/null
+++ b/test/rb/fixtures/structs.rb
@@ -0,0 +1,298 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'thrift'
+
+module Fixtures
+  module Structs
+    class OneBool
+      include Thrift::Struct
+      attr_accessor :bool
+      FIELDS = {
+        1 => {:type => Thrift::Types::BOOL, :name => 'bool'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneByte
+      include Thrift::Struct
+      attr_accessor :byte
+      FIELDS = {
+        1 => {:type => Thrift::Types::BYTE, :name => 'byte'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneI16
+      include Thrift::Struct
+      attr_accessor :i16
+      FIELDS = {
+        1 => {:type => Thrift::Types::I16, :name => 'i16'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneI32
+      include Thrift::Struct
+      attr_accessor :i32
+      FIELDS = {
+        1 => {:type => Thrift::Types::I32, :name => 'i32'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneI64
+      include Thrift::Struct
+      attr_accessor :i64
+      FIELDS = {
+        1 => {:type => Thrift::Types::I64, :name => 'i64'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneDouble
+      include Thrift::Struct
+      attr_accessor :double
+      FIELDS = {
+        1 => {:type => Thrift::Types::DOUBLE, :name => 'double'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneString
+      include Thrift::Struct
+      attr_accessor :string
+      FIELDS = {
+        1 => {:type => Thrift::Types::STRING, :name => 'string'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneMap
+      include Thrift::Struct
+      attr_accessor :map
+      FIELDS = {
+        1 => {:type => Thrift::Types::MAP, :name => 'map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRING}}
+      }
+
+      def validate
+      end
+    end
+    
+    class NestedMap
+      include Thrift::Struct
+      attr_accessor :map
+      FIELDS = {
+        0 => {:type => Thrift::Types::MAP, :name => 'map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::MAP, :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::I32}}}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneList
+      include Thrift::Struct
+      attr_accessor :list
+      FIELDS = {
+        1 => {:type => Thrift::Types::LIST, :name => 'list', :element => {:type => Thrift::Types::STRING}}
+      }
+
+      def validate
+      end
+    end
+    
+    class NestedList
+      include Thrift::Struct
+      attr_accessor :list
+      FIELDS = {
+        0 => {:type => Thrift::Types::LIST, :name => 'list', :element => {:type => Thrift::Types::LIST, :element => { :type => Thrift::Types::I32 } } }
+      }
+
+      def validate
+      end
+    end
+    
+    class OneSet
+      include Thrift::Struct
+      attr_accessor :set
+      FIELDS = {
+        1 => {:type => Thrift::Types::SET, :name => 'set', :element => {:type => Thrift::Types::STRING}}
+      }
+
+      def validate
+      end
+    end
+    
+    class NestedSet
+      include Thrift::Struct
+      attr_accessor :set
+      FIELDS = {
+        1 => {:type => Thrift::Types::SET, :name => 'set', :element => {:type => Thrift::Types::SET, :element => { :type => Thrift::Types::STRING } }}
+      }
+
+      def validate
+      end
+    end
+    
+    # struct OneOfEach {
+    #   1: bool im_true,
+    #   2: bool im_false,
+    #   3: byte a_bite,
+    #   4: i16 integer16,
+    #   5: i32 integer32,
+    #   6: i64 integer64,
+    #   7: double double_precision,
+    #   8: string some_characters,
+    #   9: string zomg_unicode,
+    #   10: bool what_who,
+    #   11: binary base64,
+    # }
+    class OneOfEach
+      include Thrift::Struct
+      attr_accessor :im_true, :im_false, :a_bite, :integer16, :integer32, :integer64, :double_precision, :some_characters, :zomg_unicode, :what_who, :base64
+      FIELDS = {
+        1 => {:type => Thrift::Types::BOOL, :name => 'im_true'},
+        2 => {:type => Thrift::Types::BOOL, :name => 'im_false'},
+        3 => {:type => Thrift::Types::BYTE, :name => 'a_bite'},
+        4 => {:type => Thrift::Types::I16, :name => 'integer16'},
+        5 => {:type => Thrift::Types::I32, :name => 'integer32'},
+        6 => {:type => Thrift::Types::I64, :name => 'integer64'},
+        7 => {:type => Thrift::Types::DOUBLE, :name => 'double_precision'},
+        8 => {:type => Thrift::Types::STRING, :name => 'some_characters'},
+        9 => {:type => Thrift::Types::STRING, :name => 'zomg_unicode'},
+        10 => {:type => Thrift::Types::BOOL, :name => 'what_who'},
+        11 => {:type => Thrift::Types::STRING, :name => 'base64'}
+      }
+
+      # Added for assert_equal
+      def ==(other)
+        [:im_true, :im_false, :a_bite, :integer16, :integer32, :integer64, :double_precision, :some_characters, :zomg_unicode, :what_who, :base64].each do |f|
+          var = "@#{f}"
+          return false if instance_variable_get(var) != other.instance_variable_get(var)
+        end
+        true
+      end
+
+      def validate
+      end
+    end
+
+    # struct Nested1 {
+    #   1: list a_list
+    #   2: map i32_map
+    #   3: map i64_map
+    #   4: map dbl_map
+    #   5: map str_map
+    # }
+    class Nested1
+      include Thrift::Struct
+      attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map
+      FIELDS = {
+        1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => OneOfEach}},
+        2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}},
+        3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}},
+        4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}},
+        5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}}
+      }
+
+      def validate
+      end
+    end
+
+    # struct Nested2 {
+    #   1: list a_list
+    #   2: map i32_map
+    #   3: map i64_map
+    #   4: map dbl_map
+    #   5: map str_map
+    # }
+    class Nested2
+      include Thrift::Struct
+      attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map
+      FIELDS = {
+        1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => Nested1}},
+        2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}},
+        3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}},
+        4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}},
+        5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}}
+      }
+
+      def validate
+      end
+    end
+
+    # struct Nested3 {
+    #   1: list a_list
+    #   2: map i32_map
+    #   3: map i64_map
+    #   4: map dbl_map
+    #   5: map str_map
+    # }
+    class Nested3
+      include Thrift::Struct
+      attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map
+      FIELDS = {
+        1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => Nested2}},
+        2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}},
+        3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}},
+        4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}},
+        5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}}
+      }
+
+      def validate
+      end
+    end
+
+    # struct Nested4 {
+    #   1: list a_list
+    #   2: map i32_map
+    #   3: map i64_map
+    #   4: map dbl_map
+    #   5: map str_map
+    # }
+    class Nested4
+      include Thrift::Struct
+      attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map
+      FIELDS = {
+        1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => Nested3}},
+        2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}},
+        3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}},
+        4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}},
+        5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}}
+      }
+
+      def validate
+      end
+    end
+  end
+end
diff --git a/test/rb/generation/test_enum.rb b/test/rb/generation/test_enum.rb
new file mode 100644
index 0000000..607ea66
--- /dev/null
+++ b/test/rb/generation/test_enum.rb
@@ -0,0 +1,34 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require File.join(File.dirname(__FILE__), '../test_helper')
+require 'thrift_test'
+
+class TestEnumGeneration < Test::Unit::TestCase
+  include Thrift::Test
+  def test_enum_valid_values
+    assert_equal(Numberz::VALID_VALUES, Set.new([Numberz::ONE, Numberz::TWO, Numberz::THREE, Numberz::FIVE, Numberz::SIX, Numberz::EIGHT]))
+  end
+  
+  def test_enum_hash
+    Numberz::VALID_VALUES.each do |value|
+      assert_equal(Numberz.const_get(Numberz::VALUE_MAP[value].to_sym), value)
+    end
+  end
+end
\ No newline at end of file
diff --git a/test/rb/generation/test_struct.rb b/test/rb/generation/test_struct.rb
new file mode 100644
index 0000000..3bd4fc9
--- /dev/null
+++ b/test/rb/generation/test_struct.rb
@@ -0,0 +1,48 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require File.join(File.dirname(__FILE__), '../test_helper')
+require 'small_service'
+
+class TestStructGeneration < Test::Unit::TestCase
+
+  def test_default_values
+    hello = TestNamespace::Hello.new
+
+    assert_kind_of(TestNamespace::Hello, hello)
+    assert_nil(hello.complexer)
+
+    assert_equal(hello.simple, 53)
+    assert_equal(hello.words, 'words')
+
+    assert_kind_of(TestNamespace::Goodbyez, hello.thinz)
+    assert_equal(hello.thinz.val, 36632)
+
+    assert_kind_of(Hash, hello.complex)
+    assert_equal(hello.complex, { 6243 => 632, 2355 => 532, 23 => 532})
+    
+    bool_passer = TestNamespace::BoolPasser.new(:value => false)
+    assert_equal false, bool_passer.value
+  end
+
+  def test_goodbyez
+    assert_equal(TestNamespace::Goodbyez.new.val, 325)
+  end
+
+end
diff --git a/test/rb/integration/TestClient.rb b/test/rb/integration/TestClient.rb
new file mode 100755
index 0000000..beebe44
--- /dev/null
+++ b/test/rb/integration/TestClient.rb
@@ -0,0 +1,353 @@
+#!/usr/bin/env ruby
+# encoding: utf-8
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+$:.push File.dirname(__FILE__) + '/..'
+
+require 'test_helper'
+require 'thrift'
+require 'thrift_test'
+
+$protocolType = "binary"
+$host = "localhost"
+$port = 9090
+$transport = "buffered"
+ARGV.each do|a|
+  if a == "--help"
+    puts "Allowed options:"
+    puts "\t -h [ --help ] \t produce help message"
+    puts "\t--host arg (=localhost) \t Host to connect"
+    puts "\t--port arg (=9090) \t Port number to listen"
+    puts "\t--protocol arg (=binary) \t protocol: binary, accel"
+    puts "\t--transport arg (=buffered) transport: buffered, framed, http"
+    exit
+  elsif a.start_with?("--host")
+    $host = a.split("=")[1]
+  elsif a.start_with?("--protocol")
+    $protocolType = a.split("=")[1]
+  elsif a.start_with?("--transport")
+    $transport = a.split("=")[1]
+  elsif a.start_with?("--port")
+    $port = a.split("=")[1].to_i
+  end
+end
+ARGV=[]
+
+class SimpleClientTest < Test::Unit::TestCase
+  def setup
+    unless @socket
+      @socket   = Thrift::Socket.new($host, $port)
+      if $transport == "buffered"
+        transportFactory = Thrift::BufferedTransport.new(@socket)
+      elsif $transport == "framed"
+        transportFactory = Thrift::FramedTransport.new(@socket)
+      else
+        raise 'Unknown transport type'
+      end
+
+      if $protocolType == "binary"
+        @protocol = Thrift::BinaryProtocol.new(transportFactory)
+      elsif $protocolType == "compact"
+        @protocol = Thrift::CompactProtocol.new(transportFactory)
+      elsif $protocolType == "json"
+        @protocol = Thrift::JsonProtocol.new(transportFactory)
+      elsif $protocolType == "accel"
+        @protocol = Thrift::BinaryProtocolAccelerated.new(transportFactory)
+      else
+        raise 'Unknown protocol type'
+      end
+      @client   = Thrift::Test::ThriftTest::Client.new(@protocol)
+      @socket.open
+    end
+  end
+
+  def teardown
+    @socket.close
+  end
+
+  def test_void
+    p 'test_void'
+    @client.testVoid()
+  end
+
+  def test_string
+    p 'test_string'
+    test_string =
+      'quote: \" backslash:' +
+      ' forwardslash-escaped: \/ ' +
+      ' backspace: \b formfeed: \f newline: \n return: \r tab: ' +
+      ' now-all-of-them-together: "\\\/\b\n\r\t' +
+      ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><' +
+      ' char-to-test-json-parsing: ]] \"]] \\" }}}{ [[[ '
+    test_string = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " +
+      "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " +
+      "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, " +
+      "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, " +
+      "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, " +
+      "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, " +
+      "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, " +
+      "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, " +
+      "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, " +
+      "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, " +
+      "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, " +
+      "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, " +
+      "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, " +
+      "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa " +
+      "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa " +
+      "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪" +
+      "Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, " +
+      "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, " +
+      "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, " +
+      "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple " +
+      "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, " +
+      "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, " +
+      "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, " +
+      "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, " +
+      "Bân-lâm-gú, 粵語"
+
+    result_string = @client.testString(test_string)
+    assert_equal(test_string, result_string.force_encoding(Encoding::UTF_8))
+  end
+
+  def test_bool
+    p 'test_bool'
+    assert_equal(@client.testBool(true), true)
+    assert_equal(@client.testBool(false), false)
+  end
+
+  def test_byte
+    p 'test_byte'
+    val = 120
+    assert_equal(@client.testByte(val), val)
+    assert_equal(@client.testByte(-val), -val)
+  end
+
+  def test_i32
+    p 'test_i32'
+    val = 2000000032
+    assert_equal(@client.testI32(val), val)
+    assert_equal(@client.testI32(-val), -val)
+  end
+
+  def test_i64
+    p 'test_i64'
+    val = 9000000000000000064
+    assert_equal(@client.testI64(val), val)
+    assert_equal(@client.testI64(-val), -val)
+  end
+
+  def test_double
+    p 'test_double'
+    val = 3.14159265358979323846
+    assert_equal(@client.testDouble(val), val)
+    assert_equal(@client.testDouble(-val), -val)
+    assert_kind_of(Float, @client.testDouble(val))
+  end
+
+  def test_binary
+    p 'test_binary'
+    val = (0...256).reverse_each.to_a
+    ret = @client.testBinary(val.pack('C*'))
+    assert_equal(val, ret.bytes.to_a)
+  end
+
+  def test_map
+    p 'test_map'
+    val = {1 => 1, 2 => 2, 3 => 3}
+    assert_equal(@client.testMap(val), val)
+    assert_kind_of(Hash, @client.testMap(val))
+  end
+
+  def test_string_map
+    p 'test_string_map'
+    val = {'a' => '2', 'b' => 'blah', 'some' => 'thing'}
+    ret = @client.testStringMap(val)
+    assert_equal(val, ret)
+    assert_kind_of(Hash, ret)
+  end
+
+  def test_list
+    p 'test_list'
+    val = [1,2,3,4,5]
+    assert_equal(@client.testList(val), val)
+    assert_kind_of(Array, @client.testList(val))
+  end
+
+  def test_enum
+    p 'test_enum'
+    val = Thrift::Test::Numberz::SIX
+    ret = @client.testEnum(val)
+
+    assert_equal(ret, 6)
+    assert_kind_of(Fixnum, ret)
+  end
+
+  def test_typedef
+    p 'test_typedef'
+    #UserId  testTypedef(1: UserId thing),
+    assert_equal(@client.testTypedef(309858235082523), 309858235082523)
+    assert_kind_of(Fixnum, @client.testTypedef(309858235082523))
+    true
+  end
+
+  def test_set
+    p 'test_set'
+    val = Set.new([1,2,3])
+    assert_equal(@client.testSet(val), val)
+    assert_kind_of(Set, @client.testSet(val))
+  end
+
+  def get_struct
+    Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 })
+  end
+
+  def test_struct
+    p 'test_struct'
+    ret = @client.testStruct(get_struct)
+
+    # TODO: not sure what unspecified "default" requiredness values should be
+    assert(ret.byte_thing == nil || ret.byte_thing == 0)
+    assert(ret.i64_thing == nil || ret.i64_thing == 0)
+
+    assert_equal(ret.string_thing, 'hi!')
+    assert_equal(ret.i32_thing, 4)
+    assert_kind_of(Thrift::Test::Xtruct, ret)
+  end
+
+  def test_nest
+    p 'test_nest'
+    struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10})
+
+    ret = @client.testNest(struct2)
+
+    # TODO: not sure what unspecified "default" requiredness values should be
+    assert(ret.struct_thing.byte_thing == nil || ret.struct_thing.byte_thing == 0)
+    assert(ret.struct_thing.i64_thing == nil || ret.struct_thing.i64_thing == 0)
+
+    assert_equal(ret.struct_thing.string_thing, 'hi!')
+    assert_equal(ret.struct_thing.i32_thing, 4)
+    assert_equal(ret.i32_thing, 10)
+
+    assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing)
+    assert_kind_of(Thrift::Test::Xtruct2, ret)
+  end
+
+  def test_insanity
+    p 'test_insanity'
+    insane = Thrift::Test::Insanity.new({
+      'userMap' => {
+        Thrift::Test::Numberz::FIVE => 5,
+        Thrift::Test::Numberz::EIGHT => 8,
+      },
+      'xtructs' => [
+        Thrift::Test::Xtruct.new({
+          'string_thing' => 'Goodbye4',
+          'byte_thing' => 4,
+          'i32_thing' => 4,
+          'i64_thing' => 4,
+        }),
+        Thrift::Test::Xtruct.new({
+          'string_thing' => 'Hello2',
+          'byte_thing' => 2,
+          'i32_thing' => 2,
+          'i64_thing' => 2,
+        })
+      ]
+    })
+
+    ret = @client.testInsanity(insane)
+
+    assert_equal(insane, ret[1][2])
+    assert_equal(insane, ret[1][3])
+
+    assert(ret[2][6].userMap == nil || ret[2][6].userMap.length == 0)
+    assert(ret[2][6].xtructs == nil || ret[2][6].xtructs.length == 0)
+  end
+
+  def test_map_map
+    p 'test_map_map'
+    ret = @client.testMapMap(4)
+    assert_kind_of(Hash, ret)
+    expected = {
+      -4 => {
+        -4 => -4,
+        -3 => -3,
+        -2 => -2,
+        -1 => -1,
+      },
+      4 => {
+        4 => 4,
+        3 => 3,
+        2 => 2,
+        1 => 1,
+      }
+    }
+    assert_equal(expected, ret)
+  end
+
+  def test_multi
+    p 'test_multi'
+    ret = @client.testMulti(42, 4242, 424242, {1 => 'blah', 2 => 'thing'}, Thrift::Test::Numberz::EIGHT, 24)
+    expected = Thrift::Test::Xtruct.new({
+      :string_thing => 'Hello2',
+      :byte_thing =>   42,
+      :i32_thing =>    4242,
+      :i64_thing =>    424242
+    })
+    assert_equal(expected, ret)
+  end
+
+  def test_exception
+    p 'test_exception'
+    assert_raise Thrift::Test::Xception do
+      @client.testException('Xception')
+    end
+    begin
+      @client.testException('TException')
+    rescue => e
+      assert e.class.ancestors.include?(Thrift::Exception)
+    end
+    assert_nothing_raised do
+      @client.testException('test')
+    end
+  end
+
+  def test_multi_exception
+    p 'test_multi_exception'
+    assert_raise Thrift::Test::Xception do
+      @client.testMultiException("Xception", "test 1")
+    end
+    assert_raise Thrift::Test::Xception2 do
+      @client.testMultiException("Xception2", "test 2")
+    end
+    assert_equal( @client.testMultiException("Success", "test 3").string_thing, "test 3")
+  end
+
+  def test_oneway
+    p 'test_oneway'
+    time1 = Time.now.to_f
+    @client.testOneway(1)
+    time2 = Time.now.to_f
+    assert_operator (time2-time1), :<, 0.1
+  end
+
+end
+
diff --git a/test/rb/integration/TestServer.rb b/test/rb/integration/TestServer.rb
new file mode 100755
index 0000000..bab723a
--- /dev/null
+++ b/test/rb/integration/TestServer.rb
@@ -0,0 +1,159 @@
+#!/usr/bin/env ruby
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+$:.push File.dirname(__FILE__) + '/..'
+
+require 'test_helper'
+require 'thrift'
+require 'thrift_test'
+require 'thrift_test_types'
+
+class SimpleHandler
+  [:testVoid, :testString, :testBool, :testByte, :testI32, :testI64, :testDouble, :testBinary,
+   :testStruct, :testMap, :testStringMap, :testSet, :testList, :testNest, :testEnum, :testTypedef,
+   :testEnum, :testTypedef, :testMultiException].each do |meth|
+
+    define_method(meth) do |thing|
+      p meth
+      p thing
+      thing
+    end
+
+  end
+
+  def testVoid()
+  end
+
+  def testInsanity(thing)
+    return {
+      1 => {
+        2 => thing,
+        3 => thing
+      },
+      2 => {
+        6 => Thrift::Test::Insanity::new()
+      }
+    }
+  end
+
+  def testMapMap(thing)
+    return {
+      -4 => {
+        -4 => -4,
+        -3 => -3,
+        -2 => -2,
+        -1 => -1,
+      },
+      4 => {
+        4 => 4,
+        3 => 3,
+        2 => 2,
+        1 => 1,
+      }
+    }
+  end
+
+  def testMulti(arg0, arg1, arg2, arg3, arg4, arg5)
+    return Thrift::Test::Xtruct.new({
+      'string_thing' => 'Hello2',
+      'byte_thing' => arg0,
+      'i32_thing' => arg1,
+      'i64_thing' => arg2,
+    })
+  end
+
+  def testException(thing)
+    if thing == "Xception"
+      raise Thrift::Test::Xception, :errorCode => 1001, :message => thing
+    elsif thing == "TException"
+      raise Thrift::Exception, :message => thing
+    else
+      # no-op
+    end
+  end
+
+  def testMultiException(arg0, arg1)
+    if arg0 == "Xception2"
+      raise Thrift::Test::Xception2, :errorCode => 2002, :struct_thing => ::Thrift::Test::Xtruct.new({ :string_thing => 'This is an Xception2' })
+    elsif arg0 == "Xception"
+      raise Thrift::Test::Xception, :errorCode => 1001, :message => 'This is an Xception'
+    else
+      return ::Thrift::Test::Xtruct.new({'string_thing' => arg1})
+    end
+  end
+
+  def testOneway(arg0)
+    sleep(arg0)
+  end
+
+end
+
+protocol = "binary"
+port = 9090
+transport = "buffered"
+@transportFactory = Thrift::BufferedTransportFactory.new
+@protocolFactory = Thrift::BinaryProtocolFactory.new
+ARGV.each do|a|
+  if a == "--help"
+    puts "Allowed options:"
+    puts "\t -h [ --help ] \t produce help message"
+    puts "\t--port arg (=9090) \t Port number to listen"
+    puts "\t--protocol arg (=binary) \t protocol: binary, accel"
+    puts "\t--transport arg (=buffered) transport: buffered, framed, http"
+    exit
+  elsif a.start_with?("--protocol")
+    protocol = a.split("=")[1]
+  elsif a.start_with?("--transport")
+    transport = a.split("=")[1]
+  elsif a.start_with?("--port")
+    port = a.split("=")[1].to_i 
+  end
+end
+
+if protocol == "binary"
+  @protocolFactory = Thrift::BinaryProtocolFactory.new
+elsif protocol == ""
+  @protocolFactory = Thrift::BinaryProtocolFactory.new
+elsif protocol == "compact"
+  @protocolFactory = Thrift::CompactProtocolFactory.new
+elsif protocol == "json"
+  @protocolFactory = Thrift::JsonProtocolFactory.new
+elsif protocol == "accel"
+  @protocolFactory = Thrift::BinaryProtocolAcceleratedFactory.new
+else
+  raise 'Unknown protocol type'
+end
+
+if transport == "buffered"
+  @transportFactory = Thrift::BufferedTransportFactory.new
+elsif transport == ""
+  @transportFactory = Thrift::BufferedTransportFactory.new
+elsif transport == "framed"
+  @transportFactory = Thrift::FramedTransportFactory.new
+else
+  raise 'Unknown transport type'
+end
+
+@handler   = SimpleHandler.new
+@processor = Thrift::Test::ThriftTest::Processor.new(@handler)
+@transport = Thrift::ServerSocket.new(port)
+@server    = Thrift::ThreadedServer.new(@processor, @transport, @transportFactory, @protocolFactory)
+@server.serve
diff --git a/test/rb/test_helper.rb b/test/rb/test_helper.rb
new file mode 100644
index 0000000..c1ed779
--- /dev/null
+++ b/test/rb/test_helper.rb
@@ -0,0 +1,35 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+$:.unshift File.dirname(__FILE__) + '/gen-rb'
+$:.unshift File.join(File.dirname(__FILE__), '../../lib/rb/lib')
+$:.unshift File.join(File.dirname(__FILE__), '../../lib/rb/ext')
+
+require 'test/unit'
+
+module Thrift
+  module Struct
+    def ==(other)
+      return false unless other.is_a? self.class
+      self.class.const_get(:FIELDS).collect {|fid, data| data[:name] }.all? do |field|
+        send(field) == other.send(field)
+      end
+    end
+  end
+end
diff --git a/test/rb/test_suite.rb b/test/rb/test_suite.rb
new file mode 100644
index 0000000..b157c2c
--- /dev/null
+++ b/test/rb/test_suite.rb
@@ -0,0 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+Dir["{core,generation}/**/*.rb"].each {|f| require f }
\ No newline at end of file
diff --git a/test/rebuild_known_failures.sh b/test/rebuild_known_failures.sh
new file mode 100644
index 0000000..08869fe
--- /dev/null
+++ b/test/rebuild_known_failures.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+if [ -z $1 ]; then
+  echo Usage: $0 LANGUAGE
+  echo Re-list all failures of a specific LANGUAGE into known_failures_Linux.json
+  echo LANGUAGE should be library name like cpp, java, py etc
+  exit 1
+fi
+
+if [ -z $PYTHON]; then
+  PYTHON=python
+fi
+
+TARGET_LANG=$1
+OUT_FILE=known_failures_Linux.json
+echo Rebuilding known failures for $TARGET_LANG
+
+TMPFILE=.__tmp__rebuild__
+grep -v -e "\"$1-" -e "\-$1_" $OUT_FILE > $TMPFILE
+mv $TMPFILE $OUT_FILE
+$PYTHON test.py --client $1
+$PYTHON test.py -U merge
+$PYTHON test.py --server $1
+$PYTHON test.py -U merge
diff --git a/test/result.js b/test/result.js
new file mode 100644
index 0000000..18b1a59
--- /dev/null
+++ b/test/result.js
@@ -0,0 +1,64 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+*/
+
+$.getJSON('results.json', function(results) {
+    $(document).ready(function() {
+        var transport = 3;
+        var socket = 4;
+        var success = 5;
+        var expected = 6;
+        var returnCode = 7;
+        var logFile = 8;
+        testTable = $('#test_results').DataTable({
+            data: results['results'],
+            columnDefs: [
+                {
+                    targets: 3,
+                    render: function(data, type, row) {
+                        return row[transport] + '-' + row[socket];
+                    },
+                },
+                {
+                    targets: 4,
+                    render: function(data, type, row) {
+                        return (row[success] ? 'success' : 'failure')
+                                + '(' + (row[returnCode] == 128 ? 'timeout' : row[returnCode]) + ')'
+                                + '(Server, '
+                                + 'Client)';
+                    },
+                },
+                {
+                    targets: 5,
+                    render: function(data, type, row) {
+                        // 'yes' rather than 'expected' to ease search
+                        return row[expected] ? 'yes' : 'unexpected';
+                    },
+                }
+            ],
+        });
+        $('#test_results_filter label input').focus().val('unexpected failure');
+        $('#test_info').text(
+            "Test Date:     " + results['date'] + "\n" +
+            "Revision:      " + results['revision'] + "\n" +
+            "Platform:      " + results['platform'] + "\n" +
+            "Test duration: " + results['duration']) + " seconds";
+    });
+});
+
diff --git a/test/rs/Cargo.toml b/test/rs/Cargo.toml
new file mode 100644
index 0000000..9b35e3c
--- /dev/null
+++ b/test/rs/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "thrift-test"
+version = "0.1.0"
+license = "Apache-2.0"
+authors = ["Apache Thrift Developers "]
+publish = false
+
+[dependencies]
+clap = "<2.28.0"
+env_logger = "0.4.0"
+log = "0.3.7"
+ordered-float = "0.3.0"
+try_from = "0.2.0"
+
+[dependencies.thrift]
+path = "../../lib/rs"
+
diff --git a/test/rs/Makefile b/test/rs/Makefile
new file mode 100644
index 0000000..d8b753a
--- /dev/null
+++ b/test/rs/Makefile
@@ -0,0 +1,643 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# test/rs/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/thrift
+pkgincludedir = $(includedir)/thrift
+pkglibdir = $(libdir)/thrift
+pkglibexecdir = $(libexecdir)/thrift
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = test/rs
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15
+ALLOCA = 
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+ANT = /usr/bin/ant
+ANT_FLAGS = 
+AR = ar
+AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf
+AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader
+AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15
+AWK = gawk
+BISON = bison
+BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a
+BOOST_CPPFLAGS = -I/usr/include
+BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a
+BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu
+BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu
+BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a
+BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a
+BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a
+BUNDLER = /usr/bin/bundle
+CABAL = /usr/bin/cabal
+CABAL_CONFIGURE_FLAGS = 
+CARGO = /usr/bin/cargo
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CLASSPATH = 
+CPP = gcc -E
+CPPFLAGS = 
+CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;
+CXX = g++ -std=c++11
+CXXCPP = g++ -E -std=c++11
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DART = /usr/lib/dart/bin/dart
+DARTPUB = /usr/lib/dart/bin/pub
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DMD = dmd
+DMD_LIBEVENT_FLAGS = 
+DMD_OF_DIRSEP = /
+DMD_OPENSSL_FLAGS = 
+DOTNETCORE = /usr/bin/dotnet
+DOTNETCORE_VERSION = 2.0.3
+DSYMUTIL = 
+DUMPBIN = 
+D_EVENT_LIB_NAME = libthriftd-event.a
+D_IMPORT_PREFIX = ${prefix}/include/d2
+D_LIB_NAME = libthriftd.a
+D_SSL_LIB_NAME = libthriftd-ssl.a
+ECHO_C = 
+ECHO_N = -n
+ECHO_T = 
+EGREP = /bin/grep -E
+ENABLE_COVERAGE = 2
+ERL = /usr/bin/erl
+ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib
+ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0
+ERLANG_LIB_DIR = /usr/lib/erlang/lib
+ERLC = /usr/bin/erlc
+ERLCFLAGS = 
+EXEEXT = 
+FGREP = /bin/grep -F
+GCOV_CFLAGS = 
+GCOV_CXXFLAGS = 
+GCOV_LDFLAGS = 
+GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GLIB_LIBS = -lglib-2.0
+GO = /usr/bin/go
+GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0
+GREP = /bin/grep
+HAVE_CXX11 = 1
+HAXE = /usr/bin/haxe
+HAXE_VERSION = 3.2.1
+INSTALL = /usr/bin/install -c
+INSTALLDIRS = vendor
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+JAVA_PREFIX = /usr/local/lib
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS = 
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBEVENT_CPPFLAGS = 
+LIBEVENT_LDFLAGS = 
+LIBEVENT_LIBS = -levent
+LIBOBJS = 
+LIBS = -lrt -lpthread 
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO = 
+LN_S = ln -s
+LTLIBOBJS = 
+LT_SYS_LIBRARY_PATH = 
+LUA = /usr/bin/lua5.3
+LUA_EXEC_PREFIX = ${exec_prefix}
+LUA_INCLUDE = -I/usr/include/lua5.3
+LUA_LIB = -llua5.3  -ldl
+LUA_PLATFORM = unknown
+LUA_PREFIX = ${prefix}
+LUA_SHORT_VERSION = 53
+LUA_VERSION = 5.3
+MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo
+MANIFEST_TOOL = :
+MAYBE_CPP = cpp
+MAYBE_CSHARP = csharp
+MAYBE_C_GLIB = c_glib
+MAYBE_D = 
+MAYBE_DART = dart
+MAYBE_DOTNETCORE = netcore
+MAYBE_ERLANG = erl
+MAYBE_GO = go
+MAYBE_HASKELL = hs
+MAYBE_JAVA = java
+MAYBE_LUA = lua
+MAYBE_NODEJS = nodejs
+MAYBE_PERL = perl
+MAYBE_PHP = php
+MAYBE_PY3 = py3
+MAYBE_PYTHON = py
+MAYBE_RS = rs
+MAYBE_RUBY = rb
+MCS = /usr/bin/mcs
+MKDIR_P = /bin/mkdir -p
+MONO_CFLAGS = 
+MONO_LIBS = 
+NM = /usr/bin/nm -B
+NMEDIT = 
+NODEJS = /usr/bin/nodejs
+NPM = /usr/bin/npm
+OBJDUMP = objdump
+OBJEXT = o
+OPENSSL_INCLUDES = 
+OPENSSL_LDFLAGS = 
+OPENSSL_LIBS = -lssl -lcrypto
+OTOOL = 
+OTOOL64 = 
+PACKAGE = thrift
+PACKAGE_BUGREPORT = 
+PACKAGE_NAME = thrift
+PACKAGE_STRING = thrift 0.11.0
+PACKAGE_TARNAME = thrift
+PACKAGE_URL = 
+PACKAGE_VERSION = 0.11.0
+PATH_SEPARATOR = :
+PERL = /usr/bin/perl
+PERL_PREFIX = /usr/local
+PHP = /usr/bin/php
+PHPUNIT = /usr/bin/phpunit
+PHP_CONFIG = /usr/bin/php-config
+PHP_CONFIG_PREFIX = /etc/php.d
+PHP_PREFIX = /usr/lib/php
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR = 
+PKG_CONFIG_PATH = 
+PYTHON = /usr/bin/python
+PYTHON3 = /usr/bin/python3
+PYTHON_EXEC_PREFIX = ${exec_prefix}
+PYTHON_PLATFORM = linux2
+PYTHON_PREFIX = ${prefix}
+PYTHON_VERSION = 2.7
+PY_PREFIX = /usr
+QT5_CFLAGS = 
+QT5_LIBS = 
+QT5_MOC = 
+QT_CFLAGS = 
+QT_LIBS = 
+QT_MOC = 
+RANLIB = ranlib
+REBAR = /usr/bin/rebar
+RUBY = /usr/bin/ruby
+RUBY_PREFIX = 
+RUNHASKELL = /usr/bin/runhaskell
+RUSTC = /usr/bin/rustc
+SED = /bin/sed
+SET_MAKE = 
+SHELL = /bin/bash
+STRIP = strip
+THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift
+TRIAL = /usr/bin/trial
+VERSION = 0.11.0
+YACC = bison -y
+YFLAGS = 
+ZLIB_CPPFLAGS = 
+ZLIB_LDFLAGS = 
+ZLIB_LIBS = -lz
+abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/test/rs
+abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/test/rs
+abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift
+abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+ac_ct_DUMPBIN = 
+am__include = include
+am__leading_dot = .
+am__quote = 
+am__tar = tar --format=ustar -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias = 
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+golang_version = 1.6.2
+have_prog_bison = yes
+host = x86_64-pc-linux-gnu
+host_alias = 
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+luadir = ${prefix}/share/lua/5.3
+luaexecdir = ${exec_prefix}/lib/lua/5.3
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+pkgluadir = ${luadir}/thrift
+pkgluaexecdir = ${luaexecdir}/thrift
+pkgpyexecdir = ${pyexecdir}/thrift
+pkgpythondir = ${pythondir}/thrift
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages
+pythondir = ${prefix}/lib/python2.7/dist-packages
+runstatedir = ${localstatedir}/run
+rustc_version = rustc 1.17.0
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+subdirs =  lib/php/src/ext/thrift_protocol
+sysconfdir = ${prefix}/etc
+target_alias = 
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+EXTRA_DIST = \
+	Cargo.toml \
+        src/lib.rs \
+	src/bin/test_server.rs \
+	src/bin/test_client.rs
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/rs/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/rs/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	clean-local cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) -I ./thrifts -out src --gen rs ../ThriftTest.thrift
+
+precross: stubs
+	$(CARGO) build
+	[ -d bin ] || mkdir bin
+	cp target/debug/test_server bin/test_server
+	cp target/debug/test_client bin/test_client
+
+clean-local:
+	$(CARGO) clean
+	-$(RM) Cargo.lock
+	-$(RM) src/thrift_test.rs
+	-$(RM) -r bin
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/rs/Makefile.am b/test/rs/Makefile.am
new file mode 100644
index 0000000..54905b4
--- /dev/null
+++ b/test/rs/Makefile.am
@@ -0,0 +1,40 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) -I ./thrifts -out src --gen rs ../ThriftTest.thrift
+
+precross: stubs
+	$(CARGO) build
+	[ -d bin ] || mkdir bin
+	cp target/debug/test_server bin/test_server
+	cp target/debug/test_client bin/test_client
+
+clean-local:
+	$(CARGO) clean
+	-$(RM) Cargo.lock
+	-$(RM) src/thrift_test.rs
+	-$(RM) -r bin
+
+EXTRA_DIST = \
+	Cargo.toml \
+        src/lib.rs \
+	src/bin/test_server.rs \
+	src/bin/test_client.rs
+
diff --git a/test/rs/Makefile.in b/test/rs/Makefile.in
new file mode 100644
index 0000000..84488a4
--- /dev/null
+++ b/test/rs/Makefile.in
@@ -0,0 +1,643 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/rs
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+	Cargo.toml \
+        src/lib.rs \
+	src/bin/test_server.rs \
+	src/bin/test_client.rs
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/rs/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/rs/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	clean-local cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	style-am style-local tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) -I ./thrifts -out src --gen rs ../ThriftTest.thrift
+
+precross: stubs
+	$(CARGO) build
+	[ -d bin ] || mkdir bin
+	cp target/debug/test_server bin/test_server
+	cp target/debug/test_client bin/test_client
+
+clean-local:
+	$(CARGO) clean
+	-$(RM) Cargo.lock
+	-$(RM) src/thrift_test.rs
+	-$(RM) -r bin
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/rs/src/bin/test_client.rs b/test/rs/src/bin/test_client.rs
new file mode 100644
index 0000000..297faf9
--- /dev/null
+++ b/test/rs/src/bin/test_client.rs
@@ -0,0 +1,605 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#[macro_use]
+extern crate log;
+extern crate env_logger;
+
+#[macro_use]
+extern crate clap;
+extern crate ordered_float;
+extern crate thrift;
+extern crate thrift_test; // huh. I have to do this to use my lib
+
+use ordered_float::OrderedFloat;
+use std::collections::{BTreeMap, BTreeSet};
+use std::fmt::Debug;
+
+use thrift::protocol::{TBinaryInputProtocol, TBinaryOutputProtocol, TCompactInputProtocol,
+                       TCompactOutputProtocol, TInputProtocol, TMultiplexedOutputProtocol,
+                       TOutputProtocol};
+use thrift::transport::{ReadHalf, TBufferedReadTransport, TBufferedWriteTransport,
+                        TFramedReadTransport, TFramedWriteTransport, TIoChannel, TReadTransport,
+                        TTcpChannel, TWriteTransport, WriteHalf};
+use thrift_test::*;
+
+fn main() {
+    env_logger::init().expect("logger setup failed");
+
+    debug!("initialized logger - running cross-test client");
+
+    match run() {
+        Ok(()) => info!("cross-test client succeeded"),
+        Err(e) => {
+            info!("cross-test client failed with error {:?}", e);
+            std::process::exit(1);
+        }
+    }
+}
+
+fn run() -> thrift::Result<()> {
+    // unsupported options:
+    // --domain-socket
+    // --named-pipe
+    // --anon-pipes
+    // --ssl
+    // --threads
+    let matches = clap_app!(rust_test_client =>
+        (version: "1.0")
+        (author: "Apache Thrift Developers ")
+        (about: "Rust Thrift test client")
+        (@arg host: --host +takes_value "Host on which the Thrift test server is located")
+        (@arg port: --port +takes_value "Port on which the Thrift test server is listening")
+        (@arg transport: --transport +takes_value "Thrift transport implementation to use (\"buffered\", \"framed\")")
+        (@arg protocol: --protocol +takes_value "Thrift protocol implementation to use (\"binary\", \"compact\")")
+        (@arg testloops: -n --testloops +takes_value "Number of times to run tests")
+    )
+        .get_matches();
+
+    let host = matches.value_of("host").unwrap_or("127.0.0.1");
+    let port = value_t!(matches, "port", u16).unwrap_or(9090);
+    let testloops = value_t!(matches, "testloops", u8).unwrap_or(1);
+    let transport = matches.value_of("transport").unwrap_or("buffered");
+    let protocol = matches.value_of("protocol").unwrap_or("binary");
+
+
+    let mut thrift_test_client = {
+        let (i_prot, o_prot) = build_protocols(host, port, transport, protocol, "ThriftTest")?;
+        ThriftTestSyncClient::new(i_prot, o_prot)
+    };
+
+    let mut second_service_client = if protocol.starts_with("multi") {
+        let (i_prot, o_prot) = build_protocols(host, port, transport, protocol, "SecondService")?;
+        Some(SecondServiceSyncClient::new(i_prot, o_prot))
+    } else {
+        None
+    };
+
+    info!(
+        "connecting to {}:{} with {}+{} stack",
+        host,
+        port,
+        protocol,
+        transport
+    );
+
+    for _ in 0..testloops {
+        make_thrift_calls(&mut thrift_test_client, &mut second_service_client)?
+    }
+
+    Ok(())
+}
+
+fn build_protocols(
+    host: &str,
+    port: u16,
+    transport: &str,
+    protocol: &str,
+    service_name: &str,
+) -> thrift::Result<(Box, Box)> {
+    let (i_chan, o_chan) = tcp_channel(host, port)?;
+
+    let (i_tran, o_tran): (Box, Box) = match transport {
+        "buffered" => {
+            (Box::new(TBufferedReadTransport::new(i_chan)),
+             Box::new(TBufferedWriteTransport::new(o_chan)))
+        }
+        "framed" => {
+            (Box::new(TFramedReadTransport::new(i_chan)),
+             Box::new(TFramedWriteTransport::new(o_chan)))
+        }
+        unmatched => return Err(format!("unsupported transport {}", unmatched).into()),
+    };
+
+    let (i_prot, o_prot): (Box, Box) = match protocol {
+        "binary" => {
+            (Box::new(TBinaryInputProtocol::new(i_tran, true)),
+             Box::new(TBinaryOutputProtocol::new(o_tran, true)))
+        }
+        "multi" => {
+            (Box::new(TBinaryInputProtocol::new(i_tran, true)),
+             Box::new(
+                TMultiplexedOutputProtocol::new(
+                    service_name,
+                    TBinaryOutputProtocol::new(o_tran, true),
+                ),
+            ))
+        }
+        "compact" => {
+            (Box::new(TCompactInputProtocol::new(i_tran)),
+             Box::new(TCompactOutputProtocol::new(o_tran)))
+        }
+        "multic" => {
+            (Box::new(TCompactInputProtocol::new(i_tran)),
+             Box::new(TMultiplexedOutputProtocol::new(service_name, TCompactOutputProtocol::new(o_tran)),))
+        }
+        unmatched => return Err(format!("unsupported protocol {}", unmatched).into()),
+    };
+
+    Ok((i_prot, o_prot))
+}
+
+// FIXME: expose "open" through the client interface so I don't have to early
+// open
+fn tcp_channel(
+    host: &str,
+    port: u16,
+) -> thrift::Result<(ReadHalf, WriteHalf)> {
+    let mut c = TTcpChannel::new();
+    c.open(&format!("{}:{}", host, port))?;
+    c.split()
+}
+
+type BuildThriftTestClient = ThriftTestSyncClient, Box>;
+type BuiltSecondServiceClient = SecondServiceSyncClient, Box>;
+
+#[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
+fn make_thrift_calls(
+    thrift_test_client: &mut BuildThriftTestClient,
+    second_service_client: &mut Option,
+) -> Result<(), thrift::Error> {
+    info!("testVoid");
+    thrift_test_client.test_void()?;
+
+    info!("testString");
+    verify_expected_result(
+        thrift_test_client.test_string("thing".to_owned()),
+        "thing".to_owned(),
+    )?;
+
+    info!("testBool");
+    verify_expected_result(thrift_test_client.test_bool(true), true)?;
+
+    info!("testBool");
+    verify_expected_result(thrift_test_client.test_bool(false), false)?;
+
+    info!("testByte");
+    verify_expected_result(thrift_test_client.test_byte(42), 42)?;
+
+    info!("testi32");
+    verify_expected_result(thrift_test_client.test_i32(1159348374), 1159348374)?;
+
+    info!("testi64");
+    // try!(verify_expected_result(thrift_test_client.test_i64(-8651829879438294565),
+    // -8651829879438294565));
+    verify_expected_result(
+        thrift_test_client.test_i64(i64::min_value()),
+        i64::min_value(),
+    )?;
+
+    info!("testDouble");
+    verify_expected_result(
+        thrift_test_client.test_double(OrderedFloat::from(42.42)),
+        OrderedFloat::from(42.42),
+    )?;
+
+    info!("testTypedef");
+    {
+        let u_snd: UserId = 2348;
+        let u_cmp: UserId = 2348;
+        verify_expected_result(thrift_test_client.test_typedef(u_snd), u_cmp)?;
+    }
+
+    info!("testEnum");
+    {
+        verify_expected_result(thrift_test_client.test_enum(Numberz::TWO), Numberz::TWO)?;
+    }
+
+    info!("testBinary");
+    {
+        let b_snd = vec![0x77, 0x30, 0x30, 0x74, 0x21, 0x20, 0x52, 0x75, 0x73, 0x74];
+        let b_cmp = vec![0x77, 0x30, 0x30, 0x74, 0x21, 0x20, 0x52, 0x75, 0x73, 0x74];
+        verify_expected_result(thrift_test_client.test_binary(b_snd), b_cmp)?;
+    }
+
+    info!("testStruct");
+    {
+        let x_snd = Xtruct {
+            string_thing: Some("foo".to_owned()),
+            byte_thing: Some(12),
+            i32_thing: Some(219129),
+            i64_thing: Some(12938492818),
+        };
+        let x_cmp = Xtruct {
+            string_thing: Some("foo".to_owned()),
+            byte_thing: Some(12),
+            i32_thing: Some(219129),
+            i64_thing: Some(12938492818),
+        };
+        verify_expected_result(thrift_test_client.test_struct(x_snd), x_cmp)?;
+    }
+
+    // Xtruct again, with optional values
+    // FIXME: apparently the erlang thrift server does not like opt-in-req-out
+    // parameters that are undefined. Joy.
+    // {
+    // let x_snd = Xtruct { string_thing: Some("foo".to_owned()), byte_thing: None,
+    // i32_thing: None, i64_thing: Some(12938492818) };
+    // let x_cmp = Xtruct { string_thing: Some("foo".to_owned()), byte_thing:
+    // Some(0), i32_thing: Some(0), i64_thing: Some(12938492818) }; // the C++
+    // server is responding correctly
+    // try!(verify_expected_result(thrift_test_client.test_struct(x_snd), x_cmp));
+    // }
+    //
+
+    info!("testNest"); // (FIXME: try Xtruct2 with optional values)
+    {
+        let x_snd = Xtruct2 {
+            byte_thing: Some(32),
+            struct_thing: Some(
+                Xtruct {
+                    string_thing: Some("foo".to_owned()),
+                    byte_thing: Some(1),
+                    i32_thing: Some(324382098),
+                    i64_thing: Some(12938492818),
+                },
+            ),
+            i32_thing: Some(293481098),
+        };
+        let x_cmp = Xtruct2 {
+            byte_thing: Some(32),
+            struct_thing: Some(
+                Xtruct {
+                    string_thing: Some("foo".to_owned()),
+                    byte_thing: Some(1),
+                    i32_thing: Some(324382098),
+                    i64_thing: Some(12938492818),
+                },
+            ),
+            i32_thing: Some(293481098),
+        };
+        verify_expected_result(thrift_test_client.test_nest(x_snd), x_cmp)?;
+    }
+
+    // do the multiplexed calls while making the main ThriftTest calls
+    if let Some(ref mut client) = second_service_client.as_mut() {
+        info!("SecondService secondtestString");
+        {
+            verify_expected_result(
+                client.secondtest_string("test_string".to_owned()),
+                "testString(\"test_string\")".to_owned(),
+            )?;
+        }
+    }
+
+    info!("testList");
+    {
+        let mut v_snd: Vec = Vec::new();
+        v_snd.push(29384);
+        v_snd.push(238);
+        v_snd.push(32498);
+
+        let mut v_cmp: Vec = Vec::new();
+        v_cmp.push(29384);
+        v_cmp.push(238);
+        v_cmp.push(32498);
+
+        verify_expected_result(thrift_test_client.test_list(v_snd), v_cmp)?;
+    }
+
+    info!("testSet");
+    {
+        let mut s_snd: BTreeSet = BTreeSet::new();
+        s_snd.insert(293481);
+        s_snd.insert(23);
+        s_snd.insert(3234);
+
+        let mut s_cmp: BTreeSet = BTreeSet::new();
+        s_cmp.insert(293481);
+        s_cmp.insert(23);
+        s_cmp.insert(3234);
+
+        verify_expected_result(thrift_test_client.test_set(s_snd), s_cmp)?;
+    }
+
+    info!("testMap");
+    {
+        let mut m_snd: BTreeMap = BTreeMap::new();
+        m_snd.insert(2, 4);
+        m_snd.insert(4, 6);
+        m_snd.insert(8, 7);
+
+        let mut m_cmp: BTreeMap = BTreeMap::new();
+        m_cmp.insert(2, 4);
+        m_cmp.insert(4, 6);
+        m_cmp.insert(8, 7);
+
+        verify_expected_result(thrift_test_client.test_map(m_snd), m_cmp)?;
+    }
+
+    info!("testStringMap");
+    {
+        let mut m_snd: BTreeMap = BTreeMap::new();
+        m_snd.insert("2".to_owned(), "4_string".to_owned());
+        m_snd.insert("4".to_owned(), "6_string".to_owned());
+        m_snd.insert("8".to_owned(), "7_string".to_owned());
+
+        let mut m_rcv: BTreeMap = BTreeMap::new();
+        m_rcv.insert("2".to_owned(), "4_string".to_owned());
+        m_rcv.insert("4".to_owned(), "6_string".to_owned());
+        m_rcv.insert("8".to_owned(), "7_string".to_owned());
+
+        verify_expected_result(thrift_test_client.test_string_map(m_snd), m_rcv)?;
+    }
+
+    // nested map
+    // expect : {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2
+    // => 2, 3 => 3, 4 => 4, }, }
+    info!("testMapMap");
+    {
+        let mut m_cmp_nested_0: BTreeMap = BTreeMap::new();
+        for i in (-4 as i32)..0 {
+            m_cmp_nested_0.insert(i, i);
+        }
+        let mut m_cmp_nested_1: BTreeMap = BTreeMap::new();
+        for i in 1..5 {
+            m_cmp_nested_1.insert(i, i);
+        }
+
+        let mut m_cmp: BTreeMap> = BTreeMap::new();
+        m_cmp.insert(-4, m_cmp_nested_0);
+        m_cmp.insert(4, m_cmp_nested_1);
+
+        verify_expected_result(thrift_test_client.test_map_map(42), m_cmp)?;
+    }
+
+    info!("testMulti");
+    {
+        let mut m_snd: BTreeMap = BTreeMap::new();
+        m_snd.insert(1298, "fizz".to_owned());
+        m_snd.insert(-148, "buzz".to_owned());
+
+        let s_cmp = Xtruct {
+            string_thing: Some("Hello2".to_owned()),
+            byte_thing: Some(1),
+            i32_thing: Some(-123948),
+            i64_thing: Some(-19234123981),
+        };
+
+        verify_expected_result(
+            thrift_test_client.test_multi(1, -123948, -19234123981, m_snd, Numberz::EIGHT, 81),
+            s_cmp,
+        )?;
+    }
+
+    // Insanity
+    // returns:
+    // { 1 => { 2 => argument,
+    //          3 => argument,
+    //        },
+    //   2 => { 6 => , },
+    // }
+    {
+        let mut arg_map_usermap: BTreeMap = BTreeMap::new();
+        arg_map_usermap.insert(Numberz::ONE, 4289);
+        arg_map_usermap.insert(Numberz::EIGHT, 19);
+
+        let mut arg_vec_xtructs: Vec = Vec::new();
+        arg_vec_xtructs.push(
+            Xtruct {
+                string_thing: Some("foo".to_owned()),
+                byte_thing: Some(8),
+                i32_thing: Some(29),
+                i64_thing: Some(92384),
+            },
+        );
+        arg_vec_xtructs.push(
+            Xtruct {
+                string_thing: Some("bar".to_owned()),
+                byte_thing: Some(28),
+                i32_thing: Some(2),
+                i64_thing: Some(-1281),
+            },
+        );
+        arg_vec_xtructs.push(
+            Xtruct {
+                string_thing: Some("baz".to_owned()),
+                byte_thing: Some(0),
+                i32_thing: Some(3948539),
+                i64_thing: Some(-12938492),
+            },
+        );
+
+        let mut s_cmp_nested_1: BTreeMap = BTreeMap::new();
+        let insanity = Insanity {
+            user_map: Some(arg_map_usermap),
+            xtructs: Some(arg_vec_xtructs),
+        };
+        s_cmp_nested_1.insert(Numberz::TWO, insanity.clone());
+        s_cmp_nested_1.insert(Numberz::THREE, insanity.clone());
+
+        let mut s_cmp_nested_2: BTreeMap = BTreeMap::new();
+        let empty_insanity = Insanity {
+            user_map: Some(BTreeMap::new()),
+            xtructs: Some(Vec::new()),
+        };
+        s_cmp_nested_2.insert(Numberz::SIX, empty_insanity);
+
+        let mut s_cmp: BTreeMap> = BTreeMap::new();
+        s_cmp.insert(1 as UserId, s_cmp_nested_1);
+        s_cmp.insert(2 as UserId, s_cmp_nested_2);
+
+        verify_expected_result(thrift_test_client.test_insanity(insanity.clone()), s_cmp)?;
+    }
+
+    info!("testException - remote throws Xception");
+    {
+        let r = thrift_test_client.test_exception("Xception".to_owned());
+        let x = match r {
+            Err(thrift::Error::User(ref e)) => {
+                match e.downcast_ref::() {
+                    Some(x) => Ok(x),
+                    None => Err(thrift::Error::User("did not get expected Xception struct".into()),),
+                }
+            }
+            _ => Err(thrift::Error::User("did not get exception".into())),
+        }?;
+
+        let x_cmp = Xception {
+            error_code: Some(1001),
+            message: Some("Xception".to_owned()),
+        };
+
+        verify_expected_result(Ok(x), &x_cmp)?;
+    }
+
+    info!("testException - remote throws TApplicationException");
+    {
+        let r = thrift_test_client.test_exception("TException".to_owned());
+        match r {
+            Err(thrift::Error::Application(ref e)) => {
+                info!("received an {:?}", e);
+                Ok(())
+            }
+            _ => Err(thrift::Error::User("did not get exception".into())),
+        }?;
+    }
+
+    info!("testException - remote succeeds");
+    {
+        let r = thrift_test_client.test_exception("foo".to_owned());
+        match r {
+            Ok(_) => Ok(()),
+            _ => Err(thrift::Error::User("received an exception".into())),
+        }?;
+    }
+
+    info!("testMultiException - remote throws Xception");
+    {
+        let r =
+            thrift_test_client.test_multi_exception("Xception".to_owned(), "ignored".to_owned());
+        let x = match r {
+            Err(thrift::Error::User(ref e)) => {
+                match e.downcast_ref::() {
+                    Some(x) => Ok(x),
+                    None => Err(thrift::Error::User("did not get expected Xception struct".into()),),
+                }
+            }
+            _ => Err(thrift::Error::User("did not get exception".into())),
+        }?;
+
+        let x_cmp = Xception {
+            error_code: Some(1001),
+            message: Some("This is an Xception".to_owned()),
+        };
+
+        verify_expected_result(Ok(x), &x_cmp)?;
+    }
+
+    info!("testMultiException - remote throws Xception2");
+    {
+        let r =
+            thrift_test_client.test_multi_exception("Xception2".to_owned(), "ignored".to_owned());
+        let x = match r {
+            Err(thrift::Error::User(ref e)) => {
+                match e.downcast_ref::() {
+                    Some(x) => Ok(x),
+                    None => Err(thrift::Error::User("did not get expected Xception struct".into()),),
+                }
+            }
+            _ => Err(thrift::Error::User("did not get exception".into())),
+        }?;
+
+        let x_cmp = Xception2 {
+            error_code: Some(2002),
+            struct_thing: Some(
+                Xtruct {
+                    string_thing: Some("This is an Xception2".to_owned()),
+                    // since this is an OPT_IN_REQ_OUT field the sender sets a default
+                    byte_thing: Some(0),
+                    // since this is an OPT_IN_REQ_OUT field the sender sets a default
+                    i32_thing: Some(0),
+                    // since this is an OPT_IN_REQ_OUT field the sender sets a default
+                    i64_thing: Some(0),
+                },
+            ),
+        };
+
+        verify_expected_result(Ok(x), &x_cmp)?;
+    }
+
+    info!("testMultiException - remote succeeds");
+    {
+        let r = thrift_test_client.test_multi_exception("haha".to_owned(), "RETURNED".to_owned());
+        let x = match r {
+            Err(e) => Err(thrift::Error::User(format!("received an unexpected exception {:?}", e).into(),),),
+            _ => r,
+        }?;
+
+        let x_cmp = Xtruct {
+            string_thing: Some("RETURNED".to_owned()),
+            // since this is an OPT_IN_REQ_OUT field the sender sets a default
+            byte_thing: Some(0),
+            // since this is an OPT_IN_REQ_OUT field the sender sets a default
+            i32_thing: Some(0),
+            // since this is an OPT_IN_REQ_OUT field the sender sets a default
+            i64_thing: Some(0),
+        };
+
+        verify_expected_result(Ok(x), x_cmp)?;
+    }
+
+    info!("testOneWay - remote sleeps for 1 second");
+    {
+        thrift_test_client.test_oneway(1)?;
+    }
+
+    // final test to verify that the connection is still writable after the one-way
+    // call
+    thrift_test_client.test_void()
+}
+
+#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
+fn verify_expected_result(
+    actual: Result,
+    expected: T,
+) -> Result<(), thrift::Error> {
+    info!("*** EXPECTED: Ok({:?})", expected);
+    info!("*** ACTUAL  : {:?}", actual);
+    match actual {
+        Ok(v) => {
+            if v == expected {
+                info!("*** OK ***");
+                Ok(())
+            } else {
+                info!("*** FAILED ***");
+                Err(thrift::Error::User(format!("expected {:?} but got {:?}", &expected, &v).into()),)
+            }
+        }
+        Err(e) => Err(e),
+    }
+}
diff --git a/test/rs/src/bin/test_server.rs b/test/rs/src/bin/test_server.rs
new file mode 100644
index 0000000..1976bf4
--- /dev/null
+++ b/test/rs/src/bin/test_server.rs
@@ -0,0 +1,398 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#[macro_use]
+extern crate log;
+extern crate env_logger;
+
+#[macro_use]
+extern crate clap;
+extern crate ordered_float;
+extern crate thrift;
+extern crate thrift_test;
+
+use ordered_float::OrderedFloat;
+use std::collections::{BTreeMap, BTreeSet};
+use std::thread;
+use std::time::Duration;
+
+use thrift::protocol::{TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory,
+                       TCompactInputProtocolFactory, TCompactOutputProtocolFactory,
+                       TInputProtocolFactory, TOutputProtocolFactory};
+use thrift::server::{TMultiplexedProcessor, TServer};
+use thrift::transport::{TBufferedReadTransportFactory, TBufferedWriteTransportFactory,
+                        TFramedReadTransportFactory, TFramedWriteTransportFactory,
+                        TReadTransportFactory, TWriteTransportFactory};
+use thrift_test::*;
+
+fn main() {
+    env_logger::init().expect("logger setup failed");
+
+    debug!("initialized logger - running cross-test server");
+
+    match run() {
+        Ok(()) => info!("cross-test server succeeded"),
+        Err(e) => {
+            info!("cross-test server failed with error {:?}", e);
+            std::process::exit(1);
+        }
+    }
+}
+
+fn run() -> thrift::Result<()> {
+
+    // unsupported options:
+    // --domain-socket
+    // --named-pipe
+    // --ssl
+    let matches = clap_app!(rust_test_client =>
+        (version: "1.0")
+        (author: "Apache Thrift Developers ")
+        (about: "Rust Thrift test server")
+        (@arg port: --port +takes_value "port on which the test server listens")
+        (@arg transport: --transport +takes_value "transport implementation to use (\"buffered\", \"framed\")")
+        (@arg protocol: --protocol +takes_value "protocol implementation to use (\"binary\", \"compact\")")
+        (@arg server_type: --server_type +takes_value "type of server instantiated (\"simple\", \"thread-pool\")")
+        (@arg workers: -n --workers +takes_value "number of thread-pool workers (\"4\")")
+    )
+            .get_matches();
+
+    let port = value_t!(matches, "port", u16).unwrap_or(9090);
+    let transport = matches.value_of("transport").unwrap_or("buffered");
+    let protocol = matches.value_of("protocol").unwrap_or("binary");
+    let server_type = matches.value_of("server_type").unwrap_or("thread-pool");
+    let workers = value_t!(matches, "workers", usize).unwrap_or(4);
+    let listen_address = format!("127.0.0.1:{}", port);
+
+    info!("binding to {}", listen_address);
+
+    let (i_transport_factory, o_transport_factory): (Box,
+                                                     Box) =
+        match &*transport {
+            "buffered" => {
+                (Box::new(TBufferedReadTransportFactory::new()),
+                 Box::new(TBufferedWriteTransportFactory::new()))
+            }
+            "framed" => {
+                (Box::new(TFramedReadTransportFactory::new()),
+                 Box::new(TFramedWriteTransportFactory::new()))
+            }
+            unknown => {
+                return Err(format!("unsupported transport type {}", unknown).into());
+            }
+        };
+
+    let (i_protocol_factory, o_protocol_factory): (Box,
+                                                   Box) =
+        match &*protocol {
+            "binary" | "multi" | "multi:binary" => {
+                (Box::new(TBinaryInputProtocolFactory::new()),
+                 Box::new(TBinaryOutputProtocolFactory::new()))
+            }
+            "compact" | "multic" | "multi:compact" => {
+                (Box::new(TCompactInputProtocolFactory::new()),
+                 Box::new(TCompactOutputProtocolFactory::new()))
+            }
+            unknown => {
+                return Err(format!("unsupported transport type {}", unknown).into());
+            }
+        };
+
+    let test_processor = ThriftTestSyncProcessor::new(ThriftTestSyncHandlerImpl {});
+
+    match &*server_type {
+        "simple" | "thread-pool" => {
+            if protocol == "multi" || protocol == "multic" {
+                let second_service_processor = SecondServiceSyncProcessor::new(SecondServiceSyncHandlerImpl {},);
+
+                let mut multiplexed_processor = TMultiplexedProcessor::new();
+                multiplexed_processor
+                    .register("ThriftTest", Box::new(test_processor), true)?;
+                multiplexed_processor
+                    .register("SecondService", Box::new(second_service_processor), false)?;
+
+                let mut server = TServer::new(
+                    i_transport_factory,
+                    i_protocol_factory,
+                    o_transport_factory,
+                    o_protocol_factory,
+                    multiplexed_processor,
+                    workers,
+                );
+
+                server.listen(&listen_address)
+            } else {
+                let mut server = TServer::new(
+                    i_transport_factory,
+                    i_protocol_factory,
+                    o_transport_factory,
+                    o_protocol_factory,
+                    test_processor,
+                    workers,
+                );
+
+                server.listen(&listen_address)
+            }
+        }
+        unknown => Err(format!("unsupported server type {}", unknown).into()),
+    }
+}
+
+struct ThriftTestSyncHandlerImpl;
+impl ThriftTestSyncHandler for ThriftTestSyncHandlerImpl {
+    fn handle_test_void(&self) -> thrift::Result<()> {
+        info!("testVoid()");
+        Ok(())
+    }
+
+    fn handle_test_string(&self, thing: String) -> thrift::Result {
+        info!("testString({})", &thing);
+        Ok(thing)
+    }
+
+    fn handle_test_bool(&self, thing: bool) -> thrift::Result {
+        info!("testBool({})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_byte(&self, thing: i8) -> thrift::Result {
+        info!("testByte({})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_i32(&self, thing: i32) -> thrift::Result {
+        info!("testi32({})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_i64(&self, thing: i64) -> thrift::Result {
+        info!("testi64({})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_double(&self, thing: OrderedFloat) -> thrift::Result> {
+        info!("testDouble({})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_binary(&self, thing: Vec) -> thrift::Result> {
+        info!("testBinary({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_struct(&self, thing: Xtruct) -> thrift::Result {
+        info!("testStruct({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_nest(&self, thing: Xtruct2) -> thrift::Result {
+        info!("testNest({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_map(&self, thing: BTreeMap) -> thrift::Result> {
+        info!("testMap({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_string_map(
+        &self,
+        thing: BTreeMap,
+    ) -> thrift::Result> {
+        info!("testStringMap({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_set(&self, thing: BTreeSet) -> thrift::Result> {
+        info!("testSet({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_list(&self, thing: Vec) -> thrift::Result> {
+        info!("testList({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_enum(&self, thing: Numberz) -> thrift::Result {
+        info!("testEnum({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_typedef(&self, thing: UserId) -> thrift::Result {
+        info!("testTypedef({})", thing);
+        Ok(thing)
+    }
+
+    /// @return map> - returns a dictionary with these values:
+    /// {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2 =>
+    /// 2, 3 => 3, 4 => 4, }, }
+    fn handle_test_map_map(&self, hello: i32) -> thrift::Result>> {
+        info!("testMapMap({})", hello);
+
+        let mut inner_map_0: BTreeMap = BTreeMap::new();
+        for i in -4..(0 as i32) {
+            inner_map_0.insert(i, i);
+        }
+
+        let mut inner_map_1: BTreeMap = BTreeMap::new();
+        for i in 1..5 {
+            inner_map_1.insert(i, i);
+        }
+
+        let mut ret_map: BTreeMap> = BTreeMap::new();
+        ret_map.insert(-4, inner_map_0);
+        ret_map.insert(4, inner_map_1);
+
+        Ok(ret_map)
+    }
+
+    /// Creates a the returned map with these values and prints it out:
+    ///     { 1 => { 2 => argument,
+    ///              3 => argument,
+    ///            },
+    ///       2 => { 6 => , },
+    ///     }
+    /// return map> - a map with the above values
+    fn handle_test_insanity(
+        &self,
+        argument: Insanity,
+    ) -> thrift::Result>> {
+        info!("testInsanity({:?})", argument);
+        let mut map_0: BTreeMap = BTreeMap::new();
+        map_0.insert(Numberz::TWO, argument.clone());
+        map_0.insert(Numberz::THREE, argument.clone());
+
+        let mut map_1: BTreeMap = BTreeMap::new();
+        let insanity = Insanity {
+            user_map: None,
+            xtructs: None,
+        };
+        map_1.insert(Numberz::SIX, insanity);
+
+        let mut ret: BTreeMap> = BTreeMap::new();
+        ret.insert(1, map_0);
+        ret.insert(2, map_1);
+
+        Ok(ret)
+    }
+
+    /// returns an Xtruct with:
+    /// string_thing = "Hello2", byte_thing = arg0, i32_thing = arg1 and
+    /// i64_thing = arg2
+    fn handle_test_multi(
+        &self,
+        arg0: i8,
+        arg1: i32,
+        arg2: i64,
+        _: BTreeMap,
+        _: Numberz,
+        _: UserId,
+    ) -> thrift::Result {
+        let x_ret = Xtruct {
+            string_thing: Some("Hello2".to_owned()),
+            byte_thing: Some(arg0),
+            i32_thing: Some(arg1),
+            i64_thing: Some(arg2),
+        };
+
+        Ok(x_ret)
+    }
+
+    /// if arg == "Xception" throw Xception with errorCode = 1001 and message =
+    /// arg
+    /// else if arg == "TException" throw TException
+    /// else do not throw anything
+    fn handle_test_exception(&self, arg: String) -> thrift::Result<()> {
+        info!("testException({})", arg);
+
+        match &*arg {
+            "Xception" => {
+                Err(
+                    (Xception {
+                             error_code: Some(1001),
+                             message: Some(arg),
+                         })
+                        .into(),
+                )
+            }
+            "TException" => Err("this is a random error".into()),
+            _ => Ok(()),
+        }
+    }
+
+    /// if arg0 == "Xception":
+    /// throw Xception with errorCode = 1001 and message = "This is an
+    /// Xception"
+    /// else if arg0 == "Xception2":
+    /// throw Xception2 with errorCode = 2002 and struct_thing.string_thing =
+    /// "This is an Xception2"
+    // else:
+    //   do not throw anything and return Xtruct with string_thing = arg1
+    fn handle_test_multi_exception(&self, arg0: String, arg1: String) -> thrift::Result {
+        match &*arg0 {
+            "Xception" => {
+                Err(
+                    (Xception {
+                             error_code: Some(1001),
+                             message: Some("This is an Xception".to_owned()),
+                         })
+                        .into(),
+                )
+            }
+            "Xception2" => {
+                Err(
+                    (Xception2 {
+                             error_code: Some(2002),
+                             struct_thing: Some(
+                            Xtruct {
+                                string_thing: Some("This is an Xception2".to_owned()),
+                                byte_thing: None,
+                                i32_thing: None,
+                                i64_thing: None,
+                            },
+                        ),
+                         })
+                        .into(),
+                )
+            }
+            _ => {
+                Ok(
+                    Xtruct {
+                        string_thing: Some(arg1),
+                        byte_thing: None,
+                        i32_thing: None,
+                        i64_thing: None,
+                    },
+                )
+            }
+        }
+    }
+
+    fn handle_test_oneway(&self, seconds_to_sleep: i32) -> thrift::Result<()> {
+        thread::sleep(Duration::from_secs(seconds_to_sleep as u64));
+        Ok(())
+    }
+}
+
+struct SecondServiceSyncHandlerImpl;
+impl SecondServiceSyncHandler for SecondServiceSyncHandlerImpl {
+    fn handle_secondtest_string(&self, thing: String) -> thrift::Result {
+        info!("(second)testString({})", &thing);
+        let ret = format!("testString(\"{}\")", &thing);
+        Ok(ret)
+    }
+}
diff --git a/test/rs/src/lib.rs b/test/rs/src/lib.rs
new file mode 100644
index 0000000..479bf90
--- /dev/null
+++ b/test/rs/src/lib.rs
@@ -0,0 +1,23 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+extern crate ordered_float;
+extern crate thrift;
+extern crate try_from;
+
+mod thrift_test;
+pub use thrift_test::*;
diff --git a/test/test.py b/test/test.py
new file mode 100755
index 0000000..5a015ea
--- /dev/null
+++ b/test/test.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Apache Thrift - integration test suite
+#
+# tests different server-client, protocol and transport combinations
+#
+# This script supports python 2.7 and later.
+# python 3.x is recommended for better stability.
+#
+
+from __future__ import print_function
+from itertools import chain
+import json
+import logging
+import multiprocessing
+import argparse
+import os
+import sys
+
+import crossrunner
+from crossrunner.compat import path_join
+
+ROOT_DIR = os.path.dirname(os.path.realpath(os.path.dirname(__file__)))
+TEST_DIR_RELATIVE = 'test'
+TEST_DIR = path_join(ROOT_DIR, TEST_DIR_RELATIVE)
+FEATURE_DIR_RELATIVE = path_join(TEST_DIR_RELATIVE, 'features')
+CONFIG_FILE = 'tests.json'
+
+
+def run_cross_tests(server_match, client_match, jobs, skip_known_failures, retry_count, regex):
+    logger = multiprocessing.get_logger()
+    logger.debug('Collecting tests')
+    with open(path_join(TEST_DIR, CONFIG_FILE), 'r') as fp:
+        j = json.load(fp)
+    tests = crossrunner.collect_cross_tests(j, server_match, client_match, regex)
+    if not tests:
+        print('No test found that matches the criteria', file=sys.stderr)
+        print('  servers: %s' % server_match, file=sys.stderr)
+        print('  clients: %s' % client_match, file=sys.stderr)
+        return False
+    if skip_known_failures:
+        logger.debug('Skipping known failures')
+        known = crossrunner.load_known_failures(TEST_DIR)
+        tests = list(filter(lambda t: crossrunner.test_name(**t) not in known, tests))
+
+    dispatcher = crossrunner.TestDispatcher(TEST_DIR, ROOT_DIR, TEST_DIR_RELATIVE, jobs)
+    logger.debug('Executing %d tests' % len(tests))
+    try:
+        for r in [dispatcher.dispatch(test, retry_count) for test in tests]:
+            r.wait()
+        logger.debug('Waiting for completion')
+        return dispatcher.wait()
+    except (KeyboardInterrupt, SystemExit):
+        logger.debug('Interrupted, shutting down')
+        dispatcher.terminate()
+        return False
+
+
+def run_feature_tests(server_match, feature_match, jobs, skip_known_failures, retry_count, regex):
+    basedir = path_join(ROOT_DIR, FEATURE_DIR_RELATIVE)
+    logger = multiprocessing.get_logger()
+    logger.debug('Collecting tests')
+    with open(path_join(TEST_DIR, CONFIG_FILE), 'r') as fp:
+        j = json.load(fp)
+    with open(path_join(basedir, CONFIG_FILE), 'r') as fp:
+        j2 = json.load(fp)
+    tests = crossrunner.collect_feature_tests(j, j2, server_match, feature_match, regex)
+    if not tests:
+        print('No test found that matches the criteria', file=sys.stderr)
+        print('  servers: %s' % server_match, file=sys.stderr)
+        print('  features: %s' % feature_match, file=sys.stderr)
+        return False
+    if skip_known_failures:
+        logger.debug('Skipping known failures')
+        known = crossrunner.load_known_failures(basedir)
+        tests = list(filter(lambda t: crossrunner.test_name(**t) not in known, tests))
+
+    dispatcher = crossrunner.TestDispatcher(TEST_DIR, ROOT_DIR, FEATURE_DIR_RELATIVE, jobs)
+    logger.debug('Executing %d tests' % len(tests))
+    try:
+        for r in [dispatcher.dispatch(test, retry_count) for test in tests]:
+            r.wait()
+        logger.debug('Waiting for completion')
+        return dispatcher.wait()
+    except (KeyboardInterrupt, SystemExit):
+        logger.debug('Interrupted, shutting down')
+        dispatcher.terminate()
+        return False
+
+
+def default_concurrenty():
+    try:
+        return int(os.environ.get('THRIFT_CROSSTEST_CONCURRENCY'))
+    except (TypeError, ValueError):
+        # Since much time is spent sleeping, use many threads
+        return int(multiprocessing.cpu_count() * 1.25) + 1
+
+
+def main(argv):
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--server', default='', nargs='*',
+                        help='list of servers to test')
+    parser.add_argument('--client', default='', nargs='*',
+                        help='list of clients to test')
+    parser.add_argument('-F', '--features', nargs='*', default=None,
+                        help='run server feature tests instead of cross language tests')
+    parser.add_argument('-R', '--regex', help='test name pattern to run')
+    parser.add_argument('-s', '--skip-known-failures', action='store_true', dest='skip_known_failures',
+                        help='do not execute tests that are known to fail')
+    parser.add_argument('-r', '--retry-count', type=int,
+                        default=0, help='maximum retry on failure')
+    parser.add_argument('-j', '--jobs', type=int,
+                        default=default_concurrenty(),
+                        help='number of concurrent test executions')
+
+    g = parser.add_argument_group(title='Advanced')
+    g.add_argument('-v', '--verbose', action='store_const',
+                   dest='log_level', const=logging.DEBUG, default=logging.WARNING,
+                   help='show debug output for test runner')
+    g.add_argument('-P', '--print-expected-failures', choices=['merge', 'overwrite'],
+                   dest='print_failures',
+                   help="generate expected failures based on last result and print to stdout")
+    g.add_argument('-U', '--update-expected-failures', choices=['merge', 'overwrite'],
+                   dest='update_failures',
+                   help="generate expected failures based on last result and save to default file location")
+    options = parser.parse_args(argv)
+
+    logger = multiprocessing.log_to_stderr()
+    logger.setLevel(options.log_level)
+
+    if options.features is not None and options.client:
+        print('Cannot specify both --features and --client ', file=sys.stderr)
+        return 1
+
+    # Allow multiple args separated with ',' for backward compatibility
+    server_match = list(chain(*[x.split(',') for x in options.server]))
+    client_match = list(chain(*[x.split(',') for x in options.client]))
+
+    if options.update_failures or options.print_failures:
+        dire = path_join(ROOT_DIR, FEATURE_DIR_RELATIVE) if options.features is not None else TEST_DIR
+        res = crossrunner.generate_known_failures(
+            dire, options.update_failures == 'overwrite',
+            options.update_failures, options.print_failures)
+    elif options.features is not None:
+        features = options.features or ['.*']
+        res = run_feature_tests(server_match, features, options.jobs, options.skip_known_failures, options.retry_count, options.regex)
+    else:
+        res = run_cross_tests(server_match, client_match, options.jobs, options.skip_known_failures, options.retry_count, options.regex)
+    return 0 if res else 1
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
diff --git a/test/tests.json b/test/tests.json
new file mode 100644
index 0000000..c4e07ee
--- /dev/null
+++ b/test/tests.json
@@ -0,0 +1,689 @@
+[
+  {
+    "name": "c_glib",
+    "platforms": [
+      "Linux"
+    ],
+    "server": {
+      "command": [
+        "test_server",
+        "--lt-debug"
+      ],
+      "protocols": [
+        "binary:multi",
+        "compact:multic"
+      ]
+    },
+    "client": {
+      "command": [
+        "test_client",
+        "--lt-debug"
+      ],
+      "protocols": [
+        "multi:binary",
+        "multic:compact"
+      ],
+      "sockets": [
+        "ip-ssl"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "multi",
+      "multic"
+    ],
+    "workdir": "c_glib"
+  },
+  {
+    "name": "d",
+    "server": {
+      "command": [
+        "thrift_test_server"
+      ]
+    },
+    "client": {
+      "command": [
+        "thrift_test_client"
+      ]
+    },
+    "transports": [
+      "http",
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "json"
+    ],
+    "workdir": "../lib/d/test"
+  },
+  {
+    "name": "go",
+    "server": {
+      "command": [
+        "testserver",
+        "--certPath=../../keys"
+      ]
+    },
+    "client": {
+      "timeout": 6,
+      "command": [
+        "testclient"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed",
+      "http"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "json"
+    ],
+    "workdir": "go/bin"
+  },
+  {
+    "name": "java",
+    "join_args": true,
+    "command": [
+      "ant",
+      "-f",
+      "build.xml",
+      "-Dno-gen-thrift=\"\"",
+      "-Dtestargs"
+    ],
+    "prepare": [
+      "ant",
+      "-f",
+      "build.xml",
+      "compile-test"
+    ],
+    "server": {
+      "delay": 10,
+      "extra_args": ["run-testserver"],
+      "protocols": [
+        "binary:multi",
+        "compact:multic",
+        "json:multij"
+      ]
+    },
+    "client": {
+      "timeout": 13,
+      "extra_args": ["run-testclient"],
+      "transports": [
+        "http"
+      ],
+      "protocols": [
+        "multi:binary",
+        "multic:compact",
+        "multij:json"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed",
+      "framed:fastframed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "json",
+      "multi",
+      "multic",
+      "multij"
+    ],
+    "workdir": "../lib/java"
+  },
+  {
+    "name": "nodejs",
+    "env": {
+      "NODE_PATH": "../lib"
+    },
+    "server": {
+      "command": [
+        "node",
+        "server.js",
+        "--type=tcp"
+      ]
+    },
+    "client": {
+      "timeout": 6,
+      "command": [
+        "node",
+        "client.js",
+        "--type=tcp"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed",
+      "http"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "compact",
+      "binary",
+      "json"
+    ],
+    "workdir": "../lib/nodejs/test"
+  },
+  {
+    "name": "hs",
+    "server": {
+      "command": [
+        "TestServer"
+      ]
+    },
+    "client": {
+      "timeout": 6,
+      "transports": [
+        "http"
+      ],
+      "command": [
+        "TestClient"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip"
+    ],
+    "protocols": [
+      "header",
+      "compact",
+      "binary",
+      "json"
+    ],
+    "workdir": "hs"
+  },
+  {
+    "name": "py",
+    "server": {
+      "extra_args": ["TSimpleServer"],
+      "command": [
+        "TestServer.py",
+        "--verbose",
+        "--genpydir=gen-py"
+      ]
+    },
+    "client": {
+      "timeout": 10,
+      "command": [
+        "TestClient.py",
+        "--verbose",
+        "--host=localhost",
+        "--genpydir=gen-py"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "compact",
+      "binary",
+      "json",
+      "binary:accel",
+      "compact:accelc"
+    ],
+    "workdir": "py"
+  },
+  {
+    "comment": "Using 'python3' executable to test py2 and 3 at once",
+    "name": "py3",
+    "server": {
+      "extra_args": ["TSimpleServer"],
+      "command": [
+        "python3",
+        "TestServer.py",
+        "--verbose",
+        "--genpydir=gen-py"
+      ]
+    },
+    "client": {
+      "timeout": 10,
+      "command": [
+        "python3",
+        "TestClient.py",
+        "--host=localhost",
+        "--genpydir=gen-py"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip-ssl",
+      "ip"
+    ],
+    "protocols": [
+      "compact",
+      "binary",
+      "json",
+      "binary:accel",
+      "compact:accelc"
+    ],
+    "workdir": "py"
+  },
+  {
+    "name": "cpp",
+    "server": {
+      "command": [
+        "TestServer"
+      ],
+      "protocols": [
+        "binary:multi",
+        "compact:multic",
+        "header:multih",
+        "json:multij"
+      ]
+    },
+    "client": {
+      "timeout": 8,
+      "command": [
+        "TestClient"
+      ],
+      "protocols": [
+        "multi:binary",
+        "multic:compact",
+        "multih:header",
+        "multij:json"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "http",
+      "framed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl",
+      "domain"
+    ],
+    "protocols": [
+      "compact",
+      "binary",
+      "json",
+      "header",
+      "multi",
+      "multic",
+      "multih",
+      "multij"
+    ],
+    "workdir": "cpp"
+  },
+  {
+    "name": "rb",
+    "server": {
+      "command": [
+        "ruby",
+        "../integration/TestServer.rb"
+      ]
+    },
+    "client": {
+      "timeout": 5,
+      "command": [
+        "ruby",
+        "../integration/TestClient.rb"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip"
+    ],
+    "protocols": [
+      "compact",
+      "binary",
+      "json",
+      "binary:accel"
+    ],
+    "workdir": "rb/gen-rb"
+  },
+  {
+    "name": "csharp",
+    "env": {
+      "MONO_PATH": "../../lib/csharp/"
+    },
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "json"
+    ],
+    "server": {
+      "command": [
+        "mono",
+        "TestClientServer.exe",
+        "server"
+      ]
+    },
+    "client": {
+      "timeout": 9,
+      "command": [
+        "mono",
+        "TestClientServer.exe",
+        "client"
+      ],
+      "protocols": [
+        "multi",
+        "multic",
+        "multi:binary",
+        "multic:compact"
+      ]
+    },
+    "workdir": "csharp"
+  },
+  {
+    "name": "netcore",
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "json"
+    ],
+    "server-disabled": {
+      "command": [
+        "dotnet",
+        "run",
+  "--no-build",
+  "--no-restore",
+  "--",
+        "server"
+      ]
+    },
+    "client": {
+      "timeout": 10,
+      "command": [
+        "dotnet",
+        "run",
+  "--no-build",
+  "--no-restore",
+  "--",
+        "client"
+      ]
+    },
+    "workdir": "netcore/ThriftTest"
+  },
+  {
+    "name": "perl",
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl",
+      "domain"
+    ],
+    "protocols": [
+      "binary",
+      "multi"
+    ],
+    "client": {
+      "command": [
+        "perl",
+        "-Igen-perl/",
+        "-I../../lib/perl/lib/",
+        "TestClient.pl",
+        "--ca=../keys/CA.pem",
+        "--cert=../keys/client.crt",
+        "--key=../keys/client.key"
+      ],
+      "protocols": [
+        "multi:binary"
+      ]
+    },
+    "server": {
+      "command": [
+        "perl",
+        "-Igen-perl/",
+        "-I../../lib/perl/lib/",
+        "TestServer.pl",
+        "--cert=../keys/server.crt",
+        "--key=../keys/server.key"
+      ],
+      "protocols": [
+        "binary:multi"
+      ]
+    },
+    "workdir": "perl"
+  },
+  {
+    "name": "php",
+    "client": {
+      "timeout": 6,
+      "transports": [
+        "buffered",
+        "framed"
+      ],
+      "sockets": [
+        "ip"
+      ],
+      "protocols": [
+        "binary",
+        "compact",
+        "binary:accel"
+      ],
+      "command": [
+        "php",
+        "-dextension_dir=php_ext_dir",
+        "--php-ini=test_php.ini",
+        "--no-php-ini",
+        "-ddisplay_errors=stderr",
+        "-dlog_errors=0",
+        "-derror_reporting=E_ALL",
+        "TestClient.php"
+      ]
+    },
+    "workdir": "php"
+  },
+  {
+    "name": "dart",
+    "client": {
+      "transports": [
+        "buffered",
+        "framed",
+        "http"
+      ],
+      "sockets": [
+        "ip"
+      ],
+      "protocols": [
+        "binary",
+        "compact",
+        "json"
+      ],
+      "command": [
+        "dart",
+        "test_client/bin/main.dart"
+      ]
+    },
+    "workdir": "dart"
+  },
+  {
+    "name": "erl",
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "binary",
+      "compact"
+    ],
+    "client": {
+      "command": [
+        "erl",
+        "+K",
+        "true",
+        "-noshell",
+        "-pa",
+        "../../lib/erl/ebin/",
+        "-pa",
+        "./ebin",
+        "-s",
+        "test_client",
+        "-s",
+        "init",
+        "stop",
+        "-extra"
+      ]
+    },
+    "server": {
+      "command": [
+        "erl",
+        "+K",
+        "true",
+        "-noshell",
+        "-pa",
+        "../../lib/erl/ebin/",
+        "-pa",
+        "./ebin",
+        "-s",
+        "test_thrift_server",
+        "-extra"
+      ]
+    },
+    "workdir": "erl"
+  },
+  {
+    "name": "js",
+    "transports": [
+      "http"
+    ],
+    "sockets": [
+      "ip"
+    ],
+    "protocols": [
+      "json"
+    ],
+    "client": {
+      "command": [
+        "phantomjs",
+        "test/phantom-client.js"
+      ]
+    },
+    "workdir": "../lib/js"
+  },
+  {
+    "name": "lua",
+    "TODO": "Add dll to LUA_CPATH",
+    "env": {
+      "LUA_PATH": ";;gen-lua/?.lua;../../lib/lua/?.lua",
+      "LUA_CPATH": ";;../../lib/lua/.libs/?.so"
+    },
+    "client": {
+      "timeout": 5,
+      "transports": [
+        "buffered",
+        "framed",
+        "http"
+      ],
+      "sockets": [
+        "ip"
+      ],
+      "protocols": [
+        "binary",
+        "compact",
+        "json"
+      ],
+      "command": [
+        "lua",
+        "test_basic_client.lua"
+      ]
+    },
+    "workdir": "lua"
+  },
+  {
+    "name": "rs",
+    "env": {
+      "RUST_BACKTRACE": "1",
+      "RUST_LOG": "info"
+    },
+    "server": {
+      "command": [
+        "test_server"
+      ],
+      "protocols": [
+        "binary:multi",
+        "compact:multic"
+      ]
+    },
+    "client": {
+      "timeout": 6,
+      "command": [
+        "test_client"
+      ],
+      "protocols": [
+        "multi:binary",
+        "multic:compact"
+      ]
+    },
+    "sockets": [
+      "ip"
+    ],
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "multi",
+      "multic"
+    ],
+    "workdir": "rs/bin"
+  }
+]
diff --git a/test/threads/Makefile b/test/threads/Makefile
new file mode 100644
index 0000000..df72396
--- /dev/null
+++ b/test/threads/Makefile
@@ -0,0 +1,63 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Default target is everything
+
+ifndef thrift_home
+thrift_home=../../
+endif #thrift_home
+
+target: all
+
+ifndef boost_home
+boost_home=/usr/local/include/boost-1_33_1
+endif #boost_home
+target: all
+
+include_paths = $(thrift_home)/lib/cpp/src \
+		$(boost_home)
+
+include_flags = $(patsubst %,-I%, $(include_paths))
+
+# Tools
+ifndef THRIFT
+THRIFT = ../../compiler/cpp/thrift
+endif # THRIFT
+
+CC     = g++
+LD     = g++
+
+# Compiler flags
+LFL   =  -L$(thrift_home)/lib/cpp/.libs -lthrift
+CCFL  = -Wall -O3 -g -I./gen-cpp $(include_flags)
+CFL   = $(CCFL) $(LFL)
+
+all: server client
+
+stubs: ThreadsTest.thrift
+	$(THRIFT) --gen cpp --gen py ThreadsTest.thrift
+
+server: stubs
+	$(CC) -o ThreadsServer $(CFL) ThreadsServer.cpp ./gen-cpp/ThreadsTest.cpp ./gen-cpp/ThreadsTest_types.cpp
+
+client: stubs
+	$(CC) -o ThreadsClient $(CFL) ThreadsClient.cpp ./gen-cpp/ThreadsTest.cpp ./gen-cpp/ThreadsTest_types.cpp
+
+clean:
+	$(RM) -r *.o ThreadsServer ThreadsClient gen-cpp gen-py
diff --git a/test/threads/ThreadsClient.cpp b/test/threads/ThreadsClient.cpp
new file mode 100644
index 0000000..9306a3f
--- /dev/null
+++ b/test/threads/ThreadsClient.cpp
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// This autogenerated skeleton file illustrates how to build a server.
+// You should copy it to another filename to avoid overwriting it.
+
+#include "ThreadsTest.h"
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#if _WIN32
+   #include 
+#endif
+
+using boost::shared_ptr;
+using namespace apache::thrift;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+using namespace apache::thrift::server;
+using namespace apache::thrift::concurrency;
+
+int main(int argc, char **argv) {
+#if _WIN32
+  transport::TWinsockSingleton::create();
+#endif
+  int port = 9090;
+  std::string host = "localhost";
+
+  shared_ptr transport(new TSocket(host, port));
+  shared_ptr protocol(new TBinaryProtocol(transport));
+
+  transport->open();
+
+  ThreadsTestClient client(protocol);
+  int val;
+  val = client.threadOne(5);
+  fprintf(stderr, "%d\n", val);
+  val = client.stop();
+  fprintf(stderr, "%d\n", val);
+  val = client.threadTwo(5);
+  fprintf(stderr, "%d\n", val);
+
+  transport->close();
+
+  fprintf(stderr, "done.\n");
+
+  return 0;
+}
+
diff --git a/test/threads/ThreadsServer.cpp b/test/threads/ThreadsServer.cpp
new file mode 100644
index 0000000..a267c3b
--- /dev/null
+++ b/test/threads/ThreadsServer.cpp
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// This autogenerated skeleton file illustrates how to build a server.
+// You should copy it to another filename to avoid overwriting it.
+
+#include "ThreadsTest.h"
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#if _WIN32
+   #include 
+#endif
+
+using boost::shared_ptr;
+using namespace apache::thrift;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+using namespace apache::thrift::server;
+using namespace apache::thrift::concurrency;
+
+
+class ThreadsTestHandler : virtual public ThreadsTestIf {
+ public:
+  ThreadsTestHandler() {
+    // Your initialization goes here
+  }
+
+  int32_t threadOne(const int32_t sleep) {
+    // Your implementation goes here
+    printf("threadOne\n");
+    go2sleep(1, sleep);
+    return 1;
+  }
+
+  int32_t threadTwo(const int32_t sleep) {
+    // Your implementation goes here
+    printf("threadTwo\n");
+    go2sleep(2, sleep);
+    return 1;
+  }
+
+  int32_t threadThree(const int32_t sleep) {
+    // Your implementation goes here
+    printf("threadThree\n");
+    go2sleep(3, sleep);
+    return 1;
+  }
+
+  int32_t threadFour(const int32_t sleep) {
+    // Your implementation goes here
+    printf("threadFour\n");
+    go2sleep(4, sleep);
+    return 1;
+  }
+
+  int32_t stop() {
+    printf("stop\n");
+    server_->stop();
+    return 1;
+  }
+
+  void setServer(boost::shared_ptr server) {
+    server_ = server;
+  }
+
+protected:
+  void go2sleep(int thread, int seconds) {
+    Monitor m;
+    Synchronized s(m);
+    for (int i = 0; i < seconds; ++i) {
+      fprintf(stderr, "Thread %d: sleep %d\n", thread, i);
+      try {
+        m.wait(1000);
+      } catch(const TimedOutException&) {
+      }
+    }
+    fprintf(stderr, "THREAD %d DONE\n", thread);
+  }
+
+private:
+  boost::shared_ptr server_;
+
+};
+
+int main(int argc, char **argv) {
+#if _WIN32
+  transport::TWinsockSingleton::create();
+#endif
+  int port = 9090;
+  shared_ptr handler(new ThreadsTestHandler());
+  shared_ptr processor(new ThreadsTestProcessor(handler));
+  shared_ptr serverTransport(new TServerSocket(port));
+  shared_ptr transportFactory(new TBufferedTransportFactory());
+  shared_ptr protocolFactory(new TBinaryProtocolFactory());
+
+  /*
+  shared_ptr threadManager =
+    ThreadManager::newSimpleThreadManager(10);
+  shared_ptr threadFactory =
+    shared_ptr(new PlatformThreadFactory());
+  threadManager->threadFactory(threadFactory);
+  threadManager->start();
+
+  shared_ptr server =
+    shared_ptr(new TThreadPoolServer(processor,
+                                              serverTransport,
+                                              transportFactory,
+                                              protocolFactory,
+                                              threadManager));
+  */
+
+  shared_ptr server =
+    shared_ptr(new TThreadedServer(processor,
+                                            serverTransport,
+                                            transportFactory,
+                                            protocolFactory));
+
+  handler->setServer(server);
+
+  server->serve();
+
+  fprintf(stderr, "done.\n");
+
+  return 0;
+}
+
diff --git a/test/threads/ThreadsTest.thrift b/test/threads/ThreadsTest.thrift
new file mode 100644
index 0000000..caa9346
--- /dev/null
+++ b/test/threads/ThreadsTest.thrift
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+service ThreadsTest {
+  i32 threadOne(1: i32 sleep=15),
+  i32 threadTwo(2: i32 sleep=15),
+  i32 threadThree(3: i32 sleep=15),
+  i32 threadFour(4: i32 sleep=15)
+
+  i32 stop();
+
+}
diff --git a/test/valgrind.suppress b/test/valgrind.suppress
new file mode 100644
index 0000000..de17cb8
--- /dev/null
+++ b/test/valgrind.suppress
@@ -0,0 +1,53 @@
+{
+   boost/get_once_per_thread_epoch/ignore
+   Memcheck:Leak
+   match-leak-kinds: reachable
+   fun:malloc
+   fun:_ZN5boost6detail25get_once_per_thread_epochEv
+}
+{
+   boostthreads/once/ignore
+   Helgrind:Race
+   fun:_ZN5boost13thread_detail17enter_once_regionERNS_9once_flagE
+   fun:_ZN5boost6detail23get_current_thread_dataEv
+   fun:_ZN5boost6detail20interruption_checkerC1EP15pthread_mutex_tP14pthread_cond_t
+   fun:_ZN5boost22condition_variable_any4waitINS_11unique_lockINS_11timed_mutexEEEEEvRT_
+   fun:_ZN6apache6thrift11concurrency7Monitor4Impl11waitForeverEv
+   fun:_ZN6apache6thrift11concurrency7Monitor4Impl19waitForTimeRelativeEl
+   fun:_ZN6apache6thrift11concurrency7Monitor4Impl4waitEl
+   fun:_ZNK6apache6thrift11concurrency7Monitor4waitEl
+   fun:_ZN6apache6thrift11concurrency11BoostThread5startEv
+   fun:_ZN6apache6thrift11concurrency4test18ThreadFactoryTests12reapNThreadsEii
+   fun:main
+}
+{
+   pthread/creation-tls/ignore
+   Helgrind:Race
+   fun:mempcpy
+   fun:_dl_allocate_tls_init
+   fun:get_cached_stack
+   fun:allocate_stack
+   fun:pthread_create@@GLIBC_2.2*
+   obj:/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so
+   fun:_ZN6apache6thrift11concurrency13PthreadThread5startEv
+   fun:_ZN6apache6thrift11concurrency4test18ThreadFactoryTests12reapNThreadsEii
+   fun:main
+}
+{
+   boost-thread/creation-tls/ignore
+   Helgrind:Race
+   fun:mempcpy
+   fun:_dl_allocate_tls_init
+   fun:get_cached_stack
+   fun:allocate_stack
+   fun:pthread_create@@GLIBC_2.2.5
+   obj:/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so
+   fun:_ZN5boost6thread21start_thread_noexceptEv
+   fun:_ZN5boost6thread12start_threadEv
+   fun:_ZN5boost6threadC1ISt5_BindIFPFPvS3_ES3_EEEEOT_
+   fun:_ZN6apache6thrift11concurrency11BoostThread5startEv
+   fun:_ZN6apache6thrift11concurrency4test18ThreadFactoryTests12reapNThreadsEii
+   fun:main
+}
+
+
diff --git a/tutorial/Makefile.am b/tutorial/Makefile.am
new file mode 100755
index 0000000..d8ad09c
--- /dev/null
+++ b/tutorial/Makefile.am
@@ -0,0 +1,106 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+SUBDIRS =
+
+if MINGW
+# do nothing, just build the compiler
+else
+
+if WITH_C_GLIB
+SUBDIRS += c_glib
+endif
+
+if WITH_CPP
+SUBDIRS += cpp
+endif
+
+if WITH_D
+SUBDIRS += d
+endif
+
+if WITH_JAVA
+SUBDIRS += java
+SUBDIRS += js
+endif
+
+if WITH_PYTHON
+SUBDIRS += py
+SUBDIRS += py.twisted
+SUBDIRS += py.tornado
+endif
+
+if WITH_RUBY
+SUBDIRS += rb
+endif
+
+if WITH_HASKELL
+SUBDIRS += hs
+endif
+
+if WITH_HAXE
+SUBDIRS += haxe
+endif
+
+if WITH_DOTNETCORE
+SUBDIRS += netcore
+endif
+
+if WITH_GO
+SUBDIRS += go
+endif
+
+if WITH_NODEJS
+SUBDIRS += nodejs
+endif
+
+if WITH_DART
+SUBDIRS += dart
+endif
+
+if WITH_RS
+SUBDIRS += rs
+endif
+
+#
+# generate html for ThriftTest.thrift
+#
+all-local:
+	$(top_builddir)/compiler/cpp/thrift --gen html -r $(top_srcdir)/tutorial/tutorial.thrift
+
+clean-local:
+	rm -rf $(top_srcdir)/tutorial/gen-html
+
+endif
+
+# Any folders or files not listed above being added to SUBDIR need to be placed here in
+# EXTRA_DIST to be included in the release
+EXTRA_DIST = \
+	as3 \
+	csharp \
+	d \
+	delphi \
+	erl \
+	hs \
+	ocaml \
+	perl \
+	php \
+	shared.thrift \
+	tutorial.thrift \
+	README.md
diff --git a/tutorial/Makefile.in b/tutorial/Makefile.in
new file mode 100644
index 0000000..bd43ed6
--- /dev/null
+++ b/tutorial/Makefile.in
@@ -0,0 +1,852 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+
+# do nothing, just build the compiler
+@MINGW_FALSE@@WITH_C_GLIB_TRUE@am__append_1 = c_glib
+@MINGW_FALSE@@WITH_CPP_TRUE@am__append_2 = cpp
+@MINGW_FALSE@@WITH_D_TRUE@am__append_3 = d
+@MINGW_FALSE@@WITH_JAVA_TRUE@am__append_4 = java js
+@MINGW_FALSE@@WITH_PYTHON_TRUE@am__append_5 = py py.twisted py.tornado
+@MINGW_FALSE@@WITH_RUBY_TRUE@am__append_6 = rb
+@MINGW_FALSE@@WITH_HASKELL_TRUE@am__append_7 = hs
+@MINGW_FALSE@@WITH_HAXE_TRUE@am__append_8 = haxe
+@MINGW_FALSE@@WITH_DOTNETCORE_TRUE@am__append_9 = netcore
+@MINGW_FALSE@@WITH_GO_TRUE@am__append_10 = go
+@MINGW_FALSE@@WITH_NODEJS_TRUE@am__append_11 = nodejs
+@MINGW_FALSE@@WITH_DART_TRUE@am__append_12 = dart
+@MINGW_FALSE@@WITH_RS_TRUE@am__append_13 = rs
+subdir = tutorial
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	distdir
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = c_glib cpp d java js py py.twisted py.tornado rb hs \
+	haxe netcore go nodejs dart rs
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = $(am__append_1) $(am__append_2) $(am__append_3) \
+	$(am__append_4) $(am__append_5) $(am__append_6) \
+	$(am__append_7) $(am__append_8) $(am__append_9) \
+	$(am__append_10) $(am__append_11) $(am__append_12) \
+	$(am__append_13)
+
+# Any folders or files not listed above being added to SUBDIR need to be placed here in
+# EXTRA_DIST to be included in the release
+EXTRA_DIST = \
+	as3 \
+	csharp \
+	d \
+	delphi \
+	erl \
+	hs \
+	ocaml \
+	perl \
+	php \
+	shared.thrift \
+	tutorial.thrift \
+	README.md
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign tutorial/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+style-local: 
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-recursive
+@MINGW_TRUE@all-local:
+all-am: Makefile all-local
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+@MINGW_TRUE@clean-local:
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+style: style-recursive
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \
+	check check-am clean clean-generic clean-libtool clean-local \
+	cscopelist-am ctags ctags-am distclean distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs installdirs-am maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+#
+# generate html for ThriftTest.thrift
+#
+@MINGW_FALSE@all-local:
+@MINGW_FALSE@	$(top_builddir)/compiler/cpp/thrift --gen html -r $(top_srcdir)/tutorial/tutorial.thrift
+
+@MINGW_FALSE@clean-local:
+@MINGW_FALSE@	rm -rf $(top_srcdir)/tutorial/gen-html
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tutorial/README.md b/tutorial/README.md
new file mode 100644
index 0000000..7772bf3
--- /dev/null
+++ b/tutorial/README.md
@@ -0,0 +1,42 @@
+Thrift Tutorial
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+
+Tutorial
+========
+
+1) First things first, you'll need to install the Thrift compiler and the
+   language libraries. Do that using the instructions in the top level
+   README.md file.
+
+2) Read tutorial.thrift to learn about the syntax of a Thrift file
+
+3) Compile the code for the language of your choice:
+
+     $ thrift
+     $ thrift -r --gen cpp tutorial.thrift
+
+4) Take a look at the generated code.
+
+5) Look in the language directories for sample client/server code.
+
+6) That's about it for now. This tutorial is intentionally brief. It should be
+   just enough to get you started and ready to build your own project.
diff --git a/tutorial/as3/build.xml b/tutorial/as3/build.xml
new file mode 100644
index 0000000..f7ed32d
--- /dev/null
+++ b/tutorial/as3/build.xml
@@ -0,0 +1,50 @@
+
+
+  Thrift actionscript 3.0 tutorial.
+
+  
+  
+  
+  
+
+  
+  
+
+  
+    
+  
+
+  
+    
+    
+  
+
+  
+    
+    
+  
+
+  
+    
+      
+      
+      
+    
+  
+
+  
+    
+    
+      
+    
+    
+      
+    
+  
+
+  
+    
+    
+  
+
+
diff --git a/tutorial/as3/src/CalculatorUI.as b/tutorial/as3/src/CalculatorUI.as
new file mode 100644
index 0000000..d996df5
--- /dev/null
+++ b/tutorial/as3/src/CalculatorUI.as
@@ -0,0 +1,142 @@
+package {
+  import flash.display.Sprite;
+  import flash.text.TextField;
+  import flash.text.TextFieldType;
+  import flash.events.MouseEvent;
+  import flash.system.Security;
+
+  import org.apache.thrift.transport.TSocket;
+  import org.apache.thrift.transport.TTransport;
+  import org.apache.thrift.protocol.TProtocol;
+  import org.apache.thrift.protocol.TBinaryProtocol;
+
+  /**
+   * Simple interface and connection logic implementation for tutorial.
+   */
+  public class CalculatorUI extends Sprite {
+    public static const BUTTON_PADDING:uint = 5;
+
+    private var mCalculatorClient:Calculator; // we use calculator through interface
+    private var mTransport:TTransport; // Transport, used to comunicate with server
+
+    private var mAddButton:Sprite;
+    private var mLeft:TextField;
+    private var mRight:TextField;
+    private var mResult:TextField;
+
+    private var pingButton:Sprite;
+
+    public function CalculatorUI() {
+      buildInterface();
+      initSecurity();
+      initConnection();
+    }
+
+    private function initSecurity():void {
+      Security.loadPolicyFile("xmlsocket://127.0.0.1:9092");
+    }
+
+    /**
+     * Example of initializing connection.
+     */
+    private function initConnection():void {
+      mTransport = new TSocket("127.0.0.1", 9090); // we connect to server
+      mTransport.open();
+      // initialize protocol:
+      var protocol:TProtocol = new TBinaryProtocol(mTransport, false, false);
+      mCalculatorClient = new CalculatorImpl(protocol); // finally, we create calculator client instance
+    }
+
+    private function onPingClick(me:MouseEvent):void {
+      if(!mTransport.isOpen()) return;
+      mCalculatorClient.ping(onPingError, onPingSuccess);
+    }
+
+    private function onPingError(error:Error):void {
+      trace("Error, while requesting ping.");
+      throw error;
+    }
+
+    private function onPingSuccess():void {
+      trace("Ping returned successfully");
+    }
+
+    private function onAddClick(me:MouseEvent):void {
+      if(!mTransport.isOpen()) return;
+      var num1:Number = Number(mLeft.text);
+      var num2:Number = Number(mRight.text);
+      mResult.text = "Processing...";
+      mCalculatorClient.add(num1, num2, onAddError, onAddSuccess);
+    }
+
+    private function onAddError(error:Error):void {
+      trace("Error, while requesting add.");
+      throw error;
+    }
+
+    private function onAddSuccess(res:Number):void {
+      mResult.text = String(res);
+    }
+
+    private function buildInterface():void {
+      addChild(pingButton = buildButton("PING"));
+      pingButton.x = (stage.stageWidth - pingButton.width) / 2;
+      pingButton.y = 10;
+      pingButton.addEventListener(MouseEvent.CLICK, onPingClick);
+
+      var top:Number = pingButton.y + pingButton.height + 20;
+      addChild(mLeft = buildDigitInput());
+      mLeft.x = 15;
+      mLeft.y = top + BUTTON_PADDING;
+      addChild(mRight = buildDigitInput());
+      mRight.x = mLeft.x + mLeft.width + 15;
+      mRight.y = top + BUTTON_PADDING;
+      addChild(mAddButton = buildButton("ADD"));
+      mAddButton.x = mRight.x + mRight.width + 15;
+      mAddButton.y = top;
+      mAddButton.addEventListener(MouseEvent.CLICK, onAddClick);
+      addChild(mResult = buildDigitInput());
+      mResult.x = mAddButton.x + mAddButton.width + 15;
+      mResult.y = top + BUTTON_PADDING;
+    }
+
+    /**
+     * Simple digit-only input field.
+     */
+    private function buildDigitInput():TextField {
+      var textField:TextField = new TextField;
+      textField.width = 75;
+      textField.height = 20;
+      textField.restrict = "0987654321.";
+      textField.type = TextFieldType.INPUT;
+      textField.background = true;
+      textField.backgroundColor = 0xaaaaff;
+      textField.textColor = 0xffff00;
+      return textField;
+    }
+
+    /**
+     * Simple button drawing.
+     */
+    private function buildButton(text:String):Sprite {
+      var button:Sprite = new Sprite;
+      var textField:TextField = new TextField;
+      textField.width = 4000;
+      textField.text = text;
+      textField.textColor = 0xffff00;
+      textField.width = textField.textWidth + 4;
+      textField.height = textField.textHeight + 4;
+      textField.mouseEnabled = false;
+      button.graphics.beginFill(0x0000ff);
+      button.graphics.lineStyle(0, 0x000000);
+      button.graphics.drawRoundRect(0, 0, textField.width + BUTTON_PADDING * 2,
+                                    textField.height + BUTTON_PADDING * 2, BUTTON_PADDING);
+      button.graphics.endFill();
+      button.addChild(textField);
+      textField.x = BUTTON_PADDING;
+      textField.y = BUTTON_PADDING;
+      button.useHandCursor = button.buttonMode = true;
+      return button;
+    }
+  }
+}
diff --git a/tutorial/c_glib/Makefile.am b/tutorial/c_glib/Makefile.am
new file mode 100755
index 0000000..4dbe655
--- /dev/null
+++ b/tutorial/c_glib/Makefile.am
@@ -0,0 +1,84 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+AUTOMAKE_OPTIONS = subdir-objects serial-tests
+
+BUILT_SOURCES = \
+	gen-c_glib/calculator.h \
+	gen-c_glib/shared_service.h \
+	gen-c_glib/shared_types.h \
+	gen-c_glib/tutorial_types.h
+
+AM_CFLAGS = -g -Wall -Wextra -pedantic $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(OPENSSL_INCLUDES) @GCOV_CFLAGS@
+AM_CPPFLAGS = -I$(top_srcdir)/lib/c_glib/src -Igen-c_glib
+AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) $(OPENSSL_LDFLAGS) $(OPENSSL_LIBS) @GCOV_LDFLAGS@
+
+noinst_LTLIBRARIES = \
+	libtutorialgencglib.la
+
+nodist_libtutorialgencglib_la_SOURCES = \
+	gen-c_glib/calculator.c \
+	gen-c_glib/calculator.h \
+	gen-c_glib/shared_service.c \
+	gen-c_glib/shared_service.h \
+	gen-c_glib/shared_types.c \
+	gen-c_glib/shared_types.h \
+	gen-c_glib/tutorial_types.c \
+	gen-c_glib/tutorial_types.h
+
+libtutorialgencglib_la_LIBADD = \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+libtutorialgencglib_la_CFLAGS = \
+	$(AM_CFLAGS) -Wno-unused-function
+
+noinst_PROGRAMS = \
+	tutorial_server \
+	tutorial_client
+
+tutorial_server_SOURCES = \
+	c_glib_server.c
+tutorial_server_LDFLAGS = $(OPENSSL_LIBS)
+
+tutorial_server_LDADD = \
+	libtutorialgencglib.la \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+tutorial_client_SOURCES = \
+	c_glib_client.c
+
+tutorial_client_LDADD = \
+	libtutorialgencglib.la \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+
+gen-c_glib/calculator.c gen-c_glib/calculator.h gen-c_glib/shared_service.c gen-c_glib/shared_service.h gen-c_glib/shared_types.c gen-c_glib/shared_types.h gen-c_glib/tutorial_types.c gen-c_glib/tutorial_types.h: $(top_srcdir)/tutorial/tutorial.thrift
+	$(THRIFT) --gen c_glib -r $<
+
+clean-local:
+	$(RM) gen-c_glib/*
+
+tutorialserver: all
+	./tutorial_server
+
+tutorialclient: all
+	./tutorial_client
+
+EXTRA_DIST = \
+	c_glib_server.c \
+	c_glib_client.c
diff --git a/tutorial/c_glib/Makefile.in b/tutorial/c_glib/Makefile.in
new file mode 100644
index 0000000..31fdf28
--- /dev/null
+++ b/tutorial/c_glib/Makefile.in
@@ -0,0 +1,936 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = tutorial_server$(EXEEXT) tutorial_client$(EXEEXT)
+subdir = tutorial/c_glib
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libtutorialgencglib_la_DEPENDENCIES =  \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+am__dirstamp = $(am__leading_dot)dirstamp
+nodist_libtutorialgencglib_la_OBJECTS =  \
+	gen-c_glib/libtutorialgencglib_la-calculator.lo \
+	gen-c_glib/libtutorialgencglib_la-shared_service.lo \
+	gen-c_glib/libtutorialgencglib_la-shared_types.lo \
+	gen-c_glib/libtutorialgencglib_la-tutorial_types.lo
+libtutorialgencglib_la_OBJECTS =  \
+	$(nodist_libtutorialgencglib_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+libtutorialgencglib_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(libtutorialgencglib_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+PROGRAMS = $(noinst_PROGRAMS)
+am_tutorial_client_OBJECTS = c_glib_client.$(OBJEXT)
+tutorial_client_OBJECTS = $(am_tutorial_client_OBJECTS)
+tutorial_client_DEPENDENCIES = libtutorialgencglib.la \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+am_tutorial_server_OBJECTS = c_glib_server.$(OBJEXT)
+tutorial_server_OBJECTS = $(am_tutorial_server_OBJECTS)
+tutorial_server_DEPENDENCIES = libtutorialgencglib.la \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+tutorial_server_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(AM_CFLAGS) $(CFLAGS) $(tutorial_server_LDFLAGS) $(LDFLAGS) \
+	-o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/lib/cpp/src/thrift -I$(top_builddir)/lib/c_glib/src/thrift
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(nodist_libtutorialgencglib_la_SOURCES) \
+	$(tutorial_client_SOURCES) $(tutorial_server_SOURCES)
+DIST_SOURCES = $(tutorial_client_SOURCES) $(tutorial_server_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+AUTOMAKE_OPTIONS = subdir-objects serial-tests
+BUILT_SOURCES = \
+	gen-c_glib/calculator.h \
+	gen-c_glib/shared_service.h \
+	gen-c_glib/shared_types.h \
+	gen-c_glib/tutorial_types.h
+
+AM_CFLAGS = -g -Wall -Wextra -pedantic $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(OPENSSL_INCLUDES) @GCOV_CFLAGS@
+AM_CPPFLAGS = -I$(top_srcdir)/lib/c_glib/src -Igen-c_glib
+AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) $(OPENSSL_LDFLAGS) $(OPENSSL_LIBS) @GCOV_LDFLAGS@
+noinst_LTLIBRARIES = \
+	libtutorialgencglib.la
+
+nodist_libtutorialgencglib_la_SOURCES = \
+	gen-c_glib/calculator.c \
+	gen-c_glib/calculator.h \
+	gen-c_glib/shared_service.c \
+	gen-c_glib/shared_service.h \
+	gen-c_glib/shared_types.c \
+	gen-c_glib/shared_types.h \
+	gen-c_glib/tutorial_types.c \
+	gen-c_glib/tutorial_types.h
+
+libtutorialgencglib_la_LIBADD = \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+libtutorialgencglib_la_CFLAGS = \
+	$(AM_CFLAGS) -Wno-unused-function
+
+tutorial_server_SOURCES = \
+	c_glib_server.c
+
+tutorial_server_LDFLAGS = $(OPENSSL_LIBS)
+tutorial_server_LDADD = \
+	libtutorialgencglib.la \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+tutorial_client_SOURCES = \
+	c_glib_client.c
+
+tutorial_client_LDADD = \
+	libtutorialgencglib.la \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+EXTRA_DIST = \
+	c_glib_server.c \
+	c_glib_client.c
+
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/c_glib/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign tutorial/c_glib/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+gen-c_glib/$(am__dirstamp):
+	@$(MKDIR_P) gen-c_glib
+	@: > gen-c_glib/$(am__dirstamp)
+gen-c_glib/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) gen-c_glib/$(DEPDIR)
+	@: > gen-c_glib/$(DEPDIR)/$(am__dirstamp)
+gen-c_glib/libtutorialgencglib_la-calculator.lo:  \
+	gen-c_glib/$(am__dirstamp) \
+	gen-c_glib/$(DEPDIR)/$(am__dirstamp)
+gen-c_glib/libtutorialgencglib_la-shared_service.lo:  \
+	gen-c_glib/$(am__dirstamp) \
+	gen-c_glib/$(DEPDIR)/$(am__dirstamp)
+gen-c_glib/libtutorialgencglib_la-shared_types.lo:  \
+	gen-c_glib/$(am__dirstamp) \
+	gen-c_glib/$(DEPDIR)/$(am__dirstamp)
+gen-c_glib/libtutorialgencglib_la-tutorial_types.lo:  \
+	gen-c_glib/$(am__dirstamp) \
+	gen-c_glib/$(DEPDIR)/$(am__dirstamp)
+
+libtutorialgencglib.la: $(libtutorialgencglib_la_OBJECTS) $(libtutorialgencglib_la_DEPENDENCIES) $(EXTRA_libtutorialgencglib_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libtutorialgencglib_la_LINK)  $(libtutorialgencglib_la_OBJECTS) $(libtutorialgencglib_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+	@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+tutorial_client$(EXEEXT): $(tutorial_client_OBJECTS) $(tutorial_client_DEPENDENCIES) $(EXTRA_tutorial_client_DEPENDENCIES) 
+	@rm -f tutorial_client$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(tutorial_client_OBJECTS) $(tutorial_client_LDADD) $(LIBS)
+
+tutorial_server$(EXEEXT): $(tutorial_server_OBJECTS) $(tutorial_server_DEPENDENCIES) $(EXTRA_tutorial_server_DEPENDENCIES) 
+	@rm -f tutorial_server$(EXEEXT)
+	$(AM_V_CCLD)$(tutorial_server_LINK) $(tutorial_server_OBJECTS) $(tutorial_server_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+	-rm -f gen-c_glib/*.$(OBJEXT)
+	-rm -f gen-c_glib/*.lo
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/c_glib_client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/c_glib_server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-calculator.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-shared_service.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-shared_types.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-tutorial_types.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+gen-c_glib/libtutorialgencglib_la-calculator.lo: gen-c_glib/calculator.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtutorialgencglib_la_CFLAGS) $(CFLAGS) -MT gen-c_glib/libtutorialgencglib_la-calculator.lo -MD -MP -MF gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-calculator.Tpo -c -o gen-c_glib/libtutorialgencglib_la-calculator.lo `test -f 'gen-c_glib/calculator.c' || echo '$(srcdir)/'`gen-c_glib/calculator.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-calculator.Tpo gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-calculator.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gen-c_glib/calculator.c' object='gen-c_glib/libtutorialgencglib_la-calculator.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtutorialgencglib_la_CFLAGS) $(CFLAGS) -c -o gen-c_glib/libtutorialgencglib_la-calculator.lo `test -f 'gen-c_glib/calculator.c' || echo '$(srcdir)/'`gen-c_glib/calculator.c
+
+gen-c_glib/libtutorialgencglib_la-shared_service.lo: gen-c_glib/shared_service.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtutorialgencglib_la_CFLAGS) $(CFLAGS) -MT gen-c_glib/libtutorialgencglib_la-shared_service.lo -MD -MP -MF gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-shared_service.Tpo -c -o gen-c_glib/libtutorialgencglib_la-shared_service.lo `test -f 'gen-c_glib/shared_service.c' || echo '$(srcdir)/'`gen-c_glib/shared_service.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-shared_service.Tpo gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-shared_service.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gen-c_glib/shared_service.c' object='gen-c_glib/libtutorialgencglib_la-shared_service.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtutorialgencglib_la_CFLAGS) $(CFLAGS) -c -o gen-c_glib/libtutorialgencglib_la-shared_service.lo `test -f 'gen-c_glib/shared_service.c' || echo '$(srcdir)/'`gen-c_glib/shared_service.c
+
+gen-c_glib/libtutorialgencglib_la-shared_types.lo: gen-c_glib/shared_types.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtutorialgencglib_la_CFLAGS) $(CFLAGS) -MT gen-c_glib/libtutorialgencglib_la-shared_types.lo -MD -MP -MF gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-shared_types.Tpo -c -o gen-c_glib/libtutorialgencglib_la-shared_types.lo `test -f 'gen-c_glib/shared_types.c' || echo '$(srcdir)/'`gen-c_glib/shared_types.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-shared_types.Tpo gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-shared_types.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gen-c_glib/shared_types.c' object='gen-c_glib/libtutorialgencglib_la-shared_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtutorialgencglib_la_CFLAGS) $(CFLAGS) -c -o gen-c_glib/libtutorialgencglib_la-shared_types.lo `test -f 'gen-c_glib/shared_types.c' || echo '$(srcdir)/'`gen-c_glib/shared_types.c
+
+gen-c_glib/libtutorialgencglib_la-tutorial_types.lo: gen-c_glib/tutorial_types.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtutorialgencglib_la_CFLAGS) $(CFLAGS) -MT gen-c_glib/libtutorialgencglib_la-tutorial_types.lo -MD -MP -MF gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-tutorial_types.Tpo -c -o gen-c_glib/libtutorialgencglib_la-tutorial_types.lo `test -f 'gen-c_glib/tutorial_types.c' || echo '$(srcdir)/'`gen-c_glib/tutorial_types.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-tutorial_types.Tpo gen-c_glib/$(DEPDIR)/libtutorialgencglib_la-tutorial_types.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gen-c_glib/tutorial_types.c' object='gen-c_glib/libtutorialgencglib_la-tutorial_types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtutorialgencglib_la_CFLAGS) $(CFLAGS) -c -o gen-c_glib/libtutorialgencglib_la-tutorial_types.lo `test -f 'gen-c_glib/tutorial_types.c' || echo '$(srcdir)/'`gen-c_glib/tutorial_types.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+	-rm -rf gen-c_glib/.libs gen-c_glib/_libs
+style-local: 
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS)
+installdirs:
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-rm -f gen-c_glib/$(DEPDIR)/$(am__dirstamp)
+	-rm -f gen-c_glib/$(am__dirstamp)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local \
+	clean-noinstLTLIBRARIES clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR) gen-c_glib/$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR) gen-c_glib/$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-local clean-noinstLTLIBRARIES \
+	clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am style-am style-local tags tags-am \
+	uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+gen-c_glib/calculator.c gen-c_glib/calculator.h gen-c_glib/shared_service.c gen-c_glib/shared_service.h gen-c_glib/shared_types.c gen-c_glib/shared_types.h gen-c_glib/tutorial_types.c gen-c_glib/tutorial_types.h: $(top_srcdir)/tutorial/tutorial.thrift
+	$(THRIFT) --gen c_glib -r $<
+
+clean-local:
+	$(RM) gen-c_glib/*
+
+tutorialserver: all
+	./tutorial_server
+
+tutorialclient: all
+	./tutorial_client
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tutorial/c_glib/c_glib_client.c b/tutorial/c_glib/c_glib_client.c
new file mode 100644
index 0000000..986d517
--- /dev/null
+++ b/tutorial/c_glib/c_glib_client.c
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include "gen-c_glib/calculator.h"
+
+int main (void)
+{
+  ThriftSocket *socket;
+  ThriftTransport *transport;
+  ThriftProtocol *protocol;
+  CalculatorIf *client;
+
+  GError *error = NULL;
+  InvalidOperation *invalid_operation = NULL;
+
+  Work *work;
+
+  gint32 sum;
+  gint32 diff;
+
+  int exit_status = 0;
+
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init ();
+#endif
+
+  socket    = g_object_new (THRIFT_TYPE_SOCKET,
+                            "hostname",  "localhost",
+                            "port",      9090,
+                            NULL);
+  transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+                            "transport", socket,
+                            NULL);
+  protocol  = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
+                            "transport", transport,
+                            NULL);
+
+  thrift_transport_open (transport, &error);
+
+
+  /* In the C (GLib) implementation of Thrift, service methods on the
+     server are accessed via a generated client class that implements
+     the service interface. In this tutorial, we access a Calculator
+     service through an instance of CalculatorClient, which implements
+     CalculatorIf. */
+  client = g_object_new (TYPE_CALCULATOR_CLIENT,
+                         "input_protocol",  protocol,
+                         "output_protocol", protocol,
+                         NULL);
+
+  /* Each of the client methods requires at least two parameters: A
+     pointer to the client-interface implementation (the client
+     object), and a handle to a GError structure to receive
+     information about any error that occurs.
+
+     On success, client methods return TRUE. A return value of FALSE
+     indicates an error occurred and the error parameter has been
+     set. */
+  if (!error && calculator_if_ping (client, &error)) {
+    puts ("ping()");
+  }
+
+  /* Service methods that return a value do so by passing the result
+     back via an output parameter (here, "sum"). */
+  if (!error && calculator_if_add (client, &sum, 1, 1, &error)) {
+    printf ("1+1=%d\n", sum);
+  }
+
+  /* Thrift structs are implemented as GObjects, with each of the
+     struct's members exposed as an object property. */
+  work = g_object_new (TYPE_WORK, NULL);
+
+  if (!error) {
+    g_object_set (work,
+                  "num1", 1,
+                  "num2", 0,
+                  "op",   OPERATION_DIVIDE,
+                  NULL);
+
+    /* Exceptions are passed back from service methods in a manner
+       similar to return values. */
+    if (calculator_if_calculate (client,
+                                 NULL,
+                                 1,
+                                 work,
+                                 &invalid_operation,
+                                 &error)) {
+      puts ("Whoa? We can divide by zero!");
+    }
+    else {
+      if (invalid_operation) {
+        gchar *why;
+
+        /* Like structs, exceptions are implemented as objects with
+           properties. */
+        g_object_get (invalid_operation, "why", &why, NULL);
+
+        printf ("InvalidOperation: %s\n", why);
+
+        if (why != NULL)
+          g_free (why);
+        g_object_unref (invalid_operation);
+        invalid_operation = NULL;
+      }
+
+      g_clear_error (&error);
+    }
+  }
+
+  if (!error) {
+    /* Struct objects can be reused across method invocations. */
+    g_object_set (work,
+                  "num1", 15,
+                  "num2", 10,
+                  "op",   OPERATION_SUBTRACT,
+                  NULL);
+
+    if (calculator_if_calculate (client,
+                                 &diff,
+                                 1,
+                                 work,
+                                 &invalid_operation,
+                                 &error)) {
+      printf ("15-10=%d\n", diff);
+    }
+  }
+
+  g_object_unref (work);
+
+  if (!error) {
+    SharedStruct *shared_struct;
+    gchar *value;
+
+    shared_struct = g_object_new (TYPE_SHARED_STRUCT, NULL);
+
+    /* As defined in the Thrift file, the Calculator service extends
+       the SharedService service. Correspondingly, in the generated
+       code CalculatorIf inherits from SharedServiceIf, and the parent
+       service's methods are accessible through a simple cast. */
+    if (shared_service_client_get_struct (SHARED_SERVICE_IF (client),
+                                          &shared_struct,
+                                          1,
+                                          &error)) {
+      g_object_get (shared_struct, "value", &value, NULL);
+      printf ("Check log: %s\n", value);
+      g_free (value);
+    }
+
+    g_object_unref (shared_struct);
+  }
+
+  if (error) {
+    printf ("ERROR: %s\n", error->message);
+    g_clear_error (&error);
+
+    exit_status = 1;
+  }
+
+  thrift_transport_close (transport, NULL);
+
+  g_object_unref (client);
+  g_object_unref (protocol);
+  g_object_unref (transport);
+  g_object_unref (socket);
+
+  return exit_status;
+}
diff --git a/tutorial/c_glib/c_glib_server.c b/tutorial/c_glib/c_glib_server.c
new file mode 100644
index 0000000..47bf47f
--- /dev/null
+++ b/tutorial/c_glib/c_glib_server.c
@@ -0,0 +1,527 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "gen-c_glib/calculator.h"
+
+G_BEGIN_DECLS
+
+/* In the C (GLib) implementation of Thrift, the actual work done by a
+   server---that is, the code that runs when a client invokes a
+   service method---is defined in a separate "handler" class that
+   implements the service interface. Here we define the
+   TutorialCalculatorHandler class, which implements the CalculatorIf
+   interface and provides the behavior expected by tutorial clients.
+   (Typically this code would be placed in its own module but for
+   clarity this tutorial is presented entirely in a single file.)
+
+   For each service the Thrift compiler generates an abstract base
+   class from which handler implementations should inherit. In our
+   case TutorialCalculatorHandler inherits from CalculatorHandler,
+   defined in gen-c_glib/calculator.h.
+
+   If you're new to GObject, try not to be intimidated by the quantity
+   of code here---much of it is boilerplate and can mostly be
+   copied-and-pasted from existing work. For more information refer to
+   the GObject Reference Manual, available online at
+   https://developer.gnome.org/gobject/. */
+
+#define TYPE_TUTORIAL_CALCULATOR_HANDLER \
+  (tutorial_calculator_handler_get_type ())
+
+#define TUTORIAL_CALCULATOR_HANDLER(obj)                                \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                                   \
+                               TYPE_TUTORIAL_CALCULATOR_HANDLER,        \
+                               TutorialCalculatorHandler))
+#define TUTORIAL_CALCULATOR_HANDLER_CLASS(c)                    \
+  (G_TYPE_CHECK_CLASS_CAST ((c),                                \
+                            TYPE_TUTORIAL_CALCULATOR_HANDLER,   \
+                            TutorialCalculatorHandlerClass))
+#define IS_TUTORIAL_CALCULATOR_HANDLER(obj)                             \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                                   \
+                               TYPE_TUTORIAL_CALCULATOR_HANDLER))
+#define IS_TUTORIAL_CALCULATOR_HANDLER_CLASS(c)                 \
+  (G_TYPE_CHECK_CLASS_TYPE ((c),                                \
+                            TYPE_TUTORIAL_CALCULATOR_HANDLER))
+#define TUTORIAL_CALCULATOR_HANDLER_GET_CLASS(obj)              \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                            \
+                              TYPE_TUTORIAL_CALCULATOR_HANDLER, \
+                              TutorialCalculatorHandlerClass))
+
+struct _TutorialCalculatorHandler {
+  CalculatorHandler parent_instance;
+
+  /* private */
+  GHashTable *log;
+};
+typedef struct _TutorialCalculatorHandler TutorialCalculatorHandler;
+
+struct _TutorialCalculatorHandlerClass {
+  CalculatorHandlerClass parent_class;
+};
+typedef struct _TutorialCalculatorHandlerClass TutorialCalculatorHandlerClass;
+
+GType tutorial_calculator_handler_get_type (void);
+
+G_END_DECLS
+
+/* ---------------------------------------------------------------- */
+
+/* The implementation of TutorialCalculatorHandler follows. */
+
+G_DEFINE_TYPE (TutorialCalculatorHandler,
+               tutorial_calculator_handler,
+               TYPE_CALCULATOR_HANDLER)
+
+/* Each of a handler's methods accepts at least two parameters: A
+   pointer to the service-interface implementation (the handler object
+   itself) and a handle to a GError structure to receive information
+   about any error that occurs.
+
+   On success, a handler method returns TRUE. A return value of FALSE
+   indicates an error occurred and the error parameter has been
+   set. (Methods should not return FALSE without first setting the
+   error parameter.) */
+static gboolean
+tutorial_calculator_handler_ping (CalculatorIf  *iface,
+                                  GError       **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  puts ("ping()");
+
+  return TRUE;
+}
+
+/* Service-method parameters are passed through as parameters to the
+   handler method.
+
+   If the service method returns a value an output parameter, _return,
+   is additionally passed to the handler method. This parameter should
+   be set appropriately before the method returns, whenever it
+   succeeds.
+
+   The return value from this method happens to be of a base type,
+   i32, but note if a method returns a complex type such as a map or
+   list *_return will point to a pre-allocated data structure that
+   does not need to be re-allocated and should not be destroyed. */
+static gboolean
+tutorial_calculator_handler_add (CalculatorIf  *iface,
+                                 gint32        *_return,
+                                 const gint32   num1,
+                                 const gint32   num2,
+                                 GError       **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("add(%d,%d)\n", num1, num2);
+  *_return = num1 + num2;
+
+  return TRUE;
+}
+
+/* Any handler method can return a ThriftApplicationException to the
+   client by setting its error parameter appropriately and returning
+   FALSE. See the ThriftApplicationExceptionError enumeration defined
+   in thrift_application_exception.h for a list of recognized
+   exception types (GError codes).
+
+   If a service method can also throw a custom exception (that is, one
+   defined in the .thrift file) an additional output parameter will be
+   provided (here, "ouch") to hold an instance of the exception, when
+   necessary. Note there will be a separate parameter added for each
+   type of exception the method can throw.
+
+   Unlike return values, exception objects are never pre-created; this
+   is always the responsibility of the handler method. */
+static gboolean
+tutorial_calculator_handler_calculate (CalculatorIf      *iface,
+                                       gint32            *_return,
+                                       const gint32       logid,
+                                       const Work        *w,
+                                       InvalidOperation **ouch,
+                                       GError           **error)
+{
+  TutorialCalculatorHandler *self;
+
+  gint *log_key;
+  gchar log_value[12];
+  SharedStruct *log_struct;
+
+  gint num1;
+  gint num2;
+  Operation op;
+  gboolean result = TRUE;
+
+  THRIFT_UNUSED_VAR (error);
+
+  g_return_val_if_fail (IS_TUTORIAL_CALCULATOR_HANDLER (iface),
+                        FALSE);
+  self = TUTORIAL_CALCULATOR_HANDLER (iface);
+
+  /* Remember: Exception objects are never pre-created */
+  g_assert (*ouch == NULL);
+
+  /* Fetch the contents of our Work parameter.
+
+     Note that integer properties of thirty-two bits or fewer in width
+     are _always_ of type gint, regardless of the range of values they
+     hold. A common error is trying to retrieve, say, a structure
+     member defined in the .thrift file as type i16 into a variable of
+     type gint16, which will clobber variables adjacent on the
+     stack. Remember: If you're retrieving an integer property the
+     receiving variable must be of either type gint or gint64, as
+     appropriate. */
+  g_object_get ((Work *)w,
+                "num1", &num1,
+                "num2", &num2,
+                "op",   &op,
+                NULL);
+
+  printf ("calculate(%d,{%d,%d,%d})\n", logid, op, num1, num2);
+
+  switch (op) {
+  case OPERATION_ADD:
+    *_return = num1 + num2;
+    break;
+
+  case OPERATION_SUBTRACT:
+    *_return = num1 - num2;
+    break;
+
+  case OPERATION_MULTIPLY:
+    *_return = num1 * num2;
+    break;
+
+  case OPERATION_DIVIDE:
+    if (num2 == 0) {
+      /* For each custom exception type a subclass of ThriftStruct is
+         generated by the Thrift compiler. Throw an exception by
+         setting the corresponding output parameter to a new instance
+         of its type and returning FALSE. */
+      *ouch = g_object_new (TYPE_INVALID_OPERATION,
+                            "whatOp", op,
+                            "why",  g_strdup ("Cannot divide by 0"),
+                            NULL);
+      result = FALSE;
+
+      /* Note the call to g_strdup above: All the memory used by a
+         ThriftStruct's properties belongs to the object itself and
+         will be freed on destruction. Removing this call to g_strdup
+         will lead to a segmentation fault as the object tries to
+         release memory allocated statically to the program. */
+    }
+    else {
+      *_return = num1 / num2;
+    }
+    break;
+
+  default:
+    *ouch = g_object_new (TYPE_INVALID_OPERATION,
+                          "whatOp", op,
+                          "why",  g_strdup ("Invalid Operation"),
+                          NULL);
+    result = FALSE;
+  }
+
+  /* On success, log a record of the result to our hash table */
+  if (result) {
+    log_key = g_malloc (sizeof *log_key);
+    *log_key = logid;
+
+    snprintf (log_value, sizeof log_value, "%d", *_return);
+
+    log_struct = g_object_new (TYPE_SHARED_STRUCT,
+                               "key",   *log_key,
+                               "value",  g_strdup (log_value),
+                               NULL);
+    g_hash_table_replace (self->log, log_key, log_struct);
+  }
+
+  return result;
+}
+
+/* A one-way method has the same signature as an equivalent, regular
+   method that returns no value. */
+static gboolean
+tutorial_calculator_handler_zip (CalculatorIf  *iface,
+                                 GError       **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  puts ("zip()");
+
+  return TRUE;
+}
+
+/* As specified in the .thrift file (tutorial.thrift), the Calculator
+   service extends the SharedService service. Correspondingly, in the
+   generated code the Calculator interface, CalculatorIf, extends the
+   SharedService interface, SharedServiceIf, and subclasses of
+   CalculatorHandler should implement its methods as well.
+
+   Here we provide an implementation for the getStruct method from the
+   parent service. */
+static gboolean
+tutorial_calculator_handler_get_struct (SharedServiceIf  *iface,
+                                        SharedStruct    **_return,
+                                        const gint32      key32,
+                                        GError          **error)
+{
+  gint key = (gint)key32;
+  TutorialCalculatorHandler *self;
+  SharedStruct *log_struct;
+  gint log_key;
+  gchar *log_value;
+
+  THRIFT_UNUSED_VAR (error);
+
+  g_return_val_if_fail (IS_TUTORIAL_CALCULATOR_HANDLER (iface),
+                        FALSE);
+  self = TUTORIAL_CALCULATOR_HANDLER (iface);
+
+  /* Remember: Complex return types are always pre-created and need
+     only be populated */
+  g_assert (*_return != NULL);
+
+  printf ("getStruct(%d)\n", key);
+
+  /* If the key exists in our log, return the corresponding logged
+     data (or an empty SharedStruct structure if it does not).
+
+     Incidentally, note we _must_ here copy the values from the hash
+     table into the return structure. All memory used by the return
+     structure belongs to the structure itself and will be freed once
+     a response is sent to the client. If we merely freed *_return and
+     set it to point to our hash-table entry, that would mean memory
+     would be released (effectively, data erased) out of the hash
+     table! */
+  log_struct = g_hash_table_lookup (self->log, &key);
+  if (log_struct != NULL) {
+    g_object_get (log_struct,
+                  "key",   &log_key,
+                  "value", &log_value,
+                  NULL);
+    g_object_set (*_return,
+                  "key",   log_key,
+                  "value", g_strdup (log_value),
+                  NULL);
+  }
+
+  return TRUE;
+}
+
+/* TutorialCalculatorHandler's instance finalizer (destructor) */
+static void
+tutorial_calculator_handler_finalize (GObject *object)
+{
+  TutorialCalculatorHandler *self =
+    TUTORIAL_CALCULATOR_HANDLER (object);
+
+  /* Free our calculation-log hash table */
+  g_hash_table_unref (self->log);
+  self->log = NULL;
+
+  /* Chain up to the parent class */
+  G_OBJECT_CLASS (tutorial_calculator_handler_parent_class)->
+    finalize (object);
+}
+
+/* TutorialCalculatorHandler's instance initializer (constructor) */
+static void
+tutorial_calculator_handler_init (TutorialCalculatorHandler *self)
+{
+  /* Create our calculation-log hash table */
+  self->log = g_hash_table_new_full (g_int_hash,
+                                     g_int_equal,
+                                     g_free,
+                                     g_object_unref);
+}
+
+/* TutorialCalculatorHandler's class initializer */
+static void
+tutorial_calculator_handler_class_init (TutorialCalculatorHandlerClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  SharedServiceHandlerClass *shared_service_handler_class =
+    SHARED_SERVICE_HANDLER_CLASS (klass);
+  CalculatorHandlerClass *calculator_handler_class =
+    CALCULATOR_HANDLER_CLASS (klass);
+
+  /* Register our destructor */
+  gobject_class->finalize = tutorial_calculator_handler_finalize;
+
+  /* Register our implementations of CalculatorHandler's methods */
+  calculator_handler_class->ping =
+    tutorial_calculator_handler_ping;
+  calculator_handler_class->add =
+    tutorial_calculator_handler_add;
+  calculator_handler_class->calculate =
+    tutorial_calculator_handler_calculate;
+  calculator_handler_class->zip =
+    tutorial_calculator_handler_zip;
+
+  /* Register our implementation of SharedServiceHandler's method */
+  shared_service_handler_class->get_struct =
+    tutorial_calculator_handler_get_struct;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* That ends the implementation of TutorialCalculatorHandler.
+   Everything below is fairly generic code that sets up a minimal
+   Thrift server for tutorial clients. */
+
+
+/* Our server object, declared globally so it is accessible within the
+   SIGINT signal handler */
+ThriftServer *server = NULL;
+
+/* A flag that indicates whether the server was interrupted with
+   SIGINT (i.e. Ctrl-C) so we can tell whether its termination was
+   abnormal */
+gboolean sigint_received = FALSE;
+
+/* Handle SIGINT ("Ctrl-C") signals by gracefully stopping the
+   server */
+static void
+sigint_handler (int signal_number)
+{
+  THRIFT_UNUSED_VAR (signal_number);
+
+  /* Take note we were called */
+  sigint_received = TRUE;
+
+  /* Shut down the server gracefully */
+  if (server != NULL)
+    thrift_server_stop (server);
+}
+
+int main (void)
+{
+  TutorialCalculatorHandler *handler;
+  CalculatorProcessor *processor;
+
+  ThriftServerTransport *server_transport;
+  ThriftTransportFactory *transport_factory;
+  ThriftProtocolFactory *protocol_factory;
+
+  struct sigaction sigint_action;
+
+  GError *error = NULL;
+  int exit_status = 0;
+
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init ();
+#endif
+
+  /* Create an instance of our handler, which provides the service's
+     methods' implementation */
+  handler =
+    g_object_new (TYPE_TUTORIAL_CALCULATOR_HANDLER,
+                  NULL);
+
+  /* Create an instance of the service's processor, automatically
+     generated by the Thrift compiler, which parses incoming messages
+     and dispatches them to the appropriate method in the handler */
+  processor =
+    g_object_new (TYPE_CALCULATOR_PROCESSOR,
+                  "handler", handler,
+                  NULL);
+
+  /* Create our server socket, which binds to the specified port and
+     listens for client connections */
+  server_transport =
+    g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+                  "port", 9090,
+                  NULL);
+
+  /* Create our transport factory, used by the server to wrap "raw"
+     incoming connections from the client (in this case with a
+     ThriftBufferedTransport to improve performance) */
+  transport_factory =
+    g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY,
+                  NULL);
+
+  /* Create our protocol factory, which determines which wire protocol
+     the server will use (in this case, Thrift's binary protocol) */
+  protocol_factory =
+    g_object_new (THRIFT_TYPE_BINARY_PROTOCOL_FACTORY,
+                  NULL);
+
+  /* Create the server itself */
+  server =
+    g_object_new (THRIFT_TYPE_SIMPLE_SERVER,
+                  "processor",                processor,
+                  "server_transport",         server_transport,
+                  "input_transport_factory",  transport_factory,
+                  "output_transport_factory", transport_factory,
+                  "input_protocol_factory",   protocol_factory,
+                  "output_protocol_factory",  protocol_factory,
+                  NULL);
+
+  /* Install our SIGINT handler, which handles Ctrl-C being pressed by
+     stopping the server gracefully (not strictly necessary, but a
+     nice touch) */
+  memset (&sigint_action, 0, sizeof (sigint_action));
+  sigint_action.sa_handler = sigint_handler;
+  sigint_action.sa_flags = SA_RESETHAND;
+  sigaction (SIGINT, &sigint_action, NULL);
+
+  /* Start the server, which will run until its stop method is invoked
+     (from within the SIGINT handler, in this case) */
+  puts ("Starting the server...");
+  thrift_server_serve (server, &error);
+
+  /* If the server stopped for any reason other than having been
+     interrupted by the user, report the error */
+  if (!sigint_received) {
+    g_message ("thrift_server_serve: %s",
+               error != NULL ? error->message : "(null)");
+    g_clear_error (&error);
+  }
+
+  puts ("done.");
+
+  g_object_unref (server);
+  g_object_unref (transport_factory);
+  g_object_unref (protocol_factory);
+  g_object_unref (server_transport);
+
+  g_object_unref (processor);
+  g_object_unref (handler);
+
+  return exit_status;
+}
diff --git a/tutorial/cpp/CMakeLists.txt b/tutorial/cpp/CMakeLists.txt
new file mode 100644
index 0000000..8634b41
--- /dev/null
+++ b/tutorial/cpp/CMakeLists.txt
@@ -0,0 +1,56 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
+
+#Make sure gen-cpp files can be included
+include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen-cpp")
+include_directories("${PROJECT_SOURCE_DIR}/lib/cpp/src")
+
+include(ThriftMacros)
+
+set(tutorialgencpp_SOURCES
+    gen-cpp/Calculator.cpp
+    gen-cpp/SharedService.cpp
+    gen-cpp/shared_constants.cpp
+    gen-cpp/shared_types.cpp
+    gen-cpp/tutorial_constants.cpp
+    gen-cpp/tutorial_types.cpp
+)
+add_library(tutorialgencpp STATIC ${tutorialgencpp_SOURCES})
+LINK_AGAINST_THRIFT_LIBRARY(tutorialgencpp thrift)
+
+add_custom_command(OUTPUT gen-cpp/Calculator.cpp gen-cpp/SharedService.cpp gen-cpp/shared_constants.cpp gen-cpp/shared_types.cpp gen-cpp/tutorial_constants.cpp gen-cpp/tutorial_types.cpp
+    COMMAND ${THRIFT_COMPILER} --gen cpp -r ${PROJECT_SOURCE_DIR}/tutorial/tutorial.thrift
+)
+
+add_executable(TutorialServer CppServer.cpp)
+target_link_libraries(TutorialServer tutorialgencpp)
+LINK_AGAINST_THRIFT_LIBRARY(TutorialServer thrift)
+if (ZLIB_FOUND)
+  target_link_libraries(TutorialServer ${ZLIB_LIBRARIES})
+endif ()
+
+add_executable(TutorialClient CppClient.cpp)
+target_link_libraries(TutorialClient tutorialgencpp)
+LINK_AGAINST_THRIFT_LIBRARY(TutorialClient thrift)
+if (ZLIB_FOUND)
+  target_link_libraries(TutorialClient ${ZLIB_LIBRARIES})
+endif ()
diff --git a/tutorial/cpp/CppClient.cpp b/tutorial/cpp/CppClient.cpp
new file mode 100644
index 0000000..f10c725
--- /dev/null
+++ b/tutorial/cpp/CppClient.cpp
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+#include "../gen-cpp/Calculator.h"
+
+using namespace std;
+using namespace apache::thrift;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+
+using namespace tutorial;
+using namespace shared;
+
+int main() {
+  stdcxx::shared_ptr socket(new TSocket("localhost", 9090));
+  stdcxx::shared_ptr transport(new TBufferedTransport(socket));
+  stdcxx::shared_ptr protocol(new TBinaryProtocol(transport));
+  CalculatorClient client(protocol);
+
+  try {
+    transport->open();
+
+    client.ping();
+    cout << "ping()" << endl;
+
+    cout << "1 + 1 = " << client.add(1, 1) << endl;
+
+    Work work;
+    work.op = Operation::DIVIDE;
+    work.num1 = 1;
+    work.num2 = 0;
+
+    try {
+      client.calculate(1, work);
+      cout << "Whoa? We can divide by zero!" << endl;
+    } catch (InvalidOperation& io) {
+      cout << "InvalidOperation: " << io.why << endl;
+      // or using generated operator<<: cout << io << endl;
+      // or by using std::exception native method what(): cout << io.what() << endl;
+    }
+
+    work.op = Operation::SUBTRACT;
+    work.num1 = 15;
+    work.num2 = 10;
+    int32_t diff = client.calculate(1, work);
+    cout << "15 - 10 = " << diff << endl;
+
+    // Note that C++ uses return by reference for complex types to avoid
+    // costly copy construction
+    SharedStruct ss;
+    client.getStruct(ss, 1);
+    cout << "Received log: " << ss << endl;
+
+    transport->close();
+  } catch (TException& tx) {
+    cout << "ERROR: " << tx.what() << endl;
+  }
+}
diff --git a/tutorial/cpp/CppServer.cpp b/tutorial/cpp/CppServer.cpp
new file mode 100644
index 0000000..80b100e
--- /dev/null
+++ b/tutorial/cpp/CppServer.cpp
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include "../gen-cpp/Calculator.h"
+
+using namespace std;
+using namespace apache::thrift;
+using namespace apache::thrift::concurrency;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+using namespace apache::thrift::server;
+
+using namespace tutorial;
+using namespace shared;
+
+class CalculatorHandler : public CalculatorIf {
+public:
+  CalculatorHandler() {}
+
+  void ping() { cout << "ping()" << endl; }
+
+  int32_t add(const int32_t n1, const int32_t n2) {
+    cout << "add(" << n1 << ", " << n2 << ")" << endl;
+    return n1 + n2;
+  }
+
+  int32_t calculate(const int32_t logid, const Work& work) {
+    cout << "calculate(" << logid << ", " << work << ")" << endl;
+    int32_t val;
+
+    switch (work.op) {
+    case Operation::ADD:
+      val = work.num1 + work.num2;
+      break;
+    case Operation::SUBTRACT:
+      val = work.num1 - work.num2;
+      break;
+    case Operation::MULTIPLY:
+      val = work.num1 * work.num2;
+      break;
+    case Operation::DIVIDE:
+      if (work.num2 == 0) {
+        InvalidOperation io;
+        io.whatOp = work.op;
+        io.why = "Cannot divide by 0";
+        throw io;
+      }
+      val = work.num1 / work.num2;
+      break;
+    default:
+      InvalidOperation io;
+      io.whatOp = work.op;
+      io.why = "Invalid Operation";
+      throw io;
+    }
+
+    SharedStruct ss;
+    ss.key = logid;
+    ss.value = to_string(val);
+
+    log[logid] = ss;
+
+    return val;
+  }
+
+  void getStruct(SharedStruct& ret, const int32_t logid) {
+    cout << "getStruct(" << logid << ")" << endl;
+    ret = log[logid];
+  }
+
+  void zip() { cout << "zip()" << endl; }
+
+protected:
+  map log;
+};
+
+/*
+  CalculatorIfFactory is code generated.
+  CalculatorCloneFactory is useful for getting access to the server side of the
+  transport.  It is also useful for making per-connection state.  Without this
+  CloneFactory, all connections will end up sharing the same handler instance.
+*/
+class CalculatorCloneFactory : virtual public CalculatorIfFactory {
+ public:
+  virtual ~CalculatorCloneFactory() {}
+  virtual CalculatorIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo)
+  {
+    stdcxx::shared_ptr sock = stdcxx::dynamic_pointer_cast(connInfo.transport);
+    cout << "Incoming connection\n";
+    cout << "\tSocketInfo: "  << sock->getSocketInfo() << "\n";
+    cout << "\tPeerHost: "    << sock->getPeerHost() << "\n";
+    cout << "\tPeerAddress: " << sock->getPeerAddress() << "\n";
+    cout << "\tPeerPort: "    << sock->getPeerPort() << "\n";
+    return new CalculatorHandler;
+  }
+  virtual void releaseHandler( ::shared::SharedServiceIf* handler) {
+    delete handler;
+  }
+};
+
+int main() {
+  TThreadedServer server(
+    stdcxx::make_shared(stdcxx::make_shared()),
+    stdcxx::make_shared(9090), //port
+    stdcxx::make_shared(),
+    stdcxx::make_shared());
+
+  /*
+  // if you don't need per-connection state, do the following instead
+  TThreadedServer server(
+    stdcxx::make_shared(stdcxx::make_shared()),
+    stdcxx::make_shared(9090), //port
+    stdcxx::make_shared(),
+    stdcxx::make_shared());
+  */
+
+  /**
+   * Here are some alternate server types...
+
+  // This server only allows one connection at a time, but spawns no threads
+  TSimpleServer server(
+    stdcxx::make_shared(stdcxx::make_shared()),
+    stdcxx::make_shared(9090),
+    stdcxx::make_shared(),
+    stdcxx::make_shared());
+
+  const int workerCount = 4;
+
+  stdcxx::shared_ptr threadManager =
+    ThreadManager::newSimpleThreadManager(workerCount);
+  threadManager->threadFactory(
+    stdcxx::make_shared());
+  threadManager->start();
+
+  // This server allows "workerCount" connection at a time, and reuses threads
+  TThreadPoolServer server(
+    stdcxx::make_shared(stdcxx::make_shared()),
+    stdcxx::make_shared(9090),
+    stdcxx::make_shared(),
+    stdcxx::make_shared(),
+    threadManager);
+  */
+
+  cout << "Starting the server..." << endl;
+  server.serve();
+  cout << "Done." << endl;
+  return 0;
+}
diff --git a/tutorial/cpp/Makefile.am b/tutorial/cpp/Makefile.am
new file mode 100755
index 0000000..49cf3be
--- /dev/null
+++ b/tutorial/cpp/Makefile.am
@@ -0,0 +1,86 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+AUTOMAKE_OPTIONS = subdir-objects serial-tests
+
+BUILT_SOURCES = gen-cpp/shared_types.cpp \
+                gen-cpp/tutorial_types.cpp
+
+noinst_LTLIBRARIES = libtutorialgencpp.la
+nodist_libtutorialgencpp_la_SOURCES = \
+	gen-cpp/Calculator.cpp \
+	gen-cpp/Calculator.h \
+	gen-cpp/SharedService.cpp \
+	gen-cpp/SharedService.h \
+	gen-cpp/shared_constants.cpp \
+	gen-cpp/shared_constants.h \
+	gen-cpp/shared_types.cpp \
+	gen-cpp/shared_types.h \
+	gen-cpp/tutorial_constants.cpp \
+	gen-cpp/tutorial_constants.h \
+	gen-cpp/tutorial_types.cpp \
+	gen-cpp/tutorial_types.h
+
+
+
+libtutorialgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la
+
+noinst_PROGRAMS = \
+	TutorialServer \
+	TutorialClient
+
+TutorialServer_SOURCES = \
+	CppServer.cpp
+
+TutorialServer_LDADD = \
+	libtutorialgencpp.la \
+	$(top_builddir)/lib/cpp/libthrift.la
+
+TutorialClient_SOURCES = \
+	CppClient.cpp
+
+TutorialClient_LDADD = \
+	libtutorialgencpp.la \
+	$(top_builddir)/lib/cpp/libthrift.la
+
+#
+# Common thrift code generation rules
+#
+gen-cpp/Calculator.cpp gen-cpp/SharedService.cpp gen-cpp/shared_constants.cpp gen-cpp/shared_types.cpp gen-cpp/tutorial_constants.cpp gen-cpp/tutorial_types.cpp: $(top_srcdir)/tutorial/tutorial.thrift
+	$(THRIFT) --gen cpp -r $<
+
+AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -Igen-cpp
+AM_CXXFLAGS = -Wall -Wextra -pedantic
+AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS)
+
+clean-local:
+	$(RM) gen-cpp/*
+
+tutorialserver: all
+	./TutorialServer
+
+tutorialclient: all
+	./TutorialClient
+
+style-local:
+	$(CPPSTYLE_CMD)
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	CppClient.cpp \
+	CppServer.cpp
diff --git a/tutorial/cpp/Makefile.in b/tutorial/cpp/Makefile.in
new file mode 100644
index 0000000..2a4c209
--- /dev/null
+++ b/tutorial/cpp/Makefile.in
@@ -0,0 +1,918 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = TutorialServer$(EXEEXT) TutorialClient$(EXEEXT)
+subdir = tutorial/cpp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libtutorialgencpp_la_DEPENDENCIES =  \
+	$(top_builddir)/lib/cpp/libthrift.la
+am__dirstamp = $(am__leading_dot)dirstamp
+nodist_libtutorialgencpp_la_OBJECTS = gen-cpp/Calculator.lo \
+	gen-cpp/SharedService.lo gen-cpp/shared_constants.lo \
+	gen-cpp/shared_types.lo gen-cpp/tutorial_constants.lo \
+	gen-cpp/tutorial_types.lo
+libtutorialgencpp_la_OBJECTS = $(nodist_libtutorialgencpp_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+PROGRAMS = $(noinst_PROGRAMS)
+am_TutorialClient_OBJECTS = CppClient.$(OBJEXT)
+TutorialClient_OBJECTS = $(am_TutorialClient_OBJECTS)
+TutorialClient_DEPENDENCIES = libtutorialgencpp.la \
+	$(top_builddir)/lib/cpp/libthrift.la
+am_TutorialServer_OBJECTS = CppServer.$(OBJEXT)
+TutorialServer_OBJECTS = $(am_TutorialServer_OBJECTS)
+TutorialServer_DEPENDENCIES = libtutorialgencpp.la \
+	$(top_builddir)/lib/cpp/libthrift.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/lib/cpp/src/thrift -I$(top_builddir)/lib/c_glib/src/thrift
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo "  CXX     " $@;
+am__v_CXX_1 = 
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo "  CXXLD   " $@;
+am__v_CXXLD_1 = 
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(nodist_libtutorialgencpp_la_SOURCES) \
+	$(TutorialClient_SOURCES) $(TutorialServer_SOURCES)
+DIST_SOURCES = $(TutorialClient_SOURCES) $(TutorialServer_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+AUTOMAKE_OPTIONS = subdir-objects serial-tests
+BUILT_SOURCES = gen-cpp/shared_types.cpp \
+                gen-cpp/tutorial_types.cpp
+
+noinst_LTLIBRARIES = libtutorialgencpp.la
+nodist_libtutorialgencpp_la_SOURCES = \
+	gen-cpp/Calculator.cpp \
+	gen-cpp/Calculator.h \
+	gen-cpp/SharedService.cpp \
+	gen-cpp/SharedService.h \
+	gen-cpp/shared_constants.cpp \
+	gen-cpp/shared_constants.h \
+	gen-cpp/shared_types.cpp \
+	gen-cpp/shared_types.h \
+	gen-cpp/tutorial_constants.cpp \
+	gen-cpp/tutorial_constants.h \
+	gen-cpp/tutorial_types.cpp \
+	gen-cpp/tutorial_types.h
+
+libtutorialgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la
+TutorialServer_SOURCES = \
+	CppServer.cpp
+
+TutorialServer_LDADD = \
+	libtutorialgencpp.la \
+	$(top_builddir)/lib/cpp/libthrift.la
+
+TutorialClient_SOURCES = \
+	CppClient.cpp
+
+TutorialClient_LDADD = \
+	libtutorialgencpp.la \
+	$(top_builddir)/lib/cpp/libthrift.la
+
+AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -Igen-cpp
+AM_CXXFLAGS = -Wall -Wextra -pedantic
+AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS)
+EXTRA_DIST = \
+	CMakeLists.txt \
+	CppClient.cpp \
+	CppServer.cpp
+
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/cpp/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign tutorial/cpp/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+gen-cpp/$(am__dirstamp):
+	@$(MKDIR_P) gen-cpp
+	@: > gen-cpp/$(am__dirstamp)
+gen-cpp/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) gen-cpp/$(DEPDIR)
+	@: > gen-cpp/$(DEPDIR)/$(am__dirstamp)
+gen-cpp/Calculator.lo: gen-cpp/$(am__dirstamp) \
+	gen-cpp/$(DEPDIR)/$(am__dirstamp)
+gen-cpp/SharedService.lo: gen-cpp/$(am__dirstamp) \
+	gen-cpp/$(DEPDIR)/$(am__dirstamp)
+gen-cpp/shared_constants.lo: gen-cpp/$(am__dirstamp) \
+	gen-cpp/$(DEPDIR)/$(am__dirstamp)
+gen-cpp/shared_types.lo: gen-cpp/$(am__dirstamp) \
+	gen-cpp/$(DEPDIR)/$(am__dirstamp)
+gen-cpp/tutorial_constants.lo: gen-cpp/$(am__dirstamp) \
+	gen-cpp/$(DEPDIR)/$(am__dirstamp)
+gen-cpp/tutorial_types.lo: gen-cpp/$(am__dirstamp) \
+	gen-cpp/$(DEPDIR)/$(am__dirstamp)
+
+libtutorialgencpp.la: $(libtutorialgencpp_la_OBJECTS) $(libtutorialgencpp_la_DEPENDENCIES) $(EXTRA_libtutorialgencpp_la_DEPENDENCIES) 
+	$(AM_V_CXXLD)$(CXXLINK)  $(libtutorialgencpp_la_OBJECTS) $(libtutorialgencpp_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+	@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+TutorialClient$(EXEEXT): $(TutorialClient_OBJECTS) $(TutorialClient_DEPENDENCIES) $(EXTRA_TutorialClient_DEPENDENCIES) 
+	@rm -f TutorialClient$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(TutorialClient_OBJECTS) $(TutorialClient_LDADD) $(LIBS)
+
+TutorialServer$(EXEEXT): $(TutorialServer_OBJECTS) $(TutorialServer_DEPENDENCIES) $(EXTRA_TutorialServer_DEPENDENCIES) 
+	@rm -f TutorialServer$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(TutorialServer_OBJECTS) $(TutorialServer_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+	-rm -f gen-cpp/*.$(OBJEXT)
+	-rm -f gen-cpp/*.lo
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CppClient.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CppServer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gen-cpp/$(DEPDIR)/Calculator.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gen-cpp/$(DEPDIR)/SharedService.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gen-cpp/$(DEPDIR)/shared_constants.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gen-cpp/$(DEPDIR)/shared_types.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gen-cpp/$(DEPDIR)/tutorial_constants.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gen-cpp/$(DEPDIR)/tutorial_types.Plo@am__quote@
+
+.cpp.o:
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@	$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+	-rm -rf gen-cpp/.libs gen-cpp/_libs
+style-local: 
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS)
+installdirs:
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-rm -f gen-cpp/$(DEPDIR)/$(am__dirstamp)
+	-rm -f gen-cpp/$(am__dirstamp)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local \
+	clean-noinstLTLIBRARIES clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR) gen-cpp/$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR) gen-cpp/$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-local clean-noinstLTLIBRARIES \
+	clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am style-am style-local tags tags-am \
+	uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+#
+# Common thrift code generation rules
+#
+gen-cpp/Calculator.cpp gen-cpp/SharedService.cpp gen-cpp/shared_constants.cpp gen-cpp/shared_types.cpp gen-cpp/tutorial_constants.cpp gen-cpp/tutorial_types.cpp: $(top_srcdir)/tutorial/tutorial.thrift
+	$(THRIFT) --gen cpp -r $<
+
+clean-local:
+	$(RM) gen-cpp/*
+
+tutorialserver: all
+	./TutorialServer
+
+tutorialclient: all
+	./TutorialClient
+
+style-local:
+	$(CPPSTYLE_CMD)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tutorial/csharp/CsharpClient/CsharpClient.cs b/tutorial/csharp/CsharpClient/CsharpClient.cs
new file mode 100644
index 0000000..113a472
--- /dev/null
+++ b/tutorial/csharp/CsharpClient/CsharpClient.cs
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using Thrift;
+using Thrift.Protocol;
+using Thrift.Server;
+using Thrift.Transport;
+
+
+namespace CSharpTutorial
+{
+    public class CSharpClient
+    {
+        public static void Main()
+        {
+            try
+            {
+                TTransport transport = new TSocket("localhost", 9090);
+                TProtocol protocol = new TBinaryProtocol(transport);
+                Calculator.Client client = new Calculator.Client(protocol);
+
+                transport.Open();
+                try
+                {
+                    client.ping();
+                    Console.WriteLine("ping()");
+
+                    int sum = client.add(1, 1);
+                    Console.WriteLine("1+1={0}", sum);
+
+                    Work work = new Work();
+
+                    work.Op = Operation.DIVIDE;
+                    work.Num1 = 1;
+                    work.Num2 = 0;
+                    try
+                    {
+                        int quotient = client.calculate(1, work);
+                        Console.WriteLine("Whoa we can divide by 0");
+                    }
+                    catch (InvalidOperation io)
+                    {
+                        Console.WriteLine("Invalid operation: " + io.Why);
+                    }
+
+                    work.Op = Operation.SUBTRACT;
+                    work.Num1 = 15;
+                    work.Num2 = 10;
+                    try
+                    {
+                        int diff = client.calculate(1, work);
+                        Console.WriteLine("15-10={0}", diff);
+                    }
+                    catch (InvalidOperation io)
+                    {
+                        Console.WriteLine("Invalid operation: " + io.Why);
+                    }
+
+                    SharedStruct log = client.getStruct(1);
+                    Console.WriteLine("Check log: {0}", log.Value);
+
+                }
+                finally
+                {
+                    transport.Close();
+                }
+            }
+            catch (TApplicationException x)
+            {
+                Console.WriteLine(x.StackTrace);
+            }
+
+        }
+    }
+}
diff --git a/tutorial/csharp/CsharpClient/CsharpClient.csproj b/tutorial/csharp/CsharpClient/CsharpClient.csproj
new file mode 100644
index 0000000..1ea7ff6
--- /dev/null
+++ b/tutorial/csharp/CsharpClient/CsharpClient.csproj
@@ -0,0 +1,110 @@
+
+
+
+  
+    Debug
+    AnyCPU
+    9.0.30729
+    2.0
+    {18F24087-4760-43DA-ACAB-7B9F0E096B11}
+    Exe
+    Properties
+    CsharpClient
+    CsharpClient
+    v3.5
+    512
+  
+  
+    true
+    full
+    false
+    bin\Debug\
+    DEBUG;TRACE
+    prompt
+    4
+  
+  
+    pdbonly
+    true
+    bin\Release\
+    TRACE
+    prompt
+    4
+  
+  
+    
+    
+      3.5
+    
+    
+      3.5
+    
+    
+      3.5
+    
+    
+    
+  
+  
+    
+      Calculator.cs
+    
+    
+      InvalidOperation.cs
+    
+    
+      Operation.cs
+    
+    
+      SharedService.cs
+    
+    
+      SharedStruct.cs
+    
+    
+      tutorial.Constants.cs
+    
+    
+      Work.cs
+    
+    
+    
+  
+  
+    
+      {499eb63c-d74c-47e8-ae48-a2fc94538e9d}
+      Thrift
+    
+  
+  
+  
+    pushd "$(SolutionDir)"
+thrift  -gen csharp   -r  ../tutorial.thrift
+popd
+
+  
+  
+
\ No newline at end of file
diff --git a/tutorial/csharp/CsharpClient/Properties/AssemblyInfo.cs b/tutorial/csharp/CsharpClient/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..2b801c2
--- /dev/null
+++ b/tutorial/csharp/CsharpClient/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CsharpClient")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("1a461214-fa28-452a-bd1d-d23ca8e947e3")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("0.11.0.0")]
+[assembly: AssemblyFileVersion("0.11.0.0")]
diff --git a/tutorial/csharp/CsharpServer/CsharpServer.cs b/tutorial/csharp/CsharpServer/CsharpServer.cs
new file mode 100644
index 0000000..439790a
--- /dev/null
+++ b/tutorial/csharp/CsharpServer/CsharpServer.cs
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace CSharpTutorial
+{
+    public class CalculatorHandler : Calculator.Iface
+    {
+        Dictionary log;
+
+        public CalculatorHandler()
+        {
+            log = new Dictionary();
+        }
+
+        public void ping()
+        {
+            Console.WriteLine("ping()");
+        }
+
+        public int add(int n1, int n2)
+        {
+            Console.WriteLine("add({0},{1})", n1, n2);
+            return n1 + n2;
+        }
+
+        public int calculate(int logid, Work work)
+        {
+            Console.WriteLine("calculate({0}, [{1},{2},{3}])", logid, work.Op, work.Num1, work.Num2);
+            int val = 0;
+            switch (work.Op)
+            {
+                case Operation.ADD:
+                    val = work.Num1 + work.Num2;
+                    break;
+
+                case Operation.SUBTRACT:
+                    val = work.Num1 - work.Num2;
+                    break;
+
+                case Operation.MULTIPLY:
+                    val = work.Num1 * work.Num2;
+                    break;
+
+                case Operation.DIVIDE:
+                    if (work.Num2 == 0)
+                    {
+                        InvalidOperation io = new InvalidOperation();
+                        io.WhatOp = (int)work.Op;
+                        io.Why = "Cannot divide by 0";
+                        throw io;
+                    }
+                    val = work.Num1 / work.Num2;
+                    break;
+
+                default:
+                    {
+                        InvalidOperation io = new InvalidOperation();
+                        io.WhatOp = (int)work.Op;
+                        io.Why = "Unknown operation";
+                        throw io;
+                    }
+            }
+
+            SharedStruct entry = new SharedStruct();
+            entry.Key = logid;
+            entry.Value = val.ToString();
+            log[logid] = entry;
+
+            return val;
+        }
+
+        public SharedStruct getStruct(int key)
+        {
+            Console.WriteLine("getStruct({0})", key);
+            return log[key];
+        }
+
+        public void zip()
+        {
+            Console.WriteLine("zip()");
+        }
+    }
+
+    public class CSharpServer
+    {
+        public static void Main()
+        {
+            try
+            {
+                CalculatorHandler handler = new CalculatorHandler();
+                Calculator.Processor processor = new Calculator.Processor(handler);
+                TServerTransport serverTransport = new TServerSocket(9090);
+                TServer server = new TSimpleServer(processor, serverTransport);
+
+                // Use this for a multithreaded server
+                // server = new TThreadPoolServer(processor, serverTransport);
+
+                Console.WriteLine("Starting the server...");
+                server.Serve();
+            }
+            catch (Exception x)
+            {
+                Console.WriteLine(x.StackTrace);
+            }
+            Console.WriteLine("done.");
+        }
+    }
+}
diff --git a/tutorial/csharp/CsharpServer/CsharpServer.csproj b/tutorial/csharp/CsharpServer/CsharpServer.csproj
new file mode 100644
index 0000000..0748180
--- /dev/null
+++ b/tutorial/csharp/CsharpServer/CsharpServer.csproj
@@ -0,0 +1,111 @@
+
+
+
+  
+    Debug
+    AnyCPU
+    9.0.30729
+    2.0
+    {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}
+    Exe
+    Properties
+    CsharpServer
+    CsharpServer
+    v3.5
+    512
+  
+  
+    true
+    full
+    false
+    bin\Debug\
+    DEBUG;TRACE
+    prompt
+    4
+  
+  
+    pdbonly
+    true
+    bin\Release\
+    TRACE
+    prompt
+    4
+  
+  
+    
+    
+      3.5
+    
+    
+      3.5
+    
+    
+      3.5
+    
+    
+    
+  
+  
+    
+      Calculator.cs
+    
+    
+      InvalidOperation.cs
+    
+    
+      Operation.cs
+    
+    
+      SharedService.cs
+    
+    
+      SharedStruct.cs
+    
+    
+      tutorial.Constants.cs
+    
+    
+      Work.cs
+    
+    
+    
+  
+  
+    
+      {499eb63c-d74c-47e8-ae48-a2fc94538e9d}
+      Thrift
+    
+  
+  
+  
+    pushd "$(SolutionDir)"
+thrift  -gen csharp   -r  ../tutorial.thrift
+popd
+
+
+  
+  
+
\ No newline at end of file
diff --git a/tutorial/csharp/CsharpServer/Properties/AssemblyInfo.cs b/tutorial/csharp/CsharpServer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..b11cbdf
--- /dev/null
+++ b/tutorial/csharp/CsharpServer/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CsharpServer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("e3b428f4-b2e9-4fc1-8a34-84abc4339860")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("0.11.0.0")]
+[assembly: AssemblyFileVersion("0.11.0.0")]
diff --git a/tutorial/csharp/tutorial.sln b/tutorial/csharp/tutorial.sln
new file mode 100644
index 0000000..ec57a18
--- /dev/null
+++ b/tutorial/csharp/tutorial.sln
@@ -0,0 +1,39 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\lib\csharp\src\Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsharpClient", "CsharpClient\CsharpClient.csproj", "{18F24087-4760-43DA-ACAB-7B9F0E096B11}"
+    ProjectSection(ProjectDependencies) = postProject
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D} = {499EB63C-D74C-47E8-AE48-A2FC94538E9D}
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8} = {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}
+    EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsharpServer", "CsharpServer\CsharpServer.csproj", "{66707BAE-BBF9-4F03-B53E-BE3AD58322F8}"
+    ProjectSection(ProjectDependencies) = postProject
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D} = {499EB63C-D74C-47E8-AE48-A2FC94538E9D}
+    EndProjectSection
+EndProject
+Global
+    GlobalSection(SolutionConfigurationPlatforms) = preSolution
+        Debug|Any CPU = Debug|Any CPU
+        Release|Any CPU = Release|Any CPU
+    EndGlobalSection
+    GlobalSection(ProjectConfigurationPlatforms) = postSolution
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU
+        {18F24087-4760-43DA-ACAB-7B9F0E096B11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+        {18F24087-4760-43DA-ACAB-7B9F0E096B11}.Debug|Any CPU.Build.0 = Debug|Any CPU
+        {18F24087-4760-43DA-ACAB-7B9F0E096B11}.Release|Any CPU.ActiveCfg = Release|Any CPU
+        {18F24087-4760-43DA-ACAB-7B9F0E096B11}.Release|Any CPU.Build.0 = Release|Any CPU
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Release|Any CPU.Build.0 = Release|Any CPU
+    EndGlobalSection
+    GlobalSection(SolutionProperties) = preSolution
+        HideSolutionNode = FALSE
+    EndGlobalSection
+EndGlobal
diff --git a/tutorial/d/Makefile b/tutorial/d/Makefile
new file mode 100644
index 0000000..fa68fa5
--- /dev/null
+++ b/tutorial/d/Makefile
@@ -0,0 +1,644 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# tutorial/d/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/thrift
+pkgincludedir = $(includedir)/thrift
+pkglibdir = $(libdir)/thrift
+pkglibexecdir = $(libexecdir)/thrift
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+#am__append_1 = async_client
+subdir = tutorial/d
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15
+ALLOCA = 
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+ANT = /usr/bin/ant
+ANT_FLAGS = 
+AR = ar
+AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf
+AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader
+AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15
+AWK = gawk
+BISON = bison
+BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a
+BOOST_CPPFLAGS = -I/usr/include
+BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a
+BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu
+BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu
+BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a
+BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a
+BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a
+BUNDLER = /usr/bin/bundle
+CABAL = /usr/bin/cabal
+CABAL_CONFIGURE_FLAGS = 
+CARGO = /usr/bin/cargo
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CLASSPATH = 
+CPP = gcc -E
+CPPFLAGS = 
+CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;
+CXX = g++ -std=c++11
+CXXCPP = g++ -E -std=c++11
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DART = /usr/lib/dart/bin/dart
+DARTPUB = /usr/lib/dart/bin/pub
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DMD = dmd
+DMD_LIBEVENT_FLAGS = 
+DMD_OF_DIRSEP = /
+DMD_OPENSSL_FLAGS = 
+DOTNETCORE = /usr/bin/dotnet
+DOTNETCORE_VERSION = 2.0.3
+DSYMUTIL = 
+DUMPBIN = 
+D_EVENT_LIB_NAME = libthriftd-event.a
+D_IMPORT_PREFIX = ${prefix}/include/d2
+D_LIB_NAME = libthriftd.a
+D_SSL_LIB_NAME = libthriftd-ssl.a
+ECHO_C = 
+ECHO_N = -n
+ECHO_T = 
+EGREP = /bin/grep -E
+ENABLE_COVERAGE = 2
+ERL = /usr/bin/erl
+ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib
+ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0
+ERLANG_LIB_DIR = /usr/lib/erlang/lib
+ERLC = /usr/bin/erlc
+ERLCFLAGS = 
+EXEEXT = 
+FGREP = /bin/grep -F
+GCOV_CFLAGS = 
+GCOV_CXXFLAGS = 
+GCOV_LDFLAGS = 
+GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GLIB_LIBS = -lglib-2.0
+GO = /usr/bin/go
+GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
+GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0
+GREP = /bin/grep
+HAVE_CXX11 = 1
+HAXE = /usr/bin/haxe
+HAXE_VERSION = 3.2.1
+INSTALL = /usr/bin/install -c
+INSTALLDIRS = vendor
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+JAVA_PREFIX = /usr/local/lib
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS = 
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBEVENT_CPPFLAGS = 
+LIBEVENT_LDFLAGS = 
+LIBEVENT_LIBS = -levent
+LIBOBJS = 
+LIBS = -lrt -lpthread 
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO = 
+LN_S = ln -s
+LTLIBOBJS = 
+LT_SYS_LIBRARY_PATH = 
+LUA = /usr/bin/lua5.3
+LUA_EXEC_PREFIX = ${exec_prefix}
+LUA_INCLUDE = -I/usr/include/lua5.3
+LUA_LIB = -llua5.3  -ldl
+LUA_PLATFORM = unknown
+LUA_PREFIX = ${prefix}
+LUA_SHORT_VERSION = 53
+LUA_VERSION = 5.3
+MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo
+MANIFEST_TOOL = :
+MAYBE_CPP = cpp
+MAYBE_CSHARP = csharp
+MAYBE_C_GLIB = c_glib
+MAYBE_D = 
+MAYBE_DART = dart
+MAYBE_DOTNETCORE = netcore
+MAYBE_ERLANG = erl
+MAYBE_GO = go
+MAYBE_HASKELL = hs
+MAYBE_JAVA = java
+MAYBE_LUA = lua
+MAYBE_NODEJS = nodejs
+MAYBE_PERL = perl
+MAYBE_PHP = php
+MAYBE_PY3 = py3
+MAYBE_PYTHON = py
+MAYBE_RS = rs
+MAYBE_RUBY = rb
+MCS = /usr/bin/mcs
+MKDIR_P = /bin/mkdir -p
+MONO_CFLAGS = 
+MONO_LIBS = 
+NM = /usr/bin/nm -B
+NMEDIT = 
+NODEJS = /usr/bin/nodejs
+NPM = /usr/bin/npm
+OBJDUMP = objdump
+OBJEXT = o
+OPENSSL_INCLUDES = 
+OPENSSL_LDFLAGS = 
+OPENSSL_LIBS = -lssl -lcrypto
+OTOOL = 
+OTOOL64 = 
+PACKAGE = thrift
+PACKAGE_BUGREPORT = 
+PACKAGE_NAME = thrift
+PACKAGE_STRING = thrift 0.11.0
+PACKAGE_TARNAME = thrift
+PACKAGE_URL = 
+PACKAGE_VERSION = 0.11.0
+PATH_SEPARATOR = :
+PERL = /usr/bin/perl
+PERL_PREFIX = /usr/local
+PHP = /usr/bin/php
+PHPUNIT = /usr/bin/phpunit
+PHP_CONFIG = /usr/bin/php-config
+PHP_CONFIG_PREFIX = /etc/php.d
+PHP_PREFIX = /usr/lib/php
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR = 
+PKG_CONFIG_PATH = 
+PYTHON = /usr/bin/python
+PYTHON3 = /usr/bin/python3
+PYTHON_EXEC_PREFIX = ${exec_prefix}
+PYTHON_PLATFORM = linux2
+PYTHON_PREFIX = ${prefix}
+PYTHON_VERSION = 2.7
+PY_PREFIX = /usr
+QT5_CFLAGS = 
+QT5_LIBS = 
+QT5_MOC = 
+QT_CFLAGS = 
+QT_LIBS = 
+QT_MOC = 
+RANLIB = ranlib
+REBAR = /usr/bin/rebar
+RUBY = /usr/bin/ruby
+RUBY_PREFIX = 
+RUNHASKELL = /usr/bin/runhaskell
+RUSTC = /usr/bin/rustc
+SED = /bin/sed
+SET_MAKE = 
+SHELL = /bin/bash
+STRIP = strip
+THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift
+TRIAL = /usr/bin/trial
+VERSION = 0.11.0
+YACC = bison -y
+YFLAGS = 
+ZLIB_CPPFLAGS = 
+ZLIB_LDFLAGS = 
+ZLIB_LIBS = -lz
+abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/tutorial/d
+abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/tutorial/d
+abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift
+abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+ac_ct_DUMPBIN = 
+am__include = include
+am__leading_dot = .
+am__quote = 
+am__tar = tar --format=ustar -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias = 
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+golang_version = 1.6.2
+have_prog_bison = yes
+host = x86_64-pc-linux-gnu
+host_alias = 
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+luadir = ${prefix}/share/lua/5.3
+luaexecdir = ${exec_prefix}/lib/lua/5.3
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+pkgluadir = ${luadir}/thrift
+pkgluaexecdir = ${luaexecdir}/thrift
+pkgpyexecdir = ${pyexecdir}/thrift
+pkgpythondir = ${pythondir}/thrift
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages
+pythondir = ${prefix}/lib/python2.7/dist-packages
+runstatedir = ${localstatedir}/run
+rustc_version = rustc 1.17.0
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+subdirs =  lib/php/src/ext/thrift_protocol
+sysconfdir = ${prefix}/etc
+target_alias = 
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+LIB_D_DIR = $(top_srcdir)/lib/d
+GEN_SRC = gen-d/share/SharedService.d gen-d/share/shared_types.d \
+	gen-d/tutorial/tutorial_types.d gen-d/tutorial/Calculator.d
+
+PROGS = server client $(am__append_1)
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/d/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign tutorial/d/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile all-local
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am all-local check check-am clean clean-generic \
+	clean-libtool cscopelist-am ctags-am distclean \
+	distclean-generic distclean-libtool distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \
+	tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+$(GEN_SRC): $(top_srcdir)/tutorial/tutorial.thrift
+	$(top_builddir)/compiler/cpp/thrift --gen d -r $<
+
+server: server.d $(GEN_SRC)
+	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd server.d ${GEN_SRC}
+
+client: client.d $(GEN_SRC)
+	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd client.d ${GEN_SRC}
+
+#async_client: async_client.d $(GEN_SRC)
+#	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd-event -L-lthriftd -L-levent async_client.d ${GEN_SRC}
+
+all-local: $(PROGS)
+
+clean:
+	$(RM) -f $(PROGS)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tutorial/d/Makefile.am b/tutorial/d/Makefile.am
new file mode 100644
index 0000000..d8c8b29
--- /dev/null
+++ b/tutorial/d/Makefile.am
@@ -0,0 +1,46 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+LIB_D_DIR = $(top_srcdir)/lib/d
+
+GEN_SRC = gen-d/share/SharedService.d gen-d/share/shared_types.d \
+	gen-d/tutorial/tutorial_types.d gen-d/tutorial/Calculator.d
+
+$(GEN_SRC): $(top_srcdir)/tutorial/tutorial.thrift
+	$(top_builddir)/compiler/cpp/thrift --gen d -r $<
+
+server: server.d $(GEN_SRC)
+	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd server.d ${GEN_SRC}
+
+client: client.d $(GEN_SRC)
+	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd client.d ${GEN_SRC}
+
+PROGS = server client
+
+if WITH_D_EVENT_TESTS
+async_client: async_client.d $(GEN_SRC)
+	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd-event -L-lthriftd -L-levent async_client.d ${GEN_SRC}
+
+PROGS += async_client
+endif
+
+all-local: $(PROGS)
+
+clean:
+	$(RM) -f $(PROGS)
diff --git a/tutorial/d/Makefile.in b/tutorial/d/Makefile.in
new file mode 100644
index 0000000..645cbed
--- /dev/null
+++ b/tutorial/d/Makefile.in
@@ -0,0 +1,644 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@WITH_D_EVENT_TESTS_TRUE@am__append_1 = async_client
+subdir = tutorial/d
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+LIB_D_DIR = $(top_srcdir)/lib/d
+GEN_SRC = gen-d/share/SharedService.d gen-d/share/shared_types.d \
+	gen-d/tutorial/tutorial_types.d gen-d/tutorial/Calculator.d
+
+PROGS = server client $(am__append_1)
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/d/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign tutorial/d/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile all-local
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am all-local check check-am clean clean-generic \
+	clean-libtool cscopelist-am ctags-am distclean \
+	distclean-generic distclean-libtool distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \
+	tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+$(GEN_SRC): $(top_srcdir)/tutorial/tutorial.thrift
+	$(top_builddir)/compiler/cpp/thrift --gen d -r $<
+
+server: server.d $(GEN_SRC)
+	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd server.d ${GEN_SRC}
+
+client: client.d $(GEN_SRC)
+	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd client.d ${GEN_SRC}
+
+@WITH_D_EVENT_TESTS_TRUE@async_client: async_client.d $(GEN_SRC)
+@WITH_D_EVENT_TESTS_TRUE@	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd-event -L-lthriftd -L-levent async_client.d ${GEN_SRC}
+
+all-local: $(PROGS)
+
+clean:
+	$(RM) -f $(PROGS)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tutorial/d/async_client.d b/tutorial/d/async_client.d
new file mode 100644
index 0000000..1defce0
--- /dev/null
+++ b/tutorial/d/async_client.d
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+module async_client;
+
+import std.exception;
+import std.stdio;
+import thrift.async.libevent;
+import thrift.async.socket;
+import thrift.base;
+import thrift.codegen.async_client;
+import thrift.protocol.binary;
+import thrift.transport.buffered;
+
+import tutorial.Calculator;
+import tutorial.tutorial_types;
+
+void main() {
+  auto asyncManager = new TLibeventAsyncManager;
+
+  // If we are done, gracefully stop the async manager to avoid hanging on
+  // appplication shutdown.
+  scope (exit) asyncManager.stop();
+
+  auto socket = new TAsyncSocket(asyncManager, "localhost", 9090);
+  auto client = new TAsyncClient!Calculator(
+    socket,
+    new TBufferedTransportFactory,
+    new TBinaryProtocolFactory!TBufferedTransport
+  );
+
+  socket.open();
+
+  // Invoke all the methods.
+  auto pingResult = client.ping();
+
+  auto addResult = client.add(1, 1);
+
+  auto work = Work();
+  work.op = Operation.DIVIDE;
+  work.num1 = 1;
+  work.num2 = 0;
+  auto quotientResult = client.calculate(1, work);
+
+  work.op = Operation.SUBTRACT;
+  work.num1 = 15;
+  work.num2 = 10;
+  auto diffResult = client.calculate(1, work);
+
+  auto logResult = client.getStruct(1);
+
+  // Await the responses.
+  pingResult.waitGet();
+  writeln("ping()");
+
+  int sum = addResult.waitGet();
+  writefln("1 + 1 = %s", sum);
+
+  try {
+    quotientResult.waitGet();
+    writeln("Whoa we can divide by 0");
+  } catch (InvalidOperation io) {
+    writeln("Invalid operation: " ~ io.why);
+  }
+
+  writefln("15 - 10 = %s", diffResult.waitGet());
+
+  // TFuture is implicitly convertible to the result type via »alias this«,
+  // for which it (eagerly, of course) awaits completion.
+  writefln("Check log: %s", logResult.value);
+}
diff --git a/tutorial/d/client.d b/tutorial/d/client.d
new file mode 100644
index 0000000..1867a17
--- /dev/null
+++ b/tutorial/d/client.d
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+module client;
+
+import std.stdio;
+import thrift.base;
+import thrift.codegen.client;
+import thrift.protocol.binary;
+import thrift.transport.buffered;
+import thrift.transport.socket;
+
+import tutorial.Calculator;
+import tutorial.tutorial_types;
+
+void main() {
+  auto socket = new TSocket("localhost", 9090);
+  auto transport = new TBufferedTransport(socket);
+  auto protocol = tBinaryProtocol(transport);
+  auto client = tClient!Calculator(protocol);
+
+  transport.open();
+
+  client.ping();
+  writeln("ping()");
+
+  int sum = client.add(1, 1);
+  writefln("1 + 1 = %s", sum);
+
+  auto work = Work();
+  work.op = Operation.DIVIDE;
+  work.num1 = 1;
+  work.num2 = 0;
+  try {
+    int quotient = client.calculate(1, work);
+    writeln("Whoa we can divide by 0");
+  } catch (InvalidOperation io) {
+    writeln("Invalid operation: " ~ io.why);
+  }
+
+  work.op = Operation.SUBTRACT;
+  work.num1 = 15;
+  work.num2 = 10;
+  int diff = client.calculate(1, work);
+  writefln("15 - 10 = %s", diff);
+
+  auto log = client.getStruct(1);
+  writefln("Check log: %s", log.value);
+}
diff --git a/tutorial/d/server.d b/tutorial/d/server.d
new file mode 100644
index 0000000..cbcedcc
--- /dev/null
+++ b/tutorial/d/server.d
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+module server;
+
+import std.conv : to;
+import std.stdio;
+import thrift.codegen.processor;
+import thrift.protocol.binary;
+import thrift.server.simple;
+import thrift.server.transport.socket;
+import thrift.transport.buffered;
+
+import share.SharedService;
+import share.shared_types;
+import tutorial.Calculator;
+import tutorial.tutorial_types;
+
+/**
+ * The actual implementation of the Calculator interface that is called by
+ * the server to answer the requests.
+ */
+class CalculatorHandler : Calculator {
+  void ping() {
+    writeln("ping()");
+  }
+
+  int add(int n1, int n2) {
+    writefln("add(%s,%s)", n1, n2);
+    return n1 + n2;
+  }
+
+  int calculate(int logid, ref const(Work) work) {
+    writefln("calculate(%s, {%s, %s, %s})", logid, work.op, work.num1, work.num2);
+    int val;
+
+    switch (work.op) {
+    case Operation.ADD:
+      val = work.num1 + work.num2;
+      break;
+    case Operation.SUBTRACT:
+      val = work.num1 - work.num2;
+      break;
+    case Operation.MULTIPLY:
+      val = work.num1 * work.num2;
+      break;
+    case Operation.DIVIDE:
+      if (work.num2 == 0) {
+        auto io = new InvalidOperation();
+        io.whatOp = work.op;
+        io.why = "Cannot divide by 0";
+        throw io;
+      }
+      val = work.num1 / work.num2;
+      break;
+    default:
+      auto io = new InvalidOperation();
+      io.whatOp = work.op;
+      io.why = "Invalid Operation";
+      throw io;
+    }
+
+    auto ss = SharedStruct();
+    ss.key = logid;
+    ss.value = to!string(val);
+    log[logid] = ss;
+
+    return val;
+  }
+
+  SharedStruct getStruct(int logid) {
+    writefln("getStruct(%s)", logid);
+    return log[logid];
+  }
+
+  void zip() {
+    writeln("zip()");
+  }
+
+protected:
+  SharedStruct[int] log;
+}
+
+void main() {
+  auto protocolFactory = new TBinaryProtocolFactory!();
+  auto processor = new TServiceProcessor!Calculator(new CalculatorHandler);
+  auto serverTransport = new TServerSocket(9090);
+  auto transportFactory = new TBufferedTransportFactory;
+
+  auto server = new TSimpleServer(
+    processor, serverTransport, transportFactory, protocolFactory);
+
+  writeln("Starting the server on port 9090...");
+  server.serve();
+  writeln("done.");
+}
diff --git a/tutorial/dart/Makefile.am b/tutorial/dart/Makefile.am
new file mode 100644
index 0000000..0495aca
--- /dev/null
+++ b/tutorial/dart/Makefile.am
@@ -0,0 +1,73 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+BUILT_SOURCES = gen-dart/tutorial/lib/tutorial.dart gen-dart/shared/lib/shared.dart
+
+gen-dart/tutorial/lib/tutorial.dart gen-dart/shared/lib/shared.dart: $(top_srcdir)/tutorial/tutorial.thrift
+	$(THRIFT) --gen dart -r $<
+
+all-local: gen-dart/tutorial/lib/tutorial.dart pub-get
+
+clean-local:
+	$(RM) -r gen-*
+	find . -type d -name "packages" | xargs $(RM) -r
+	find . -type f -name ".packages" | xargs $(RM)
+	find . -type f -name "pubspec.lock" | xargs $(RM)
+
+pub-get: pub-get-gen pub-get-client pub-get-console-client pub-get-server
+
+pub-get-gen: pub-get-tutorial pub-get-shared
+
+pub-get-tutorial: gen-dart/tutorial/lib/tutorial.dart
+	cd gen-dart/tutorial; ${DARTPUB} get
+
+pub-get-shared: gen-dart/shared/lib/shared.dart
+	cd gen-dart/shared; ${DARTPUB} get
+
+pub-get-client:
+	cd client; ${DARTPUB} get
+
+pub-get-console-client:
+	cd console_client; ${DARTPUB} get
+
+pub-get-server:
+	cd server; ${DARTPUB} get
+
+tutorialserver: pub-get-gen pub-get-server
+	${DART} server/bin/main.dart
+
+tutorialclient: pub-get-gen pub-get-client
+	cd client; ${DARTPUB} serve
+
+tutorialconsoleclient: pub-get-console-client
+	${DART} console_client/bin/main.dart
+
+EXTRA_DIST = \
+	client/web/client.dart \
+	client/web/index.html \
+	client/web/styles.css \
+	client/pubspec.yaml \
+	console_client/bin/main.dart \
+	console_client/pubspec.yaml \
+	server/bin/main.dart \
+	server/pubspec.yaml \
+	console_client/.analysis_options \
+	client/.analysis_options \
+	server/.analysis_options \
+	build.sh
diff --git a/tutorial/dart/Makefile.in b/tutorial/dart/Makefile.in
new file mode 100644
index 0000000..93d938e
--- /dev/null
+++ b/tutorial/dart/Makefile.in
@@ -0,0 +1,681 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = tutorial/dart
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \
+	$(top_srcdir)/aclocal/ax_boost_base.m4 \
+	$(top_srcdir)/aclocal/ax_check_openssl.m4 \
+	$(top_srcdir)/aclocal/ax_compare_version.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/aclocal/ax_dmd.m4 \
+	$(top_srcdir)/aclocal/ax_javac_and_java.m4 \
+	$(top_srcdir)/aclocal/ax_lib_event.m4 \
+	$(top_srcdir)/aclocal/ax_lib_zlib.m4 \
+	$(top_srcdir)/aclocal/ax_lua.m4 \
+	$(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \
+	$(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \
+	$(top_srcdir)/aclocal/ax_signed_right_shift.m4 \
+	$(top_srcdir)/aclocal/ax_thrift_internal.m4 \
+	$(top_srcdir)/aclocal/libtool.m4 \
+	$(top_srcdir)/aclocal/ltoptions.m4 \
+	$(top_srcdir)/aclocal/ltsugar.m4 \
+	$(top_srcdir)/aclocal/ltversion.m4 \
+	$(top_srcdir)/aclocal/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/lib/cpp/src/thrift/config.h \
+	$(top_builddir)/lib/c_glib/src/thrift/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__extra_recursive_targets = style-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANT = @ANT@
+ANT_FLAGS = @ANT_FLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BISON = @BISON@
+BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+BOOST_LIB_DIR = @BOOST_LIB_DIR@
+BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@
+BOOST_TEST_LDADD = @BOOST_TEST_LDADD@
+BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@
+BUNDLER = @BUNDLER@
+CABAL = @CABAL@
+CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLASSPATH = @CLASSPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPSTYLE_CMD = @CPPSTYLE_CMD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DART = @DART@
+DARTPUB = @DARTPUB@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DMD = @DMD@
+DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@
+DMD_OF_DIRSEP = @DMD_OF_DIRSEP@
+DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@
+DOTNETCORE = @DOTNETCORE@
+DOTNETCORE_VERSION = @DOTNETCORE_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@
+D_IMPORT_PREFIX = @D_IMPORT_PREFIX@
+D_LIB_NAME = @D_LIB_NAME@
+D_SSL_LIB_NAME = @D_SSL_LIB_NAME@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE = @ENABLE_COVERAGE@
+ERL = @ERL@
+ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@
+ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@
+ERLANG_LIB_DIR = @ERLANG_LIB_DIR@
+ERLC = @ERLC@
+ERLCFLAGS = @ERLCFLAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_CXXFLAGS = @GCOV_CXXFLAGS@
+GCOV_LDFLAGS = @GCOV_LDFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GO = @GO@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAXE = @HAXE@
+HAXE_VERSION = @HAXE_VERSION@
+INSTALL = @INSTALL@
+INSTALLDIRS = @INSTALLDIRS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA_PREFIX = @JAVA_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@
+LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@
+LIBEVENT_LIBS = @LIBEVENT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA = @LUA@
+LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@
+LUA_INCLUDE = @LUA_INCLUDE@
+LUA_LIB = @LUA_LIB@
+LUA_PLATFORM = @LUA_PLATFORM@
+LUA_PREFIX = @LUA_PREFIX@
+LUA_SHORT_VERSION = @LUA_SHORT_VERSION@
+LUA_VERSION = @LUA_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAYBE_CPP = @MAYBE_CPP@
+MAYBE_CSHARP = @MAYBE_CSHARP@
+MAYBE_C_GLIB = @MAYBE_C_GLIB@
+MAYBE_D = @MAYBE_D@
+MAYBE_DART = @MAYBE_DART@
+MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@
+MAYBE_ERLANG = @MAYBE_ERLANG@
+MAYBE_GO = @MAYBE_GO@
+MAYBE_HASKELL = @MAYBE_HASKELL@
+MAYBE_JAVA = @MAYBE_JAVA@
+MAYBE_LUA = @MAYBE_LUA@
+MAYBE_NODEJS = @MAYBE_NODEJS@
+MAYBE_PERL = @MAYBE_PERL@
+MAYBE_PHP = @MAYBE_PHP@
+MAYBE_PY3 = @MAYBE_PY3@
+MAYBE_PYTHON = @MAYBE_PYTHON@
+MAYBE_RS = @MAYBE_RS@
+MAYBE_RUBY = @MAYBE_RUBY@
+MCS = @MCS@
+MKDIR_P = @MKDIR_P@
+MONO_CFLAGS = @MONO_CFLAGS@
+MONO_LIBS = @MONO_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NODEJS = @NODEJS@
+NPM = @NPM@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_INCLUDES = @OPENSSL_INCLUDES@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_PREFIX = @PERL_PREFIX@
+PHP = @PHP@
+PHPUNIT = @PHPUNIT@
+PHP_CONFIG = @PHP_CONFIG@
+PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@
+PHP_PREFIX = @PHP_PREFIX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON3 = @PYTHON3@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+PY_PREFIX = @PY_PREFIX@
+QT5_CFLAGS = @QT5_CFLAGS@
+QT5_LIBS = @QT5_LIBS@
+QT5_MOC = @QT5_MOC@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+QT_MOC = @QT_MOC@
+RANLIB = @RANLIB@
+REBAR = @REBAR@
+RUBY = @RUBY@
+RUBY_PREFIX = @RUBY_PREFIX@
+RUNHASKELL = @RUNHASKELL@
+RUSTC = @RUSTC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THRIFT = @THRIFT@
+TRIAL = @TRIAL@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@
+ZLIB_LDFLAGS = @ZLIB_LDFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+golang_version = @golang_version@
+have_prog_bison = @have_prog_bison@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+luadir = @luadir@
+luaexecdir = @luaexecdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgluadir = @pkgluadir@
+pkgluaexecdir = @pkgluaexecdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+rustc_version = @rustc_version@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+BUILT_SOURCES = gen-dart/tutorial/lib/tutorial.dart gen-dart/shared/lib/shared.dart
+EXTRA_DIST = \
+	client/web/client.dart \
+	client/web/index.html \
+	client/web/styles.css \
+	client/pubspec.yaml \
+	console_client/bin/main.dart \
+	console_client/pubspec.yaml \
+	server/bin/main.dart \
+	server/pubspec.yaml \
+	console_client/.analysis_options \
+	client/.analysis_options \
+	server/.analysis_options \
+	build.sh
+
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/dart/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign tutorial/dart/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+style-local: 
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile all-local
+installdirs:
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+style: style-am
+
+style-am: style-local
+
+uninstall-am:
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: all all-am all-local check check-am clean clean-generic \
+	clean-libtool clean-local cscopelist-am ctags-am distclean \
+	distclean-generic distclean-libtool distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \
+	tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+gen-dart/tutorial/lib/tutorial.dart gen-dart/shared/lib/shared.dart: $(top_srcdir)/tutorial/tutorial.thrift
+	$(THRIFT) --gen dart -r $<
+
+all-local: gen-dart/tutorial/lib/tutorial.dart pub-get
+
+clean-local:
+	$(RM) -r gen-*
+	find . -type d -name "packages" | xargs $(RM) -r
+	find . -type f -name ".packages" | xargs $(RM)
+	find . -type f -name "pubspec.lock" | xargs $(RM)
+
+pub-get: pub-get-gen pub-get-client pub-get-console-client pub-get-server
+
+pub-get-gen: pub-get-tutorial pub-get-shared
+
+pub-get-tutorial: gen-dart/tutorial/lib/tutorial.dart
+	cd gen-dart/tutorial; ${DARTPUB} get
+
+pub-get-shared: gen-dart/shared/lib/shared.dart
+	cd gen-dart/shared; ${DARTPUB} get
+
+pub-get-client:
+	cd client; ${DARTPUB} get
+
+pub-get-console-client:
+	cd console_client; ${DARTPUB} get
+
+pub-get-server:
+	cd server; ${DARTPUB} get
+
+tutorialserver: pub-get-gen pub-get-server
+	${DART} server/bin/main.dart
+
+tutorialclient: pub-get-gen pub-get-client
+	cd client; ${DARTPUB} serve
+
+tutorialconsoleclient: pub-get-console-client
+	${DART} console_client/bin/main.dart
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tutorial/dart/build.sh b/tutorial/dart/build.sh
new file mode 100644
index 0000000..eabe04a
--- /dev/null
+++ b/tutorial/dart/build.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# 'License'); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+set -e;
+rm -r gen-dart || true;
+
+thrift --gen dart ../shared.thrift;
+cd gen-dart/shared;
+pub get;
+cd ../..;
+
+thrift --gen dart ../tutorial.thrift;
+cd gen-dart/tutorial;
+pub get;
+cd ../..;
+
+cd client;
+pub get;
+cd ..;
+
+cd console_client;
+pub get;
+cd ..;
+
+cd server;
+pub get;
+cd ..;
+
+dartfmt -w gen-dart;
+
+echo "\nEnjoy the Dart tutorial!";
+echo "\nTo run the server:";
+echo "> dart server/bin/main.dart";
+echo "\nTo run the client:";
+echo "# Serve the app from the client directory and view in a browser";
+echo "> cd client;";
+echo "> pub serve;";
+echo "\nTo run the console client:";
+echo "> dart console_client/bin/main.dart";
+echo "";
diff --git a/tutorial/dart/client/.analysis_options b/tutorial/dart/client/.analysis_options
new file mode 100644
index 0000000..a10d4c5
--- /dev/null
+++ b/tutorial/dart/client/.analysis_options
@@ -0,0 +1,2 @@
+analyzer:
+  strong-mode: true
diff --git a/tutorial/dart/client/pubspec.yaml b/tutorial/dart/client/pubspec.yaml
new file mode 100644
index 0000000..51b7ad2
--- /dev/null
+++ b/tutorial/dart/client/pubspec.yaml
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# 'License'); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+name: tutorial_client
+version: 0.11.0
+description: A Dart client implementation of the Apache Thrift tutorial
+author: Apache Thrift Developers 
+homepage: http://thrift.apache.org
+
+environment:
+  sdk: ">=1.13.0 <2.0.0"
+
+dependencies:
+  browser: ^0.11.0
+  shared:
+    path: ../gen-dart/shared
+  thrift:
+    path: ../../../lib/dart
+  tutorial:
+    path: ../gen-dart/tutorial
diff --git a/tutorial/dart/client/web/client.dart b/tutorial/dart/client/web/client.dart
new file mode 100644
index 0000000..4f02d0d
--- /dev/null
+++ b/tutorial/dart/client/web/client.dart
@@ -0,0 +1,278 @@
+/// Licensed to the Apache Software Foundation (ASF) under one
+/// or more contributor license agreements. See the NOTICE file
+/// distributed with this work for additional information
+/// regarding copyright ownership. The ASF licenses this file
+/// to you under the Apache License, Version 2.0 (the
+/// "License"); you may not use this file except in compliance
+/// with the License. You may obtain a copy of the License at
+///
+/// http://www.apache.org/licenses/LICENSE-2.0
+///
+/// Unless required by applicable law or agreed to in writing,
+/// software distributed under the License is distributed on an
+/// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+/// KIND, either express or implied. See the License for the
+/// specific language governing permissions and limitations
+/// under the License.
+
+import 'dart:html';
+
+import 'package:thrift/thrift.dart';
+import 'package:thrift/thrift_browser.dart';
+import 'package:shared/shared.dart';
+import 'package:tutorial/tutorial.dart';
+
+/// Adapted from the AS3 tutorial
+void main() {
+  new CalculatorUI(querySelector('#output')).start();
+}
+
+class CalculatorUI {
+  final DivElement output;
+
+  CalculatorUI(this.output);
+
+  TTransport _transport;
+  Calculator _calculatorClient;
+
+  void start() {
+    _buildInterface();
+    _initConnection();
+  }
+
+  void _validate() {
+    if (!_transport.isOpen) {
+      window.alert("The transport is not open!");
+    }
+  }
+
+  void _initConnection() {
+    _transport = new TAsyncClientSocketTransport(
+        new TWebSocket(Uri.parse('ws://127.0.0.1:9090/ws')),
+        new TMessageReader(new TBinaryProtocolFactory()));
+    TProtocol protocol = new TBinaryProtocol(_transport);
+    _transport.open();
+
+    _calculatorClient = new CalculatorClient(protocol);
+  }
+
+  void _buildInterface() {
+    output.children.forEach((e) {
+      e.remove();
+    });
+
+    _buildPingComponent();
+
+    _buildAddComponent();
+
+    _buildCalculatorComponent();
+
+    _buildGetStructComponent();
+  }
+
+  void _buildPingComponent() {
+    output.append(new HeadingElement.h3()..text = "Ping");
+    ButtonElement pingButton = new ButtonElement()
+      ..text = "PING"
+      ..onClick.listen(_onPingClick);
+    output.append(pingButton);
+  }
+
+  void _onPingClick(MouseEvent e) {
+    _validate();
+
+    _calculatorClient.ping();
+  }
+
+  void _buildAddComponent() {
+    output.append(new HeadingElement.h3()..text = "Add");
+    InputElement num1 = new InputElement()
+      ..id = "add1"
+      ..type = "number"
+      ..style.fontSize = "14px"
+      ..style.width = "50px";
+    output.append(num1);
+    SpanElement op = new SpanElement()
+      ..text = "+"
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px";
+    output.append(op);
+    InputElement num2 = new InputElement()
+      ..id = "add2"
+      ..type = "number"
+      ..style.fontSize = "14px"
+      ..style.width = "50px"
+      ..style.marginLeft = "10px";
+    output.append(num2);
+    ButtonElement addButton = new ButtonElement()
+      ..text = "="
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px"
+      ..onClick.listen(_onAddClick);
+    output.append(addButton);
+    SpanElement result = new SpanElement()
+      ..id = "addResult"
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px";
+    output.append(result);
+  }
+
+  void _onAddClick(MouseEvent e) {
+    _validate();
+
+    InputElement num1 = querySelector("#add1");
+    InputElement num2 = querySelector("#add2");
+    SpanElement result = querySelector("#addResult");
+
+    _calculatorClient
+        .add(int.parse(num1.value), int.parse(num2.value))
+        .then((int n) {
+      result.text = "$n";
+    });
+  }
+
+  void _buildCalculatorComponent() {
+    output.append(new HeadingElement.h3()..text = "Calculator");
+    InputElement num1 = new InputElement()
+      ..id = "calc1"
+      ..type = "number"
+      ..style.fontSize = "14px"
+      ..style.width = "50px";
+    output.append(num1);
+    SelectElement op = new SelectElement()
+      ..id = "calcOp"
+      ..multiple = false
+      ..selectedIndex = 0
+      ..style.fontSize = "16px"
+      ..style.marginLeft = "10px"
+      ..style.width = "50px";
+    OptionElement addOp = new OptionElement()
+      ..text = "+"
+      ..value = Operation.ADD.toString();
+    op.add(addOp, 0);
+    OptionElement subtractOp = new OptionElement()
+      ..text = "-"
+      ..value = Operation.SUBTRACT.toString();
+    op.add(subtractOp, 1);
+    OptionElement multiplyOp = new OptionElement()
+      ..text = "*"
+      ..value = Operation.MULTIPLY.toString();
+    op.add(multiplyOp, 2);
+    OptionElement divideOp = new OptionElement()
+      ..text = "/"
+      ..value = Operation.DIVIDE.toString();
+    op.add(divideOp, 3);
+    output.append(op);
+    InputElement num2 = new InputElement()
+      ..id = "calc2"
+      ..type = "number"
+      ..style.fontSize = "14px"
+      ..style.width = "50px"
+      ..style.marginLeft = "10px";
+    output.append(num2);
+    ButtonElement calcButton = new ButtonElement()
+      ..text = "="
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px"
+      ..onClick.listen(_onCalcClick);
+    output.append(calcButton);
+    SpanElement result = new SpanElement()
+      ..id = "calcResult"
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px";
+    output.append(result);
+    output.append(new BRElement());
+    output.append(new BRElement());
+    LabelElement logIdLabel = new LabelElement()
+      ..text = "Log ID:"
+      ..style.fontSize = "14px";
+    output.append(logIdLabel);
+    InputElement logId = new InputElement()
+      ..id = "logId"
+      ..type = "number"
+      ..value = "1"
+      ..style.fontSize = "14px"
+      ..style.width = "50px"
+      ..style.marginLeft = "10px";
+    output.append(logId);
+    LabelElement commentLabel = new LabelElement()
+      ..text = "Comment:"
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px";
+    output.append(commentLabel);
+    InputElement comment = new InputElement()
+      ..id = "comment"
+      ..style.fontSize = "14px"
+      ..style.width = "100px"
+      ..style.marginLeft = "10px";
+    output.append(comment);
+  }
+
+  void _onCalcClick(MouseEvent e) {
+    _validate();
+
+    InputElement num1 = querySelector("#calc1");
+    InputElement num2 = querySelector("#calc2");
+    SelectElement op = querySelector("#calcOp");
+    SpanElement result = querySelector("#calcResult");
+    InputElement logId = querySelector("#logId");
+    InputElement comment = querySelector("#comment");
+
+    int logIdValue = int.parse(logId.value);
+    logId.value = (logIdValue + 1).toString();
+
+    Work work = new Work();
+    work.num1 = int.parse(num1.value);
+    work.num2 = int.parse(num2.value);
+    work.op = int.parse(op.options[op.selectedIndex].value);
+    work.comment = comment.value;
+
+    _calculatorClient.calculate(logIdValue, work).then((int n) {
+      result.text = "$n";
+    });
+  }
+
+  void _buildGetStructComponent() {
+    output.append(new HeadingElement.h3()..text = "Get Struct");
+    LabelElement logIdLabel = new LabelElement()
+      ..text = "Struct Key:"
+      ..style.fontSize = "14px";
+    output.append(logIdLabel);
+    InputElement logId = new InputElement()
+      ..id = "structKey"
+      ..type = "number"
+      ..value = "1"
+      ..style.fontSize = "14px"
+      ..style.width = "50px"
+      ..style.marginLeft = "10px";
+    output.append(logId);
+    ButtonElement getStructButton = new ButtonElement()
+      ..text = "GET"
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px"
+      ..onClick.listen(_onGetStructClick);
+    output.append(getStructButton);
+    output.append(new BRElement());
+    output.append(new BRElement());
+    TextAreaElement result = new TextAreaElement()
+      ..id = "getStructResult"
+      ..style.fontSize = "14px"
+      ..style.width = "300px"
+      ..style.height = "50px"
+      ..style.marginLeft = "10px";
+    output.append(result);
+  }
+
+  void _onGetStructClick(MouseEvent e) {
+    _validate();
+
+    InputElement structKey = querySelector("#structKey");
+    TextAreaElement result = querySelector("#getStructResult");
+
+    _calculatorClient
+        .getStruct(int.parse(structKey.value))
+        .then((SharedStruct s) {
+      result.text = "${s.toString()}";
+    });
+  }
+}
diff --git a/tutorial/dart/client/web/index.html b/tutorial/dart/client/web/index.html
new file mode 100644
index 0000000..64b184e
--- /dev/null
+++ b/tutorial/dart/client/web/index.html
@@ -0,0 +1,36 @@
+
+
+
+
+    
+    
+    
+    Thrift Tutorial
+    
+    
+    
+
+
+
+
+  
+ + + diff --git a/tutorial/dart/client/web/styles.css b/tutorial/dart/client/web/styles.css new file mode 100644 index 0000000..c031502 --- /dev/null +++ b/tutorial/dart/client/web/styles.css @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +@import url(https://fonts.googleapis.com/css?family=Roboto); + +html, body { + width: 100%; + height: 100%; + margin: 0; + padding: 10px; + font-family: 'Roboto', sans-serif; +} + +h3 { + border-bottom: solid; + border-width: thin; + padding-top: 20px; +} diff --git a/tutorial/dart/console_client/.analysis_options b/tutorial/dart/console_client/.analysis_options new file mode 100644 index 0000000..a10d4c5 --- /dev/null +++ b/tutorial/dart/console_client/.analysis_options @@ -0,0 +1,2 @@ +analyzer: + strong-mode: true diff --git a/tutorial/dart/console_client/bin/main.dart b/tutorial/dart/console_client/bin/main.dart new file mode 100644 index 0000000..fda206a --- /dev/null +++ b/tutorial/dart/console_client/bin/main.dart @@ -0,0 +1,149 @@ +/// Licensed to the Apache Software Foundation (ASF) under one +/// or more contributor license agreements. See the NOTICE file +/// distributed with this work for additional information +/// regarding copyright ownership. The ASF licenses this file +/// to you under the Apache License, Version 2.0 (the +/// "License"); you may not use this file except in compliance +/// with the License. You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, +/// software distributed under the License is distributed on an +/// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +/// KIND, either express or implied. See the License for the +/// specific language governing permissions and limitations +/// under the License. + +import 'dart:async'; +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:logging/logging.dart'; +import 'package:thrift/thrift.dart'; +import 'package:thrift/thrift_console.dart'; +import 'package:tutorial/tutorial.dart'; + +TTransport _transport; +Calculator _calculator; +int logid = 0; + +const Map operationLookup = const { + '+': Operation.ADD, + '-': Operation.SUBTRACT, + '*': Operation.MULTIPLY, + '/': Operation.DIVIDE +}; + +main(List args) { + Logger.root.level = Level.ALL; + Logger.root.onRecord.listen((LogRecord rec) { + print('${rec.level.name}: ${rec.time}: ${rec.message}'); + }); + + var parser = new ArgParser(); + parser.addOption('port', defaultsTo: '9090', help: 'The port to connect to'); + + ArgResults results; + try { + results = parser.parse(args); + } catch (e) { + results = null; + } + + if (results == null) { + print(parser.usage); + exit(0); + } + + int port = int.parse(results['port']); + + _initConnection(port).then((_) => _run()); +} + +Future _initConnection(int port) async { + var socket = await Socket.connect('127.0.0.1', port); + _transport = new TAsyncClientSocketTransport( + new TTcpSocket(socket), new TMessageReader(new TBinaryProtocolFactory())); + TProtocol protocol = new TBinaryProtocol(_transport); + await _transport.open(); + + _calculator = new CalculatorClient(protocol); +} + +Future _run() async { + _help(); + + while (true) { + stdout.write("> "); + var input = stdin.readLineSync(); + var parts = input.split(' '); + var command = parts[0]; + var args = parts.length > 1 ? parts.sublist(1) : []; + + switch (command) { + case 'ping': + await _ping(); + break; + + case 'add': + await _add(int.parse(args[0]), int.parse(args[1])); + break; + + case 'calc': + int op = operationLookup[args[1]]; + if (!Operation.VALID_VALUES.contains(op)) { + stdout.writeln('Unknown operator ${args[1]}'); + break; + } + + var work = new Work() + ..num1 = int.parse(args[0]) + ..op = op + ..num2 = int.parse(args[2]) + ..comment = args.length > 3 ? args[3] : ''; + + await _calc(work); + break; + + case 'struct': + await _struct(int.parse(args[0])); + break; + + case 'help': + default: + _help(); + break; + } + } +} + +void _help() { + stdout.writeln('Commands:'); + stdout.writeln(' help'); + stdout.writeln(' ping'); + stdout.writeln(' add x y'); + stdout.writeln(' calc x op y [comment]'); + stdout.writeln(' struct id'); + stdout.writeln(''); +} + +Future _ping() async { + await _calculator.ping(); + stdout.writeln('ping succeeded'); +} + +Future _add(int x, int y) async { + int result = await _calculator.add(x, y); + stdout.writeln('= $result'); +} + +Future _calc(Work work) async { + int result = await _calculator.calculate(logid++, work); + stdout.writeln('= $result'); +} + +Future _struct(int key) async { + var struct = await _calculator.getStruct(key); + stdout.writeln(struct.toString()); +} diff --git a/tutorial/dart/console_client/pubspec.yaml b/tutorial/dart/console_client/pubspec.yaml new file mode 100644 index 0000000..dea5449 --- /dev/null +++ b/tutorial/dart/console_client/pubspec.yaml @@ -0,0 +1,36 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# 'License'); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: tutorial_console_client +version: 0.11.0 +description: > + A Dart console client to implementation of the Apache Thrift tutorial +author: Apache Thrift Developers +homepage: http://thrift.apache.org + +environment: + sdk: ">=1.13.0 <2.0.0" + +dependencies: + args: ^0.13.0 + collection: ^1.1.0 + shared: + path: ../gen-dart/shared + thrift: + path: ../../../lib/dart + tutorial: + path: ../gen-dart/tutorial diff --git a/tutorial/dart/server/.analysis_options b/tutorial/dart/server/.analysis_options new file mode 100644 index 0000000..a10d4c5 --- /dev/null +++ b/tutorial/dart/server/.analysis_options @@ -0,0 +1,2 @@ +analyzer: + strong-mode: true diff --git a/tutorial/dart/server/bin/main.dart b/tutorial/dart/server/bin/main.dart new file mode 100644 index 0000000..b8ac30d --- /dev/null +++ b/tutorial/dart/server/bin/main.dart @@ -0,0 +1,163 @@ +/// Licensed to the Apache Software Foundation (ASF) under one +/// or more contributor license agreements. See the NOTICE file +/// distributed with this work for additional information +/// regarding copyright ownership. The ASF licenses this file +/// to you under the Apache License, Version 2.0 (the +/// "License"); you may not use this file except in compliance +/// with the License. You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, +/// software distributed under the License is distributed on an +/// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +/// KIND, either express or implied. See the License for the +/// specific language governing permissions and limitations +/// under the License. + +import 'dart:async'; +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:logging/logging.dart'; +import 'package:thrift/thrift.dart'; +import 'package:thrift/thrift_console.dart'; +import 'package:tutorial/tutorial.dart'; +import 'package:shared/shared.dart'; + +TProtocol _protocol; +TProcessor _processor; +WebSocket _webSocket; + +main(List args) { + Logger.root.level = Level.ALL; + Logger.root.onRecord.listen((LogRecord rec) { + print('${rec.level.name}: ${rec.time}: ${rec.message}'); + }); + + var parser = new ArgParser(); + parser.addOption('port', defaultsTo: '9090', help: 'The port to listen on'); + parser.addOption('type', + defaultsTo: 'ws', + allowed: ['ws', 'tcp'], + help: 'The type of socket', + allowedHelp: {'ws': 'WebSocket', 'tcp': 'TCP Socket'}); + + ArgResults results; + try { + results = parser.parse(args); + } catch (e) { + results = null; + } + + if (results == null) { + print(parser.usage); + exit(0); + } + + int port = int.parse(results['port']); + String socketType = results['type']; + + if (socketType == 'tcp') { + _runTcpServer(port); + } else if (socketType == 'ws') { + _runWebSocketServer(port); + } +} + +Future _runWebSocketServer(int port) async { + var httpServer = await HttpServer.bind('127.0.0.1', port); + print('listening for WebSocket connections on $port'); + + httpServer.listen((HttpRequest request) async { + if (request.uri.path == '/ws') { + _webSocket = await WebSocketTransformer.upgrade(request); + await _initProcessor(new TWebSocket(_webSocket)); + } else { + print('Invalid path: ${request.uri.path}'); + } + }); +} + +Future _runTcpServer(int port) async { + var serverSocket = await ServerSocket.bind('127.0.0.1', port); + print('listening for TCP connections on $port'); + + Socket socket = await serverSocket.first; + await _initProcessor(new TTcpSocket(socket)); +} + +Future _initProcessor(TSocket socket) async { + TServerSocketTransport transport = new TServerSocketTransport(socket); + transport.onIncomingMessage.listen(_processMessage); + _processor = new CalculatorProcessor(new CalculatorServer()); + _protocol = new TBinaryProtocol(transport); + await _protocol.transport.open(); + + print('connected'); +} + +Future _processMessage(_) async { + _processor.process(_protocol, _protocol); +} + +class CalculatorServer implements Calculator { + final Map _log = {}; + + Future ping() async { + print('ping()'); + } + + Future add(int num1, int num2) async { + print('add($num1, $num2)'); + + return num1 + num2; + } + + Future calculate(int logid, Work work) async { + print('calulate($logid, ${work.toString()})'); + + int val; + + switch (work.op) { + case Operation.ADD: + val = work.num1 + work.num2; + break; + + case Operation.SUBTRACT: + val = work.num1 - work.num2; + break; + + case Operation.MULTIPLY: + val = work.num1 * work.num2; + break; + + case Operation.DIVIDE: + if (work.num2 == 0) { + var x = new InvalidOperation(); + x.whatOp = work.op; + x.why = 'Cannot divide by 0'; + throw x; + } + val = (work.num1 / work.num2).floor(); + break; + } + + var log = new SharedStruct(); + log.key = logid; + log.value = '$val "${work.comment}"'; + this._log[logid] = log; + + return val; + } + + Future zip() async { + print('zip()'); + } + + Future getStruct(int key) async { + print('getStruct($key)'); + + return _log[key]; + } +} diff --git a/tutorial/dart/server/pubspec.yaml b/tutorial/dart/server/pubspec.yaml new file mode 100644 index 0000000..b925d2f --- /dev/null +++ b/tutorial/dart/server/pubspec.yaml @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# 'License'); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: tutorial_server +version: 0.11.0 +description: A Dart server to support the Apache Thrift tutorial +author: Apache Thrift Developers +homepage: http://thrift.apache.org + +environment: + sdk: ">=1.13.0 <2.0.0" + +dependencies: + args: ^0.13.0 + shared: + path: ../gen-dart/shared + thrift: + path: ../../../lib/dart + tutorial: + path: ../gen-dart/tutorial diff --git a/tutorial/delphi/DelphiClient/DelphiClient.dpr b/tutorial/delphi/DelphiClient/DelphiClient.dpr new file mode 100644 index 0000000..0f380b0 --- /dev/null +++ b/tutorial/delphi/DelphiClient/DelphiClient.dpr @@ -0,0 +1,114 @@ +(* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *) +program DelphiClient; + +{$APPTYPE CONSOLE} +{$D 'Copyright (c) 2012 The Apache Software Foundation'} + +uses + SysUtils, + Generics.Collections, + Thrift in '..\..\..\lib\delphi\src\Thrift.pas', + Thrift.Collections in '..\..\..\lib\delphi\src\Thrift.Collections.pas', + Thrift.Console in '..\..\..\lib\delphi\src\Thrift.Console.pas', + Thrift.Utils in '..\..\..\lib\delphi\src\Thrift.Utils.pas', + Thrift.Stream in '..\..\..\lib\delphi\src\Thrift.Stream.pas', + Thrift.Protocol in '..\..\..\lib\delphi\src\Thrift.Protocol.pas', + Thrift.Server in '..\..\..\lib\delphi\src\Thrift.Server.pas', + Thrift.Transport in '..\..\..\lib\delphi\src\Thrift.Transport.pas', + Shared in '..\..\gen-delphi\Shared.pas', + Tutorial in '..\..\gen-delphi\Tutorial.pas'; + + +type + DelphiTutorialClient = class + public + class procedure Main; + end; + + +//--- DelphiTutorialClient --------------------------------------- + + +class procedure DelphiTutorialClient.Main; +var transport : ITransport; + protocol : IProtocol; + client : TCalculator.Iface; + work : IWork; + sum, quotient, diff : Integer; + log : ISharedStruct; +begin + try + transport := TSocketImpl.Create( 'localhost', 9090); + protocol := TBinaryProtocolImpl.Create( transport); + client := TCalculator.TClient.Create( protocol); + + transport.Open; + + client.ping; + Console.WriteLine('ping()'); + + sum := client.add( 1, 1); + Console.WriteLine( Format( '1+1=%d', [sum])); + + work := TWorkImpl.Create; + + work.Op := TOperation.DIVIDE; + work.Num1 := 1; + work.Num2 := 0; + try + quotient := client.calculate(1, work); + Console.WriteLine( 'Whoa we can divide by 0'); + Console.WriteLine( Format('1/0=%d',[quotient])); + except + on io: TInvalidOperation + do Console.WriteLine( 'Invalid operation: ' + io.Why); + end; + + work.Op := TOperation.SUBTRACT; + work.Num1 := 15; + work.Num2 := 10; + try + diff := client.calculate( 1, work); + Console.WriteLine( Format('15-10=%d', [diff])); + except + on io: TInvalidOperation + do Console.WriteLine( 'Invalid operation: ' + io.Why); + end; + + log := client.getStruct(1); + Console.WriteLine( Format( 'Check log: %s', [log.Value])); + + transport.Close(); + + except + on e : Exception + do Console.WriteLine( e.ClassName+': '+e.Message); + end; +end; + + +begin + try + DelphiTutorialClient.Main; + except + on E: Exception do + Writeln(E.ClassName, ': ', E.Message); + end; +end. diff --git a/tutorial/delphi/DelphiClient/DelphiClient.dproj b/tutorial/delphi/DelphiClient/DelphiClient.dproj new file mode 100644 index 0000000..38226b3 --- /dev/null +++ b/tutorial/delphi/DelphiClient/DelphiClient.dproj @@ -0,0 +1,119 @@ + + + {2B8FB3A1-2F9E-4883-8C53-0F56220B34F6} + DelphiClient.dpr + 12.3 + True + Debug + Win32 + Console + None + DCC32 + + + true + + + true + Base + true + + + true + Base + true + + + ..\..\..\lib\delphi\src;$(DCC_UnitSearchPath) + 00400000 + .\dcu\$(Config)\$(Platform) + WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;$(DCC_UnitAlias) + ..\bin\$(Config)\$(Platform) + false + false + false + false + false + + + DEBUG;$(DCC_Define) + false + true + + + false + RELEASE;$(DCC_Define) + 0 + false + + + + MainSource + + + + + + + + + + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + + + + + + Delphi.Personality.12 + + + + + True + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 1033 + 1252 + + + + Thrift Tutorial + 0.11.0.0 + DelphiClient + Copyright © 2012 The Apache Software Foundation + + DelphiClient.exe + Thrift + 0.11.0.0 + + + + DelphiClient.dpr + + + + True + + + 12 + + diff --git a/tutorial/delphi/DelphiServer/DelphiServer.dpr b/tutorial/delphi/DelphiServer/DelphiServer.dpr new file mode 100644 index 0000000..9d54a2e --- /dev/null +++ b/tutorial/delphi/DelphiServer/DelphiServer.dpr @@ -0,0 +1,173 @@ +(* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *) +program DelphiServer; + +{$APPTYPE CONSOLE} +{$D 'Copyright (c) 2012 The Apache Software Foundation'} + +{$Q+} // throws exceptions on numeric overflows + +uses + SysUtils, + Generics.Collections, + Thrift in '..\..\..\lib\delphi\src\Thrift.pas', + Thrift.Collections in '..\..\..\lib\delphi\src\Thrift.Collections.pas', + Thrift.Console in '..\..\..\lib\delphi\src\Thrift.Console.pas', + Thrift.Utils in '..\..\..\lib\delphi\src\Thrift.Utils.pas', + Thrift.Stream in '..\..\..\lib\delphi\src\Thrift.Stream.pas', + Thrift.Protocol in '..\..\..\lib\delphi\src\Thrift.Protocol.pas', + Thrift.Server in '..\..\..\lib\delphi\src\Thrift.Server.pas', + Thrift.Transport in '..\..\..\lib\delphi\src\Thrift.Transport.pas', + Shared in '..\..\gen-delphi\Shared.pas', + Tutorial in '..\..\gen-delphi\Tutorial.pas'; + + +type + TCalculatorHandler = class( TInterfacedObject, TCalculator.Iface) + protected + FLog : TDictionary< Integer, ISharedStruct>; + + // TSharedService.Iface + function getStruct(key: Integer): ISharedStruct; + + // TCalculator.Iface + procedure ping(); + function add(num1: Integer; num2: Integer): Integer; + function calculate(logid: Integer; const w: IWork): Integer; + procedure zip(); + + public + constructor Create; + destructor Destroy; override; + + end; + + DelphiTutorialServer = class + public + class procedure Main; + end; + + +//--- TCalculatorHandler --------------------------------------------------- + + +constructor TCalculatorHandler.Create; +begin + inherited Create; + FLog := TDictionary< Integer, ISharedStruct>.Create(); +end; + + +destructor TCalculatorHandler.Destroy; +begin + try + FreeAndNil( FLog); + finally + inherited Destroy; + end; +end; + + +procedure TCalculatorHandler.ping; +begin + Console.WriteLine( 'ping()'); +end; + + +function TCalculatorHandler.add(num1: Integer; num2: Integer): Integer; +begin + Console.WriteLine( Format( 'add( %d, %d)', [num1, num2])); + result := num1 + num2; +end; + + +function TCalculatorHandler.calculate(logid: Integer; const w: IWork): Integer; +var entry : ISharedStruct; +begin + try + Console.WriteLine( Format('calculate( %d, [%d,%d,%d])', [logid, Ord(w.Op), w.Num1, w.Num2])); + + case w.Op of + TOperation.ADD : result := w.Num1 + w.Num2; + TOperation.SUBTRACT : result := w.Num1 - w.Num2; + TOperation.MULTIPLY : result := w.Num1 * w.Num2; + TOperation.DIVIDE : result := Round( w.Num1 / w.Num2); + else + raise TInvalidOperation.Create( Ord(w.Op), 'Unknown operation'); + end; + + except + on e:Thrift.TException do raise; // let Thrift Exceptions pass through + on e:Exception do raise TInvalidOperation.Create( Ord(w.Op), e.Message); // repackage all other + end; + + entry := TSharedStructImpl.Create; + entry.Key := logid; + entry.Value := IntToStr( result); + FLog.AddOrSetValue( logid, entry); +end; + + +function TCalculatorHandler.getStruct(key: Integer): ISharedStruct; +begin + Console.WriteLine( Format( 'getStruct(%d)', [key])); + result := FLog[key]; +end; + + +procedure TCalculatorHandler.zip; +begin + Console.WriteLine( 'zip()'); +end; + + +//--- DelphiTutorialServer ---------------------------------------------------------------------- + + +class procedure DelphiTutorialServer.Main; +var handler : TCalculator.Iface; + processor : IProcessor; + transport : IServerTransport; + server : IServer; +begin + try + handler := TCalculatorHandler.Create; + processor := TCalculator.TProcessorImpl.Create( handler); + transport := TServerSocketImpl.Create( 9090); + server := TSimpleServer.Create( processor, transport); + + Console.WriteLine( 'Starting the server...'); + server.Serve(); + + except + on e: Exception do Console.WriteLine( e.Message); + end; + + Console.WriteLine('done.'); +end; + + +begin + try + DelphiTutorialServer.Main; + except + on E: Exception do + Writeln(E.ClassName, ': ', E.Message); + end; +end. diff --git a/tutorial/delphi/DelphiServer/DelphiServer.dproj b/tutorial/delphi/DelphiServer/DelphiServer.dproj new file mode 100644 index 0000000..ad47a53 --- /dev/null +++ b/tutorial/delphi/DelphiServer/DelphiServer.dproj @@ -0,0 +1,118 @@ + + + {2B8FB3A1-2F9E-4883-8C53-0F56220B34F6} + DelphiServer.dpr + 12.3 + True + Debug + Win32 + Console + None + DCC32 + + + true + + + true + Base + true + + + true + Base + true + + + 00400000 + .\dcu\$(Config)\$(Platform) + WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;$(DCC_UnitAlias) + ..\bin\$(Config)\$(Platform) + false + false + false + false + false + + + DEBUG;$(DCC_Define) + false + true + + + false + RELEASE;$(DCC_Define) + 0 + false + + + + MainSource + + + + + + + + + + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + + + + + + Delphi.Personality.12 + + + + + True + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 1033 + 1252 + + + + Thrift Tutorial + 0.11.0.0 + DelphiServer + Copyright © 2012 The Apache Software Foundation + + DelphiServer.exe + Thrift + 0.11.0.0 + + + + DelphiServer.dpr + + + + True + + + 12 + + diff --git a/tutorial/delphi/Tutorial.groupproj b/tutorial/delphi/Tutorial.groupproj new file mode 100644 index 0000000..3a2a237 --- /dev/null +++ b/tutorial/delphi/Tutorial.groupproj @@ -0,0 +1,48 @@ + + + {3D042C7F-3EF2-4574-8304-AB7FB79F814C} + + + + + + + + + + + Default.Personality.12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tutorial/erl/README.md b/tutorial/erl/README.md new file mode 100644 index 0000000..9d17cd0 --- /dev/null +++ b/tutorial/erl/README.md @@ -0,0 +1,8 @@ +To try things out, run + +% ./server.sh +Erlang R14B (erts-5.8.1) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false] + +Eshell V5.8.1 (abort with ^G) +> server:start(). +> client:t(). diff --git a/tutorial/erl/client.erl b/tutorial/erl/client.erl new file mode 100644 index 0000000..0374220 --- /dev/null +++ b/tutorial/erl/client.erl @@ -0,0 +1,78 @@ +%% +%% Licensed to the Apache Software Foundation (ASF) under one +%% or more contributor license agreements. See the NOTICE file +%% distributed with this work for additional information +%% regarding copyright ownership. The ASF licenses this file +%% to you under the Apache License, Version 2.0 (the +%% "License"); you may not use this file except in compliance +%% with the License. You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, +%% software distributed under the License is distributed on an +%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%% KIND, either express or implied. See the License for the +%% specific language governing permissions and limitations +%% under the License. +%% + +-module(client). + +-include("calculator_thrift.hrl"). + +-export([t/0]). + +p(X) -> + io:format("~p~n", [X]), + ok. + +t() -> + Port = 9090, + + {ok, Client0} = thrift_client_util:new("127.0.0.1", + Port, + calculator_thrift, + []), + + {Client1, {ok, ok}} = thrift_client:call(Client0, ping, []), + io:format("ping~n", []), + + {Client2, {ok, Sum}} = thrift_client:call(Client1, add, [1, 1]), + io:format("1+1=~p~n", [Sum]), + + {Client3, {ok, Sum1}} = thrift_client:call(Client2, add, [1, 4]), + io:format("1+4=~p~n", [Sum1]), + + Work = #'Work'{op=?TUTORIAL_OPERATION_SUBTRACT, + num1=15, + num2=10}, + {Client4, {ok, Diff}} = thrift_client:call(Client3, calculate, [1, Work]), + io:format("15-10=~p~n", [Diff]), + + {Client5, {ok, Log}} = thrift_client:call(Client4, getStruct, [1]), + io:format("Log: ~p~n", [Log]), + + Client6 = + try + Work1 = #'Work'{op=?TUTORIAL_OPERATION_DIVIDE, + num1=1, + num2=0}, + {ClientS1, {ok, _Quot}} = thrift_client:call(Client5, calculate, [2, Work1]), + + io:format("LAME: exception handling is broken~n", []), + ClientS1 + catch + throw:{ClientS2, Z} -> + io:format("Got exception where expecting - the " ++ + "following is NOT a problem!!!~n"), + p(Z), + ClientS2 + end, + + + {Client7, {ok, ok}} = thrift_client:call(Client6, zip, []), + io:format("zip~n", []), + + {_Client8, ok} = thrift_client:close(Client7), + ok. diff --git a/tutorial/erl/client.sh b/tutorial/erl/client.sh new file mode 100755 index 0000000..775afb6 --- /dev/null +++ b/tutorial/erl/client.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +ERL_THRIFT=../../lib/erl + +if ! [ -d ${ERL_THRIFT}/ebin ]; then + echo "Please build the Thrift library by running \`make' in ${ERL_THRIFT}" + exit 1 +fi + +if ! [ -d gen-erl ]; then + ../../compiler/cpp/thrift -r --gen erl ../tutorial.thrift +fi + + +erlc -I ${ERL_THRIFT}/include -I ${ERL_THRIFT}/ebin \ + -I gen-erl -o gen-erl gen-erl/*.erl && + erlc -I ${ERL_THRIFT}/include -I gen-erl *.erl && + erl +K true -pa ${ERL_THRIFT}/ebin -pa gen-erl diff --git a/tutorial/erl/json_client.erl b/tutorial/erl/json_client.erl new file mode 100644 index 0000000..0b39ced --- /dev/null +++ b/tutorial/erl/json_client.erl @@ -0,0 +1,89 @@ +%% +%% Licensed to the Apache Software Foundation (ASF) under one +%% or more contributor license agreements. See the NOTICE file +%% distributed with this work for additional information +%% regarding copyright ownership. The ASF licenses this file +%% to you under the Apache License, Version 2.0 (the +%% "License"); you may not use this file except in compliance +%% with the License. You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, +%% software distributed under the License is distributed on an +%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%% KIND, either express or implied. See the License for the +%% specific language governing permissions and limitations +%% under the License. +%% +%% The JSON protocol over HTTP implementation was created by +%% Peter Neumark based on +%% the binary protocol + socket tutorial. Use with the same server +%% that the Javascript tutorial uses! + +-module(json_client). + +-include("calculator_thrift.hrl"). + +-export([t/0]). + +%% Client constructor for the http transports +%% with the json protocol +new_client(Host, Path, Service, _Options) -> + {ProtoOpts, TransOpts} = {[],[]}, + TransportFactory = fun() -> thrift_http_transport:new(Host, Path, TransOpts) end, + {ok, ProtocolFactory} = thrift_json_protocol:new_protocol_factory( + TransportFactory, ProtoOpts), + {ok, Protocol} = ProtocolFactory(), + thrift_client:new(Protocol, Service). + +p(X) -> + io:format("~p~n", [X]), + ok. + +t() -> + inets:start(), + {ok, Client0} = new_client("127.0.0.1:8088", "/thrift/service/tutorial/", + calculator_thrift, + []), + {Client1, {ok, ok}} = thrift_client:call(Client0, ping, []), + io:format("ping~n", []), + + {Client2, {ok, Sum}} = thrift_client:call(Client1, add, [1, 1]), + io:format("1+1=~p~n", [Sum]), + + {Client3, {ok, Sum1}} = thrift_client:call(Client2, add, [1, 4]), + io:format("1+4=~p~n", [Sum1]), + + Work = #'Work'{op=?TUTORIAL_OPERATION_SUBTRACT, + num1=15, + num2=10}, + {Client4, {ok, Diff}} = thrift_client:call(Client3, calculate, [1, Work]), + io:format("15-10=~p~n", [Diff]), + + {Client5, {ok, Log}} = thrift_client:call(Client4, getStruct, [1]), + io:format("Log: ~p~n", [Log]), + + Client6 = + try + Work1 = #'Work'{op=?TUTORIAL_OPERATION_DIVIDE, + num1=1, + num2=0}, + {ClientS1, {ok, _Quot}} = thrift_client:call(Client5, calculate, [2, Work1]), + + io:format("LAME: exception handling is broken~n", []), + ClientS1 + catch + throw:{ClientS2, Z} -> + io:format("Got exception where expecting - the " ++ + "following is NOT a problem!!!~n"), + p(Z), + ClientS2 + end, + + + {Client7, {ok, ok}} = thrift_client:call(Client6, zip, []), + io:format("zip~n", []), + + {_Client8, ok} = thrift_client:close(Client7), + ok. diff --git a/tutorial/erl/server.erl b/tutorial/erl/server.erl new file mode 100644 index 0000000..647cc24 --- /dev/null +++ b/tutorial/erl/server.erl @@ -0,0 +1,82 @@ +%% +%% Licensed to the Apache Software Foundation (ASF) under one +%% or more contributor license agreements. See the NOTICE file +%% distributed with this work for additional information +%% regarding copyright ownership. The ASF licenses this file +%% to you under the Apache License, Version 2.0 (the +%% "License"); you may not use this file except in compliance +%% with the License. You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, +%% software distributed under the License is distributed on an +%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%% KIND, either express or implied. See the License for the +%% specific language governing permissions and limitations +%% under the License. +%% + +-module(server). + +-include("calculator_thrift.hrl"). + +-export([start/0, start/1, handle_function/2, + stop/1, ping/0, add/2, calculate/2, getStruct/1, zip/0]). + +debug(Format, Data) -> + error_logger:info_msg(Format, Data). + +ping() -> + debug("ping()",[]), + ok. + +add(N1, N2) -> + debug("add(~p,~p)",[N1,N2]), + N1+N2. + +calculate(Logid, Work) -> + { Op, Num1, Num2 } = { Work#'Work'.op, Work#'Work'.num1, Work#'Work'.num2 }, + debug("calculate(~p, {~p,~p,~p})", [Logid, Op, Num1, Num2]), + case Op of + ?TUTORIAL_OPERATION_ADD -> Num1 + Num2; + ?TUTORIAL_OPERATION_SUBTRACT -> Num1 - Num2; + ?TUTORIAL_OPERATION_MULTIPLY -> Num1 * Num2; + + ?TUTORIAL_OPERATION_DIVIDE when Num2 == 0 -> + throw(#'InvalidOperation'{whatOp=Op, why="Cannot divide by 0"}); + ?TUTORIAL_OPERATION_DIVIDE -> + Num1 div Num2; + + _Else -> + throw(#'InvalidOperation'{whatOp=Op, why="Invalid operation"}) + end. + +getStruct(Key) -> + debug("getStruct(~p)", [Key]), + #'SharedStruct'{key=Key, value="RARG"}. + +zip() -> + debug("zip", []), + ok. + +%% + +start() -> + start(9090). + +start(Port) -> + Handler = ?MODULE, + thrift_socket_server:start([{handler, Handler}, + {service, calculator_thrift}, + {port, Port}, + {name, tutorial_server}]). + +stop(Server) -> + thrift_socket_server:stop(Server). + +handle_function(Function, Args) when is_atom(Function), is_tuple(Args) -> + case apply(?MODULE, Function, tuple_to_list(Args)) of + ok -> ok; + Reply -> {reply, Reply} + end. diff --git a/tutorial/erl/server.sh b/tutorial/erl/server.sh new file mode 100755 index 0000000..775afb6 --- /dev/null +++ b/tutorial/erl/server.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +ERL_THRIFT=../../lib/erl + +if ! [ -d ${ERL_THRIFT}/ebin ]; then + echo "Please build the Thrift library by running \`make' in ${ERL_THRIFT}" + exit 1 +fi + +if ! [ -d gen-erl ]; then + ../../compiler/cpp/thrift -r --gen erl ../tutorial.thrift +fi + + +erlc -I ${ERL_THRIFT}/include -I ${ERL_THRIFT}/ebin \ + -I gen-erl -o gen-erl gen-erl/*.erl && + erlc -I ${ERL_THRIFT}/include -I gen-erl *.erl && + erl +K true -pa ${ERL_THRIFT}/ebin -pa gen-erl diff --git a/tutorial/go/Makefile.am b/tutorial/go/Makefile.am new file mode 100644 index 0000000..a146d5c --- /dev/null +++ b/tutorial/go/Makefile.am @@ -0,0 +1,69 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +if GOVERSION_LT_17 +COMPILER_EXTRAFLAG=":legacy_context" +endif + +gen-go/tutorial/calculator.go gen-go/shared/shared_service.go: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen go$(COMPILER_EXTRAFLAG) -r $< + +all-local: gen-go/tutorial/calculator.go + +check: src/git.apache.org/thrift.git/lib/go/thrift thirdparty-dep + $(THRIFT) -r --gen go$(COMPILER_EXTRAFLAG) $(top_srcdir)/tutorial/tutorial.thrift + cp -r gen-go/* src/ + GOPATH=`pwd` $(GO) build -o go-tutorial ./src + GOPATH=`pwd` $(GO) build -o calculator-remote src/tutorial/calculator-remote/calculator-remote.go + +src/git.apache.org/thrift.git/lib/go/thrift: + mkdir -p src/git.apache.org/thrift.git/lib/go + ln -sf $(realpath $(top_srcdir)/lib/go/thrift) src/git.apache.org/thrift.git/lib/go/thrift + +thirdparty-dep: + mkdir -p src/golang.org/x/net + GOPATH=`pwd`/gopath $(GO) get golang.org/x/net/context + ln -sf `pwd`/gopath/src/golang.org/x/net/context src/golang.org/x/net/context + +tutorialserver: all + GOPATH=`pwd` $(GO) run src/*.go -server=true + +tutorialclient: all + GOPATH=`pwd` $(GO) run src/*.go + +tutorialsecureserver: all + GOPATH=`pwd` $(GO) run src/*.go -server=true -secure=true + +tutorialsecureclient: all + GOPATH=`pwd` $(GO) run src/*.go -secure=true + +clean-local: + $(RM) -r gen-* src/shared src/tutorial src/git.apache.org go-tutorial calculator-remote + +EXTRA_DIST = \ + src/client.go \ + src/handler.go \ + src/server.go \ + src/main.go \ + src/go17.go \ + src/handler_go17.go \ + src/pre_go17.go \ + server.crt \ + server.key + diff --git a/tutorial/go/Makefile.in b/tutorial/go/Makefile.in new file mode 100644 index 0000000..85db616 --- /dev/null +++ b/tutorial/go/Makefile.in @@ -0,0 +1,670 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tutorial/go +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +@GOVERSION_LT_17_TRUE@COMPILER_EXTRAFLAG = ":legacy_context" +EXTRA_DIST = \ + src/client.go \ + src/handler.go \ + src/server.go \ + src/main.go \ + src/go17.go \ + src/handler_go17.go \ + src/pre_go17.go \ + server.crt \ + server.key + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/go/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tutorial/go/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am all-local check check-am clean clean-generic \ + clean-libtool clean-local cscopelist-am ctags-am distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +gen-go/tutorial/calculator.go gen-go/shared/shared_service.go: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen go$(COMPILER_EXTRAFLAG) -r $< + +all-local: gen-go/tutorial/calculator.go + +check: src/git.apache.org/thrift.git/lib/go/thrift thirdparty-dep + $(THRIFT) -r --gen go$(COMPILER_EXTRAFLAG) $(top_srcdir)/tutorial/tutorial.thrift + cp -r gen-go/* src/ + GOPATH=`pwd` $(GO) build -o go-tutorial ./src + GOPATH=`pwd` $(GO) build -o calculator-remote src/tutorial/calculator-remote/calculator-remote.go + +src/git.apache.org/thrift.git/lib/go/thrift: + mkdir -p src/git.apache.org/thrift.git/lib/go + ln -sf $(realpath $(top_srcdir)/lib/go/thrift) src/git.apache.org/thrift.git/lib/go/thrift + +thirdparty-dep: + mkdir -p src/golang.org/x/net + GOPATH=`pwd`/gopath $(GO) get golang.org/x/net/context + ln -sf `pwd`/gopath/src/golang.org/x/net/context src/golang.org/x/net/context + +tutorialserver: all + GOPATH=`pwd` $(GO) run src/*.go -server=true + +tutorialclient: all + GOPATH=`pwd` $(GO) run src/*.go + +tutorialsecureserver: all + GOPATH=`pwd` $(GO) run src/*.go -server=true -secure=true + +tutorialsecureclient: all + GOPATH=`pwd` $(GO) run src/*.go -secure=true + +clean-local: + $(RM) -r gen-* src/shared src/tutorial src/git.apache.org go-tutorial calculator-remote + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tutorial/go/server.crt b/tutorial/go/server.crt new file mode 100644 index 0000000..8a5ef3c --- /dev/null +++ b/tutorial/go/server.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD +VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs +MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV +BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3 +DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy +MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU +MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh +cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ +bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ +GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6 +L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg +2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw +AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX +wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n +AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME +GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 +DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5 +U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm +T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD +1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I +p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO +r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0 +-----END CERTIFICATE----- diff --git a/tutorial/go/server.key b/tutorial/go/server.key new file mode 100644 index 0000000..263cfce --- /dev/null +++ b/tutorial/go/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR +tLQVDSGQGV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCy +SN8I2Xw6L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/H +jKNg6ZKg2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQB +GmZmMIUwAinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xk +u62LipkXwCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDm +trhVQF4nAgMBAAECggEAW/y52YYW6ypROGbZ94DQpFV0kLO7qT8q0Ksxw5sPNaIt +fEPRIymDa8ikyHWJS5Oxmw84wo5jnJV26jaLmwe2Lupq7Xf1lqej8f5LJtuv7cQR +xfzp1vM65KJFFJHp6WqjGqJ6HSSZOpVDsnQYcXQjQCdpyAmaSWd3p+FqYSZ1mQmD +bFNI7jqpczWSZhTdotQ7p7Hn9TVCehflP3yGIB3bQ+wCcCB85dOBz201L+YgaIck +Sz43A4NvWaQIRLRDw7s9GW4jY5T0Jv282WIeAlVpVxLIwu48r4R4yGTIx9Ydowvq +57+Y5iPPjAXxu0V9t00oS3bYxDaKh2DUfc/5zowq8QKBgQDYNVPXmaG0aIH4vjQ9 +7fRdw/UDkYcQbn6CnglQOu77/S8ogQzpKCVJgJgkZNqOVtQMEPzekGEcLTbje1gU +8Bky2k+PL9UwbFy0emnOVh4rqrNXHsRvJcehNT/PRb5hjF3MUMFV/0iD4b+naFaE +jrSWiZ2ZXj2qfwAK52GFbtOuBQKBgQDJYQuGiY0r22E4waJmCSKczoBT3cwlVzWj +V2ljgA9RHLNTVkvNNYQLGu2qngFrtwpeaSnsMDerVG4wKAQWyCnYzxVrlnC4uDrJ +HXuFEltBWi9Ffbgfsnd3749AT0oBP1NT2tMleguyf5DFgjCR3VRJLdrVaaZ8row/ +LqKcFMqnOwKBgB+OIO99l7E584Y3VG6ZdSneOLtNmRXX2pT7tcZE465ZdHGH7Dd3 +SYHhx9K/+Xn+yDH+pLli/xlarAEldmSP6k2WuTfftlC78AfTOfAId5zN7CDR9791 +Fx67I9X/itq33tS8EIuZl57P6uXm/4GXRloWOa8xpvRkVsBApuYPl8t1AoGATQDS +y2sllDObBXzlgGbV2WgNIgSZ311toTv3jJiXQsjauW8yJRHln+l4H9mzaWDgkiFc +ang1kUoDqF5k0eFQPxtQcYdhKwEnWWfwp33RbzfxA32DPnubuzzbZhfrkHaKgnIW +cyor9uFYlm2l7ODZLfJez2RKyTplXnOSsmQw6akCgYAz3dj9Hskyj+HVJ+ht1OcE +c7ai/ESkSA7Vajp0tjJp0EKjW/zq8DvUSXOtcdnJgkKycFluLwbmnaN4txBds1C1 +Qr8Rt2sUCCBNZe1L6DHe3XBdbkJe9sgZVNTjtUSQrzy8UhvsCqG4YWeCu07Szcbc +rdPUV9/uQkdx8VrShxlD8A== +-----END PRIVATE KEY----- diff --git a/tutorial/go/src/client.go b/tutorial/go/src/client.go new file mode 100644 index 0000000..25616bf --- /dev/null +++ b/tutorial/go/src/client.go @@ -0,0 +1,105 @@ +package main + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import ( + "crypto/tls" + "fmt" + "tutorial" + + "git.apache.org/thrift.git/lib/go/thrift" +) + +func handleClient(client *tutorial.CalculatorClient) (err error) { + client.Ping(defaultCtx) + fmt.Println("ping()") + + sum, _ := client.Add(defaultCtx, 1, 1) + fmt.Print("1+1=", sum, "\n") + + work := tutorial.NewWork() + work.Op = tutorial.Operation_DIVIDE + work.Num1 = 1 + work.Num2 = 0 + quotient, err := client.Calculate(defaultCtx, 1, work) + if err != nil { + switch v := err.(type) { + case *tutorial.InvalidOperation: + fmt.Println("Invalid operation:", v) + default: + fmt.Println("Error during operation:", err) + } + return err + } else { + fmt.Println("Whoa we can divide by 0 with new value:", quotient) + } + + work.Op = tutorial.Operation_SUBTRACT + work.Num1 = 15 + work.Num2 = 10 + diff, err := client.Calculate(defaultCtx, 1, work) + if err != nil { + switch v := err.(type) { + case *tutorial.InvalidOperation: + fmt.Println("Invalid operation:", v) + default: + fmt.Println("Error during operation:", err) + } + return err + } else { + fmt.Print("15-10=", diff, "\n") + } + + log, err := client.GetStruct(defaultCtx, 1) + if err != nil { + fmt.Println("Unable to get struct:", err) + return err + } else { + fmt.Println("Check log:", log.Value) + } + return err +} + +func runClient(transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory, addr string, secure bool) error { + var transport thrift.TTransport + var err error + if secure { + cfg := new(tls.Config) + cfg.InsecureSkipVerify = true + transport, err = thrift.NewTSSLSocket(addr, cfg) + } else { + transport, err = thrift.NewTSocket(addr) + } + if err != nil { + fmt.Println("Error opening socket:", err) + return err + } + transport, err = transportFactory.GetTransport(transport) + if err != nil { + return err + } + defer transport.Close() + if err := transport.Open(); err != nil { + return err + } + iprot := protocolFactory.GetProtocol(transport) + oprot := protocolFactory.GetProtocol(transport) + return handleClient(tutorial.NewCalculatorClient(thrift.NewTStandardClient(iprot, oprot))) +} diff --git a/tutorial/go/src/go17.go b/tutorial/go/src/go17.go new file mode 100644 index 0000000..a6003a9 --- /dev/null +++ b/tutorial/go/src/go17.go @@ -0,0 +1,26 @@ +// +build go1.7 + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package main + +import "context" + +var defaultCtx = context.Background() diff --git a/tutorial/go/src/handler.go b/tutorial/go/src/handler.go new file mode 100644 index 0000000..783b432 --- /dev/null +++ b/tutorial/go/src/handler.go @@ -0,0 +1,105 @@ +// +build !go1.7 + +package main + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import ( + "fmt" + "shared" + "strconv" + "tutorial" + + "golang.org/x/net/context" +) + +type CalculatorHandler struct { + log map[int]*shared.SharedStruct +} + +func NewCalculatorHandler() *CalculatorHandler { + return &CalculatorHandler{log: make(map[int]*shared.SharedStruct)} +} + +func (p *CalculatorHandler) Ping(ctx context.Context) (err error) { + fmt.Print("ping()\n") + return nil +} + +func (p *CalculatorHandler) Add(ctx context.Context, num1 int32, num2 int32) (retval17 int32, err error) { + fmt.Print("add(", num1, ",", num2, ")\n") + return num1 + num2, nil +} + +func (p *CalculatorHandler) Calculate(ctx context.Context, logid int32, w *tutorial.Work) (val int32, err error) { + fmt.Print("calculate(", logid, ", {", w.Op, ",", w.Num1, ",", w.Num2, "})\n") + switch w.Op { + case tutorial.Operation_ADD: + val = w.Num1 + w.Num2 + break + case tutorial.Operation_SUBTRACT: + val = w.Num1 - w.Num2 + break + case tutorial.Operation_MULTIPLY: + val = w.Num1 * w.Num2 + break + case tutorial.Operation_DIVIDE: + if w.Num2 == 0 { + ouch := tutorial.NewInvalidOperation() + ouch.WhatOp = int32(w.Op) + ouch.Why = "Cannot divide by 0" + err = ouch + return + } + val = w.Num1 / w.Num2 + break + default: + ouch := tutorial.NewInvalidOperation() + ouch.WhatOp = int32(w.Op) + ouch.Why = "Unknown operation" + err = ouch + return + } + entry := shared.NewSharedStruct() + entry.Key = logid + entry.Value = strconv.Itoa(int(val)) + k := int(logid) + /* + oldvalue, exists := p.log[k] + if exists { + fmt.Print("Replacing ", oldvalue, " with ", entry, " for key ", k, "\n") + } else { + fmt.Print("Adding ", entry, " for key ", k, "\n") + } + */ + p.log[k] = entry + return val, err +} + +func (p *CalculatorHandler) GetStruct(ctx context.Context, key int32) (*shared.SharedStruct, error) { + fmt.Print("getStruct(", key, ")\n") + v, _ := p.log[int(key)] + return v, nil +} + +func (p *CalculatorHandler) Zip(ctx context.Context) (err error) { + fmt.Print("zip()\n") + return nil +} diff --git a/tutorial/go/src/handler_go17.go b/tutorial/go/src/handler_go17.go new file mode 100644 index 0000000..d6752cc --- /dev/null +++ b/tutorial/go/src/handler_go17.go @@ -0,0 +1,104 @@ +// +build go1.7 + +package main + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import ( + "context" + "fmt" + "shared" + "strconv" + "tutorial" +) + +type CalculatorHandler struct { + log map[int]*shared.SharedStruct +} + +func NewCalculatorHandler() *CalculatorHandler { + return &CalculatorHandler{log: make(map[int]*shared.SharedStruct)} +} + +func (p *CalculatorHandler) Ping(ctx context.Context) (err error) { + fmt.Print("ping()\n") + return nil +} + +func (p *CalculatorHandler) Add(ctx context.Context, num1 int32, num2 int32) (retval17 int32, err error) { + fmt.Print("add(", num1, ",", num2, ")\n") + return num1 + num2, nil +} + +func (p *CalculatorHandler) Calculate(ctx context.Context, logid int32, w *tutorial.Work) (val int32, err error) { + fmt.Print("calculate(", logid, ", {", w.Op, ",", w.Num1, ",", w.Num2, "})\n") + switch w.Op { + case tutorial.Operation_ADD: + val = w.Num1 + w.Num2 + break + case tutorial.Operation_SUBTRACT: + val = w.Num1 - w.Num2 + break + case tutorial.Operation_MULTIPLY: + val = w.Num1 * w.Num2 + break + case tutorial.Operation_DIVIDE: + if w.Num2 == 0 { + ouch := tutorial.NewInvalidOperation() + ouch.WhatOp = int32(w.Op) + ouch.Why = "Cannot divide by 0" + err = ouch + return + } + val = w.Num1 / w.Num2 + break + default: + ouch := tutorial.NewInvalidOperation() + ouch.WhatOp = int32(w.Op) + ouch.Why = "Unknown operation" + err = ouch + return + } + entry := shared.NewSharedStruct() + entry.Key = logid + entry.Value = strconv.Itoa(int(val)) + k := int(logid) + /* + oldvalue, exists := p.log[k] + if exists { + fmt.Print("Replacing ", oldvalue, " with ", entry, " for key ", k, "\n") + } else { + fmt.Print("Adding ", entry, " for key ", k, "\n") + } + */ + p.log[k] = entry + return val, err +} + +func (p *CalculatorHandler) GetStruct(ctx context.Context, key int32) (*shared.SharedStruct, error) { + fmt.Print("getStruct(", key, ")\n") + v, _ := p.log[int(key)] + return v, nil +} + +func (p *CalculatorHandler) Zip(ctx context.Context) (err error) { + fmt.Print("zip()\n") + return nil +} diff --git a/tutorial/go/src/main.go b/tutorial/go/src/main.go new file mode 100644 index 0000000..63154e3 --- /dev/null +++ b/tutorial/go/src/main.go @@ -0,0 +1,82 @@ +package main + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import ( + "flag" + "fmt" + "git.apache.org/thrift.git/lib/go/thrift" + "os" +) + +func Usage() { + fmt.Fprint(os.Stderr, "Usage of ", os.Args[0], ":\n") + flag.PrintDefaults() + fmt.Fprint(os.Stderr, "\n") +} + +func main() { + flag.Usage = Usage + server := flag.Bool("server", false, "Run server") + protocol := flag.String("P", "binary", "Specify the protocol (binary, compact, json, simplejson)") + framed := flag.Bool("framed", false, "Use framed transport") + buffered := flag.Bool("buffered", false, "Use buffered transport") + addr := flag.String("addr", "localhost:9090", "Address to listen to") + secure := flag.Bool("secure", false, "Use tls secure transport") + + flag.Parse() + + var protocolFactory thrift.TProtocolFactory + switch *protocol { + case "compact": + protocolFactory = thrift.NewTCompactProtocolFactory() + case "simplejson": + protocolFactory = thrift.NewTSimpleJSONProtocolFactory() + case "json": + protocolFactory = thrift.NewTJSONProtocolFactory() + case "binary", "": + protocolFactory = thrift.NewTBinaryProtocolFactoryDefault() + default: + fmt.Fprint(os.Stderr, "Invalid protocol specified", protocol, "\n") + Usage() + os.Exit(1) + } + + var transportFactory thrift.TTransportFactory + if *buffered { + transportFactory = thrift.NewTBufferedTransportFactory(8192) + } else { + transportFactory = thrift.NewTTransportFactory() + } + + if *framed { + transportFactory = thrift.NewTFramedTransportFactory(transportFactory) + } + + if *server { + if err := runServer(transportFactory, protocolFactory, *addr, *secure); err != nil { + fmt.Println("error running server:", err) + } + } else { + if err := runClient(transportFactory, protocolFactory, *addr, *secure); err != nil { + fmt.Println("error running client:", err) + } + } +} diff --git a/tutorial/go/src/pre_go17.go b/tutorial/go/src/pre_go17.go new file mode 100644 index 0000000..10a6fb8 --- /dev/null +++ b/tutorial/go/src/pre_go17.go @@ -0,0 +1,26 @@ +// +build !go1.7 + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package main + +import "golang.org/x/net/context" + +var defaultCtx = context.Background() diff --git a/tutorial/go/src/server.go b/tutorial/go/src/server.go new file mode 100644 index 0000000..e4c4b97 --- /dev/null +++ b/tutorial/go/src/server.go @@ -0,0 +1,54 @@ +package main + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import ( + "crypto/tls" + "fmt" + "git.apache.org/thrift.git/lib/go/thrift" + "tutorial" +) + +func runServer(transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory, addr string, secure bool) error { + var transport thrift.TServerTransport + var err error + if secure { + cfg := new(tls.Config) + if cert, err := tls.LoadX509KeyPair("server.crt", "server.key"); err == nil { + cfg.Certificates = append(cfg.Certificates, cert) + } else { + return err + } + transport, err = thrift.NewTSSLServerSocket(addr, cfg) + } else { + transport, err = thrift.NewTServerSocket(addr) + } + + if err != nil { + return err + } + fmt.Printf("%T\n", transport) + handler := NewCalculatorHandler() + processor := tutorial.NewCalculatorProcessor(handler) + server := thrift.NewTSimpleServer4(processor, transport, transportFactory, protocolFactory) + + fmt.Println("Starting the simple server... on ", addr) + return server.Serve() +} diff --git a/tutorial/haxe/Makefile.am b/tutorial/haxe/Makefile.am new file mode 100644 index 0000000..e6f2713 --- /dev/null +++ b/tutorial/haxe/Makefile.am @@ -0,0 +1,97 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +BIN_CPP = bin/Main-debug +BIN_PHP = bin/php/Main-debug.php +BIN_PHP_WEB = bin/php-web-server/Main-debug.php + +gen-haxe/tutorial/calculator.hx gen-haxe/shared/shared_service.hx: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen haxe -r $< + +all-local: $(BIN_CPP) $(BIN_PHP) $(BIN_PHP_WEB) + +check: gen-haxe/tutorial/calculator.hx + +$(BIN_CPP): \ + src/*.hx \ + ../../lib/haxe/src/org/apache/thrift/**/*.hx \ + gen-haxe/tutorial/calculator.hx + $(HAXE) --cwd . cpp.hxml + +$(BIN_PHP): \ + src/*.hx \ + ../../lib/haxe/src/org/apache/thrift/**/*.hx \ + gen-haxe/tutorial/calculator.hx + $(HAXE) --cwd . php.hxml + +$(BIN_PHP_WEB): \ + src/*.hx \ + ../../lib/haxe/src/org/apache/thrift/**/*.hx \ + gen-haxe/tutorial/calculator.hx + $(HAXE) --cwd . php-web-server.hxml + +tutorialserver: all + $(BIN_CPP) server + +tutorialserver_php: all + php -f $(BIN_PHP) server + +tutorialclient: all + $(BIN_CPP) + +tutorialclient_php: all + php -f $(BIN_PHP) + +tutorialsecureserver: all + $(BIN_CPP) server secure + +tutorialsecureserver_php: all + php -f $(BIN_PHP) server secure + +tutorialsecureclient: all + $(BIN_CPP) secure + +tutorialsecureclient_php: all + php -f $(BIN_PHP) secure + +tutorialserver_php_http: all + php -S 127.0.0.1:9090 router.php + +tutorialclient_http: all + $(BIN_CPP) client http + +clean-local: + $(RM) -r gen-haxe bin + +EXTRA_DIST = \ + src \ + cpp.hxml \ + csharp.hxml \ + flash.hxml \ + java.hxml \ + javascript.hxml \ + php-web-server.hxml \ + neko.hxml \ + php.hxml \ + python.hxml \ + router.php \ + project.hide \ + Tutorial.hxproj \ + make_all.bat \ + make_all.sh diff --git a/tutorial/haxe/Makefile.in b/tutorial/haxe/Makefile.in new file mode 100644 index 0000000..c7dd92f --- /dev/null +++ b/tutorial/haxe/Makefile.in @@ -0,0 +1,701 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tutorial/haxe +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +BIN_CPP = bin/Main-debug +BIN_PHP = bin/php/Main-debug.php +BIN_PHP_WEB = bin/php-web-server/Main-debug.php +EXTRA_DIST = \ + src \ + cpp.hxml \ + csharp.hxml \ + flash.hxml \ + java.hxml \ + javascript.hxml \ + php-web-server.hxml \ + neko.hxml \ + php.hxml \ + python.hxml \ + router.php \ + project.hide \ + Tutorial.hxproj \ + make_all.bat \ + make_all.sh + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/haxe/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tutorial/haxe/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am all-local check check-am clean clean-generic \ + clean-libtool clean-local cscopelist-am ctags-am distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +gen-haxe/tutorial/calculator.hx gen-haxe/shared/shared_service.hx: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen haxe -r $< + +all-local: $(BIN_CPP) $(BIN_PHP) $(BIN_PHP_WEB) + +check: gen-haxe/tutorial/calculator.hx + +$(BIN_CPP): \ + src/*.hx \ + ../../lib/haxe/src/org/apache/thrift/**/*.hx \ + gen-haxe/tutorial/calculator.hx + $(HAXE) --cwd . cpp.hxml + +$(BIN_PHP): \ + src/*.hx \ + ../../lib/haxe/src/org/apache/thrift/**/*.hx \ + gen-haxe/tutorial/calculator.hx + $(HAXE) --cwd . php.hxml + +$(BIN_PHP_WEB): \ + src/*.hx \ + ../../lib/haxe/src/org/apache/thrift/**/*.hx \ + gen-haxe/tutorial/calculator.hx + $(HAXE) --cwd . php-web-server.hxml + +tutorialserver: all + $(BIN_CPP) server + +tutorialserver_php: all + php -f $(BIN_PHP) server + +tutorialclient: all + $(BIN_CPP) + +tutorialclient_php: all + php -f $(BIN_PHP) + +tutorialsecureserver: all + $(BIN_CPP) server secure + +tutorialsecureserver_php: all + php -f $(BIN_PHP) server secure + +tutorialsecureclient: all + $(BIN_CPP) secure + +tutorialsecureclient_php: all + php -f $(BIN_PHP) secure + +tutorialserver_php_http: all + php -S 127.0.0.1:9090 router.php + +tutorialclient_http: all + $(BIN_CPP) client http + +clean-local: + $(RM) -r gen-haxe bin + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tutorial/haxe/Tutorial.hxproj b/tutorial/haxe/Tutorial.hxproj new file mode 100644 index 0000000..796f648 --- /dev/null +++ b/tutorial/haxe/Tutorial.hxproj @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + thrift -r -gen haxe ../tutorial.thrift + + + + + + + + \ No newline at end of file diff --git a/tutorial/haxe/cpp.hxml b/tutorial/haxe/cpp.hxml new file mode 100644 index 0000000..6adb52d --- /dev/null +++ b/tutorial/haxe/cpp.hxml @@ -0,0 +1,41 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +#integrate files to classpath +-cp src +-cp gen-haxe +-cp ../../lib/haxe/src + +#this class wil be used as entry point for your app. +-main Main + +#CPP target +-cpp bin + +#To produce 64 bit binaries the file should define the HXCPP_M64 compile variable: +#-D HXCPP_M64 + +#Add debug information +-debug + +#dead code elimination : remove unused code +#"-dce no" : do not remove unused code +#"-dce std" : remove unused code in the std lib (default) +#"-dce full" : remove all unused code +-dce full \ No newline at end of file diff --git a/tutorial/haxe/csharp.hxml b/tutorial/haxe/csharp.hxml new file mode 100644 index 0000000..295c017 --- /dev/null +++ b/tutorial/haxe/csharp.hxml @@ -0,0 +1,38 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +#integrate files to classpath +-cp src +-cp gen-haxe +-cp ../../lib/haxe/src + +#this class wil be used as entry point for your app. +-main Main + +#CSHARP target +-cs bin/Tutorial.exe + +#Add debug information +-debug + +#dead code elimination : remove unused code +#"-dce no" : do not remove unused code +#"-dce std" : remove unused code in the std lib (default) +#"-dce full" : remove all unused code +-dce full \ No newline at end of file diff --git a/tutorial/haxe/flash.hxml b/tutorial/haxe/flash.hxml new file mode 100644 index 0000000..a1f0568 --- /dev/null +++ b/tutorial/haxe/flash.hxml @@ -0,0 +1,41 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +#integrate files to classpath +-cp src +-cp gen-haxe +-cp ../../lib/haxe/src + +#this class wil be used as entry point for your app. +-main Main + +#Flash target +-swf bin/Tutorial.swf + +#Add debug information +-debug + +# we need some goodies from sys.net +# --macro allowPackage("sys") + +#dead code elimination : remove unused code +#"-dce no" : do not remove unused code +#"-dce std" : remove unused code in the std lib (default) +#"-dce full" : remove all unused code +-dce full \ No newline at end of file diff --git a/tutorial/haxe/java.hxml b/tutorial/haxe/java.hxml new file mode 100644 index 0000000..c615565 --- /dev/null +++ b/tutorial/haxe/java.hxml @@ -0,0 +1,38 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +#integrate files to classpath +-cp src +-cp gen-haxe +-cp ../../lib/haxe/src + +#this class wil be used as entry point for your app. +-main Main + +#Java target +-java bin/Tutorial.jar + +#Add debug information +-debug + +#dead code elimination : remove unused code +#"-dce no" : do not remove unused code +#"-dce std" : remove unused code in the std lib (default) +#"-dce full" : remove all unused code +-dce full \ No newline at end of file diff --git a/tutorial/haxe/javascript.hxml b/tutorial/haxe/javascript.hxml new file mode 100644 index 0000000..b2b3876 --- /dev/null +++ b/tutorial/haxe/javascript.hxml @@ -0,0 +1,44 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +#integrate files to classpath +-cp src +-cp gen-haxe +-cp ../../lib/haxe/src + +#this class wil be used as entry point for your app. +-main Main + +#JavaScript target +-js bin/Tutorial.js + +#You can use -D source-map-content (requires Haxe 3.1+) to have the .hx +#files directly embedded into the map file, this way you only have to +#upload it, and it will be always in sync with the compiled .js even if +#you modify your .hx files. +-D source-map-content + +#Generate source map and add debug information +-debug + +#dead code elimination : remove unused code +#"-dce no" : do not remove unused code +#"-dce std" : remove unused code in the std lib (default) +#"-dce full" : remove all unused code +-dce full \ No newline at end of file diff --git a/tutorial/haxe/make_all.bat b/tutorial/haxe/make_all.bat new file mode 100644 index 0000000..656dd15 --- /dev/null +++ b/tutorial/haxe/make_all.bat @@ -0,0 +1,68 @@ +@echo off +rem /* +rem * Licensed to the Apache Software Foundation (ASF) under one +rem * or more contributor license agreements. See the NOTICE file +rem * distributed with this work for additional information +rem * regarding copyright ownership. The ASF licenses this file +rem * to you under the Apache License, Version 2.0 (the +rem * "License"); you may not use this file except in compliance +rem * with the License. You may obtain a copy of the License at +rem * +rem * http://www.apache.org/licenses/LICENSE-2.0 +rem * +rem * Unless required by applicable law or agreed to in writing, +rem * software distributed under the License is distributed on an +rem * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +rem * KIND, either express or implied. See the License for the +rem * specific language governing permissions and limitations +rem * under the License. +rem */ + +setlocal +if "%HOMEDRIVE%"=="" goto MISSINGVARS +if "%HOMEPATH%"=="" goto MISSINGVARS +if "%HAXEPATH%"=="" goto NOTINSTALLED + +set path=%HAXEPATH%;%HAXEPATH%\..\neko;%path% + +rem # invoke Thrift comnpiler +thrift -r -gen haxe ..\tutorial.thrift +if errorlevel 1 goto STOP + +rem # invoke Haxe compiler for all targets +for %%a in (*.hxml) do ( + rem * filter Python, as it is not supported by Haxe 3.1.3 (but will be in 3.1.4) + if not "%%a"=="python.hxml" ( + echo -------------------------- + echo Building %%a ... + echo -------------------------- + haxe --cwd . %%a + ) +) + + +echo. +echo done. +pause +goto eof + +:NOTINSTALLED +echo FATAL: Either Haxe is not installed, or the HAXEPATH variable is not set. +pause +goto eof + +:MISSINGVARS +echo FATAL: Unable to locate home folder. +echo. +echo Both HOMEDRIVE and HOMEPATH need to be set to point to your Home folder. +echo The current values are: +echo HOMEDRIVE=%HOMEDRIVE% +echo HOMEPATH=%HOMEPATH% +pause +goto eof + +:STOP +pause +goto eof + +:eof diff --git a/tutorial/haxe/make_all.sh b/tutorial/haxe/make_all.sh new file mode 100644 index 0000000..2ee650d --- /dev/null +++ b/tutorial/haxe/make_all.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# invoke Thrift comnpiler +thrift -r -gen haxe ../tutorial.thrift + +# output folder +if [ ! -d bin ]; then + mkdir bin +fi + +# invoke Haxe compoiler +for target in *.hxml; do + echo -------------------------- + echo Building ${target} ... + echo -------------------------- + if [ ! -d bin/${target} ]; then + mkdir bin/${target} + fi + haxe --cwd . ${target} +done + + +#eof diff --git a/tutorial/haxe/neko.hxml b/tutorial/haxe/neko.hxml new file mode 100644 index 0000000..6161f69 --- /dev/null +++ b/tutorial/haxe/neko.hxml @@ -0,0 +1,38 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +#integrate files to classpath +-cp src +-cp gen-haxe +-cp ../../lib/haxe/src + +#this class wil be used as entry point for your app. +-main Main + +#neko target +-neko bin/Tutorial.n + +#Add debug information +-debug + +#dead code elimination : remove unused code +#"-dce no" : do not remove unused code +#"-dce std" : remove unused code in the std lib (default) +#"-dce full" : remove all unused code +-dce full \ No newline at end of file diff --git a/tutorial/haxe/php-web-server.hxml b/tutorial/haxe/php-web-server.hxml new file mode 100644 index 0000000..395a852 --- /dev/null +++ b/tutorial/haxe/php-web-server.hxml @@ -0,0 +1,43 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +#integrate files to classpath +-cp src +-cp gen-haxe +-cp ../../lib/haxe/src + +#this class wil be used as entry point for your app. +-main Main + +#PHP target +-php bin/php-web-server/ +--php-front Main-debug.php + +#defines +-D phpwebserver + + +#Add debug information +-debug + +#dead code elimination : remove unused code +#"-dce no" : do not remove unused code +#"-dce std" : remove unused code in the std lib (default) +#"-dce full" : remove all unused code +-dce full diff --git a/tutorial/haxe/php.hxml b/tutorial/haxe/php.hxml new file mode 100644 index 0000000..c2f6887 --- /dev/null +++ b/tutorial/haxe/php.hxml @@ -0,0 +1,39 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +#integrate files to classpath +-cp src +-cp gen-haxe +-cp ../../lib/haxe/src + +#this class wil be used as entry point for your app. +-main Main + +#PHP target +-php bin/php/ +--php-front Main-debug.php + +#Add debug information +-debug + +#dead code elimination : remove unused code +#"-dce no" : do not remove unused code +#"-dce std" : remove unused code in the std lib (default) +#"-dce full" : remove all unused code +-dce full diff --git a/tutorial/haxe/project.hide b/tutorial/haxe/project.hide new file mode 100644 index 0000000..8d5d4ec --- /dev/null +++ b/tutorial/haxe/project.hide @@ -0,0 +1,105 @@ +{ + "type" : 0 + ,"target" : 4 + ,"name" : "Apache Thrift Tutorial" + ,"main" : null + ,"projectPackage" : "" + ,"company" : "Apache Software Foundation (ASF)" + ,"license" : "Apache License, Version 2.0" + ,"url" : "http://www.apache.org/licenses/LICENSE-2.0" + ,"targetData" : [ + { + "pathToHxml" : "flash.hxml" + ,"runActionType" : 1 + ,"runActionText" : "bin/Tutorial.swf" + } + ,{ + "pathToHxml" : "javascript.hxml" + ,"runActionType" : 1 + ,"runActionText" : "bin\\index.html" + } + ,{ + "pathToHxml" : "neko.hxml" + ,"runActionType" : 2 + ,"runActionText" : "neko bin/Tutorial.n" + } + ,{ + "pathToHxml" : "php.hxml" + } + ,{ + "pathToHxml" : "cpp.hxml" + ,"runActionType" : 2 + ,"runActionText" : "bin/Main-debug.exe" + } + ,{ + "pathToHxml" : "java.hxml" + } + ,{ + "pathToHxml" : "csharp.hxml" + ,"runActionType" : 2 + ,"runActionText" : "bin\\Tutorial.exe\\bin\\Main-Debug.exe" + } + ,{ + "pathToHxml" : "python.hxml" + ,"runActionType" : 2 + ,"runActionText" : "python bin/Tutorial.py" + } + ] + ,"files" : [ + { + "path" : "src\\org\\apache\\thrift\\server\\TServer.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 76 + } + ,{ + "path" : "src\\org\\apache\\thrift\\server\\TSimpleServer.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 100 + } + ,{ + "path" : "src\\shared\\SharedServiceProcessor.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 20 + } + ,{ + "path" : "src\\tutorial\\CalculatorProcessor.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 79 + } + ,{ + "path" : "src\\Main.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 0 + } + ] + ,"activeFile" : "src\\Main.hx" + ,"openFLTarget" : null + ,"openFLBuildMode" : "Debug" + ,"runActionType" : null + ,"runActionText" : null + ,"buildActionCommand" : null + ,"hiddenItems" : [ + + ] + ,"showHiddenItems" : false +} \ No newline at end of file diff --git a/tutorial/haxe/python.hxml b/tutorial/haxe/python.hxml new file mode 100644 index 0000000..f2c19fa --- /dev/null +++ b/tutorial/haxe/python.hxml @@ -0,0 +1,38 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +#integrate files to classpath +-cp src +-cp gen-haxe +-cp ../../lib/haxe/src + +#this class wil be used as entry point for your app. +-main Main + +#Python target +-python bin/Tutorial.py + +#Add debug information +-debug + +#dead code elimination : remove unused code +#"-dce no" : do not remove unused code +#"-dce std" : remove unused code in the std lib (default) +#"-dce full" : remove all unused code +-dce full \ No newline at end of file diff --git a/tutorial/haxe/router.php b/tutorial/haxe/router.php new file mode 100644 index 0000000..e34135c --- /dev/null +++ b/tutorial/haxe/router.php @@ -0,0 +1,31 @@ +(); + + public function new() { + } + + public function ping() : Void { + trace("ping()"); + } + + + public function add( num1 : haxe.Int32, num2 : haxe.Int32) : haxe.Int32 { + trace('add( $num1, $num2)'); + return num1 + num2; + } + + public function calculate( logid : haxe.Int32, work : Work) : haxe.Int32 { + trace('calculate( $logid, '+work.op+","+work.num1+","+work.num2+")"); + + var val : haxe.Int32 = 0; + switch (work.op) + { + case Operation.ADD: + val = work.num1 + work.num2; + + case Operation.SUBTRACT: + val = work.num1 - work.num2; + + case Operation.MULTIPLY: + val = work.num1 * work.num2; + + case Operation.DIVIDE: + if (work.num2 == 0) + { + var io = new InvalidOperation(); + io.whatOp = work.op; + io.why = "Cannot divide by 0"; + throw io; + } + val = Std.int( work.num1 / work.num2); + + default: + var io = new InvalidOperation(); + io.whatOp = work.op; + io.why = "Unknown operation"; + throw io; + } + + var entry = new SharedStruct(); + entry.key = logid; + entry.value = '$val'; + log.set(logid, entry); + + return val; + } + + public function getStruct( key : haxe.Int32) : SharedStruct { + trace('getStruct($key)'); + return log.get(key); + } + + // oneway method, no args + public function zip() : Void { + trace("zip()"); + } + +} diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx new file mode 100644 index 0000000..6bebe71 --- /dev/null +++ b/tutorial/haxe/src/Main.hx @@ -0,0 +1,375 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package; + +import org.apache.thrift.*; +import org.apache.thrift.protocol.*; +import org.apache.thrift.transport.*; +import org.apache.thrift.server.*; +import org.apache.thrift.meta_data.*; + +import tutorial.*; +import shared.*; + + +enum Prot { + binary; + json; +} + +enum Trns { + socket; + http; +} + +class Main { + + private static var server : Bool = false; + private static var framed : Bool = false; + private static var buffered : Bool = false; + private static var prot : Prot = binary; + private static var trns : Trns = socket; + + private static var targetHost : String = "localhost"; + private static var targetPort : Int = 9090; + + static function main() { + + #if ! (flash || js || phpwebserver) + try { + ParseArgs(); + } catch (e : String) { + trace(e); + trace(GetHelp()); + return; + } + + #elseif phpwebserver + //forcing server + server = true; + trns = http; + initPhpWebServer(); + //check method + if(php.Web.getMethod() != 'POST') { + Sys.println('http endpoint for thrift test server'); + return; + } + #end + + try { + if (server) + RunServer(); + else + RunClient(); + } catch (e : String) { + trace(e); + } + + trace("Completed."); + } + + #if phpwebserver + private static function initPhpWebServer() + { + //remap trace to error log + haxe.Log.trace = function(v:Dynamic, ?infos:haxe.PosInfos) + { + // handle trace + var newValue : Dynamic; + if (infos != null && infos.customParams!=null) { + var extra:String = ""; + for( v in infos.customParams ) + extra += "," + v; + newValue = v + extra; + } + else { + newValue = v; + } + var msg = infos != null ? infos.fileName + ':' + infos.lineNumber + ': ' : ''; + Sys.stderr().writeString('${msg}${newValue}\n'); + } + } + #end + + + #if ! (flash || js) + + private static function GetHelp() : String { + return Sys.executablePath()+" modus trnsOption transport protocol\n" + +"Options:\n" + +" modus: client, server (default: client)\n" + +" trnsOption: framed, buffered (default: none)\n" + +" transport: socket, http (default: socket)\n" + +" protocol: binary, json (default: binary)\n" + +"\n" + +"All arguments are optional.\n"; + } + + + private static function ParseArgs() : Void { + var step = 0; + for (arg in Sys.args()) { + + // server|client + switch(step) { + case 0: + ++step; + if ( arg == "client") + server = false; + else if ( arg == "server") + server = true; + else + throw "First argument must be 'server' or 'client'"; + + case 1: + if ( arg == "framed") { + framed = true; + } else if ( arg == "buffered") { + buffered = true; + } else if ( arg == "socket") { + trns = socket; + ++step; + } else if ( arg == "http") { + trns = http; + ++step; + } else { + throw "Unknown transport "+arg; + } + + case 2: + if ( arg == "binary") { + prot = binary; + ++step; + } else if ( arg == "json") { + prot = json; + ++step; + } else { + throw "Unknown protocol "+arg; + } + + default: + throw "Unexpected argument "+arg; + } + + if ( framed && buffered) + { + trace("WN: framed supersedes buffered"); + } + + } + } + + #end + + private static function ClientSetup() : Calculator { + trace("Client configuration:"); + + // endpoint transport + var transport : TTransport; + switch(trns) + { + case socket: + trace('- socket transport $targetHost:$targetPort'); + transport = new TSocket( targetHost, targetPort); + case http: + var uri = 'http://${targetHost}:${targetPort}'; + trace('- HTTP transport $uri'); + transport = new THttpClient(uri); + default: + throw "Unhandled transport"; + } + + + // optinal layered transport + if ( framed) { + trace("- framed transport"); + transport = new TFramedTransport(transport); + } else if ( buffered) { + trace("- buffered transport"); + transport = new TBufferedTransport(transport); + } + + + // protocol + var protocol : TProtocol; + switch(prot) + { + case binary: + trace("- binary protocol"); + protocol = new TBinaryProtocol( transport); + case json: + trace("- JSON protocol"); + protocol = new TJSONProtocol( transport); + default: + throw "Unhandled protocol"; + } + + + // put everything together + transport.open(); + return new CalculatorImpl(protocol,protocol); + } + + + private static function RunClient() : Void { + var client = ClientSetup(); + + try { + client.ping(); + trace("ping() successful"); + } catch(error : TException) { + trace('ping() failed: $error'); + } catch(error : Dynamic) { + trace('ping() failed: $error'); + } + + try { + var sum = client.add( 1, 1); + trace('1+1=$sum'); + } catch(error : TException) { + trace('add() failed: $error'); + } catch(error : Dynamic) { + trace('add() failed: $error'); + } + + + var work = new tutorial.Work(); + work.op = tutorial.Operation.DIVIDE; + work.num1 = 1; + work.num2 = 0; + try { + var quotient = client.calculate( 1, work); + trace('Whoa we can divide by 0! Result = $quotient'); + } catch(error : TException) { + trace('calculate() failed: $error'); + } catch(error : Dynamic) { + trace('calculate() failed: $error'); + } + + work.op = tutorial.Operation.SUBTRACT; + work.num1 = 15; + work.num2 = 10; + try { + var diff = client.calculate( 1, work); + trace('15-10=$diff'); + } catch(error : TException) { + trace('calculate() failed: $error'); + } catch(error : Dynamic) { + trace('calculate() failed: $error'); + } + + + try { + var log : SharedStruct = client.getStruct( 1); + var logval = log.value; + trace('Check log: $logval'); + } catch(error : TException) { + trace('getStruct() failed: $error'); + } catch(error : Dynamic) { + trace('getStruct() failed: $error'); + } + } + + + private static function ServerSetup() : TServer { + trace("Server configuration:"); + + // endpoint transport + var transport : TServerTransport = null; + switch(trns) + { + case socket: + #if (flash || js) + throw 'current platform does not support socket servers'; + #else + trace('- socket transport port $targetPort'); + transport = new TServerSocket( targetPort); + #end + case http: + #if !phpwebserver + throw "HTTP server not implemented yet"; + //trace("- http transport"); + //transport = new THttpClient( targetHost); + #else + trace("- http transport"); + transport = new TWrappingServerTransport( + new TStreamTransport( + new TFileStream("php://input", Read), + new TFileStream("php://output", Append) + ) + ); + + #end + default: + throw "Unhandled transport"; + } + + // optional: layered transport + var transfactory : TTransportFactory = null; + if ( framed) { + trace("- framed transport"); + transfactory = new TFramedTransportFactory(); + } else if ( buffered) { + trace("- buffered transport"); + transfactory = new TBufferedTransportFactory(); + } + + // protocol + var protfactory : TProtocolFactory = null; + switch(prot) + { + case binary: + trace("- binary protocol"); + protfactory = new TBinaryProtocolFactory(); + case json: + trace("- JSON protocol"); + protfactory = new TJSONProtocolFactory(); + default: + throw "Unhandled protocol"; + } + + var handler = new CalculatorHandler(); + var processor = new CalculatorProcessor(handler); + var server = new TSimpleServer( processor, transport, transfactory, protfactory); + #if phpwebserver + server.runOnce = true; + #end + + return server; + } + + + private static function RunServer() : Void { + try + { + var server = ServerSetup(); + + trace("\nStarting the server..."); + server.Serve(); + } + catch( e : Dynamic) + { + trace('RunServer() failed: $e'); + } + trace("done."); + } + +} + diff --git a/tutorial/hs/HaskellClient.hs b/tutorial/hs/HaskellClient.hs new file mode 100644 index 0000000..bd29df0 --- /dev/null +++ b/tutorial/hs/HaskellClient.hs @@ -0,0 +1,76 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +import qualified Calculator +import qualified Calculator_Client as Client +import qualified SharedService_Client as SClient +import Tutorial_Types +import SharedService_Iface +import Shared_Types + +import Thrift +import Thrift.Protocol.Binary +import Thrift.Transport +import Thrift.Transport.Handle +import Thrift.Server + +import Control.Exception +import Data.Maybe +import Data.Text.Lazy +import Text.Printf +import Network + +main = do + transport <- hOpen ("localhost", PortNumber 9090) + let binProto = BinaryProtocol transport + let client = (binProto, binProto) + + Client.ping client + print "ping()" + + sum <- Client.add client 1 1 + printf "1+1=%d\n" sum + + + let work = Work { work_op = DIVIDE, + work_num1 = 1, + work_num2 = 0, + work_comment = Nothing + } + + Control.Exception.catch (printf "1/0=%d\n" =<< Client.calculate client 1 work) + (\e -> printf "InvalidOperation %s\n" (show (e :: InvalidOperation))) + + + let work = Work { work_op = SUBTRACT, + work_num1 = 15, + work_num2 = 10, + work_comment = Nothing + } + + diff <- Client.calculate client 1 work + printf "15-10=%d\n" diff + + log <- SClient.getStruct client 1 + printf "Check log: %s\n" $ unpack $ sharedStruct_value log + + -- Close! + tClose transport + + diff --git a/tutorial/hs/HaskellServer.hs b/tutorial/hs/HaskellServer.hs new file mode 100644 index 0000000..cfe1344 --- /dev/null +++ b/tutorial/hs/HaskellServer.hs @@ -0,0 +1,103 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +{-# LANGUAGE OverloadedStrings #-} + +import qualified Calculator +import Calculator_Iface +import Tutorial_Types +import SharedService_Iface +import Shared_Types + +import Thrift +import Thrift.Protocol.Binary +import Thrift.Transport +import Thrift.Server + +import Data.Int +import Data.String +import Data.Maybe +import Text.Printf +import Control.Exception (throw) +import Control.Concurrent.MVar +import qualified Data.Map as M +import Data.Map ((!)) +import Data.Monoid + +data CalculatorHandler = CalculatorHandler {mathLog :: MVar (M.Map Int32 SharedStruct)} + +newCalculatorHandler = do + log <- newMVar mempty + return $ CalculatorHandler log + +instance SharedService_Iface CalculatorHandler where + getStruct self k = do + myLog <- readMVar (mathLog self) + return $ (myLog ! k) + + +instance Calculator_Iface CalculatorHandler where + ping _ = + print "ping()" + + add _ n1 n2 = do + printf "add(%d,%d)\n" n1 n2 + return (n1 + n2) + + calculate self mlogid mwork = do + printf "calculate(%d, %s)\n" logid (show work) + + let val = case op work of + ADD -> + num1 work + num2 work + SUBTRACT -> + num1 work - num2 work + MULTIPLY -> + num1 work * num2 work + DIVIDE -> + if num2 work == 0 then + throw $ + InvalidOperation { + invalidOperation_whatOp = fromIntegral $ fromEnum $ op work, + invalidOperation_why = "Cannot divide by 0" + } + else + num1 work `div` num2 work + + let logEntry = SharedStruct logid (fromString $ show $ val) + modifyMVar_ (mathLog self) $ return .(M.insert logid logEntry) + + return $! val + + where + -- stupid dynamic languages f'ing it up + num1 = work_num1 + num2 = work_num2 + op = work_op + logid = mlogid + work = mwork + + zip _ = + print "zip()" + +main = do + handler <- newCalculatorHandler + print "Starting the server..." + runBasicServer handler Calculator.process 9090 + print "done." diff --git a/tutorial/hs/LICENSE b/tutorial/hs/LICENSE new file mode 100644 index 0000000..3b6d7d7 --- /dev/null +++ b/tutorial/hs/LICENSE @@ -0,0 +1,239 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +-------------------------------------------------- +SOFTWARE DISTRIBUTED WITH THRIFT: + +The Apache Thrift software includes a number of subcomponents with +separate copyright notices and license terms. Your use of the source +code for the these subcomponents is subject to the terms and +conditions of the following licenses. + +-------------------------------------------------- +Portions of the following files are licensed under the MIT License: + + lib/erl/src/Makefile.am + +Please see doc/otp-base-license.txt for the full terms of this license. + +-------------------------------------------------- +For the aclocal/ax_boost_base.m4 and contrib/fb303/aclocal/ax_boost_base.m4 components: + +# Copyright (c) 2007 Thomas Porschberg +# +# Copying and distribution of this file, with or without +# modification, are permitted in any medium without royalty provided +# the copyright notice and this notice are preserved. + +-------------------------------------------------- +For the lib/nodejs/lib/thrift/json_parse.js: + +/* + json_parse.js + 2015-05-02 + Public Domain. + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + +*/ +(By Douglas Crockford ) +-------------------------------------------------- diff --git a/tutorial/hs/Makefile b/tutorial/hs/Makefile new file mode 100644 index 0000000..b1402ee --- /dev/null +++ b/tutorial/hs/Makefile @@ -0,0 +1,649 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# tutorial/hs/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/thrift +pkgincludedir = $(includedir)/thrift +pkglibdir = $(libdir)/thrift +pkglibexecdir = $(libexecdir)/thrift +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-pc-linux-gnu +host_triplet = x86_64-pc-linux-gnu +subdir = tutorial/hs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_$(V)) +am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing aclocal-1.15 +ALLOCA = +AMTAR = $${TAR-tar} +AM_DEFAULT_VERBOSITY = 1 +ANT = /usr/bin/ant +ANT_FLAGS = +AR = ar +AUTOCONF = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoconf +AUTOHEADER = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing autoheader +AUTOMAKE = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing automake-1.15 +AWK = gawk +BISON = bison +BOOST_CHRONO_LDADD = /usr/lib/x86_64-linux-gnu/libboost_chrono.a +BOOST_CPPFLAGS = -I/usr/include +BOOST_FILESYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_filesystem.a +BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu +BOOST_LIB_DIR = /usr/lib/x86_64-linux-gnu +BOOST_SYSTEM_LDADD = /usr/lib/x86_64-linux-gnu/libboost_system.a +BOOST_TEST_LDADD = /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.a +BOOST_THREAD_LDADD = /usr/lib/x86_64-linux-gnu/libboost_thread.a +BUNDLER = /usr/bin/bundle +CABAL = /usr/bin/cabal +CABAL_CONFIGURE_FLAGS = +CARGO = /usr/bin/cargo +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 +CLASSPATH = +CPP = gcc -E +CPPFLAGS = +CPPSTYLE_CMD = find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \; +CXX = g++ -std=c++11 +CXXCPP = g++ -E -std=c++11 +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -g -O2 +CYGPATH_W = echo +DART = /usr/lib/dart/bin/dart +DARTPUB = /usr/lib/dart/bin/pub +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +DLLTOOL = false +DMD = dmd +DMD_LIBEVENT_FLAGS = +DMD_OF_DIRSEP = / +DMD_OPENSSL_FLAGS = +DOTNETCORE = /usr/bin/dotnet +DOTNETCORE_VERSION = 2.0.3 +DSYMUTIL = +DUMPBIN = +D_EVENT_LIB_NAME = libthriftd-event.a +D_IMPORT_PREFIX = ${prefix}/include/d2 +D_LIB_NAME = libthriftd.a +D_SSL_LIB_NAME = libthriftd-ssl.a +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +ENABLE_COVERAGE = 2 +ERL = /usr/bin/erl +ERLANG_INSTALL_LIB_DIR = /usr/lib/erlang/lib +ERLANG_INSTALL_LIB_DIR_thrift = ${ERLANG_INSTALL_LIB_DIR}/thrift-0.11.0 +ERLANG_LIB_DIR = /usr/lib/erlang/lib +ERLC = /usr/bin/erlc +ERLCFLAGS = +EXEEXT = +FGREP = /bin/grep -F +GCOV_CFLAGS = +GCOV_CXXFLAGS = +GCOV_LDFLAGS = +GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GLIB_LIBS = -lglib-2.0 +GO = /usr/bin/go +GOBJECT_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include +GOBJECT_LIBS = -lgobject-2.0 -lglib-2.0 +GREP = /bin/grep +HAVE_CXX11 = 1 +HAXE = /usr/bin/haxe +HAXE_VERSION = 3.2.1 +INSTALL = /usr/bin/install -c +INSTALLDIRS = vendor +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +JAVA_PREFIX = /usr/local/lib +LD = /usr/bin/ld -m elf_x86_64 +LDFLAGS = +LEX = flex +LEXLIB = -lfl +LEX_OUTPUT_ROOT = lex.yy +LIBEVENT_CPPFLAGS = +LIBEVENT_LDFLAGS = +LIBEVENT_LIBS = -levent +LIBOBJS = +LIBS = -lrt -lpthread +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LIPO = +LN_S = ln -s +LTLIBOBJS = +LT_SYS_LIBRARY_PATH = +LUA = /usr/bin/lua5.3 +LUA_EXEC_PREFIX = ${exec_prefix} +LUA_INCLUDE = -I/usr/include/lua5.3 +LUA_LIB = -llua5.3 -ldl +LUA_PLATFORM = unknown +LUA_PREFIX = ${prefix} +LUA_SHORT_VERSION = 53 +LUA_VERSION = 5.3 +MAKEINFO = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/missing makeinfo +MANIFEST_TOOL = : +MAYBE_CPP = cpp +MAYBE_CSHARP = csharp +MAYBE_C_GLIB = c_glib +MAYBE_D = +MAYBE_DART = dart +MAYBE_DOTNETCORE = netcore +MAYBE_ERLANG = erl +MAYBE_GO = go +MAYBE_HASKELL = hs +MAYBE_JAVA = java +MAYBE_LUA = lua +MAYBE_NODEJS = nodejs +MAYBE_PERL = perl +MAYBE_PHP = php +MAYBE_PY3 = py3 +MAYBE_PYTHON = py +MAYBE_RS = rs +MAYBE_RUBY = rb +MCS = /usr/bin/mcs +MKDIR_P = /bin/mkdir -p +MONO_CFLAGS = +MONO_LIBS = +NM = /usr/bin/nm -B +NMEDIT = +NODEJS = /usr/bin/nodejs +NPM = /usr/bin/npm +OBJDUMP = objdump +OBJEXT = o +OPENSSL_INCLUDES = +OPENSSL_LDFLAGS = +OPENSSL_LIBS = -lssl -lcrypto +OTOOL = +OTOOL64 = +PACKAGE = thrift +PACKAGE_BUGREPORT = +PACKAGE_NAME = thrift +PACKAGE_STRING = thrift 0.11.0 +PACKAGE_TARNAME = thrift +PACKAGE_URL = +PACKAGE_VERSION = 0.11.0 +PATH_SEPARATOR = : +PERL = /usr/bin/perl +PERL_PREFIX = /usr/local +PHP = /usr/bin/php +PHPUNIT = /usr/bin/phpunit +PHP_CONFIG = /usr/bin/php-config +PHP_CONFIG_PREFIX = /etc/php.d +PHP_PREFIX = /usr/lib/php +PKG_CONFIG = /usr/bin/pkg-config +PKG_CONFIG_LIBDIR = +PKG_CONFIG_PATH = +PYTHON = /usr/bin/python +PYTHON3 = /usr/bin/python3 +PYTHON_EXEC_PREFIX = ${exec_prefix} +PYTHON_PLATFORM = linux2 +PYTHON_PREFIX = ${prefix} +PYTHON_VERSION = 2.7 +PY_PREFIX = /usr +QT5_CFLAGS = +QT5_LIBS = +QT5_MOC = +QT_CFLAGS = +QT_LIBS = +QT_MOC = +RANLIB = ranlib +REBAR = /usr/bin/rebar +RUBY = /usr/bin/ruby +RUBY_PREFIX = +RUNHASKELL = /usr/bin/runhaskell +RUSTC = /usr/bin/rustc +SED = /bin/sed +SET_MAKE = +SHELL = /bin/bash +STRIP = strip +THRIFT = /home/jens/Schreibtisch/Develop/Thrift/compiler/cpp/thrift +TRIAL = /usr/bin/trial +VERSION = 0.11.0 +YACC = bison -y +YFLAGS = +ZLIB_CPPFLAGS = +ZLIB_LDFLAGS = +ZLIB_LIBS = -lz +abs_builddir = /home/jens/Schreibtisch/Develop/Thrift/tutorial/hs +abs_srcdir = /home/jens/Schreibtisch/Develop/Thrift/tutorial/hs +abs_top_builddir = /home/jens/Schreibtisch/Develop/Thrift +abs_top_srcdir = /home/jens/Schreibtisch/Develop/Thrift +ac_ct_AR = ar +ac_ct_CC = gcc +ac_ct_CXX = g++ +ac_ct_DUMPBIN = +am__include = include +am__leading_dot = . +am__quote = +am__tar = tar --format=ustar -chf - "$$tardir" +am__untar = tar -xf - +bindir = ${exec_prefix}/bin +build = x86_64-pc-linux-gnu +build_alias = +build_cpu = x86_64 +build_os = linux-gnu +build_vendor = pc +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +golang_version = 1.6.2 +have_prog_bison = yes +host = x86_64-pc-linux-gnu +host_alias = +host_cpu = x86_64 +host_os = linux-gnu +host_vendor = pc +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /home/jens/Schreibtisch/Develop/Thrift/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +luadir = ${prefix}/share/lua/5.3 +luaexecdir = ${exec_prefix}/lib/lua/5.3 +mandir = ${datarootdir}/man +mkdir_p = $(MKDIR_P) +oldincludedir = /usr/include +pdfdir = ${docdir} +pkgluadir = ${luadir}/thrift +pkgluaexecdir = ${luaexecdir}/thrift +pkgpyexecdir = ${pyexecdir}/thrift +pkgpythondir = ${pythondir}/thrift +prefix = /usr/local +program_transform_name = s,x,x, +psdir = ${docdir} +pyexecdir = ${exec_prefix}/lib/python2.7/dist-packages +pythondir = ${prefix}/lib/python2.7/dist-packages +runstatedir = ${localstatedir}/run +rustc_version = rustc 1.17.0 +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +subdirs = lib/php/src/ext/thrift_protocol +sysconfdir = ${prefix}/etc +target_alias = +top_build_prefix = ../../ +top_builddir = ../.. +top_srcdir = ../.. +EXTRA_DIST = \ + LICENSE + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/hs/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tutorial/hs/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: check-am install-am install-exec-am install-strip + +.PHONY: all all-am all-local check check-am check-local clean \ + clean-generic clean-libtool clean-local cscopelist-am ctags-am \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-exec-hook install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +all-local: + $(top_builddir)/compiler/cpp/thrift --gen hs -r $(top_srcdir)/tutorial/tutorial.thrift + $(CABAL) install + +install-exec-hook: + $(CABAL) install + +# Make sure this doesn't fail if Haskell is not configured. +clean-local: + $(CABAL) clean + $(RM) -r gen-* + +check-local: + $(CABAL) check + +tutorialserver: all + dist/build/HaskellServer/HaskellServer + +tutorialclient: all + dist/build/HaskellClient/HaskellClient + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tutorial/hs/Makefile.am b/tutorial/hs/Makefile.am new file mode 100755 index 0000000..a3eccc2 --- /dev/null +++ b/tutorial/hs/Makefile.am @@ -0,0 +1,42 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +all-local: + $(top_builddir)/compiler/cpp/thrift --gen hs -r $(top_srcdir)/tutorial/tutorial.thrift + $(CABAL) install + +install-exec-hook: + $(CABAL) install + +# Make sure this doesn't fail if Haskell is not configured. +clean-local: + $(CABAL) clean + $(RM) -r gen-* + +check-local: + $(CABAL) check + +tutorialserver: all + dist/build/HaskellServer/HaskellServer + +tutorialclient: all + dist/build/HaskellClient/HaskellClient + +EXTRA_DIST = \ + LICENSE diff --git a/tutorial/hs/Makefile.in b/tutorial/hs/Makefile.in new file mode 100644 index 0000000..1810cfa --- /dev/null +++ b/tutorial/hs/Makefile.in @@ -0,0 +1,649 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tutorial/hs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + LICENSE + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/hs/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tutorial/hs/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: check-am install-am install-exec-am install-strip + +.PHONY: all all-am all-local check check-am check-local clean \ + clean-generic clean-libtool clean-local cscopelist-am ctags-am \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-exec-hook install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + style-am style-local tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +all-local: + $(top_builddir)/compiler/cpp/thrift --gen hs -r $(top_srcdir)/tutorial/tutorial.thrift + $(CABAL) install + +install-exec-hook: + $(CABAL) install + +# Make sure this doesn't fail if Haskell is not configured. +clean-local: + $(CABAL) clean + $(RM) -r gen-* + +check-local: + $(CABAL) check + +tutorialserver: all + dist/build/HaskellServer/HaskellServer + +tutorialclient: all + dist/build/HaskellClient/HaskellClient + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tutorial/hs/Setup.lhs b/tutorial/hs/Setup.lhs new file mode 100644 index 0000000..c7df182 --- /dev/null +++ b/tutorial/hs/Setup.lhs @@ -0,0 +1,21 @@ +#!/usr/bin/env runhaskell + +> -- Licensed to the Apache Software Foundation (ASF) under one +> -- or more contributor license agreements. See the NOTICE file +> -- distributed with this work for additional information +> -- regarding copyright ownership. The ASF licenses this file +> -- to you under the Apache License, Version 2.0 (the +> -- "License"); you may not use this file except in compliance +> -- with the License. You may obtain a copy of the License at +> -- +> -- http://www.apache.org/licenses/LICENSE-2.0 +> -- +> -- Unless required by applicable law or agreed to in writing, +> -- software distributed under the License is distributed on an +> -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +> -- KIND, either express or implied. See the License for the +> -- specific language governing permissions and limitations +> -- under the License. + +> import Distribution.Simple +> main = defaultMain diff --git a/tutorial/hs/ThriftTutorial.cabal b/tutorial/hs/ThriftTutorial.cabal new file mode 100755 index 0000000..98fbd7b --- /dev/null +++ b/tutorial/hs/ThriftTutorial.cabal @@ -0,0 +1,73 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +Name: ThriftTutorial +Version: 0.11.0 +Cabal-Version: >= 1.4 +License: OtherLicense +Category: Foreign +Build-Type: Simple +Synopsis: Thrift Tutorial library package +Homepage: http://thrift.apache.org +Bug-Reports: https://issues.apache.org/jira/browse/THRIFT +Maintainer: dev@thrift.apache.org +License-File: LICENSE + +Description: + Haskell tutorial for the Apache Thrift RPC system. Requires the use of the thrift code generator. + +flag network-uri + description: Get Network.URI from the network-uri package + default: True + +Executable HaskellServer + Main-is: HaskellServer.hs + Hs-Source-Dirs: + ., gen-hs/ + Build-Depends: + base >= 4, base < 5, ghc-prim, containers, thrift, vector, unordered-containers, text, hashable, bytestring, QuickCheck + Extensions: + DeriveDataTypeable, + ExistentialQuantification, + FlexibleInstances, + KindSignatures, + MagicHash, + RankNTypes, + ScopedTypeVariables, + TypeSynonymInstances + +Executable HaskellClient + Main-is: HaskellClient.hs + Hs-Source-Dirs: + ., gen-hs/ + Build-Depends: + base >= 4, base < 5, ghc-prim, containers, thrift, vector, QuickCheck + if flag(network-uri) + build-depends: network-uri >= 2.6, network >= 2.6 + else + build-depends: network < 2.6 + Extensions: + DeriveDataTypeable, + ExistentialQuantification, + FlexibleInstances, + KindSignatures, + MagicHash, + RankNTypes, + ScopedTypeVariables, + TypeSynonymInstances diff --git a/tutorial/java/Makefile.am b/tutorial/java/Makefile.am new file mode 100755 index 0000000..95908b1 --- /dev/null +++ b/tutorial/java/Makefile.am @@ -0,0 +1,45 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +export CLASSPATH + +# Make sure this doesn't fail if ant is not configured. +clean-local: + ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ + $$ANT $(ANT_FLAGS) clean + +all-local: + $(ANT) $(ANT_FLAGS) compile + +check-local: all + $(ANT) $(ANT_FLAGS) test + +tutorial: all + $(ANT) $(ANT_FLAGS) tutorial + +tutorialserver: all + $(ANT) $(ANT_FLAGS) tutorialserver + +tutorialclient: all + $(ANT) $(ANT_FLAGS) tutorialclient + +EXTRA_DIST = \ + build.xml \ + src \ + README.md diff --git a/tutorial/java/Makefile.in b/tutorial/java/Makefile.in new file mode 100644 index 0000000..7f6c901 --- /dev/null +++ b/tutorial/java/Makefile.in @@ -0,0 +1,651 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tutorial/java +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + build.xml \ + src \ + README.md + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/java/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tutorial/java/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: all all-am all-local check check-am check-local clean \ + clean-generic clean-libtool clean-local cscopelist-am ctags-am \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +export CLASSPATH + +# Make sure this doesn't fail if ant is not configured. +clean-local: + ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ + $$ANT $(ANT_FLAGS) clean + +all-local: + $(ANT) $(ANT_FLAGS) compile + +check-local: all + $(ANT) $(ANT_FLAGS) test + +tutorial: all + $(ANT) $(ANT_FLAGS) tutorial + +tutorialserver: all + $(ANT) $(ANT_FLAGS) tutorialserver + +tutorialclient: all + $(ANT) $(ANT_FLAGS) tutorialclient + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tutorial/java/README.md b/tutorial/java/README.md new file mode 100644 index 0000000..f109fea --- /dev/null +++ b/tutorial/java/README.md @@ -0,0 +1,24 @@ +Thrift Java Tutorial +================================================== +1) Compile the Java library + + thrift/lib/java$ make +or: + + thrift/lib/java$ ant + +4) Run the tutorial: + +start server and client with one step: + + thrift/tutorial/java$ make tutorial + +or: + + thrift/tutorial/java$ make tutorialserver + thrift/tutorial/java$ make tutorialclient + +or: + + thrift/tutorial/java$ ant tutorialserver + thrift/tutorial/java$ ant tutorialclient diff --git a/tutorial/java/build.xml b/tutorial/java/build.xml new file mode 100644 index 0000000..c895ea9 --- /dev/null +++ b/tutorial/java/build.xml @@ -0,0 +1,113 @@ + + + + Thrift Java Tutorial + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + tutorial client simple: + + + + tutorial client secure: + + + + + + + + + + + + + + + + tutorial client simple: + + + + tutorial client secure: + + + + + + + + + + + + + + + + + diff --git a/tutorial/java/src/CalculatorHandler.java b/tutorial/java/src/CalculatorHandler.java new file mode 100644 index 0000000..92944b0 --- /dev/null +++ b/tutorial/java/src/CalculatorHandler.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.thrift.TException; + +// Generated code +import tutorial.*; +import shared.*; + +import java.util.HashMap; + +public class CalculatorHandler implements Calculator.Iface { + + private HashMap log; + + public CalculatorHandler() { + log = new HashMap(); + } + + public void ping() { + System.out.println("ping()"); + } + + public int add(int n1, int n2) { + System.out.println("add(" + n1 + "," + n2 + ")"); + return n1 + n2; + } + + public int calculate(int logid, Work work) throws InvalidOperation { + System.out.println("calculate(" + logid + ", {" + work.op + "," + work.num1 + "," + work.num2 + "})"); + int val = 0; + switch (work.op) { + case ADD: + val = work.num1 + work.num2; + break; + case SUBTRACT: + val = work.num1 - work.num2; + break; + case MULTIPLY: + val = work.num1 * work.num2; + break; + case DIVIDE: + if (work.num2 == 0) { + InvalidOperation io = new InvalidOperation(); + io.whatOp = work.op.getValue(); + io.why = "Cannot divide by 0"; + throw io; + } + val = work.num1 / work.num2; + break; + default: + InvalidOperation io = new InvalidOperation(); + io.whatOp = work.op.getValue(); + io.why = "Unknown operation"; + throw io; + } + + SharedStruct entry = new SharedStruct(); + entry.key = logid; + entry.value = Integer.toString(val); + log.put(logid, entry); + + return val; + } + + public SharedStruct getStruct(int key) { + System.out.println("getStruct(" + key + ")"); + return log.get(key); + } + + public void zip() { + System.out.println("zip()"); + } + +} + diff --git a/tutorial/java/src/JavaClient.java b/tutorial/java/src/JavaClient.java new file mode 100644 index 0000000..2e35d41 --- /dev/null +++ b/tutorial/java/src/JavaClient.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// Generated code +import tutorial.*; +import shared.*; + +import org.apache.thrift.TException; +import org.apache.thrift.transport.TSSLTransportFactory; +import org.apache.thrift.transport.TTransport; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.protocol.TProtocol; + +public class JavaClient { + public static void main(String [] args) { + + if (args.length != 1) { + System.out.println("Please enter 'simple' or 'secure'"); + System.exit(0); + } + + try { + TTransport transport; + if (args[0].contains("simple")) { + transport = new TSocket("localhost", 9090); + transport.open(); + } + else { + /* + * Similar to the server, you can use the parameters to setup client parameters or + * use the default settings. On the client side, you will need a TrustStore which + * contains the trusted certificate along with the public key. + * For this example it's a self-signed cert. + */ + TSSLTransportParameters params = new TSSLTransportParameters(); + params.setTrustStore("../../lib/java/test/.truststore", "thrift", "SunX509", "JKS"); + /* + * Get a client transport instead of a server transport. The connection is opened on + * invocation of the factory method, no need to specifically call open() + */ + transport = TSSLTransportFactory.getClientSocket("localhost", 9091, 0, params); + } + + TProtocol protocol = new TBinaryProtocol(transport); + Calculator.Client client = new Calculator.Client(protocol); + + perform(client); + + transport.close(); + } catch (TException x) { + x.printStackTrace(); + } + } + + private static void perform(Calculator.Client client) throws TException + { + client.ping(); + System.out.println("ping()"); + + int sum = client.add(1,1); + System.out.println("1+1=" + sum); + + Work work = new Work(); + + work.op = Operation.DIVIDE; + work.num1 = 1; + work.num2 = 0; + try { + int quotient = client.calculate(1, work); + System.out.println("Whoa we can divide by 0"); + } catch (InvalidOperation io) { + System.out.println("Invalid operation: " + io.why); + } + + work.op = Operation.SUBTRACT; + work.num1 = 15; + work.num2 = 10; + try { + int diff = client.calculate(1, work); + System.out.println("15-10=" + diff); + } catch (InvalidOperation io) { + System.out.println("Invalid operation: " + io.why); + } + + SharedStruct log = client.getStruct(1); + System.out.println("Check log: " + log.value); + } +} diff --git a/tutorial/java/src/JavaServer.java b/tutorial/java/src/JavaServer.java new file mode 100644 index 0000000..788473a --- /dev/null +++ b/tutorial/java/src/JavaServer.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.thrift.server.TServer; +import org.apache.thrift.server.TServer.Args; +import org.apache.thrift.server.TSimpleServer; +import org.apache.thrift.server.TThreadPoolServer; +import org.apache.thrift.transport.TSSLTransportFactory; +import org.apache.thrift.transport.TServerSocket; +import org.apache.thrift.transport.TServerTransport; +import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters; + +// Generated code +import tutorial.*; +import shared.*; + +import java.util.HashMap; + +public class JavaServer { + + public static CalculatorHandler handler; + + public static Calculator.Processor processor; + + public static void main(String [] args) { + try { + handler = new CalculatorHandler(); + processor = new Calculator.Processor(handler); + + Runnable simple = new Runnable() { + public void run() { + simple(processor); + } + }; + Runnable secure = new Runnable() { + public void run() { + secure(processor); + } + }; + + new Thread(simple).start(); + new Thread(secure).start(); + } catch (Exception x) { + x.printStackTrace(); + } + } + + public static void simple(Calculator.Processor processor) { + try { + TServerTransport serverTransport = new TServerSocket(9090); + TServer server = new TSimpleServer(new Args(serverTransport).processor(processor)); + + // Use this for a multithreaded server + // TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor)); + + System.out.println("Starting the simple server..."); + server.serve(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void secure(Calculator.Processor processor) { + try { + /* + * Use TSSLTransportParameters to setup the required SSL parameters. In this example + * we are setting the keystore and the keystore password. Other things like algorithms, + * cipher suites, client auth etc can be set. + */ + TSSLTransportParameters params = new TSSLTransportParameters(); + // The Keystore contains the private key + params.setKeyStore("../../lib/java/test/.keystore", "thrift", null, null); + + /* + * Use any of the TSSLTransportFactory to get a server transport with the appropriate + * SSL configuration. You can use the default settings if properties are set in the command line. + * Ex: -Djavax.net.ssl.keyStore=.keystore and -Djavax.net.ssl.keyStorePassword=thrift + * + * Note: You need not explicitly call open(). The underlying server socket is bound on return + * from the factory class. + */ + TServerTransport serverTransport = TSSLTransportFactory.getServerSocket(9091, 0, null, params); + TServer server = new TSimpleServer(new Args(serverTransport).processor(processor)); + + // Use this for a multi threaded server + // TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor)); + + System.out.println("Starting the secure server..."); + server.serve(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/tutorial/js/Makefile.am b/tutorial/js/Makefile.am new file mode 100755 index 0000000..3fe0888 --- /dev/null +++ b/tutorial/js/Makefile.am @@ -0,0 +1,39 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +export CLASSPATH + +# Make sure this doesn't fail if ant is not configured. +clean-local: + ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ + $$ANT $(ANT_FLAGS) clean + +all-local: + $(ANT) $(ANT_FLAGS) compile + +check-local: all + $(ANT) $(ANT_FLAGS) test + +tutorialserver: all + $(ANT) $(ANT_FLAGS) tutorialserver + +EXTRA_DIST = \ + build.xml \ + src \ + tutorial.html diff --git a/tutorial/js/Makefile.in b/tutorial/js/Makefile.in new file mode 100644 index 0000000..e8a325a --- /dev/null +++ b/tutorial/js/Makefile.in @@ -0,0 +1,645 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tutorial/js +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + build.xml \ + src \ + tutorial.html + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/js/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tutorial/js/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: all all-am all-local check check-am check-local clean \ + clean-generic clean-libtool clean-local cscopelist-am ctags-am \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +export CLASSPATH + +# Make sure this doesn't fail if ant is not configured. +clean-local: + ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ + $$ANT $(ANT_FLAGS) clean + +all-local: + $(ANT) $(ANT_FLAGS) compile + +check-local: all + $(ANT) $(ANT_FLAGS) test + +tutorialserver: all + $(ANT) $(ANT_FLAGS) tutorialserver + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tutorial/js/build.xml b/tutorial/js/build.xml new file mode 100644 index 0000000..2df2e71 --- /dev/null +++ b/tutorial/js/build.xml @@ -0,0 +1,90 @@ + + + + Thrift JavaScript Tutorial + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tutorial/js/src/Httpd.java b/tutorial/js/src/Httpd.java new file mode 100644 index 0000000..4985471 --- /dev/null +++ b/tutorial/js/src/Httpd.java @@ -0,0 +1,299 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +import java.io.File; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URLDecoder; +import java.util.Locale; + +import org.apache.http.ConnectionClosedException; +import org.apache.http.HttpEntity; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.HttpServerConnection; +import org.apache.http.HttpStatus; +import org.apache.http.MethodNotSupportedException; +import org.apache.http.entity.ContentProducer; +import org.apache.http.entity.EntityTemplate; +import org.apache.http.entity.FileEntity; +import org.apache.http.impl.DefaultHttpResponseFactory; +import org.apache.http.impl.DefaultHttpServerConnection; +import org.apache.http.impl.NoConnectionReuseStrategy; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.params.CoreProtocolPNames; +import org.apache.http.params.HttpParams; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.BasicHttpProcessor; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpProcessor; +import org.apache.http.protocol.HttpRequestHandler; +import org.apache.http.protocol.HttpRequestHandlerRegistry; +import org.apache.http.protocol.HttpService; +import org.apache.http.util.EntityUtils; +import org.apache.thrift.TProcessor; +import org.apache.thrift.protocol.TJSONProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.transport.TMemoryBuffer; + +// Generated code +import tutorial.*; +import shared.*; + +import java.util.HashMap; + +/** + * Basic, yet fully functional and spec compliant, HTTP/1.1 file server. + *

+ * Please note the purpose of this application is demonstrate the usage of + * HttpCore APIs. It is NOT intended to demonstrate the most efficient way of + * building an HTTP file server. + * + * + */ +public class Httpd { + + public static void main(String[] args) throws Exception { + if (args.length < 1) { + System.err.println("Please specify document root directory"); + System.exit(1); + } + Thread t = new RequestListenerThread(8088, args[0]); + t.setDaemon(false); + t.start(); + } + + static class HttpFileHandler implements HttpRequestHandler { + + private final String docRoot; + + public HttpFileHandler(final String docRoot) { + super(); + this.docRoot = docRoot; + } + + public void handle(final HttpRequest request, final HttpResponse response, final HttpContext context) throws HttpException, IOException { + + String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH); + if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST")) { + throw new MethodNotSupportedException(method + " method not supported"); + } + String target = request.getRequestLine().getUri(); + + if (request instanceof HttpEntityEnclosingRequest && target.equals("/thrift/service/tutorial/")) { + HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); + byte[] entityContent = EntityUtils.toByteArray(entity); + System.out.println("Incoming content: " + new String(entityContent)); + + final String output = this.thriftRequest(entityContent); + + System.out.println("Outgoing content: "+output); + + EntityTemplate body = new EntityTemplate(new ContentProducer() { + + public void writeTo(final OutputStream outstream) throws IOException { + OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8"); + writer.write(output); + writer.flush(); + } + + }); + body.setContentType("text/html; charset=UTF-8"); + response.setEntity(body); + } else { + final File file = new File(this.docRoot, URLDecoder.decode(target, "UTF-8")); + if (!file.exists()) { + + response.setStatusCode(HttpStatus.SC_NOT_FOUND); + EntityTemplate body = new EntityTemplate(new ContentProducer() { + + public void writeTo(final OutputStream outstream) throws IOException { + OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8"); + writer.write("

"); + writer.write("File "); + writer.write(file.getPath()); + writer.write(" not found"); + writer.write("

"); + writer.flush(); + } + + }); + body.setContentType("text/html; charset=UTF-8"); + response.setEntity(body); + System.out.println("File " + file.getPath() + " not found"); + + } else if (!file.canRead() || file.isDirectory()) { + + response.setStatusCode(HttpStatus.SC_FORBIDDEN); + EntityTemplate body = new EntityTemplate(new ContentProducer() { + + public void writeTo(final OutputStream outstream) throws IOException { + OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8"); + writer.write("

"); + writer.write("Access denied"); + writer.write("

"); + writer.flush(); + } + + }); + body.setContentType("text/html; charset=UTF-8"); + response.setEntity(body); + System.out.println("Cannot read file " + file.getPath()); + + } else { + + response.setStatusCode(HttpStatus.SC_OK); + FileEntity body = new FileEntity(file, "text/html"); + response.setEntity(body); + System.out.println("Serving file " + file.getPath()); + + } + } + } + + private String thriftRequest(byte[] input){ + try{ + + //Input + TMemoryBuffer inbuffer = new TMemoryBuffer(input.length); + inbuffer.write(input); + TProtocol inprotocol = new TJSONProtocol(inbuffer); + + //Output + TMemoryBuffer outbuffer = new TMemoryBuffer(100); + TProtocol outprotocol = new TJSONProtocol(outbuffer); + + TProcessor processor = new Calculator.Processor(new CalculatorHandler()); + processor.process(inprotocol, outprotocol); + + byte[] output = new byte[outbuffer.length()]; + outbuffer.readAll(output, 0, output.length); + + return new String(output,"UTF-8"); + }catch(Throwable t){ + return "Error:"+t.getMessage(); + } + + + } + + } + + static class RequestListenerThread extends Thread { + + private final ServerSocket serversocket; + private final HttpParams params; + private final HttpService httpService; + + public RequestListenerThread(int port, final String docroot) throws IOException { + this.serversocket = new ServerSocket(port); + this.params = new BasicHttpParams(); + this.params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 1000).setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) + .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false).setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) + .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); + + // Set up the HTTP protocol processor + HttpProcessor httpproc = new BasicHttpProcessor(); + + // Set up request handlers + HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry(); + reqistry.register("*", new HttpFileHandler(docroot)); + + // Set up the HTTP service + this.httpService = new HttpService(httpproc, new NoConnectionReuseStrategy(), new DefaultHttpResponseFactory()); + this.httpService.setParams(this.params); + this.httpService.setHandlerResolver(reqistry); + } + + public void run() { + System.out.println("Listening on port " + this.serversocket.getLocalPort()); + System.out.println("Point your browser to http://localhost:8088/tutorial/js/tutorial.html"); + + while (!Thread.interrupted()) { + try { + // Set up HTTP connection + Socket socket = this.serversocket.accept(); + DefaultHttpServerConnection conn = new DefaultHttpServerConnection(); + System.out.println("Incoming connection from " + socket.getInetAddress()); + conn.bind(socket, this.params); + + // Start worker thread + Thread t = new WorkerThread(this.httpService, conn); + t.setDaemon(true); + t.start(); + } catch (InterruptedIOException ex) { + break; + } catch (IOException e) { + System.err.println("I/O error initialising connection thread: " + e.getMessage()); + break; + } + } + } + } + + static class WorkerThread extends Thread { + + private final HttpService httpservice; + private final HttpServerConnection conn; + + public WorkerThread(final HttpService httpservice, final HttpServerConnection conn) { + super(); + this.httpservice = httpservice; + this.conn = conn; + } + + public void run() { + System.out.println("New connection thread"); + HttpContext context = new BasicHttpContext(null); + try { + while (!Thread.interrupted() && this.conn.isOpen()) { + this.httpservice.handleRequest(this.conn, context); + } + } catch (ConnectionClosedException ex) { + System.err.println("Client closed connection"); + } catch (IOException ex) { + System.err.println("I/O error: " + ex.getMessage()); + } catch (HttpException ex) { + System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage()); + } finally { + try { + this.conn.shutdown(); + } catch (IOException ignore) { + } + } + } + + } + +} diff --git a/tutorial/js/tutorial.html b/tutorial/js/tutorial.html new file mode 100755 index 0000000..d7f3945 --- /dev/null +++ b/tutorial/js/tutorial.html @@ -0,0 +1,109 @@ + + + + + + Thrift Javascript Bindings - Tutorial Example + + + + + + + + + + + + + + +

Thrift Javascript Bindings

+
+ + + + + + + + + + + + + + + + + + + +
num1
Operation
num2
result
autoupdate
+
+ +

This Java Script example uses tutorial.thrift and a Thrift server using JSON protocol and HTTP transport. +

+

+ Valid XHTML 1.0! +

+ + diff --git a/tutorial/netcore/Client/Client.csproj b/tutorial/netcore/Client/Client.csproj new file mode 100644 index 0000000..911272d --- /dev/null +++ b/tutorial/netcore/Client/Client.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp2.0 + Client + Client + Exe + false + false + false + false + + + + + + + + diff --git a/tutorial/netcore/Client/Program.cs b/tutorial/netcore/Client/Program.cs new file mode 100644 index 0000000..ae1837b --- /dev/null +++ b/tutorial/netcore/Client/Program.cs @@ -0,0 +1,355 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Thrift; +using Thrift.Protocols; +using Thrift.Transports; +using Thrift.Transports.Client; +using tutorial; +using shared; + +namespace Client +{ + public class Program + { + private static readonly ILogger Logger = new LoggerFactory().AddConsole().AddDebug().CreateLogger(nameof(Client)); + + private static void DisplayHelp() + { + Logger.LogInformation(@" +Usage: + Client.exe -h + will diplay help information + + Client.exe -t: -p: -mc: + will run client with specified arguments (tcp transport and binary protocol by default) and with 1 client + +Options: + -t (transport): + tcp - (default) tcp transport will be used (host - ""localhost"", port - 9090) + tcpbuffered - buffered transport over tcp will be used (host - ""localhost"", port - 9090) + namedpipe - namedpipe transport will be used (pipe address - "".test"") + http - http transport will be used (address - ""http://localhost:9090"") + tcptls - tcp tls transport will be used (host - ""localhost"", port - 9090) + framed - tcp framed transport will be used (host - ""localhost"", port - 9090) + + -p (protocol): + binary - (default) binary protocol will be used + compact - compact protocol will be used + json - json protocol will be used + multiplexed - multiplexed protocol will be used + + -mc (multiple clients): + - number of multiple clients to connect to server (max 100, default 1) + +Sample: + Client.exe -t:tcp -p:binary +"); + } + + public static void Main(string[] args) + { + args = args ?? new string[0]; + + if (args.Any(x => x.StartsWith("-h", StringComparison.OrdinalIgnoreCase))) + { + DisplayHelp(); + return; + } + + Logger.LogInformation("Starting client..."); + + using (var source = new CancellationTokenSource()) + { + RunAsync(args, source.Token).GetAwaiter().GetResult(); + } + } + + private static async Task RunAsync(string[] args, CancellationToken cancellationToken) + { + var numClients = GetNumberOfClients(args); + + Logger.LogInformation($"Selected # of clients: {numClients}"); + + var transports = new TClientTransport[numClients]; + for (int i = 0; i < numClients; i++) + { + var t = GetTransport(args); + transports[i] = t; + } + + Logger.LogInformation($"Selected client transport: {transports[0]}"); + + var protocols = new Tuple[numClients]; + for (int i = 0; i < numClients; i++) + { + var p = GetProtocol(args, transports[i]); + protocols[i] = p; + } + + Logger.LogInformation($"Selected client protocol: {protocols[0].Item1}"); + + var tasks = new Task[numClients]; + for (int i = 0; i < numClients; i++) + { + var task = RunClientAsync(protocols[i], cancellationToken); + tasks[i] = task; + } + + Task.WaitAll(tasks); + + await Task.CompletedTask; + } + + private static TClientTransport GetTransport(string[] args) + { + var transport = args.FirstOrDefault(x => x.StartsWith("-t"))?.Split(':')?[1]; + + Transport selectedTransport; + if (Enum.TryParse(transport, true, out selectedTransport)) + { + switch (selectedTransport) + { + case Transport.Tcp: + return new TSocketClientTransport(IPAddress.Loopback, 9090); + case Transport.NamedPipe: + return new TNamedPipeClientTransport(".test"); + case Transport.Http: + return new THttpClientTransport(new Uri("http://localhost:9090"), null); + case Transport.TcpBuffered: + return new TBufferedClientTransport(new TSocketClientTransport(IPAddress.Loopback, 9090)); + case Transport.TcpTls: + return new TTlsSocketClientTransport(IPAddress.Loopback, 9090, GetCertificate(), CertValidator, LocalCertificateSelectionCallback); + case Transport.Framed: + return new TFramedClientTransport(new TSocketClientTransport(IPAddress.Loopback, 9090)); + } + } + + return new TSocketClientTransport(IPAddress.Loopback, 9090); + } + + private static int GetNumberOfClients(string[] args) + { + var numClients = args.FirstOrDefault(x => x.StartsWith("-mc"))?.Split(':')?[1]; + + Logger.LogInformation($"Selected # of clients: {numClients}"); + + int c; + if( int.TryParse(numClients, out c) && (0 < c) && (c <= 100)) + return c; + else + return 1; + } + + private static X509Certificate2 GetCertificate() + { + // due to files location in net core better to take certs from top folder + var certFile = GetCertPath(Directory.GetParent(Directory.GetCurrentDirectory())); + return new X509Certificate2(certFile, "ThriftTest"); + } + + private static string GetCertPath(DirectoryInfo di, int maxCount = 6) + { + var topDir = di; + var certFile = + topDir.EnumerateFiles("ThriftTest.pfx", SearchOption.AllDirectories) + .FirstOrDefault(); + if (certFile == null) + { + if (maxCount == 0) + throw new FileNotFoundException("Cannot find file in directories"); + return GetCertPath(di.Parent, maxCount - 1); + } + + return certFile.FullName; + } + + private static X509Certificate LocalCertificateSelectionCallback(object sender, + string targetHost, X509CertificateCollection localCertificates, + X509Certificate remoteCertificate, string[] acceptableIssuers) + { + return GetCertificate(); + } + + private static bool CertValidator(object sender, X509Certificate certificate, + X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + return true; + } + + private static Tuple GetProtocol(string[] args, TClientTransport transport) + { + var protocol = args.FirstOrDefault(x => x.StartsWith("-p"))?.Split(':')?[1]; + + Protocol selectedProtocol; + if (Enum.TryParse(protocol, true, out selectedProtocol)) + { + switch (selectedProtocol) + { + case Protocol.Binary: + return new Tuple(selectedProtocol, new TBinaryProtocol(transport)); + case Protocol.Compact: + return new Tuple(selectedProtocol, new TCompactProtocol(transport)); + case Protocol.Json: + return new Tuple(selectedProtocol, new TJsonProtocol(transport)); + case Protocol.Multiplexed: + // it returns BinaryProtocol to avoid making wrapped protocol as public in TProtocolDecorator (in RunClientAsync it will be wrapped into Multiplexed protocol) + return new Tuple(selectedProtocol, new TBinaryProtocol(transport)); + } + } + + return new Tuple(selectedProtocol, new TBinaryProtocol(transport)); + } + + private static async Task RunClientAsync(Tuple protocolTuple, CancellationToken cancellationToken) + { + try + { + var protocol = protocolTuple.Item2; + var protocolType = protocolTuple.Item1; + + TBaseClient client = null; + + try + { + if (protocolType != Protocol.Multiplexed) + { + + client = new Calculator.Client(protocol); + await ExecuteCalculatorClientOperations(cancellationToken, (Calculator.Client)client); + } + else + { + // it uses binary protocol there to create Multiplexed protocols + var multiplex = new TMultiplexedProtocol(protocol, nameof(Calculator)); + client = new Calculator.Client(multiplex); + await ExecuteCalculatorClientOperations(cancellationToken, (Calculator.Client)client); + + multiplex = new TMultiplexedProtocol(protocol, nameof(SharedService)); + client = new SharedService.Client(multiplex); + await ExecuteSharedServiceClientOperations(cancellationToken, (SharedService.Client)client); + } + } + catch (Exception ex) + { + Logger.LogError($"{client?.ClientId} " + ex); + } + finally + { + protocol.Transport.Close(); + } + } + catch (TApplicationException x) + { + Logger.LogError(x.ToString()); + } + } + + private static async Task ExecuteCalculatorClientOperations(CancellationToken cancellationToken, Calculator.Client client) + { + await client.OpenTransportAsync(cancellationToken); + + // Async version + + Logger.LogInformation($"{client.ClientId} PingAsync()"); + await client.pingAsync(cancellationToken); + + Logger.LogInformation($"{client.ClientId} AddAsync(1,1)"); + var sum = await client.addAsync(1, 1, cancellationToken); + Logger.LogInformation($"{client.ClientId} AddAsync(1,1)={sum}"); + + var work = new Work + { + Op = Operation.DIVIDE, + Num1 = 1, + Num2 = 0 + }; + + try + { + Logger.LogInformation($"{client.ClientId} CalculateAsync(1)"); + await client.calculateAsync(1, work, cancellationToken); + Logger.LogInformation($"{client.ClientId} Whoa we can divide by 0"); + } + catch (InvalidOperation io) + { + Logger.LogInformation($"{client.ClientId} Invalid operation: " + io); + } + + work.Op = Operation.SUBTRACT; + work.Num1 = 15; + work.Num2 = 10; + + try + { + Logger.LogInformation($"{client.ClientId} CalculateAsync(1)"); + var diff = await client.calculateAsync(1, work, cancellationToken); + Logger.LogInformation($"{client.ClientId} 15-10={diff}"); + } + catch (InvalidOperation io) + { + Logger.LogInformation($"{client.ClientId} Invalid operation: " + io); + } + + Logger.LogInformation($"{client.ClientId} GetStructAsync(1)"); + var log = await client.getStructAsync(1, cancellationToken); + Logger.LogInformation($"{client.ClientId} Check log: {log.Value}"); + + Logger.LogInformation($"{client.ClientId} ZipAsync() with delay 100mc on server side"); + await client.zipAsync(cancellationToken); + } + private static async Task ExecuteSharedServiceClientOperations(CancellationToken cancellationToken, SharedService.Client client) + { + await client.OpenTransportAsync(cancellationToken); + + // Async version + + Logger.LogInformation($"{client.ClientId} SharedService GetStructAsync(1)"); + var log = await client.getStructAsync(1, cancellationToken); + Logger.LogInformation($"{client.ClientId} SharedService Value: {log.Value}"); + } + + + private enum Transport + { + Tcp, + NamedPipe, + Http, + TcpBuffered, + Framed, + TcpTls + } + + private enum Protocol + { + Binary, + Compact, + Json, + Multiplexed + } + } +} \ No newline at end of file diff --git a/tutorial/netcore/Client/Properties/AssemblyInfo.cs b/tutorial/netcore/Client/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..568382e --- /dev/null +++ b/tutorial/netcore/Client/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("The Apache Software Foundation")] +[assembly: AssemblyProduct("Thrift")] +[assembly: AssemblyCopyright("The Apache Software Foundation")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. + +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM + +[assembly: Guid("de78a01b-f7c6-49d1-97da-669d2ed37641")] \ No newline at end of file diff --git a/tutorial/netcore/Client/Properties/launchSettings.json b/tutorial/netcore/Client/Properties/launchSettings.json new file mode 100644 index 0000000..6b7b60d --- /dev/null +++ b/tutorial/netcore/Client/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Client": { + "commandName": "Project", + "commandLineArgs": "-p:multiplexed" + } + } +} \ No newline at end of file diff --git a/tutorial/netcore/Client/ThriftTest.pfx b/tutorial/netcore/Client/ThriftTest.pfx new file mode 100644 index 0000000000000000000000000000000000000000..f0ded28173dc2c33cebbb2b74e1e9e9e870b5876 GIT binary patch literal 2661 zcmY+Fc{r5q7ssC&Gb1!J$(kiQNi-_kNTzK}lBB4-#%>tDNgCV8K7;IKOK6d75tC&a zp={ZTH)}K@WXZmpv83PB^)A`wF(pXt7XpsY=bHUSlV3;5-A{d&ZS=A9rAjL!JLlxE zU_0M6u}dL5dyZUM*eZRTK7%!HnQk@RhDO-B4XYapVO%Fw7K^smqmrq9#TGaL=NEIm z?!`FK&>hR?Z@)%UKPau-%?m`A(>#}=i#q*6>Xe+P#mwBs6Q0@@Ixp|5@9I+wut zA#tRevtir~_G0T(aAFKzvy!O$=C`*W)A|(nrt(YY1n}Kp^LEZq_lyzXl)hwOG@G=i zxbiB-SnTQD^sz>x%QCdt1fw!Er?MpQ>#O~U^B1Ih|GdFM1{`4ISt#RHN4|ZYyq|=< z{j;$~n=*954;otf@)^47LvcfPIKt$_Y2BL+D}7sV7s{aov!F89pkkhg#@d`RVvtv8 zqhf(QFGtL@?Vi^c`LJWbZE9|TN_1?X9?l3DaIjMO5`V9F;~;j1FwiWFV#DZK zPZjSTs!0RAwSeaugCPfE_z~82e~?}o;1!SDpMJeV`Q?+Y@TQRE z%jhKjwXIG1?LW{8%1ry~$CvoFtuttc!kQ${aiZfTlsc}(9#g1pD3VzLU3ij7h2^CD z;6Lz8^m(Xe5?)8Y0Gr#QxBP*P)`mX~ycEnzpRed9N46To2eUk?5^Lp}$Xu=>65C8xu{J&6G(`>&f z-~~7X>HrGR1atr=u0{d&fFqaa0!O&99#K(?2gPlgcy9MFU_Ez}9Obs^@?Q}%0v{+j;MU>669QYwovF;u<-Oys<_RI{b3>F|lw0+!xJ>$_T%M|8 z*-&MWR7IRjyg|Rdz}Y^1c3>+=Wp`aAotnEcJk{mR2!9S=p@lzc?XYcYm9LJXMtHbTOVA7ageNhdBfi0|v1eLr9PtqI`)XEsA zC0p*r#f2MT4Hybzy5V<-3)*Qcno)THYn1lrjq6Dik zc86XkszLcvn;9QTVpJ9nk<@$OqssciMrRF6FvCqZbspu(u*qkj2*`%Mz8yK zJdDp2+luWj&vuSBXbE_thM;=6A| zTxptZh*kG4;p+`oVSXP~RY=Ckmncb%Q_UISo?$+pr{w0qs^nnM(Hjvem6Iv&+#MtM zv{NJq4}S()s9l6QL`u&D)**e1PVG7Kle}4G&E6j*6WUk@Gf{A7t$m7Kzgxiio)Vux zaUZfKT(@FZ>2x``Vy-=XKo?(27vH5gZ(9I{TgrlFvqh3z9qJGySLfwbj9a-H4Nq*qFpUg@ld}K z)hFz#CqBwVT7Rl=a|*hQAa-`0o9X{L*g@fX}@vnbf G^#21?=Cu0& literal 0 HcmV?d00001 diff --git a/tutorial/netcore/Interfaces/Interfaces.csproj b/tutorial/netcore/Interfaces/Interfaces.csproj new file mode 100644 index 0000000..14fad79 --- /dev/null +++ b/tutorial/netcore/Interfaces/Interfaces.csproj @@ -0,0 +1,20 @@ + + + + netstandard2.0 + Interfaces + Interfaces + false + false + false + false + + + + + + + + + + diff --git a/tutorial/netcore/Interfaces/Properties/AssemblyInfo.cs b/tutorial/netcore/Interfaces/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9126b17 --- /dev/null +++ b/tutorial/netcore/Interfaces/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("The Apache Software Foundation")] +[assembly: AssemblyProduct("Thrift")] +[assembly: AssemblyCopyright("The Apache Software Foundation")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. + +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM + +[assembly: Guid("4d13163d-9067-4c9c-8af0-64e08451397d")] \ No newline at end of file diff --git a/tutorial/netcore/Makefile.am b/tutorial/netcore/Makefile.am new file mode 100644 index 0000000..ef3d618 --- /dev/null +++ b/tutorial/netcore/Makefile.am @@ -0,0 +1,75 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +SUBDIRS = . + +THRIFT = $(top_builddir)/compiler/cpp/thrift + +GENDIR = Interfaces/gen-netcore + +# Due to a known issue with "dotnet restore" the Thrift.dll dependency cannot be resolved from cmdline. +# The problem does NOT affect Visual Studio builds, only cmdline. +# - For details see https://github.com/dotnet/cli/issues/3199 and related tickets. +# - Workaround is to temporarily copy the Thrift project into the solution +COPYCMD = cp -u -p -r + + +THRIFTCODE = \ + Interfaces/Properties/AssemblyInfo.cs \ + Client/Properties/AssemblyInfo.cs \ + Client/Program.cs \ + Server/Properties/AssemblyInfo.cs \ + Server/Program.cs + +all-local: \ + Client.exe + +Client.exe: $(THRIFTCODE) + $(MKDIR_P) $(GENDIR) + $(THRIFT) -gen netcore:wcf -r -out $(GENDIR) $(top_srcdir)/tutorial/tutorial.thrift + $(DOTNETCORE) --info + $(DOTNETCORE) restore + $(DOTNETCORE) build + +clean-local: + $(RM) Client.exe + $(RM) Server.exe + $(RM) Interfaces.dll + $(RM) -r $(GENDIR) + $(RM) -r Client/bin + $(RM) -r Client/obj + $(RM) -r Server/bin + $(RM) -r Server/obj + $(RM) -r Interfaces/bin + $(RM) -r Interfaces/obj + +EXTRA_DIST = \ + $(THRIFTCODE) \ + Tutorial.sln \ + Interfaces/Interfaces.csproj \ + Client/Client.csproj \ + Client/ThriftTest.pfx \ + Client/Properties/launchSettings.json \ + Server/Server.csproj \ + Server/ThriftTest.pfx \ + Server/Properties/launchSettings.json \ + build.cmd \ + build.sh \ + README.md + diff --git a/tutorial/netcore/Makefile.in b/tutorial/netcore/Makefile.in new file mode 100644 index 0000000..093e310 --- /dev/null +++ b/tutorial/netcore/Makefile.in @@ -0,0 +1,854 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tutorial/netcore +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = $(top_builddir)/compiler/cpp/thrift +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . +GENDIR = Interfaces/gen-netcore + +# Due to a known issue with "dotnet restore" the Thrift.dll dependency cannot be resolved from cmdline. +# The problem does NOT affect Visual Studio builds, only cmdline. +# - For details see https://github.com/dotnet/cli/issues/3199 and related tickets. +# - Workaround is to temporarily copy the Thrift project into the solution +COPYCMD = cp -u -p -r +THRIFTCODE = \ + Interfaces/Properties/AssemblyInfo.cs \ + Client/Properties/AssemblyInfo.cs \ + Client/Program.cs \ + Server/Properties/AssemblyInfo.cs \ + Server/Program.cs + +EXTRA_DIST = \ + $(THRIFTCODE) \ + Tutorial.sln \ + Interfaces/Interfaces.csproj \ + Client/Client.csproj \ + Client/ThriftTest.pfx \ + Client/Properties/launchSettings.json \ + Server/Server.csproj \ + Server/ThriftTest.pfx \ + Server/Properties/launchSettings.json \ + build.cmd \ + build.sh \ + README.md + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/netcore/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tutorial/netcore/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" +style-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile all-local +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +style: style-recursive + +style-am: style-local + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \ + check check-am clean clean-generic clean-libtool clean-local \ + cscopelist-am ctags ctags-am distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +all-local: \ + Client.exe + +Client.exe: $(THRIFTCODE) + $(MKDIR_P) $(GENDIR) + $(THRIFT) -gen netcore:wcf -r -out $(GENDIR) $(top_srcdir)/tutorial/tutorial.thrift + $(DOTNETCORE) --info + $(DOTNETCORE) restore + $(DOTNETCORE) build + +clean-local: + $(RM) Client.exe + $(RM) Server.exe + $(RM) Interfaces.dll + $(RM) -r $(GENDIR) + $(RM) -r Client/bin + $(RM) -r Client/obj + $(RM) -r Server/bin + $(RM) -r Server/obj + $(RM) -r Interfaces/bin + $(RM) -r Interfaces/obj + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tutorial/netcore/README.md b/tutorial/netcore/README.md new file mode 100644 index 0000000..6b2f660 --- /dev/null +++ b/tutorial/netcore/README.md @@ -0,0 +1,281 @@ +# Building of samples for different platforms + +# Reused components +- NET Core Standard 1.6 (SDK 1.0.0-preview2-003121) +- NET Core App 1.1 + +# How to build +- Download and install .NET Core SDK for your platform https://www.microsoft.com/net/core#windowsvs2015 (archive for SDK 1.0.0-preview2-003121 located by: https://github.com/dotnet/core/blob/master/release-notes/download-archive.md) +- Ensure that you have thrift.exe which supports netcore lib and it added to PATH +- Go to current folder +- Run **build.sh** or **build.cmd** from the root of cloned repository +- Check tests in **src/Tests** folder +- Continue with /tutorials/netcore + +# How to run + +Notes: dotnet run supports passing arguments to app after -- symbols (https://docs.microsoft.com/en-us/dotnet/articles/core/tools/dotnet-run) - example: **dotnet run -- -h** will show help for app + +- build +- go to folder (Client/Server) +- run with specifying of correct parameters **dotnet run -t:tcp -p:multiplexed**, **dotnet run -help** (later, after migration to csproj and latest SDK will be possibility to use more usable form **dotnet run -- arguments**) + +#Notes +- Migration to .NET Standard 2.0 planned for later (Q1 2017) according to https://blogs.msdn.microsoft.com/dotnet/2016/09/26/introducing-net-standard/ +- Possible adding additional platforms after stabilization of .NET Core (runtimes, platforms (Red Hat Linux, OpenSuse, etc.) + +#Known issues +- In trace logging mode you can see some not important internal exceptions +- Ubuntu 16.10 still not supported fully +- There is some problems with .NET Core CLI and usage specific -r|--runtime for building and publishing projects with different target frameworks (netstandard1.6 and netcoreapp1.1) + +# Running of samples +Please install Thrift C# .NET Core library or copy sources and build them to correcly build and run samples + +# NetCore Server + +Usage: + + Server.exe -h + will diplay help information + + Server.exe -t: -p: + will run server with specified arguments (tcp transport and binary protocol by default) + +Options: + + -t (transport): + tcp - (default) tcp transport will be used (host - ""localhost"", port - 9090) + tcpbuffered - tcp buffered transport will be used (host - ""localhost"", port - 9090) + namedpipe - namedpipe transport will be used (pipe address - "".test"") + http - http transport will be used (http address - ""localhost:9090"") + tcptls - tcp transport with tls will be used (host - ""localhost"", port - 9090) + framed - tcp framed transport will be used (host - ""localhost"", port - 9090) + + -p (protocol): + binary - (default) binary protocol will be used + compact - compact protocol will be used + json - json protocol will be used + +Sample: + + Server.exe -t:tcp + +**Remarks**: + + For TcpTls mode certificate's file ThriftTest.pfx should be in directory with binaries in case of command line usage (or at project level in case of debugging from IDE). + Password for certificate - "ThriftTest". + + + +# NetCore Client + +Usage: + + Client.exe -h + will diplay help information + + Client.exe -t: -p: -mc: + will run client with specified arguments (tcp transport and binary protocol by default) + +Options: + + -t (transport): + tcp - (default) tcp transport will be used (host - ""localhost"", port - 9090) + tcpbuffered - buffered transport over tcp will be used (host - ""localhost"", port - 9090) + namedpipe - namedpipe transport will be used (pipe address - "".test"") + http - http transport will be used (address - ""http://localhost:9090"") + tcptls - tcp tls transport will be used (host - ""localhost"", port - 9090) + framed - tcp framed transport will be used (host - ""localhost"", port - 9090) + + -p (protocol): + binary - (default) binary protocol will be used + compact - compact protocol will be used + json - json protocol will be used + + -mc (multiple clients): + - number of multiple clients to connect to server (max 100, default 1) + +Sample: + + Client.exe -t:tcp -p:binary -mc:10 + +Remarks: + + For TcpTls mode certificate's file ThriftTest.pfx should be in directory + with binaries in case of command line usage (or at project level in case of debugging from IDE). + Password for certificate - "ThriftTest". + +# How to test communication between NetCore and Python + +* Generate code with the latest **thrift.exe** util +* Ensure that **thrift.exe** util generated folder **gen-py** with generated code for Python +* Create **client.py** and **server.py** from the code examples below and save them to the folder with previosly generated folder **gen-py** +* Run netcore samples (client and server) and python samples (client and server) + +Remarks: + +Samples of client and server code below use correct methods (operations) +and fields (properties) according to generated contracts from *.thrift files + +At Windows 10 add record **127.0.0.1 testserver** to **C:\Windows\System32\drivers\etc\hosts** file +for correct work of python server + + +**Python Client:** + +```python +import sys +import glob +sys.path.append('gen-py') + +from tutorial import Calculator +from tutorial.ttypes import InvalidOperation, Operation, Work + +from thrift import Thrift +from thrift.transport import TSocket +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol + + +def main(): + # Make socket + transport = TSocket.TSocket('127.0.0.1', 9090) + + # Buffering is critical. Raw sockets are very slow + transport = TTransport.TBufferedTransport(transport) + + # Wrap in a protocol + protocol = TBinaryProtocol.TBinaryProtocol(transport) + + # Create a client to use the protocol encoder + client = Calculator.Client(protocol) + + # Connect! + transport.open() + + client.Ping() + print('ping()') + + sum = client.Add(1, 1) + print(('1+1=%d' % (sum))) + + work = Work() + + work.Op = Operation.Divide + work.Num1 = 1 + work.Num2 = 0 + + try: + quotient = client.Calculate(1, work) + print('Whoa? You know how to divide by zero?') + print('FYI the answer is %d' % quotient) + except InvalidOperation as e: + print(('InvalidOperation: %r' % e)) + + work.Op = Operation.Substract + work.Num1 = 15 + work.Num2 = 10 + + diff = client.Calculate(1, work) + print(('15-10=%d' % (diff))) + + log = client.GetStruct(1) + print(('Check log: %s' % (log.Value))) + + client.Zip() + print('zip()') + + # Close! + transport.close() + +if __name__ == '__main__': + try: + main() + except Thrift.TException as tx: + print('%s' % tx.message) +``` + + +**Python Server:** + + +```python +import glob +import sys +sys.path.append('gen-py') + +from tutorial import Calculator +from tutorial.ttypes import InvalidOperation, Operation + +from shared.ttypes import SharedStruct + +from thrift.transport import TSocket +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol +from thrift.server import TServer + + +class CalculatorHandler: + def __init__(self): + self.log = {} + + def Ping(self): + print('ping()') + + def Add(self, n1, n2): + print('add(%d,%d)' % (n1, n2)) + return n1 + n2 + + def Calculate(self, logid, work): + print('calculate(%d, %r)' % (logid, work)) + + if work.Op == Operation.Add: + val = work.Num1 + work.Num2 + elif work.Op == Operation.Substract: + val = work.Num1 - work.Num2 + elif work.Op == Operation.Multiply: + val = work.Num1 * work.Num2 + elif work.Op == Operation.Divide: + if work.Num2 == 0: + x = InvalidOperation() + x.WhatOp = work.Op + x.Why = 'Cannot divide by 0' + raise x + val = work.Num1 / work.Num2 + else: + x = InvalidOperation() + x.WhatOp = work.Op + x.Why = 'Invalid operation' + raise x + + log = SharedStruct() + log.Key = logid + log.Value = '%d' % (val) + self.log[logid] = log + + return val + + def GetStruct(self, key): + print('getStruct(%d)' % (key)) + return self.log[key] + + def Zip(self): + print('zip()') + +if __name__ == '__main__': + handler = CalculatorHandler() + processor = Calculator.Processor(handler) + transport = TSocket.TServerSocket(host="testserver", port=9090) + tfactory = TTransport.TBufferedTransportFactory() + pfactory = TBinaryProtocol.TBinaryProtocolFactory() + + server = TServer.TSimpleServer(processor, transport, tfactory, pfactory) + print('Starting the server...') + server.serve() + print('done.') + + # You could do one of these for a multithreaded server + # server = TServer.TThreadedServer(processor, transport, tfactory, pfactory) + # server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory) +``` diff --git a/tutorial/netcore/Server/Program.cs b/tutorial/netcore/Server/Program.cs new file mode 100644 index 0000000..b8cc02e --- /dev/null +++ b/tutorial/netcore/Server/Program.cs @@ -0,0 +1,431 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Thrift; +using Thrift.Protocols; +using Thrift.Server; +using Thrift.Transports; +using Thrift.Transports.Server; +using tutorial; +using shared; + +namespace Server +{ + public class Program + { + private static readonly ILogger Logger = new LoggerFactory().AddConsole(LogLevel.Trace).AddDebug(LogLevel.Trace).CreateLogger(nameof(Server)); + + public static void Main(string[] args) + { + args = args ?? new string[0]; + + if (args.Any(x => x.StartsWith("-h", StringComparison.OrdinalIgnoreCase))) + { + DisplayHelp(); + return; + } + + using (var source = new CancellationTokenSource()) + { + RunAsync(args, source.Token).GetAwaiter().GetResult(); + + Logger.LogInformation("Press any key to stop..."); + + Console.ReadLine(); + source.Cancel(); + } + + Logger.LogInformation("Server stopped"); + } + + private static void DisplayHelp() + { + Logger.LogInformation(@" +Usage: + Server.exe -h + will diplay help information + + Server.exe -t: -p: + will run server with specified arguments (tcp transport and binary protocol by default) + +Options: + -t (transport): + tcp - (default) tcp transport will be used (host - ""localhost"", port - 9090) + tcpbuffered - tcp buffered transport will be used (host - ""localhost"", port - 9090) + namedpipe - namedpipe transport will be used (pipe address - "".test"") + http - http transport will be used (http address - ""localhost:9090"") + tcptls - tcp transport with tls will be used (host - ""localhost"", port - 9090) + framed - tcp framed transport will be used (host - ""localhost"", port - 9090) + + -p (protocol): + binary - (default) binary protocol will be used + compact - compact protocol will be used + json - json protocol will be used + multiplexed - multiplexed protocol will be used + +Sample: + Server.exe -t:tcp +"); + } + + private static async Task RunAsync(string[] args, CancellationToken cancellationToken) + { + var selectedTransport = GetTransport(args); + var selectedProtocol = GetProtocol(args); + + if (selectedTransport == Transport.Http) + { + new HttpServerSample().Run(cancellationToken); + } + else + { + await RunSelectedConfigurationAsync(selectedTransport, selectedProtocol, cancellationToken); + } + } + + private static Protocol GetProtocol(string[] args) + { + var transport = args.FirstOrDefault(x => x.StartsWith("-p"))?.Split(':')?[1]; + Protocol selectedProtocol; + + Enum.TryParse(transport, true, out selectedProtocol); + + return selectedProtocol; + } + + private static Transport GetTransport(string[] args) + { + var transport = args.FirstOrDefault(x => x.StartsWith("-t"))?.Split(':')?[1]; + Transport selectedTransport; + + Enum.TryParse(transport, true, out selectedTransport); + + return selectedTransport; + } + + private static async Task RunSelectedConfigurationAsync(Transport transport, Protocol protocol, CancellationToken cancellationToken) + { + var fabric = new LoggerFactory().AddConsole(LogLevel.Trace).AddDebug(LogLevel.Trace); + var handler = new CalculatorAsyncHandler(); + ITAsyncProcessor processor = null; + + TServerTransport serverTransport = null; + + switch (transport) + { + case Transport.Tcp: + serverTransport = new TServerSocketTransport(9090); + break; + case Transport.TcpBuffered: + serverTransport = new TServerSocketTransport(port: 9090, clientTimeout: 10000, useBufferedSockets: true); + break; + case Transport.NamedPipe: + serverTransport = new TNamedPipeServerTransport(".test"); + break; + case Transport.TcpTls: + serverTransport = new TTlsServerSocketTransport(9090, false, GetCertificate(), ClientCertValidator, LocalCertificateSelectionCallback); + break; + case Transport.Framed: + serverTransport = new TServerFramedTransport(9090); + break; + } + + ITProtocolFactory inputProtocolFactory; + ITProtocolFactory outputProtocolFactory; + + switch (protocol) + { + case Protocol.Binary: + { + inputProtocolFactory = new TBinaryProtocol.Factory(); + outputProtocolFactory = new TBinaryProtocol.Factory(); + processor = new Calculator.AsyncProcessor(handler); + } + break; + case Protocol.Compact: + { + inputProtocolFactory = new TCompactProtocol.Factory(); + outputProtocolFactory = new TCompactProtocol.Factory(); + processor = new Calculator.AsyncProcessor(handler); + } + break; + case Protocol.Json: + { + inputProtocolFactory = new TJsonProtocol.Factory(); + outputProtocolFactory = new TJsonProtocol.Factory(); + processor = new Calculator.AsyncProcessor(handler); + } + break; + case Protocol.Multiplexed: + { + inputProtocolFactory = new TBinaryProtocol.Factory(); + outputProtocolFactory = new TBinaryProtocol.Factory(); + + var calcHandler = new CalculatorAsyncHandler(); + var calcProcessor = new Calculator.AsyncProcessor(calcHandler); + + var sharedServiceHandler = new SharedServiceAsyncHandler(); + var sharedServiceProcessor = new SharedService.AsyncProcessor(sharedServiceHandler); + + var multiplexedProcessor = new TMultiplexedProcessor(); + multiplexedProcessor.RegisterProcessor(nameof(Calculator), calcProcessor); + multiplexedProcessor.RegisterProcessor(nameof(SharedService), sharedServiceProcessor); + + processor = multiplexedProcessor; + } + break; + default: + throw new ArgumentOutOfRangeException(nameof(protocol), protocol, null); + } + + try + { + Logger.LogInformation( + $"Selected TAsyncServer with {serverTransport} transport, {processor} processor and {inputProtocolFactory} protocol factories"); + + var server = new AsyncBaseServer(processor, serverTransport, inputProtocolFactory, outputProtocolFactory, fabric); + + Logger.LogInformation("Starting the server..."); + await server.ServeAsync(cancellationToken); + } + catch (Exception x) + { + Logger.LogInformation(x.ToString()); + } + } + + private static X509Certificate2 GetCertificate() + { + // due to files location in net core better to take certs from top folder + var certFile = GetCertPath(Directory.GetParent(Directory.GetCurrentDirectory())); + return new X509Certificate2(certFile, "ThriftTest"); + } + + private static string GetCertPath(DirectoryInfo di, int maxCount = 6) + { + var topDir = di; + var certFile = + topDir.EnumerateFiles("ThriftTest.pfx", SearchOption.AllDirectories) + .FirstOrDefault(); + if (certFile == null) + { + if (maxCount == 0) + throw new FileNotFoundException("Cannot find file in directories"); + return GetCertPath(di.Parent, maxCount - 1); + } + + return certFile.FullName; + } + + private static X509Certificate LocalCertificateSelectionCallback(object sender, + string targetHost, X509CertificateCollection localCertificates, + X509Certificate remoteCertificate, string[] acceptableIssuers) + { + return GetCertificate(); + } + + private static bool ClientCertValidator(object sender, X509Certificate certificate, + X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + return true; + } + + private enum Transport + { + Tcp, + TcpBuffered, + NamedPipe, + Http, + TcpTls, + Framed + } + + private enum Protocol + { + Binary, + Compact, + Json, + Multiplexed + } + + public class HttpServerSample + { + public void Run(CancellationToken cancellationToken) + { + var config = new ConfigurationBuilder() + .AddEnvironmentVariables(prefix: "ASPNETCORE_") + .Build(); + + var host = new WebHostBuilder() + .UseConfiguration(config) + .UseKestrel() + .UseUrls("http://localhost:9090") + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup() + .Build(); + + host.StartAsync(cancellationToken); // was Run() in earlier .NET Core SDKs? + } + + public class Startup + { + public Startup(IHostingEnvironment env) + { + var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddEnvironmentVariables(); + + Configuration = builder.Build(); + } + + public IConfigurationRoot Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env, + ILoggerFactory loggerFactory) + { + app.UseMiddleware(); + } + } + } + + public class CalculatorAsyncHandler : Calculator.IAsync + { + private readonly Dictionary _log = new Dictionary(); + + public CalculatorAsyncHandler() + { + } + + public async Task getStructAsync(int key, + CancellationToken cancellationToken) + { + Logger.LogInformation("GetStructAsync({0})", key); + return await Task.FromResult(_log[key]); + } + + public async Task pingAsync(CancellationToken cancellationToken) + { + Logger.LogInformation("PingAsync()"); + await Task.CompletedTask; + } + + public async Task addAsync(int num1, int num2, CancellationToken cancellationToken) + { + Logger.LogInformation($"AddAsync({num1},{num2})"); + return await Task.FromResult(num1 + num2); + } + + public async Task calculateAsync(int logid, Work w, CancellationToken cancellationToken) + { + Logger.LogInformation($"CalculateAsync({logid}, [{w.Op},{w.Num1},{w.Num2}])"); + + var val = 0; + switch (w.Op) + { + case Operation.ADD: + val = w.Num1 + w.Num2; + break; + + case Operation.SUBTRACT: + val = w.Num1 - w.Num2; + break; + + case Operation.MULTIPLY: + val = w.Num1 * w.Num2; + break; + + case Operation.DIVIDE: + if (w.Num2 == 0) + { + var io = new InvalidOperation + { + WhatOp = (int) w.Op, + Why = "Cannot divide by 0" + }; + + throw io; + } + val = w.Num1 / w.Num2; + break; + + default: + { + var io = new InvalidOperation + { + WhatOp = (int) w.Op, + Why = "Unknown operation" + }; + + throw io; + } + } + + var entry = new SharedStruct + { + Key = logid, + Value = val.ToString() + }; + + _log[logid] = entry; + + return await Task.FromResult(val); + } + + public async Task zipAsync(CancellationToken cancellationToken) + { + Logger.LogInformation("ZipAsync() with delay 100mc"); + await Task.Delay(100, CancellationToken.None); + } + } + + public class SharedServiceAsyncHandler : SharedService.IAsync + { + public async Task getStructAsync(int key, CancellationToken cancellationToken) + { + Logger.LogInformation("GetStructAsync({0})", key); + return await Task.FromResult(new SharedStruct() + { + Key = key, + Value = "GetStructAsync" + }); + } + } + } +} diff --git a/tutorial/netcore/Server/Properties/AssemblyInfo.cs b/tutorial/netcore/Server/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a044235 --- /dev/null +++ b/tutorial/netcore/Server/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("The Apache Software Foundation")] +[assembly: AssemblyProduct("Thrift")] +[assembly: AssemblyCopyright("The Apache Software Foundation")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. + +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM + +[assembly: Guid("e210fc10-5aff-4b04-ac21-58afc7b74b0c")] \ No newline at end of file diff --git a/tutorial/netcore/Server/Properties/launchSettings.json b/tutorial/netcore/Server/Properties/launchSettings.json new file mode 100644 index 0000000..78076ff --- /dev/null +++ b/tutorial/netcore/Server/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Server": { + "commandName": "Project", + "commandLineArgs": "-p:multiplexed" + } + } +} \ No newline at end of file diff --git a/tutorial/netcore/Server/Server.csproj b/tutorial/netcore/Server/Server.csproj new file mode 100644 index 0000000..0fbd303 --- /dev/null +++ b/tutorial/netcore/Server/Server.csproj @@ -0,0 +1,26 @@ + + + + netcoreapp2.0 + Server + Server + Exe + false + false + false + false + + + + + + + + + + + + + + + diff --git a/tutorial/netcore/Server/ThriftTest.pfx b/tutorial/netcore/Server/ThriftTest.pfx new file mode 100644 index 0000000000000000000000000000000000000000..f0ded28173dc2c33cebbb2b74e1e9e9e870b5876 GIT binary patch literal 2661 zcmY+Fc{r5q7ssC&Gb1!J$(kiQNi-_kNTzK}lBB4-#%>tDNgCV8K7;IKOK6d75tC&a zp={ZTH)}K@WXZmpv83PB^)A`wF(pXt7XpsY=bHUSlV3;5-A{d&ZS=A9rAjL!JLlxE zU_0M6u}dL5dyZUM*eZRTK7%!HnQk@RhDO-B4XYapVO%Fw7K^smqmrq9#TGaL=NEIm z?!`FK&>hR?Z@)%UKPau-%?m`A(>#}=i#q*6>Xe+P#mwBs6Q0@@Ixp|5@9I+wut zA#tRevtir~_G0T(aAFKzvy!O$=C`*W)A|(nrt(YY1n}Kp^LEZq_lyzXl)hwOG@G=i zxbiB-SnTQD^sz>x%QCdt1fw!Er?MpQ>#O~U^B1Ih|GdFM1{`4ISt#RHN4|ZYyq|=< z{j;$~n=*954;otf@)^47LvcfPIKt$_Y2BL+D}7sV7s{aov!F89pkkhg#@d`RVvtv8 zqhf(QFGtL@?Vi^c`LJWbZE9|TN_1?X9?l3DaIjMO5`V9F;~;j1FwiWFV#DZK zPZjSTs!0RAwSeaugCPfE_z~82e~?}o;1!SDpMJeV`Q?+Y@TQRE z%jhKjwXIG1?LW{8%1ry~$CvoFtuttc!kQ${aiZfTlsc}(9#g1pD3VzLU3ij7h2^CD z;6Lz8^m(Xe5?)8Y0Gr#QxBP*P)`mX~ycEnzpRed9N46To2eUk?5^Lp}$Xu=>65C8xu{J&6G(`>&f z-~~7X>HrGR1atr=u0{d&fFqaa0!O&99#K(?2gPlgcy9MFU_Ez}9Obs^@?Q}%0v{+j;MU>669QYwovF;u<-Oys<_RI{b3>F|lw0+!xJ>$_T%M|8 z*-&MWR7IRjyg|Rdz}Y^1c3>+=Wp`aAotnEcJk{mR2!9S=p@lzc?XYcYm9LJXMtHbTOVA7ageNhdBfi0|v1eLr9PtqI`)XEsA zC0p*r#f2MT4Hybzy5V<-3)*Qcno)THYn1lrjq6Dik zc86XkszLcvn;9QTVpJ9nk<@$OqssciMrRF6FvCqZbspu(u*qkj2*`%Mz8yK zJdDp2+luWj&vuSBXbE_thM;=6A| zTxptZh*kG4;p+`oVSXP~RY=Ckmncb%Q_UISo?$+pr{w0qs^nnM(Hjvem6Iv&+#MtM zv{NJq4}S()s9l6QL`u&D)**e1PVG7Kle}4G&E6j*6WUk@Gf{A7t$m7Kzgxiio)Vux zaUZfKT(@FZ>2x``Vy-=XKo?(27vH5gZ(9I{TgrlFvqh3z9qJGySLfwbj9a-H4Nq*qFpUg@ld}K z)hFz#CqBwVT7Rl=a|*hQAa-`0o9X{L*g@fX}@vnbf G^#21?=Cu0& literal 0 HcmV?d00001 diff --git a/tutorial/netcore/Tutorial.sln b/tutorial/netcore/Tutorial.sln new file mode 100644 index 0000000..bff110c --- /dev/null +++ b/tutorial/netcore/Tutorial.sln @@ -0,0 +1,68 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26114.2 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\lib\netcore\Thrift\Thrift.csproj", "{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Interfaces", "Interfaces\Interfaces.csproj", "{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Client\Client.csproj", "{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6850CF46-5467-4C65-BD78-871581C539FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6850CF46-5467-4C65-BD78-871581C539FC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6850CF46-5467-4C65-BD78-871581C539FC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6850CF46-5467-4C65-BD78-871581C539FC}.Release|Any CPU.Build.0 = Release|Any CPU + {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|x64.ActiveCfg = Debug|x64 + {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|x64.Build.0 = Debug|x64 + {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|x86.ActiveCfg = Debug|x86 + {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|x86.Build.0 = Debug|x86 + {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|Any CPU.Build.0 = Release|Any CPU + {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|x64.ActiveCfg = Release|x64 + {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|x64.Build.0 = Release|x64 + {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|x86.ActiveCfg = Release|x86 + {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|x86.Build.0 = Release|x86 + {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|x64.ActiveCfg = Debug|x64 + {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|x64.Build.0 = Debug|x64 + {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|x86.ActiveCfg = Debug|x86 + {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|x86.Build.0 = Debug|x86 + {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|Any CPU.Build.0 = Release|Any CPU + {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|x64.ActiveCfg = Release|x64 + {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|x64.Build.0 = Release|x64 + {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|x86.ActiveCfg = Release|x86 + {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|x86.Build.0 = Release|x86 + {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|x64.ActiveCfg = Debug|x64 + {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|x64.Build.0 = Debug|x64 + {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|x86.ActiveCfg = Debug|x86 + {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|x86.Build.0 = Debug|x86 + {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|Any CPU.Build.0 = Release|Any CPU + {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|x64.ActiveCfg = Release|x64 + {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|x64.Build.0 = Release|x64 + {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|x86.ActiveCfg = Release|x86 + {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tutorial/netcore/build.cmd b/tutorial/netcore/build.cmd new file mode 100644 index 0000000..e971799 --- /dev/null +++ b/tutorial/netcore/build.cmd @@ -0,0 +1,30 @@ +@echo off +rem /* +rem * Licensed to the Apache Software Foundation (ASF) under one +rem * or more contributor license agreements. See the NOTICE file +rem * distributed with this work for additional information +rem * regarding copyright ownership. The ASF licenses this file +rem * to you under the Apache License, Version 2.0 (the +rem * "License"); you may not use this file except in compliance +rem * with the License. You may obtain a copy of the License at +rem * +rem * http://www.apache.org/licenses/LICENSE-2.0 +rem * +rem * Unless required by applicable law or agreed to in writing, +rem * software distributed under the License is distributed on an +rem * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +rem * KIND, either express or implied. See the License for the +rem * specific language governing permissions and limitations +rem * under the License. +rem */ +setlocal + +cd Interfaces +thrift -gen netcore:wcf -r ..\..\tutorial.thrift +cd .. + +dotnet --info +dotnet restore +dotnet build + +:eof diff --git a/tutorial/netcore/build.sh b/tutorial/netcore/build.sh new file mode 100755 index 0000000..d2cb465 --- /dev/null +++ b/tutorial/netcore/build.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +#exit if any command fails +set -e + +cd Interfaces +../../../compiler/cpp/thrift -gen netcore:wcf -r ../../tutorial.thrift +cd .. + +dotnet --info +dotnet restore +dotnet build diff --git a/tutorial/nodejs/Makefile.am b/tutorial/nodejs/Makefile.am new file mode 100644 index 0000000..1516fec --- /dev/null +++ b/tutorial/nodejs/Makefile.am @@ -0,0 +1,45 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +gen-nodejs/Calculator.js gen-nodejs/SharedService.js: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen js:node -r $< + +all-local: gen-nodejs/Calculator.js + +tutorialserver: all + NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeServer.js + +tutorialclient: all + NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeClient.js + +tutorialserver_promise: all + NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeServerPromise.js + +tutorialclient_promise: all + NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeClientPromise.js + + +clean-local: + $(RM) -r gen-* + +EXTRA_DIST = \ + NodeServer.js \ + NodeClient.js \ + NodeServerPromise.js \ + NodeClientPromise.js diff --git a/tutorial/nodejs/Makefile.in b/tutorial/nodejs/Makefile.in new file mode 100644 index 0000000..8698a7b --- /dev/null +++ b/tutorial/nodejs/Makefile.in @@ -0,0 +1,649 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tutorial/nodejs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + NodeServer.js \ + NodeClient.js \ + NodeServerPromise.js \ + NodeClientPromise.js + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/nodejs/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tutorial/nodejs/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am all-local check check-am clean clean-generic \ + clean-libtool clean-local cscopelist-am ctags-am distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +gen-nodejs/Calculator.js gen-nodejs/SharedService.js: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen js:node -r $< + +all-local: gen-nodejs/Calculator.js + +tutorialserver: all + NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeServer.js + +tutorialclient: all + NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeClient.js + +tutorialserver_promise: all + NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeServerPromise.js + +tutorialclient_promise: all + NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeClientPromise.js + +clean-local: + $(RM) -r gen-* + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tutorial/nodejs/NodeClient.js b/tutorial/nodejs/NodeClient.js new file mode 100644 index 0000000..b4886e8 --- /dev/null +++ b/tutorial/nodejs/NodeClient.js @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var thrift = require('thrift'); +var Calculator = require('./gen-nodejs/Calculator'); +var ttypes = require('./gen-nodejs/tutorial_types'); +const assert = require('assert'); + +var transport = thrift.TBufferedTransport; +var protocol = thrift.TBinaryProtocol; + +var connection = thrift.createConnection("localhost", 9090, { + transport : transport, + protocol : protocol +}); + +connection.on('error', function(err) { + assert(false, err); +}); + +// Create a Calculator client with the connection +var client = thrift.createClient(Calculator, connection); + + +client.ping(function(err, response) { + console.log('ping()'); +}); + + +client.add(1,1, function(err, response) { + console.log("1+1=" + response); +}); + + +work = new ttypes.Work(); +work.op = ttypes.Operation.DIVIDE; +work.num1 = 1; +work.num2 = 0; + +client.calculate(1, work, function(err, message) { + if (err) { + console.log("InvalidOperation " + err); + } else { + console.log('Whoa? You know how to divide by zero?'); + } +}); + +work.op = ttypes.Operation.SUBTRACT; +work.num1 = 15; +work.num2 = 10; + +client.calculate(1, work, function(err, message) { + console.log('15-10=' + message); + + client.getStruct(1, function(err, message){ + console.log('Check log: ' + message.value); + + //close the connection once we're done + connection.end(); + }); +}); diff --git a/tutorial/nodejs/NodeClientPromise.js b/tutorial/nodejs/NodeClientPromise.js new file mode 100644 index 0000000..2cdc184 --- /dev/null +++ b/tutorial/nodejs/NodeClientPromise.js @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var thrift = require('thrift'); +var Calculator = require('./gen-nodejs/Calculator'); +var ttypes = require('./gen-nodejs/tutorial_types'); +const assert = require('assert'); + +var transport = thrift.TBufferedTransport; +var protocol = thrift.TBinaryProtocol; + +var connection = thrift.createConnection("localhost", 9090, { + transport : transport, + protocol : protocol +}); + +connection.on('error', function(err) { + assert(false, err); +}); + +// Create a Calculator client with the connection +var client = thrift.createClient(Calculator, connection); + + +client.ping() + .then(function() { + console.log('ping()'); + }); + +client.add(1,1) + .then(function(response) { + console.log("1+1=" + response); + }); + +work = new ttypes.Work(); +work.op = ttypes.Operation.DIVIDE; +work.num1 = 1; +work.num2 = 0; + +client.calculate(1, work) + .then(function(message) { + console.log('Whoa? You know how to divide by zero?'); + }) + .fail(function(err) { + console.log("InvalidOperation " + err); + }); + + +work.op = ttypes.Operation.SUBTRACT; +work.num1 = 15; +work.num2 = 10; + +client.calculate(1, work) + .then(function(value) { + console.log('15-10=' + value); + return client.getStruct(1); + }) + .then(function(message) { + console.log('Check log: ' + message.value); + }) + .fin(function() { + //close the connection once we're done + connection.end(); + }); diff --git a/tutorial/nodejs/NodeServer.js b/tutorial/nodejs/NodeServer.js new file mode 100644 index 0000000..55d3817 --- /dev/null +++ b/tutorial/nodejs/NodeServer.js @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var thrift = require("thrift"); +var Calculator = require("./gen-nodejs/Calculator"); +var ttypes = require("./gen-nodejs/tutorial_types"); +var SharedStruct = require("./gen-nodejs/shared_types").SharedStruct; + +var data = {}; + +var server = thrift.createServer(Calculator, { + ping: function(result) { + console.log("ping()"); + result(null); + }, + + add: function(n1, n2, result) { + console.log("add(", n1, ",", n2, ")"); + result(null, n1 + n2); + }, + + calculate: function(logid, work, result) { + console.log("calculate(", logid, ",", work, ")"); + + var val = 0; + if (work.op == ttypes.Operation.ADD) { + val = work.num1 + work.num2; + } else if (work.op === ttypes.Operation.SUBTRACT) { + val = work.num1 - work.num2; + } else if (work.op === ttypes.Operation.MULTIPLY) { + val = work.num1 * work.num2; + } else if (work.op === ttypes.Operation.DIVIDE) { + if (work.num2 === 0) { + var x = new ttypes.InvalidOperation(); + x.whatOp = work.op; + x.why = 'Cannot divide by 0'; + result(x); + return; + } + val = work.num1 / work.num2; + } else { + var x = new ttypes.InvalidOperation(); + x.whatOp = work.op; + x.why = 'Invalid operation'; + result(x); + return; + } + + var entry = new SharedStruct(); + entry.key = logid; + entry.value = ""+val; + data[logid] = entry; + + result(null, val); + }, + + getStruct: function(key, result) { + console.log("getStruct(", key, ")"); + result(null, data[key]); + }, + + zip: function() { + console.log("zip()"); + result(null); + } + +}); + +server.listen(9090); diff --git a/tutorial/nodejs/NodeServerPromise.js b/tutorial/nodejs/NodeServerPromise.js new file mode 100644 index 0000000..bff287b --- /dev/null +++ b/tutorial/nodejs/NodeServerPromise.js @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var thrift = require("thrift"); +var Calculator = require("./gen-nodejs/Calculator"); +var ttypes = require("./gen-nodejs/tutorial_types"); +var SharedStruct = require("./gen-nodejs/shared_types").SharedStruct; + +var data = {}; + +var server = thrift.createServer(Calculator, { + ping: function() { + console.log("ping()"); + }, + + add: function(n1, n2) { + console.log("add(", n1, ",", n2, ")"); + return n1 + n2; + }, + + calculate: function(logid, work) { + console.log("calculate(", logid, ",", work, ")"); + + var val = 0; + if (work.op == ttypes.Operation.ADD) { + val = work.num1 + work.num2; + } else if (work.op === ttypes.Operation.SUBTRACT) { + val = work.num1 - work.num2; + } else if (work.op === ttypes.Operation.MULTIPLY) { + val = work.num1 * work.num2; + } else if (work.op === ttypes.Operation.DIVIDE) { + if (work.num2 === 0) { + var x = new ttypes.InvalidOperation(); + x.whatOp = work.op; + x.why = 'Cannot divide by 0'; + throw x; + } + val = work.num1 / work.num2; + } else { + var x = new ttypes.InvalidOperation(); + x.whatOp = work.op; + x.why = 'Invalid operation'; + throw x; + } + + var entry = new SharedStruct(); + entry.key = logid; + entry.value = ""+val; + data[logid] = entry; + return val; + }, + + getStruct: function(key) { + console.log("getStruct(", key, ")"); + return data[key]; + }, + + zip: function() { + console.log("zip()"); + } + +}); + +server.listen(9090); diff --git a/tutorial/ocaml/CalcClient.ml b/tutorial/ocaml/CalcClient.ml new file mode 100755 index 0000000..5a8467b --- /dev/null +++ b/tutorial/ocaml/CalcClient.ml @@ -0,0 +1,74 @@ +(* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*) + +open Arg +open Thrift +open Tutorial_types +open Shared_types + +exception Die;; +let sod = function + Some v -> v + | None -> raise Die;; + +type connection = { + trans : Transport.t ; + proto : Thrift.Protocol.t; + calc : Calculator.client ; +} + +let connect ~host port = + let tx = new TSocket.t host port in + let proto = new TBinaryProtocol.t tx in + let calc = new Calculator.client proto proto in + tx#opn; + { trans = tx ; proto = proto; calc = calc } +;; + +let doclient () = + let cli = connect ~host:"127.0.0.1" 9090 in + try + cli.calc#ping ; + Printf.printf "ping()\n" ; flush stdout ; + (let sum = cli.calc#add (Int32.of_int 1) (Int32.of_int 1) in + Printf.printf "1+1=%ld\n" sum ; + flush stdout) ; + (let w = new work in + w#set_op Operation.DIVIDE ; + w#set_num1 (Int32.of_int 1) ; + w#set_num2 (Int32.of_int 0) ; + try + let quotient = cli.calc#calculate (Int32.of_int 1) w in + Printf.printf "Whoa? We can divide by zero!\n" ; flush stdout + with InvalidOperation io -> + Printf.printf "InvalidOperation: %s\n" io#grab_why ; flush stdout) ; + (let w = new work in + w#set_op Operation.SUBTRACT ; + w#set_num1 (Int32.of_int 15) ; + w#set_num2 (Int32.of_int 10) ; + let diff = cli.calc#calculate (Int32.of_int 1) w in + Printf.printf "15-10=%ld\n" diff ; flush stdout) ; + (let ss = cli.calc#getStruct (Int32.of_int 1) in + Printf.printf "Check log: %s\n" ss#grab_value ; flush stdout) ; + cli.trans#close + with Transport.E (_,what) -> + Printf.printf "ERROR: %s\n" what ; flush stdout +;; + +doclient();; diff --git a/tutorial/ocaml/CalcServer.ml b/tutorial/ocaml/CalcServer.ml new file mode 100755 index 0000000..b5facb7 --- /dev/null +++ b/tutorial/ocaml/CalcServer.ml @@ -0,0 +1,89 @@ +(* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*) + +open Arg +open Thrift +open Tutorial_types +open Shared_types + +exception Die;; +let sod = function + Some v -> v + | None -> raise Die;; + +class calc_handler = +object (self) + inherit Calculator.iface + val log = Hashtbl.create 23 + method ping = Printf.printf "ping()\n" ; flush stdout + method add a b = + Printf.printf"add(%ld,%ld)\n" (sod a) (sod b); flush stdout ; + Int32.add (sod a) (sod b) + method calculate logid w = + let w = sod w in + Printf.printf "calculate(%ld,{%ld,%ld,%ld})\n" (sod logid) (Operation.to_i w#grab_op) w#grab_num1 w#grab_num2; flush stdout ; + let rv = + match w#grab_op with + Operation.ADD -> + Int32.add w#grab_num1 w#grab_num2 + | Operation.SUBTRACT -> + Int32.sub w#grab_num1 w#grab_num2 + | Operation.MULTIPLY -> + Int32.mul w#grab_num1 w#grab_num2 + | Operation.DIVIDE -> + if w#grab_num2 = Int32.zero then + let io = new invalidOperation in + io#set_whatOp (Operation.to_i w#grab_op) ; + io#set_why "Cannot divide by 0" ; + raise (InvalidOperation io) + else + Int32.div w#grab_num1 w#grab_num2 in + + let ss = new sharedStruct in + ss#set_key (sod logid) ; + let buffer = Int32.to_string rv in + ss#set_value buffer ; + Hashtbl.add log (sod logid) ss ; + rv + + method zip = + Printf.printf "zip()\n"; flush stdout + + method getStruct logid = + Printf.printf "getStruct(%ld)\n" (sod logid) ; flush stdout ; + Hashtbl.find log (sod logid) + +end + +let doserver () = + let h = new calc_handler in + let proc = new Calculator.processor h in + let port = 9090 in + let pf = new TBinaryProtocol.factory in + let server = new TThreadedServer.t + proc + (new TServerSocket.t port) + (new Transport.factory) + pf + pf + in + server#serve +;; + +doserver();; diff --git a/tutorial/ocaml/README.md b/tutorial/ocaml/README.md new file mode 100644 index 0000000..f68e835 --- /dev/null +++ b/tutorial/ocaml/README.md @@ -0,0 +1,15 @@ + +This is the ocaml tutorial example. It assumes that you've already +built and installed the thrift ocaml runtime libraries in lib/ocaml. + +To compile this, you will need to generate the Thrift sources for +ocaml in this directory (due to limitations in the OASIS build-tool): + + % thrift -r --gen ocaml ../tutorial.thrift + % oasis setup + % make + +This will produce two executables Calc{Server,Client}. where + is one of "byte" or "native", depending on your ocaml +installation. Just run the server in the background, then the client +(as you would do for the C++ example). diff --git a/tutorial/ocaml/_oasis b/tutorial/ocaml/_oasis new file mode 100644 index 0000000..898261d --- /dev/null +++ b/tutorial/ocaml/_oasis @@ -0,0 +1,32 @@ +Name: tutorial +Version: 0.11.0 +OASISFormat: 0.3 +Synopsis: OCaml Tutorial example +Authors: Apache Thrift Developers +License: Apache-2.0 +Homepage: http://thrift.apache.org +BuildTools: ocamlbuild +Plugins: META (0.3), + DevFiles (0.3) + +Library tutorial_thrift + Path: gen-ocaml + FindlibName: tutorial_thrift + buildTools: ocamlbuild + BuildDepends: threads,thrift + Modules: Calculator,Shared_consts,Tutorial_consts,SharedService,Shared_types,Tutorial_types + XMETARequires: threads + +Executable CalcClient + Path: . + MainIs: CalcClient.ml + Build$: true + CompiledObject: best + BuildDepends: thrift, tutorial_thrift, threads + +Executable CalcServer + Path: . + MainIs: CalcServer.ml + Build$: true + CompiledObject: best + BuildDepends: thrift, tutorial_thrift, threads diff --git a/tutorial/perl/PerlClient.pl b/tutorial/perl/PerlClient.pl new file mode 100644 index 0000000..1d59656 --- /dev/null +++ b/tutorial/perl/PerlClient.pl @@ -0,0 +1,82 @@ +#!/usr/bin/env perl + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use strict; +use warnings; + +use lib '../../lib/perl/lib'; +use lib '../gen-perl'; + +use Thrift; +use Thrift::BinaryProtocol; +use Thrift::Socket; +use Thrift::BufferedTransport; + +use shared::SharedService; +use tutorial::Calculator; +use shared::Types; +use tutorial::Types; + +use Data::Dumper; + +my $socket = new Thrift::Socket('localhost',9090); +my $transport = new Thrift::BufferedTransport($socket,1024,1024); +my $protocol = new Thrift::BinaryProtocol($transport); +my $client = new tutorial::CalculatorClient($protocol); + + +eval{ + $transport->open(); + + $client->ping(); + print "ping()\n"; + + + my $sum = $client->add(1,1); + print "1+1=$sum\n"; + + my $work = new tutorial::Work(); + + $work->op(tutorial::Operation::DIVIDE); + $work->num1(1); + $work->num2(0); + + eval { + $client->calculate(1, $work); + print "Whoa! We can divide by zero?\n"; + }; if($@) { + warn "InvalidOperation: ".Dumper($@); + } + + $work->op(tutorial::Operation::SUBTRACT); + $work->num1(15); + $work->num2(10); + my $diff = $client->calculate(1, $work); + print "15-10=$diff\n"; + + my $log = $client->getStruct(1); + print "Log: $log->{value}\n"; + + $transport->close(); + +}; if($@){ + warn(Dumper($@)); +} diff --git a/tutorial/perl/PerlServer.pl b/tutorial/perl/PerlServer.pl new file mode 100644 index 0000000..adec978 --- /dev/null +++ b/tutorial/perl/PerlServer.pl @@ -0,0 +1,124 @@ +#!/usr/bin/perl + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use strict; +use lib '../gen-perl'; +use Thrift::Socket; +use Thrift::Server; +use tutorial::Calculator; + +package CalculatorHandler; +use base qw(tutorial::CalculatorIf); + +sub new { + my $classname = shift; + my $self = {}; + + return bless($self,$classname); +} + + +sub ping +{ + print "ping()\n"; +} + +sub add +{ + my($self, $n1, $n2) = @_; + printf("add(%d,%d)\n", $n1, $n2); + return $n1 + $n2; +} + +sub calculate +{ + my($self, $logid, $work) = @_; + my $op = $work->{op}; + my $num1 = $work->{num1}; + my $num2 = $work->{num2}; + printf("calculate(%d, %d %d %d)\n", $logid, $num1, $num2, $op); + + my $val; + + if ($op == tutorial::Operation::ADD) { + $val = $num1 + $num2; + } elsif ($op == tutorial::Operation::SUBTRACT) { + $val = $num1 - $num2; + } elsif ($op == tutorial::Operation::MULTIPLY) { + $val = $num1 * $num2; + } elsif ($op == tutorial::Operation::DIVIDE) { + if ($num2 == 0) + { + my $x = new tutorial::InvalidOperation; + $x->whatOp($op); + $x->why('Cannot divide by 0'); + die $x; + } + $val = $num1 / $num2; + } else { + my $x = new tutorial::InvalidOperation; + $x->whatOp($op); + $x->why('Invalid operation'); + die $x; + } + + my $log = new shared::SharedStruct; + $log->key($logid); + $log->value(int($val)); + $self->{log}->{$logid} = $log; + + return $val; +} + +sub getStruct +{ + my($self, $key) = @_; + printf("getStruct(%d)\n", $key); + return $self->{log}->{$key}; +} + +sub zip +{ + my($self) = @_; + print "zip()\n"; +} + + + +eval { + my $handler = new CalculatorHandler; + my $processor = new tutorial::CalculatorProcessor($handler); + my $serversocket = new Thrift::ServerSocket(9090); + my $forkingserver = new Thrift::ForkingServer($processor, $serversocket); + print "Starting the server...\n"; + $forkingserver->serve(); + print "done.\n"; +}; if ($@) { + if ($@ =~ m/TException/ and exists $@->{message}) { + my $message = $@->{message}; + my $code = $@->{code}; + my $out = $code . ':' . $message; + die $out; + } else { + die $@; + } +} + diff --git a/tutorial/php/PhpClient.php b/tutorial/php/PhpClient.php new file mode 100755 index 0000000..d262b8f --- /dev/null +++ b/tutorial/php/PhpClient.php @@ -0,0 +1,91 @@ +#!/usr/bin/env php +registerNamespace('Thrift', __DIR__ . '/../../lib/php/lib'); +$loader->registerDefinition('shared', $GEN_DIR); +$loader->registerDefinition('tutorial', $GEN_DIR); +$loader->register(); + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use Thrift\Protocol\TBinaryProtocol; +use Thrift\Transport\TSocket; +use Thrift\Transport\THttpClient; +use Thrift\Transport\TBufferedTransport; +use Thrift\Exception\TException; + +try { + if (array_search('--http', $argv)) { + $socket = new THttpClient('localhost', 8080, '/php/PhpServer.php'); + } else { + $socket = new TSocket('localhost', 9090); + } + $transport = new TBufferedTransport($socket, 1024, 1024); + $protocol = new TBinaryProtocol($transport); + $client = new \tutorial\CalculatorClient($protocol); + + $transport->open(); + + $client->ping(); + print "ping()\n"; + + $sum = $client->add(1,1); + print "1+1=$sum\n"; + + $work = new \tutorial\Work(); + + $work->op = \tutorial\Operation::DIVIDE; + $work->num1 = 1; + $work->num2 = 0; + + try { + $client->calculate(1, $work); + print "Whoa! We can divide by zero?\n"; + } catch (\tutorial\InvalidOperation $io) { + print "InvalidOperation: $io->why\n"; + } + + $work->op = \tutorial\Operation::SUBTRACT; + $work->num1 = 15; + $work->num2 = 10; + $diff = $client->calculate(1, $work); + print "15-10=$diff\n"; + + $log = $client->getStruct(1); + print "Log: $log->value\n"; + + $transport->close(); + +} catch (TException $tx) { + print 'TException: '.$tx->getMessage()."\n"; +} + +?> diff --git a/tutorial/php/PhpServer.php b/tutorial/php/PhpServer.php new file mode 100755 index 0000000..22ae43e --- /dev/null +++ b/tutorial/php/PhpServer.php @@ -0,0 +1,130 @@ +#!/usr/bin/env php +registerNamespace('Thrift', __DIR__ . '/../../lib/php/lib'); +$loader->registerDefinition('shared', $GEN_DIR); +$loader->registerDefinition('tutorial', $GEN_DIR); +$loader->register(); + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * This is not a stand-alone server. It should be run as a normal + * php web script (like through Apache's mod_php) or as a cgi script + * (like with the included runserver.py). You can connect to it with + * THttpClient in any language that supports it. The PHP tutorial client + * will work if you pass it the argument "--http". + */ + +if (php_sapi_name() == 'cli') { + ini_set("display_errors", "stderr"); +} + +use Thrift\Protocol\TBinaryProtocol; +use Thrift\Transport\TPhpStream; +use Thrift\Transport\TBufferedTransport; + +class CalculatorHandler implements \tutorial\CalculatorIf { + protected $log = array(); + + public function ping() { + error_log("ping()"); + } + + public function add($num1, $num2) { + error_log("add({$num1}, {$num2})"); + return $num1 + $num2; + } + + public function calculate($logid, \tutorial\Work $w) { + error_log("calculate({$logid}, {{$w->op}, {$w->num1}, {$w->num2}})"); + switch ($w->op) { + case \tutorial\Operation::ADD: + $val = $w->num1 + $w->num2; + break; + case \tutorial\Operation::SUBTRACT: + $val = $w->num1 - $w->num2; + break; + case \tutorial\Operation::MULTIPLY: + $val = $w->num1 * $w->num2; + break; + case \tutorial\Operation::DIVIDE: + if ($w->num2 == 0) { + $io = new \tutorial\InvalidOperation(); + $io->whatOp = $w->op; + $io->why = "Cannot divide by 0"; + throw $io; + } + $val = $w->num1 / $w->num2; + break; + default: + $io = new \tutorial\InvalidOperation(); + $io->whatOp = $w->op; + $io->why = "Invalid Operation"; + throw $io; + } + + $log = new \shared\SharedStruct(); + $log->key = $logid; + $log->value = (string)$val; + $this->log[$logid] = $log; + + return $val; + } + + public function getStruct($key) { + error_log("getStruct({$key})"); + // This actually doesn't work because the PHP interpreter is + // restarted for every request. + //return $this->log[$key]; + return new \shared\SharedStruct(array("key" => $key, "value" => "PHP is stateless!")); + } + + public function zip() { + error_log("zip()"); + } + +}; + +header('Content-Type', 'application/x-thrift'); +if (php_sapi_name() == 'cli') { + echo "\r\n"; +} + +$handler = new CalculatorHandler(); +$processor = new \tutorial\CalculatorProcessor($handler); + +$transport = new TBufferedTransport(new TPhpStream(TPhpStream::MODE_R | TPhpStream::MODE_W)); +$protocol = new TBinaryProtocol($transport, true, true); + +$transport->open(); +$processor->process($protocol, $protocol); +$transport->close(); diff --git a/tutorial/php/runserver.py b/tutorial/php/runserver.py new file mode 100755 index 0000000..077daa1 --- /dev/null +++ b/tutorial/php/runserver.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import os +import BaseHTTPServer +import CGIHTTPServer + +# chdir(2) into the tutorial directory. +os.chdir(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) + + +class Handler(CGIHTTPServer.CGIHTTPRequestHandler): + cgi_directories = ['/php'] + +BaseHTTPServer.HTTPServer(('', 8080), Handler).serve_forever() diff --git a/tutorial/py.tornado/Makefile.am b/tutorial/py.tornado/Makefile.am new file mode 100755 index 0000000..4b73c1e --- /dev/null +++ b/tutorial/py.tornado/Makefile.am @@ -0,0 +1,36 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +gen-py.tornado/tutorial/Calculator.py gen-py.tornado/shared/SharedService.py: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen py:tornado -r $< + +all-local: gen-py.tornado/tutorial/Calculator.py + +tutorialserver: all + ${PYTHON} PythonServer.py + +tutorialclient: all + ${PYTHON} PythonClient.py + +clean-local: + $(RM) -r gen-* + +EXTRA_DIST = \ + PythonServer.py \ + PythonClient.py diff --git a/tutorial/py.tornado/Makefile.in b/tutorial/py.tornado/Makefile.in new file mode 100644 index 0000000..9a62d92 --- /dev/null +++ b/tutorial/py.tornado/Makefile.in @@ -0,0 +1,641 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tutorial/py.tornado +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + PythonServer.py \ + PythonClient.py + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/py.tornado/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tutorial/py.tornado/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am all-local check check-am clean clean-generic \ + clean-libtool clean-local cscopelist-am ctags-am distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +gen-py.tornado/tutorial/Calculator.py gen-py.tornado/shared/SharedService.py: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen py:tornado -r $< + +all-local: gen-py.tornado/tutorial/Calculator.py + +tutorialserver: all + ${PYTHON} PythonServer.py + +tutorialclient: all + ${PYTHON} PythonClient.py + +clean-local: + $(RM) -r gen-* + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tutorial/py.tornado/PythonClient.py b/tutorial/py.tornado/PythonClient.py new file mode 100755 index 0000000..426146f --- /dev/null +++ b/tutorial/py.tornado/PythonClient.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import glob +import logging +import sys + +sys.path.append('gen-py.tornado') +sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) + +from tutorial import Calculator +from tutorial.ttypes import Operation, Work, InvalidOperation + +from thrift import TTornado +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol + +from tornado import gen +from tornado import ioloop + + +@gen.coroutine +def communicate(): + # create client + transport = TTornado.TTornadoStreamTransport('localhost', 9090) + # open the transport, bail on error + try: + yield transport.open() + print('Transport is opened') + except TTransport.TTransportException as ex: + logging.error(ex) + raise gen.Return() + + pfactory = TBinaryProtocol.TBinaryProtocolFactory() + client = Calculator.Client(transport, pfactory) + + # ping + yield client.ping() + print("ping()") + + # add + sum_ = yield client.add(1, 1) + print("1 + 1 = {0}".format(sum_)) + + # make a oneway call without a callback (schedule the write and continue + # without blocking) + client.zip() + print("zip() without callback") + + # make a oneway call with a callback (we'll wait for the stream write to + # complete before continuing) + client.zip() + print("zip() with callback") + + # calculate 1/0 + work = Work() + work.op = Operation.DIVIDE + work.num1 = 1 + work.num2 = 0 + + try: + quotient = yield client.calculate(1, work) + print("Whoa? You know how to divide by zero ? -> {0}".format(quotient)) + except InvalidOperation as io: + print("InvalidOperation: {0}".format(io)) + + # calculate 15-10 + work.op = Operation.SUBTRACT + work.num1 = 15 + work.num2 = 10 + + diff = yield client.calculate(1, work) + print("15 - 10 = {0}".format(diff)) + + # getStruct + log = yield client.getStruct(1) + print("Check log: {0}".format(log.value)) + + # close the transport + client._transport.close() + raise gen.Return() + + +def main(): + # create an ioloop, do the above, then stop + ioloop.IOLoop.current().run_sync(communicate) + + +if __name__ == "__main__": + main() diff --git a/tutorial/py.tornado/PythonServer.py b/tutorial/py.tornado/PythonServer.py new file mode 100755 index 0000000..e0229a2 --- /dev/null +++ b/tutorial/py.tornado/PythonServer.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import glob +import sys + +sys.path.append('gen-py.tornado') +sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) + +from tutorial import Calculator +from tutorial.ttypes import Operation, InvalidOperation + +from shared.ttypes import SharedStruct + +from thrift import TTornado +from thrift.protocol import TBinaryProtocol + +from tornado import ioloop + + +class CalculatorHandler(object): + def __init__(self): + self.log = {} + + def ping(self): + print("ping()") + + def add(self, n1, n2): + print("add({}, {})".format(n1, n2)) + return n1 + n2 + + def calculate(self, logid, work): + print("calculate({}, {})".format(logid, work)) + + if work.op == Operation.ADD: + val = work.num1 + work.num2 + elif work.op == Operation.SUBTRACT: + val = work.num1 - work.num2 + elif work.op == Operation.MULTIPLY: + val = work.num1 * work.num2 + elif work.op == Operation.DIVIDE: + if work.num2 == 0: + x = InvalidOperation() + x.whatOp = work.op + x.why = "Cannot divide by 0" + raise x + val = work.num1 / work.num2 + else: + x = InvalidOperation() + x.whatOp = work.op + x.why = "Invalid operation" + raise x + + log = SharedStruct() + log.key = logid + log.value = '%d' % (val) + self.log[logid] = log + return val + + def getStruct(self, key): + print("getStruct({})".format(key)) + return self.log[key] + + def zip(self): + print("zip()") + + +def main(): + handler = CalculatorHandler() + processor = Calculator.Processor(handler) + pfactory = TBinaryProtocol.TBinaryProtocolFactory() + server = TTornado.TTornadoServer(processor, pfactory) + + print("Starting the server...") + server.bind(9090) + server.start(1) + ioloop.IOLoop.instance().start() + print("done.") + + +if __name__ == "__main__": + main() diff --git a/tutorial/py.twisted/Makefile.am b/tutorial/py.twisted/Makefile.am new file mode 100755 index 0000000..50cd342 --- /dev/null +++ b/tutorial/py.twisted/Makefile.am @@ -0,0 +1,37 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +gen-py/tutorial/Calculator.py gen-py/shared/SharedService.py: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen py:twisted -r $< + +all-local: gen-py/tutorial/Calculator.py + +tutorialserver: all + ${PYTHON} PythonServer.py + +tutorialclient: all + ${PYTHON} PythonClient.py + +clean-local: + $(RM) -r gen-* + +EXTRA_DIST = \ + PythonClient.py \ + PythonServer.py \ + PythonServer.tac diff --git a/tutorial/py.twisted/Makefile.in b/tutorial/py.twisted/Makefile.in new file mode 100644 index 0000000..9f33b4f --- /dev/null +++ b/tutorial/py.twisted/Makefile.in @@ -0,0 +1,642 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tutorial/py.twisted +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + PythonClient.py \ + PythonServer.py \ + PythonServer.tac + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/py.twisted/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tutorial/py.twisted/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am all-local check check-am clean clean-generic \ + clean-libtool clean-local cscopelist-am ctags-am distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +gen-py/tutorial/Calculator.py gen-py/shared/SharedService.py: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen py:twisted -r $< + +all-local: gen-py/tutorial/Calculator.py + +tutorialserver: all + ${PYTHON} PythonServer.py + +tutorialclient: all + ${PYTHON} PythonClient.py + +clean-local: + $(RM) -r gen-* + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tutorial/py.twisted/PythonClient.py b/tutorial/py.twisted/PythonClient.py new file mode 100755 index 0000000..63dde7e --- /dev/null +++ b/tutorial/py.twisted/PythonClient.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import glob +import sys +sys.path.append('gen-py.twisted') +sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) + +from tutorial import Calculator +from tutorial.ttypes import InvalidOperation, Operation, Work + +from twisted.internet.defer import inlineCallbacks +from twisted.internet import reactor +from twisted.internet.protocol import ClientCreator + +from thrift.transport import TTwisted +from thrift.protocol import TBinaryProtocol + + +@inlineCallbacks +def main(client): + yield client.ping() + print('ping()') + + sum = yield client.add(1, 1) + print(('1+1=%d' % (sum))) + + work = Work() + + work.op = Operation.DIVIDE + work.num1 = 1 + work.num2 = 0 + + try: + quotient = yield client.calculate(1, work) + print('Whoa? You know how to divide by zero?') + print('FYI the answer is %d' % quotient) + except InvalidOperation as e: + print(('InvalidOperation: %r' % e)) + + work.op = Operation.SUBTRACT + work.num1 = 15 + work.num2 = 10 + + diff = yield client.calculate(1, work) + print(('15-10=%d' % (diff))) + + log = yield client.getStruct(1) + print(('Check log: %s' % (log.value))) + reactor.stop() + +if __name__ == '__main__': + d = ClientCreator(reactor, + TTwisted.ThriftClientProtocol, + Calculator.Client, + TBinaryProtocol.TBinaryProtocolFactory(), + ).connectTCP("127.0.0.1", 9090) + d.addCallback(lambda conn: conn.client) + d.addCallback(main) + + reactor.run() diff --git a/tutorial/py.twisted/PythonServer.py b/tutorial/py.twisted/PythonServer.py new file mode 100755 index 0000000..1b0e2d5 --- /dev/null +++ b/tutorial/py.twisted/PythonServer.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import glob +import sys +sys.path.append('gen-py.twisted') +sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) + +from tutorial import Calculator +from tutorial.ttypes import InvalidOperation, Operation + +from shared.ttypes import SharedStruct + +from zope.interface import implements +from twisted.internet import reactor + +from thrift.transport import TTwisted +from thrift.protocol import TBinaryProtocol + + +class CalculatorHandler: + implements(Calculator.Iface) + + def __init__(self): + self.log = {} + + def ping(self): + print('ping()') + + def add(self, n1, n2): + print('add(%d,%d)' % (n1, n2)) + return n1 + n2 + + def calculate(self, logid, work): + print('calculate(%d, %r)' % (logid, work)) + + if work.op == Operation.ADD: + val = work.num1 + work.num2 + elif work.op == Operation.SUBTRACT: + val = work.num1 - work.num2 + elif work.op == Operation.MULTIPLY: + val = work.num1 * work.num2 + elif work.op == Operation.DIVIDE: + if work.num2 == 0: + x = InvalidOperation() + x.whatOp = work.op + x.why = 'Cannot divide by 0' + raise x + val = work.num1 / work.num2 + else: + x = InvalidOperation() + x.whatOp = work.op + x.why = 'Invalid operation' + raise x + + log = SharedStruct() + log.key = logid + log.value = '%d' % (val) + self.log[logid] = log + + return val + + def getStruct(self, key): + print('getStruct(%d)' % (key)) + return self.log[key] + + def zip(self): + print('zip()') + +if __name__ == '__main__': + handler = CalculatorHandler() + processor = Calculator.Processor(handler) + pfactory = TBinaryProtocol.TBinaryProtocolFactory() + server = reactor.listenTCP( + 9090, + TTwisted.ThriftServerFactory(processor, pfactory), + interface="127.0.0.1") + reactor.run() diff --git a/tutorial/py.twisted/PythonServer.tac b/tutorial/py.twisted/PythonServer.tac new file mode 100755 index 0000000..0479636 --- /dev/null +++ b/tutorial/py.twisted/PythonServer.tac @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from twisted.application import internet, service +from thrift.transport import TTwisted + +import glob +import sys +sys.path.append('gen-py.twisted') +sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) +from tutorial import Calculator +from PythonServer import CalculatorHandler +from thrift.protocol import TBinaryProtocol + + +def make_application(): + application = service.Application('CalcServer') + + handler = CalculatorHandler() + processor = Calculator.Processor(handler) + + serverFactory = TTwisted.ThriftServerFactory( + processor, + TBinaryProtocol.TBinaryProtocolFactory()) + + calcService = internet.TCPServer(9090, serverFactory) + + multiService = service.MultiService() + calcService.setServiceParent(multiService) + multiService.setServiceParent(application) + + return application + +if __name__ == '__main__': + application = make_application() diff --git a/tutorial/py/Makefile.am b/tutorial/py/Makefile.am new file mode 100755 index 0000000..7db816d --- /dev/null +++ b/tutorial/py/Makefile.am @@ -0,0 +1,37 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +gen-py/tutorial/Calculator.py gen-py/shared/SharedService.py: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen py -r $< + +all-local: gen-py/tutorial/Calculator.py + +tutorialserver: all + ${PYTHON} PythonServer.py + +tutorialclient: all + ${PYTHON} PythonClient.py + +clean-local: + $(RM) -r gen-* + +EXTRA_DIST = \ + setup.cfg \ + PythonServer.py \ + PythonClient.py diff --git a/tutorial/py/Makefile.in b/tutorial/py/Makefile.in new file mode 100644 index 0000000..ab989f1 --- /dev/null +++ b/tutorial/py/Makefile.in @@ -0,0 +1,642 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tutorial/py +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + setup.cfg \ + PythonServer.py \ + PythonClient.py + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/py/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tutorial/py/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am all-local check check-am clean clean-generic \ + clean-libtool clean-local cscopelist-am ctags-am distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +gen-py/tutorial/Calculator.py gen-py/shared/SharedService.py: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen py -r $< + +all-local: gen-py/tutorial/Calculator.py + +tutorialserver: all + ${PYTHON} PythonServer.py + +tutorialclient: all + ${PYTHON} PythonClient.py + +clean-local: + $(RM) -r gen-* + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tutorial/py/PythonClient.py b/tutorial/py/PythonClient.py new file mode 100755 index 0000000..a6c1966 --- /dev/null +++ b/tutorial/py/PythonClient.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import sys +import glob +sys.path.append('gen-py') +sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) + +from tutorial import Calculator +from tutorial.ttypes import InvalidOperation, Operation, Work + +from thrift import Thrift +from thrift.transport import TSocket +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol + + +def main(): + # Make socket + transport = TSocket.TSocket('localhost', 9090) + + # Buffering is critical. Raw sockets are very slow + transport = TTransport.TBufferedTransport(transport) + + # Wrap in a protocol + protocol = TBinaryProtocol.TBinaryProtocol(transport) + + # Create a client to use the protocol encoder + client = Calculator.Client(protocol) + + # Connect! + transport.open() + + client.ping() + print('ping()') + + sum_ = client.add(1, 1) + print('1+1=%d' % sum_) + + work = Work() + + work.op = Operation.DIVIDE + work.num1 = 1 + work.num2 = 0 + + try: + quotient = client.calculate(1, work) + print('Whoa? You know how to divide by zero?') + print('FYI the answer is %d' % quotient) + except InvalidOperation as e: + print('InvalidOperation: %r' % e) + + work.op = Operation.SUBTRACT + work.num1 = 15 + work.num2 = 10 + + diff = client.calculate(1, work) + print('15-10=%d' % diff) + + log = client.getStruct(1) + print('Check log: %s' % log.value) + + # Close! + transport.close() + + +if __name__ == '__main__': + try: + main() + except Thrift.TException as tx: + print('%s' % tx.message) diff --git a/tutorial/py/PythonServer.py b/tutorial/py/PythonServer.py new file mode 100755 index 0000000..e6421ef --- /dev/null +++ b/tutorial/py/PythonServer.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import glob +import sys +sys.path.append('gen-py') +sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) + +from tutorial import Calculator +from tutorial.ttypes import InvalidOperation, Operation + +from shared.ttypes import SharedStruct + +from thrift.transport import TSocket +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol +from thrift.server import TServer + + +class CalculatorHandler: + def __init__(self): + self.log = {} + + def ping(self): + print('ping()') + + def add(self, n1, n2): + print('add(%d,%d)' % (n1, n2)) + return n1 + n2 + + def calculate(self, logid, work): + print('calculate(%d, %r)' % (logid, work)) + + if work.op == Operation.ADD: + val = work.num1 + work.num2 + elif work.op == Operation.SUBTRACT: + val = work.num1 - work.num2 + elif work.op == Operation.MULTIPLY: + val = work.num1 * work.num2 + elif work.op == Operation.DIVIDE: + if work.num2 == 0: + x = InvalidOperation() + x.whatOp = work.op + x.why = 'Cannot divide by 0' + raise x + val = work.num1 / work.num2 + else: + x = InvalidOperation() + x.whatOp = work.op + x.why = 'Invalid operation' + raise x + + log = SharedStruct() + log.key = logid + log.value = '%d' % (val) + self.log[logid] = log + + return val + + def getStruct(self, key): + print('getStruct(%d)' % (key)) + return self.log[key] + + def zip(self): + print('zip()') + + +if __name__ == '__main__': + handler = CalculatorHandler() + processor = Calculator.Processor(handler) + transport = TSocket.TServerSocket(host='127.0.0.1', port=9090) + tfactory = TTransport.TBufferedTransportFactory() + pfactory = TBinaryProtocol.TBinaryProtocolFactory() + + server = TServer.TSimpleServer(processor, transport, tfactory, pfactory) + + # You could do one of these for a multithreaded server + # server = TServer.TThreadedServer( + # processor, transport, tfactory, pfactory) + # server = TServer.TThreadPoolServer( + # processor, transport, tfactory, pfactory) + + print('Starting the server...') + server.serve() + print('done.') diff --git a/tutorial/py/setup.cfg b/tutorial/py/setup.cfg new file mode 100644 index 0000000..2a7120a --- /dev/null +++ b/tutorial/py/setup.cfg @@ -0,0 +1,2 @@ +[flake8] +ignore = E402 diff --git a/tutorial/rb/Makefile.am b/tutorial/rb/Makefile.am new file mode 100755 index 0000000..9372413 --- /dev/null +++ b/tutorial/rb/Makefile.am @@ -0,0 +1,36 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +gen-py/calculator.rb gen-py/shared_service.rb: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen rb -r $< + +all-local: gen-py/calculator.rb + +tutorialserver: all + ${RUBY} RubyServer.rb + +tutorialclient: all + ${RUBY} RubyClient.rb + +clean-local: + $(RM) -r gen-* + +EXTRA_DIST = \ + RubyServer.rb \ + RubyClient.rb diff --git a/tutorial/rb/Makefile.in b/tutorial/rb/Makefile.in new file mode 100644 index 0000000..bc92b60 --- /dev/null +++ b/tutorial/rb/Makefile.in @@ -0,0 +1,641 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tutorial/rb +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = @THRIFT@ +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + RubyServer.rb \ + RubyClient.rb + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/rb/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tutorial/rb/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am all-local check check-am clean clean-generic \ + clean-libtool clean-local cscopelist-am ctags-am distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +gen-py/calculator.rb gen-py/shared_service.rb: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) --gen rb -r $< + +all-local: gen-py/calculator.rb + +tutorialserver: all + ${RUBY} RubyServer.rb + +tutorialclient: all + ${RUBY} RubyClient.rb + +clean-local: + $(RM) -r gen-* + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tutorial/rb/RubyClient.rb b/tutorial/rb/RubyClient.rb new file mode 100755 index 0000000..9a5aa43 --- /dev/null +++ b/tutorial/rb/RubyClient.rb @@ -0,0 +1,75 @@ +#!/usr/bin/env ruby + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +$:.push('gen-rb') +$:.unshift '../../lib/rb/lib' + +require 'thrift' + +require 'calculator' + +begin + port = ARGV[0] || 9090 + + transport = Thrift::BufferedTransport.new(Thrift::Socket.new('localhost', port)) + protocol = Thrift::BinaryProtocol.new(transport) + client = Calculator::Client.new(protocol) + + transport.open() + + client.ping() + print "ping()\n" + + sum = client.add(1,1) + print "1+1=", sum, "\n" + + sum = client.add(1,4) + print "1+4=", sum, "\n" + + work = Work.new() + + work.op = Operation::SUBTRACT + work.num1 = 15 + work.num2 = 10 + diff = client.calculate(1, work) + print "15-10=", diff, "\n" + + log = client.getStruct(1) + print "Log: ", log.value, "\n" + + begin + work.op = Operation::DIVIDE + work.num1 = 1 + work.num2 = 0 + quot = client.calculate(1, work) + puts "Whoa, we can divide by 0 now?" + rescue InvalidOperation => io + print "InvalidOperation: ", io.why, "\n" + end + + client.zip() + print "zip\n" + + transport.close() + +rescue Thrift::Exception => tx + print 'Thrift::Exception: ', tx.message, "\n" +end diff --git a/tutorial/rb/RubyServer.rb b/tutorial/rb/RubyServer.rb new file mode 100755 index 0000000..1d707d7 --- /dev/null +++ b/tutorial/rb/RubyServer.rb @@ -0,0 +1,95 @@ +#!/usr/bin/env ruby + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +$:.push('gen-rb') +$:.unshift '../../lib/rb/lib' + +require 'thrift' + +require 'calculator' +require 'shared_types' + +class CalculatorHandler + def initialize() + @log = {} + end + + def ping() + puts "ping()" + end + + def add(n1, n2) + print "add(", n1, ",", n2, ")\n" + return n1 + n2 + end + + def calculate(logid, work) + print "calculate(", logid, ", {", work.op, ",", work.num1, ",", work.num2,"})\n" + if work.op == Operation::ADD + val = work.num1 + work.num2 + elsif work.op == Operation::SUBTRACT + val = work.num1 - work.num2 + elsif work.op == Operation::MULTIPLY + val = work.num1 * work.num2 + elsif work.op == Operation::DIVIDE + if work.num2 == 0 + x = InvalidOperation.new() + x.whatOp = work.op + x.why = "Cannot divide by 0" + raise x + end + val = work.num1 / work.num2 + else + x = InvalidOperation.new() + x.whatOp = work.op + x.why = "Invalid operation" + raise x + end + + entry = SharedStruct.new() + entry.key = logid + entry.value = "#{val}" + @log[logid] = entry + + return val + + end + + def getStruct(key) + print "getStruct(", key, ")\n" + return @log[key] + end + + def zip() + print "zip\n" + end + +end + +handler = CalculatorHandler.new() +processor = Calculator::Processor.new(handler) +transport = Thrift::ServerSocket.new(9090) +transportFactory = Thrift::BufferedTransportFactory.new() +server = Thrift::SimpleServer.new(processor, transport, transportFactory) + +puts "Starting the server..." +server.serve() +puts "done." diff --git a/tutorial/rs/Cargo.toml b/tutorial/rs/Cargo.toml new file mode 100644 index 0000000..210a0da --- /dev/null +++ b/tutorial/rs/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "thrift-tutorial" +version = "0.1.0" +license = "Apache-2.0" +authors = ["Apache Thrift Developers "] +exclude = ["Makefile*", "shared.rs", "tutorial.rs"] +publish = false + +[dependencies] +clap = "<2.28.0" +ordered-float = "0.3.0" +try_from = "0.2.0" + +[dependencies.thrift] +path = "../../lib/rs" + diff --git a/tutorial/rs/Makefile.am b/tutorial/rs/Makefile.am new file mode 100644 index 0000000..666331e --- /dev/null +++ b/tutorial/rs/Makefile.am @@ -0,0 +1,52 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +THRIFT = $(top_builddir)/compiler/cpp/thrift + +gen-rs/tutorial.rs gen-rs/shared.rs: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) -out src --gen rs -r $< + +all-local: gen-rs/tutorial.rs + $(CARGO) build + [ -d bin ] || mkdir bin + cp target/debug/tutorial_server bin/tutorial_server + cp target/debug/tutorial_client bin/tutorial_client + +check: all + +tutorialserver: all + bin/tutorial_server + +tutorialclient: all + bin/tutorial_client + +clean-local: + $(CARGO) clean + -$(RM) Cargo.lock + -$(RM) src/shared.rs + -$(RM) src/tutorial.rs + -$(RM) -r bin + +EXTRA_DIST = \ + Cargo.toml \ + src/lib.rs \ + src/bin/tutorial_server.rs \ + src/bin/tutorial_client.rs \ + README.md + diff --git a/tutorial/rs/Makefile.in b/tutorial/rs/Makefile.in new file mode 100644 index 0000000..28c1012 --- /dev/null +++ b/tutorial/rs/Makefile.in @@ -0,0 +1,654 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tutorial/rs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ac_prog_bison.m4 \ + $(top_srcdir)/aclocal/ax_boost_base.m4 \ + $(top_srcdir)/aclocal/ax_check_openssl.m4 \ + $(top_srcdir)/aclocal/ax_compare_version.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/aclocal/ax_cxx_compile_stdcxx_11.m4 \ + $(top_srcdir)/aclocal/ax_dmd.m4 \ + $(top_srcdir)/aclocal/ax_javac_and_java.m4 \ + $(top_srcdir)/aclocal/ax_lib_event.m4 \ + $(top_srcdir)/aclocal/ax_lib_zlib.m4 \ + $(top_srcdir)/aclocal/ax_lua.m4 \ + $(top_srcdir)/aclocal/ax_prog_dotnetcore_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_haxe_version.m4 \ + $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/aclocal/ax_signed_right_shift.m4 \ + $(top_srcdir)/aclocal/ax_thrift_internal.m4 \ + $(top_srcdir)/aclocal/libtool.m4 \ + $(top_srcdir)/aclocal/ltoptions.m4 \ + $(top_srcdir)/aclocal/ltsugar.m4 \ + $(top_srcdir)/aclocal/ltversion.m4 \ + $(top_srcdir)/aclocal/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/lib/cpp/src/thrift/config.h \ + $(top_builddir)/lib/c_glib/src/thrift/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__extra_recursive_targets = style-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +ANT = @ANT@ +ANT_FLAGS = @ANT_FLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON = @BISON@ +BOOST_CHRONO_LDADD = @BOOST_CHRONO_LDADD@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDADD = @BOOST_FILESYSTEM_LDADD@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +BOOST_LIB_DIR = @BOOST_LIB_DIR@ +BOOST_SYSTEM_LDADD = @BOOST_SYSTEM_LDADD@ +BOOST_TEST_LDADD = @BOOST_TEST_LDADD@ +BOOST_THREAD_LDADD = @BOOST_THREAD_LDADD@ +BUNDLER = @BUNDLER@ +CABAL = @CABAL@ +CABAL_CONFIGURE_FLAGS = @CABAL_CONFIGURE_FLAGS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLASSPATH = @CLASSPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPSTYLE_CMD = @CPPSTYLE_CMD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DART = @DART@ +DARTPUB = @DARTPUB@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DMD = @DMD@ +DMD_LIBEVENT_FLAGS = @DMD_LIBEVENT_FLAGS@ +DMD_OF_DIRSEP = @DMD_OF_DIRSEP@ +DMD_OPENSSL_FLAGS = @DMD_OPENSSL_FLAGS@ +DOTNETCORE = @DOTNETCORE@ +DOTNETCORE_VERSION = @DOTNETCORE_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +D_EVENT_LIB_NAME = @D_EVENT_LIB_NAME@ +D_IMPORT_PREFIX = @D_IMPORT_PREFIX@ +D_LIB_NAME = @D_LIB_NAME@ +D_SSL_LIB_NAME = @D_SSL_LIB_NAME@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_COVERAGE = @ENABLE_COVERAGE@ +ERL = @ERL@ +ERLANG_INSTALL_LIB_DIR = @ERLANG_INSTALL_LIB_DIR@ +ERLANG_INSTALL_LIB_DIR_thrift = @ERLANG_INSTALL_LIB_DIR_thrift@ +ERLANG_LIB_DIR = @ERLANG_LIB_DIR@ +ERLC = @ERLC@ +ERLCFLAGS = @ERLCFLAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_CXXFLAGS = @GCOV_CXXFLAGS@ +GCOV_LDFLAGS = @GCOV_LDFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GO = @GO@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +HAXE = @HAXE@ +HAXE_VERSION = @HAXE_VERSION@ +INSTALL = @INSTALL@ +INSTALLDIRS = @INSTALLDIRS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA_PREFIX = @JAVA_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBEVENT_CPPFLAGS = @LIBEVENT_CPPFLAGS@ +LIBEVENT_LDFLAGS = @LIBEVENT_LDFLAGS@ +LIBEVENT_LIBS = @LIBEVENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA = @LUA@ +LUA_EXEC_PREFIX = @LUA_EXEC_PREFIX@ +LUA_INCLUDE = @LUA_INCLUDE@ +LUA_LIB = @LUA_LIB@ +LUA_PLATFORM = @LUA_PLATFORM@ +LUA_PREFIX = @LUA_PREFIX@ +LUA_SHORT_VERSION = @LUA_SHORT_VERSION@ +LUA_VERSION = @LUA_VERSION@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAYBE_CPP = @MAYBE_CPP@ +MAYBE_CSHARP = @MAYBE_CSHARP@ +MAYBE_C_GLIB = @MAYBE_C_GLIB@ +MAYBE_D = @MAYBE_D@ +MAYBE_DART = @MAYBE_DART@ +MAYBE_DOTNETCORE = @MAYBE_DOTNETCORE@ +MAYBE_ERLANG = @MAYBE_ERLANG@ +MAYBE_GO = @MAYBE_GO@ +MAYBE_HASKELL = @MAYBE_HASKELL@ +MAYBE_JAVA = @MAYBE_JAVA@ +MAYBE_LUA = @MAYBE_LUA@ +MAYBE_NODEJS = @MAYBE_NODEJS@ +MAYBE_PERL = @MAYBE_PERL@ +MAYBE_PHP = @MAYBE_PHP@ +MAYBE_PY3 = @MAYBE_PY3@ +MAYBE_PYTHON = @MAYBE_PYTHON@ +MAYBE_RS = @MAYBE_RS@ +MAYBE_RUBY = @MAYBE_RUBY@ +MCS = @MCS@ +MKDIR_P = @MKDIR_P@ +MONO_CFLAGS = @MONO_CFLAGS@ +MONO_LIBS = @MONO_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NODEJS = @NODEJS@ +NPM = @NPM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_PREFIX = @PERL_PREFIX@ +PHP = @PHP@ +PHPUNIT = @PHPUNIT@ +PHP_CONFIG = @PHP_CONFIG@ +PHP_CONFIG_PREFIX = @PHP_CONFIG_PREFIX@ +PHP_PREFIX = @PHP_PREFIX@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_PREFIX = @PY_PREFIX@ +QT5_CFLAGS = @QT5_CFLAGS@ +QT5_LIBS = @QT5_LIBS@ +QT5_MOC = @QT5_MOC@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +QT_MOC = @QT_MOC@ +RANLIB = @RANLIB@ +REBAR = @REBAR@ +RUBY = @RUBY@ +RUBY_PREFIX = @RUBY_PREFIX@ +RUNHASKELL = @RUNHASKELL@ +RUSTC = @RUSTC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +THRIFT = $(top_builddir)/compiler/cpp/thrift +TRIAL = @TRIAL@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ +ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +golang_version = @golang_version@ +have_prog_bison = @have_prog_bison@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +luadir = @luadir@ +luaexecdir = @luaexecdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgluadir = @pkgluadir@ +pkgluaexecdir = @pkgluaexecdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +rustc_version = @rustc_version@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + Cargo.toml \ + src/lib.rs \ + src/bin/tutorial_server.rs \ + src/bin/tutorial_client.rs \ + README.md + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tutorial/rs/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tutorial/rs/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +style-local: +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +style: style-am + +style-am: style-local + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am all-local check check-am clean clean-generic \ + clean-libtool clean-local cscopelist-am ctags-am distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am style-am style-local \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +gen-rs/tutorial.rs gen-rs/shared.rs: $(top_srcdir)/tutorial/tutorial.thrift + $(THRIFT) -out src --gen rs -r $< + +all-local: gen-rs/tutorial.rs + $(CARGO) build + [ -d bin ] || mkdir bin + cp target/debug/tutorial_server bin/tutorial_server + cp target/debug/tutorial_client bin/tutorial_client + +check: all + +tutorialserver: all + bin/tutorial_server + +tutorialclient: all + bin/tutorial_client + +clean-local: + $(CARGO) clean + -$(RM) Cargo.lock + -$(RM) src/shared.rs + -$(RM) src/tutorial.rs + -$(RM) -r bin + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tutorial/rs/README.md b/tutorial/rs/README.md new file mode 100644 index 0000000..384e9f8 --- /dev/null +++ b/tutorial/rs/README.md @@ -0,0 +1,317 @@ +# Rust Language Bindings for Thrift + +## Getting Started + +1. Get the [Thrift compiler](https://thrift.apache.org). + +2. Add the following crates to your `Cargo.toml`. + +```toml +thrift = "x.y.z" # x.y.z is the version of the thrift compiler +ordered_float = "0.3.0" +try_from = "0.2.0" +``` + +3. Add the same crates to your `lib.rs` or `main.rs`. + +```rust +extern crate ordered_float; +extern crate thrift; +extern crate try_from; +``` + +4. Generate Rust sources for your IDL (for example, `Tutorial.thrift`). + +```shell +thrift -out my_rust_program/src --gen rs -r Tutorial.thrift +``` + +5. Use the generated source in your code. + +```rust +// add extern crates here, or in your lib.rs +extern crate ordered_float; +extern crate thrift; +extern crate try_from; + +// generated Rust module +use tutorial; + +use thrift::protocol::{TCompactInputProtocol, TCompactOutputProtocol}; +use thrift::protocol::{TInputProtocol, TOutputProtocol}; +use thrift::transport::{TFramedReadTransport, TFramedWriteTransport}; +use thrift::transport::{TIoChannel, TTcpChannel}; +use tutorial::{CalculatorSyncClient, TCalculatorSyncClient}; +use tutorial::{Operation, Work}; + +fn main() { + match run() { + Ok(()) => println!("client ran successfully"), + Err(e) => { + println!("client failed with {:?}", e); + std::process::exit(1); + } + } +} + +fn run() -> thrift::Result<()> { + // + // build client + // + + println!("connect to server on 127.0.0.1:9090"); + let mut c = TTcpTransport::new(); + c.open("127.0.0.1:9090")?; + + let (i_chan, o_chan) = c.split()?; + + let i_prot = TCompactInputProtocol::new( + TFramedReadTransport::new(i_chan) + ); + let o_prot = TCompactOutputProtocol::new( + TFramedWriteTransport::new(o_chan) + ); + + let client = CalculatorSyncClient::new(i_prot, o_prot); + + // + // alright! - let's make some calls + // + + // two-way, void return + client.ping()?; + + // two-way with some return + let res = client.calculate( + 72, + Work::new(7, 8, Operation::MULTIPLY, None) + )?; + println!("multiplied 7 and 8, got {}", res); + + // two-way and returns a Thrift-defined exception + let res = client.calculate( + 77, + Work::new(2, 0, Operation::DIVIDE, None) + ); + match res { + Ok(v) => panic!("shouldn't have succeeded with result {}", v), + Err(e) => println!("divide by zero failed with {:?}", e), + } + + // one-way + client.zip()?; + + // done! + Ok(()) +} +``` + +## Code Generation + +### Thrift Files and Generated Modules + +The Thrift code generator takes each Thrift file and generates a Rust module +with the same name snake-cased. For example, running the compiler on +`ThriftTest.thrift` creates `thrift_test.rs`. To use these generated files add +`mod ...` and `use ...` declarations to your `lib.rs` or `main.rs` - one for +each generated file. + +### Results and Errors + +The Thrift runtime library defines a `thrift::Result` and a `thrift::Error` type, +both of which are used throught the runtime library and in all generated code. +Conversions are defined from `std::io::Error`, `str` and `String` into +`thrift::Error`. + +### Thrift Type and their Rust Equivalents + +Thrift defines a number of types, each of which is translated into its Rust +equivalent by the code generator. + +* Primitives (bool, i8, i16, i32, i64, double, string, binary) +* Typedefs +* Enums +* Containers +* Structs +* Unions +* Exceptions +* Services +* Constants (primitives, containers, structs) + +In addition, unless otherwise noted, thrift includes are translated into +`use ...` statements in the generated code, and all declarations, parameters, +traits and types in the generated code are namespaced appropriately. + +The following subsections cover each type and their generated Rust equivalent. + +### Primitives + +Thrift primitives have straightforward Rust equivalents. + +* bool: `bool` +* i8: `i8` +* i16: `i16` +* i32: `i32` +* i64: `i64` +* double: `OrderedFloat` +* string: `String` +* binary: `Vec` + +### Typedefs + +A typedef is translated to a `pub type` declaration. + +```thrift +typedef i64 UserId + +typedef map MapType +``` +```rust +pub type UserId = i64; + +pub type MapType = BTreeMap; +``` + +### Enums + +A Thrift enum is represented as a Rust enum, and each variant is transcribed 1:1. + +```thrift +enum Numberz +{ + ONE = 1, + TWO, + THREE, + FIVE = 5, + SIX, + EIGHT = 8 +} +``` + +```rust +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum Numberz { + ONE = 1, + TWO = 2, + THREE = 3, + FIVE = 5, + SIX = 6, + EIGHT = 8, +} + +impl TryFrom for Numberz { + // ... +} + +``` + +### Containers + +Thrift has three container types: list, set and map. They are translated into +Rust `Vec`, `BTreeSet` and `BTreeMap` respectively. Any Thrift type (this +includes structs, enums and typedefs) can be a list/set element or a map +key/value. + +#### List + +```thrift +list numbers +``` + +```rust +numbers: Vec +``` + +#### Set + +```thrift +set numbers +``` + +```rust +numbers: BTreeSet +``` + +#### Map + +```thrift +map numbers +``` + +```rust +numbers: BTreeMap +``` + +### Structs + +A Thrift struct is represented as a Rust struct, and each field transcribed 1:1. + +```thrift +struct CrazyNesting { + 1: string string_field, + 2: optional set set_field, + 3: required list< + map, map>>>> + > + 4: binary binary_field +} +``` +```rust +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct CrazyNesting { + pub string_field: Option, + pub set_field: Option>, + pub list_field: Vec< + BTreeMap< + BTreeSet, + BTreeMap>>> + > + >, + pub binary_field: Option>, +} + +impl CrazyNesting { + pub fn read_from_in_protocol(i_prot: &mut TInputProtocol) + -> + thrift::Result { + // ... + } + pub fn write_to_out_protocol(&self, o_prot: &mut TOutputProtocol) + -> + thrift::Result<()> { + // ... + } +} + +``` +##### Optionality + +Thrift has 3 "optionality" types: + +1. Required +2. Optional +3. Default + +The Rust code generator encodes *Required* fields as the bare type itself, while +*Optional* and *Default* fields are encoded as `Option`. + +```thrift +struct Foo { + 1: required string bar // 1. required + 2: optional string baz // 2. optional + 3: string qux // 3. default +} +``` + +```rust +pub struct Foo { + bar: String, // 1. required + baz: Option, // 2. optional + qux: Option, // 3. default +} +``` + +## Known Issues + +* Struct constants are not supported +* Map, list and set constants require a const holder struct diff --git a/tutorial/rs/src/bin/tutorial_client.rs b/tutorial/rs/src/bin/tutorial_client.rs new file mode 100644 index 0000000..24ab4be --- /dev/null +++ b/tutorial/rs/src/bin/tutorial_client.rs @@ -0,0 +1,131 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#[macro_use] +extern crate clap; + +extern crate thrift; +extern crate thrift_tutorial; + +use thrift::protocol::{TCompactInputProtocol, TCompactOutputProtocol}; +use thrift::transport::{ReadHalf, TFramedReadTransport, TFramedWriteTransport, TIoChannel, + TTcpChannel, WriteHalf}; + +use thrift_tutorial::shared::TSharedServiceSyncClient; +use thrift_tutorial::tutorial::{CalculatorSyncClient, Operation, TCalculatorSyncClient, Work}; + +fn main() { + match run() { + Ok(()) => println!("tutorial client ran successfully"), + Err(e) => { + println!("tutorial client failed with error {:?}", e); + std::process::exit(1); + } + } +} + +fn run() -> thrift::Result<()> { + let options = clap_app!(rust_tutorial_client => + (version: "0.1.0") + (author: "Apache Thrift Developers ") + (about: "Thrift Rust tutorial client") + (@arg host: --host +takes_value "host on which the tutorial server listens") + (@arg port: --port +takes_value "port on which the tutorial server listens") + ); + let matches = options.get_matches(); + + // get any passed-in args or the defaults + let host = matches.value_of("host").unwrap_or("127.0.0.1"); + let port = value_t!(matches, "port", u16).unwrap_or(9090); + + // build our client and connect to the host:port + let mut client = new_client(host, port)?; + + // alright! + // let's start making some calls + + // let's start with a ping; the server should respond + println!("ping!"); + client.ping()?; + + // simple add + println!("add"); + let res = client.add(1, 2)?; + println!("added 1, 2 and got {}", res); + + let logid = 32; + + // let's do...a multiply! + let res = client + .calculate(logid, Work::new(7, 8, Operation::MULTIPLY, None))?; + println!("multiplied 7 and 8 and got {}", res); + + // let's get the log for it + let res = client.get_struct(32)?; + println!("got log {:?} for operation {}", res, logid); + + // ok - let's be bad :( + // do a divide by 0 + // logid doesn't matter; won't be recorded + let res = client.calculate(77, Work::new(2, 0, Operation::DIVIDE, "we bad".to_owned())); + + // we should have gotten an exception back + match res { + Ok(v) => panic!("should not have succeeded with result {}", v), + Err(e) => println!("divide by zero failed with error {:?}", e), + } + + // let's do a one-way call + println!("zip"); + client.zip()?; + + // and then close out with a final ping + println!("ping!"); + client.ping()?; + + Ok(()) +} + +type ClientInputProtocol = TCompactInputProtocol>>; +type ClientOutputProtocol = TCompactOutputProtocol>>; + +fn new_client + ( + host: &str, + port: u16, +) -> thrift::Result> { + let mut c = TTcpChannel::new(); + + // open the underlying TCP stream + println!("connecting to tutorial server on {}:{}", host, port); + c.open(&format!("{}:{}", host, port))?; + + // clone the TCP channel into two halves, one which + // we'll use for reading, the other for writing + let (i_chan, o_chan) = c.split()?; + + // wrap the raw sockets (slow) with a buffered transport of some kind + let i_tran = TFramedReadTransport::new(i_chan); + let o_tran = TFramedWriteTransport::new(o_chan); + + // now create the protocol implementations + let i_prot = TCompactInputProtocol::new(i_tran); + let o_prot = TCompactOutputProtocol::new(o_tran); + + // we're done! + Ok(CalculatorSyncClient::new(i_prot, o_prot)) +} diff --git a/tutorial/rs/src/bin/tutorial_server.rs b/tutorial/rs/src/bin/tutorial_server.rs new file mode 100644 index 0000000..8db8eed --- /dev/null +++ b/tutorial/rs/src/bin/tutorial_server.rs @@ -0,0 +1,176 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#[macro_use] +extern crate clap; + +extern crate thrift; +extern crate thrift_tutorial; + +use std::collections::HashMap; +use std::convert::{From, Into}; +use std::default::Default; +use std::sync::Mutex; + +use thrift::protocol::{TCompactInputProtocolFactory, TCompactOutputProtocolFactory}; +use thrift::server::TServer; + +use thrift::transport::{TFramedReadTransportFactory, TFramedWriteTransportFactory}; +use thrift_tutorial::shared::{SharedServiceSyncHandler, SharedStruct}; +use thrift_tutorial::tutorial::{CalculatorSyncHandler, CalculatorSyncProcessor}; +use thrift_tutorial::tutorial::{InvalidOperation, Operation, Work}; + +fn main() { + match run() { + Ok(()) => println!("tutorial server ran successfully"), + Err(e) => { + println!("tutorial server failed with error {:?}", e); + std::process::exit(1); + } + } +} + +fn run() -> thrift::Result<()> { + let options = clap_app!(rust_tutorial_server => + (version: "0.1.0") + (author: "Apache Thrift Developers ") + (about: "Thrift Rust tutorial server") + (@arg port: --port +takes_value "port on which the tutorial server listens") + ); + let matches = options.get_matches(); + + let port = value_t!(matches, "port", u16).unwrap_or(9090); + let listen_address = format!("127.0.0.1:{}", port); + + println!("binding to {}", listen_address); + + let i_tran_fact = TFramedReadTransportFactory::new(); + let i_prot_fact = TCompactInputProtocolFactory::new(); + + let o_tran_fact = TFramedWriteTransportFactory::new(); + let o_prot_fact = TCompactOutputProtocolFactory::new(); + + // demux incoming messages + let processor = CalculatorSyncProcessor::new(CalculatorServer { ..Default::default() }); + + // create the server and start listening + let mut server = TServer::new( + i_tran_fact, + i_prot_fact, + o_tran_fact, + o_prot_fact, + processor, + 10, + ); + + server.listen(&listen_address) +} + +/// Handles incoming Calculator service calls. +struct CalculatorServer { + log: Mutex>, +} + +impl Default for CalculatorServer { + fn default() -> CalculatorServer { + CalculatorServer { log: Mutex::new(HashMap::new()) } + } +} + +// since Calculator extends SharedService we have to implement the +// handler for both traits. +// + +// SharedService handler +impl SharedServiceSyncHandler for CalculatorServer { + fn handle_get_struct(&self, key: i32) -> thrift::Result { + let log = self.log.lock().unwrap(); + log.get(&key) + .cloned() + .ok_or_else(|| format!("could not find log for key {}", key).into()) + } +} + +// Calculator handler +impl CalculatorSyncHandler for CalculatorServer { + fn handle_ping(&self) -> thrift::Result<()> { + println!("pong!"); + Ok(()) + } + + fn handle_add(&self, num1: i32, num2: i32) -> thrift::Result { + println!("handling add: n1:{} n2:{}", num1, num2); + Ok(num1 + num2) + } + + fn handle_calculate(&self, logid: i32, w: Work) -> thrift::Result { + println!("handling calculate: l:{}, w:{:?}", logid, w); + + let res = if let Some(ref op) = w.op { + if w.num1.is_none() || w.num2.is_none() { + Err( + InvalidOperation { + what_op: Some(*op as i32), + why: Some("no operands specified".to_owned()), + }, + ) + } else { + // so that I don't have to call unwrap() multiple times below + let num1 = w.num1.as_ref().expect("operands checked"); + let num2 = w.num2.as_ref().expect("operands checked"); + + match *op { + Operation::ADD => Ok(num1 + num2), + Operation::SUBTRACT => Ok(num1 - num2), + Operation::MULTIPLY => Ok(num1 * num2), + Operation::DIVIDE => { + if *num2 == 0 { + Err( + InvalidOperation { + what_op: Some(*op as i32), + why: Some("divide by 0".to_owned()), + }, + ) + } else { + Ok(num1 / num2) + } + } + } + } + } else { + Err(InvalidOperation::new(None, "no operation specified".to_owned()),) + }; + + // if the operation was successful log it + if let Ok(ref v) = res { + let mut log = self.log.lock().unwrap(); + log.insert(logid, SharedStruct::new(logid, format!("{}", v))); + } + + // the try! macro automatically maps errors + // but, since we aren't using that here we have to map errors manually + // + // exception structs defined in the IDL have an auto-generated + // impl of From::from + res.map_err(From::from) + } + + fn handle_zip(&self) -> thrift::Result<()> { + println!("handling zip"); + Ok(()) + } +} diff --git a/tutorial/rs/src/lib.rs b/tutorial/rs/src/lib.rs new file mode 100644 index 0000000..40007e5 --- /dev/null +++ b/tutorial/rs/src/lib.rs @@ -0,0 +1,23 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +extern crate ordered_float; +extern crate thrift; +extern crate try_from; + +pub mod shared; +pub mod tutorial; diff --git a/tutorial/shared.thrift b/tutorial/shared.thrift new file mode 100644 index 0000000..3cc1bb3 --- /dev/null +++ b/tutorial/shared.thrift @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * This Thrift file can be included by other Thrift files that want to share + * these definitions. + */ + +namespace cpp shared +namespace d share // "shared" would collide with the eponymous D keyword. +namespace dart shared +namespace java shared +namespace perl shared +namespace php shared +namespace haxe shared +namespace netcore shared + +struct SharedStruct { + 1: i32 key + 2: string value +} + +service SharedService { + SharedStruct getStruct(1: i32 key) +} diff --git a/tutorial/tutorial.thrift b/tutorial/tutorial.thrift new file mode 100644 index 0000000..f8c5320 --- /dev/null +++ b/tutorial/tutorial.thrift @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +# Thrift Tutorial +# Mark Slee (mcslee@facebook.com) +# +# This file aims to teach you how to use Thrift, in a .thrift file. Neato. The +# first thing to notice is that .thrift files support standard shell comments. +# This lets you make your thrift file executable and include your Thrift build +# step on the top line. And you can place comments like this anywhere you like. +# +# Before running this file, you will need to have installed the thrift compiler +# into /usr/local/bin. + +/** + * The first thing to know about are types. The available types in Thrift are: + * + * bool Boolean, one byte + * i8 (byte) Signed 8-bit integer + * i16 Signed 16-bit integer + * i32 Signed 32-bit integer + * i64 Signed 64-bit integer + * double 64-bit floating point value + * string String + * binary Blob (byte array) + * map Map from one type to another + * list Ordered list of one type + * set Set of unique elements of one type + * + * Did you also notice that Thrift supports C style comments? + */ + +// Just in case you were wondering... yes. We support simple C comments too. + +/** + * Thrift files can reference other Thrift files to include common struct + * and service definitions. These are found using the current path, or by + * searching relative to any paths specified with the -I compiler flag. + * + * Included objects are accessed using the name of the .thrift file as a + * prefix. i.e. shared.SharedObject + */ +include "shared.thrift" + +/** + * Thrift files can namespace, package, or prefix their output in various + * target languages. + */ +namespace cpp tutorial +namespace d tutorial +namespace dart tutorial +namespace java tutorial +namespace php tutorial +namespace perl tutorial +namespace haxe tutorial +namespace netcore tutorial + +/** + * Thrift lets you do typedefs to get pretty names for your types. Standard + * C style here. + */ +typedef i32 MyInteger + +/** + * Thrift also lets you define constants for use across languages. Complex + * types and structs are specified using JSON notation. + */ +const i32 INT32CONSTANT = 9853 +const map MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} + +/** + * You can define enums, which are just 32 bit integers. Values are optional + * and start at 1 if not supplied, C style again. + */ +enum Operation { + ADD = 1, + SUBTRACT = 2, + MULTIPLY = 3, + DIVIDE = 4 +} + +/** + * Structs are the basic complex data structures. They are comprised of fields + * which each have an integer identifier, a type, a symbolic name, and an + * optional default value. + * + * Fields can be declared "optional", which ensures they will not be included + * in the serialized output if they aren't set. Note that this requires some + * manual management in some languages. + */ +struct Work { + 1: i32 num1 = 0, + 2: i32 num2, + 3: Operation op, + 4: optional string comment, +} + +/** + * Structs can also be exceptions, if they are nasty. + */ +exception InvalidOperation { + 1: i32 whatOp, + 2: string why +} + +/** + * Ahh, now onto the cool part, defining a service. Services just need a name + * and can optionally inherit from another service using the extends keyword. + */ +service Calculator extends shared.SharedService { + + /** + * A method definition looks like C code. It has a return type, arguments, + * and optionally a list of exceptions that it may throw. Note that argument + * lists and exception lists are specified using the exact same syntax as + * field lists in struct or exception definitions. + */ + + void ping(), + + i32 add(1:i32 num1, 2:i32 num2), + + i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), + + /** + * This method has a oneway modifier. That means the client only makes + * a request and does not listen for any response at all. Oneway methods + * must be void. + */ + oneway void zip() + +} + +/** + * That just about covers the basics. Take a look in the test/ folder for more + * detailed examples. After you run this file, your generated code shows up + * in folders with names gen-. The generated code isn't too scary + * to look at. It even has pretty indentation. + */ diff --git a/ylwrap b/ylwrap new file mode 100755 index 0000000..7c2d927 --- /dev/null +++ b/ylwrap @@ -0,0 +1,247 @@ +#! /bin/sh +# ylwrap - wrapper for lex/yacc invocations. + +scriptversion=2013-01-12.17; # UTC + +# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +get_dirname () +{ + case $1 in + */*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';; + # Otherwise, we want the empty string (not "."). + esac +} + +# guard FILE +# ---------- +# The CPP macro used to guard inclusion of FILE. +guard () +{ + printf '%s\n' "$1" \ + | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g' \ + -e 's/__*/_/g' +} + +# quote_for_sed [STRING] +# ---------------------- +# Return STRING (or stdin) quoted to be used as a sed pattern. +quote_for_sed () +{ + case $# in + 0) cat;; + 1) printf '%s\n' "$1";; + esac \ + | sed -e 's|[][\\.*]|\\&|g' +} + +case "$1" in + '') + echo "$0: No files given. Try '$0 --help' for more information." 1>&2 + exit 1 + ;; + --basedir) + basedir=$2 + shift 2 + ;; + -h|--h*) + cat <<\EOF +Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... + +Wrapper for lex/yacc invocations, renaming files as desired. + + INPUT is the input file + OUTPUT is one file PROG generates + DESIRED is the file we actually want instead of OUTPUT + PROGRAM is program to run + ARGS are passed to PROG + +Any number of OUTPUT,DESIRED pairs may be used. + +Report bugs to . +EOF + exit $? + ;; + -v|--v*) + echo "ylwrap $scriptversion" + exit $? + ;; +esac + + +# The input. +input=$1 +shift +# We'll later need for a correct munging of "#line" directives. +input_sub_rx=`get_dirname "$input" | quote_for_sed` +case $input in + [\\/]* | ?:[\\/]*) + # Absolute path; do nothing. + ;; + *) + # Relative path. Make it absolute. + input=`pwd`/$input + ;; +esac +input_rx=`get_dirname "$input" | quote_for_sed` + +# Since DOS filename conventions don't allow two dots, +# the DOS version of Bison writes out y_tab.c instead of y.tab.c +# and y_tab.h instead of y.tab.h. Test to see if this is the case. +y_tab_nodot=false +if test -f y_tab.c || test -f y_tab.h; then + y_tab_nodot=true +fi + +# The parser itself, the first file, is the destination of the .y.c +# rule in the Makefile. +parser=$1 + +# A sed program to s/FROM/TO/g for all the FROM/TO so that, for +# instance, we rename #include "y.tab.h" into #include "parse.h" +# during the conversion from y.tab.c to parse.c. +sed_fix_filenames= + +# Also rename header guards, as Bison 2.7 for instance uses its header +# guard in its implementation file. +sed_fix_header_guards= + +while test $# -ne 0; do + if test x"$1" = x"--"; then + shift + break + fi + from=$1 + # Handle y_tab.c and y_tab.h output by DOS + if $y_tab_nodot; then + case $from in + "y.tab.c") from=y_tab.c;; + "y.tab.h") from=y_tab.h;; + esac + fi + shift + to=$1 + shift + sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;" + sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;" +done + +# The program to run. +prog=$1 +shift +# Make any relative path in $prog absolute. +case $prog in + [\\/]* | ?:[\\/]*) ;; + *[\\/]*) prog=`pwd`/$prog ;; +esac + +dirname=ylwrap$$ +do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret' +trap "ret=129; $do_exit" 1 +trap "ret=130; $do_exit" 2 +trap "ret=141; $do_exit" 13 +trap "ret=143; $do_exit" 15 +mkdir $dirname || exit 1 + +cd $dirname + +case $# in + 0) "$prog" "$input" ;; + *) "$prog" "$@" "$input" ;; +esac +ret=$? + +if test $ret -eq 0; then + for from in * + do + to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"` + if test -f "$from"; then + # If $2 is an absolute path name, then just use that, + # otherwise prepend '../'. + case $to in + [\\/]* | ?:[\\/]*) target=$to;; + *) target=../$to;; + esac + + # Do not overwrite unchanged header files to avoid useless + # recompilations. Always update the parser itself: it is the + # destination of the .y.c rule in the Makefile. Divert the + # output of all other files to a temporary file so we can + # compare them to existing versions. + if test $from != $parser; then + realtarget=$target + target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'` + fi + + # Munge "#line" or "#" directives. Don't let the resulting + # debug information point at an absolute srcdir. Use the real + # output file name, not yy.lex.c for instance. Adjust the + # include guards too. + sed -e "/^#/!b" \ + -e "s|$input_rx|$input_sub_rx|" \ + -e "$sed_fix_filenames" \ + -e "$sed_fix_header_guards" \ + "$from" >"$target" || ret=$? + + # Check whether files must be updated. + if test "$from" != "$parser"; then + if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then + echo "$to is unchanged" + rm -f "$target" + else + echo "updating $to" + mv -f "$target" "$realtarget" + fi + fi + else + # A missing file is only an error for the parser. This is a + # blatant hack to let us support using "yacc -d". If -d is not + # specified, don't fail when the header file is "missing". + if test "$from" = "$parser"; then + ret=1 + fi + fi + done +fi + +# Remove the directory. +cd .. +rm -rf $dirname + +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: -- 2.30.2